I had some success today getting FCKeditor to place nice with AJAX so that it will work for edit-in-line in the same way that Flickr works.
The trick with using FCKeditor and AJAX is that the content you want to edit is often whole paragraphs of text and markup. Grabbing the whole of that content straight from an existing <div> just doesn’t work because it is considered an object array by the DOM. What you’ll end up with when you grab the content is just the text - no markup.
So, as I indicated in my earlier post, you need to do the following:
- Dynamically create a textarea box and give it a name and an id
- Ask your database for the content as text, including all its markup
- Put the content into the textarea
- Create an instance of FCKeditor using the same name as the textarea
- Use oFCKeditor.ReplaceTextarea(); to swap the textarea with the FCKeditor
It’s important to be mindful of some posts around the place that suggest that, for Firefox to play nice with AJAX, you need to set the FCkeditor to null.
FCKeditorAPI = null;
__FCKeditorNS = null;
What I found was that it just made sure that the FCKeditor couldn’t be referenced once it was created (because it was null). So, I just removed it and it worked fine in Firefox.
So, enough with the commentary, let’s begin!
The main ajax functions are called by an onclick on the content:
<div id=”story” onclick=”javascript:fetchAndLoadFCKeditor(’http://mysite.com/form.php’, ‘content=myDatabaseID’,'FCKeditor1′ );”>
<!– begin content from database –>
<div id=”story-content”>
<p>Here is some nice content.</p>
<p>Isn’t it <a href=”nice.php”>nice</a></p>
</div>
<!– end content from database –>
</div>
I use AJAX to go fetch the content blob from a database via a little widget. It waits until the response and then uses the content returned to stick into the FCKeditor.
For fetch of content is particularly important for me because my content is in xml and, via xsl, the content I show on the page has special extra bits, like automated generation of title=”more information about”. I don’t want this to appear for editing, so I need to fetch a more plain version of the content for editing.
function fetchAndLoadFCKeditor(url, parameters, editorname) {
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, …
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType(’text/xml’);
// See note below about this line
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject(”MSXML4.XMLHTTP”);
} catch (e) {
try {
http_request = new ActiveXObject(”Microsoft.XMLHTTP”);
} catch (e) {}
}
}
if (!http_request) {
alert(’Giving up
Cannot create an XMLHTTP instance’);
return false;
}
http_request.onreadystatechange = function() {
var strText = alertContents(http_request);
if (strText == ‘undefined’) {
//do something … anything you like … replaceContentInLayer (’story’, ‘Loading…’);
} else {
//this is where the interesting stuff begins
// basically, we’re going to dynamically create content, including the FCKeditor
//first, we need a reference point for these new layers - <div id=”story”>
var targetLayer = document.getElementById(’story’);
//create a textarea layer ..note that editorname will be used again for the instance name
//for the FCKeditor
var textarea = document.createElement(’textarea’);
textarea.setAttribute(’id’, editorname);
textarea.setAttribute(’name’, editorname);
//create a submit button
var someSubmitButton = document.createElement(’button’);
someSubmitButton.setAttribute(’id’, ’submitAjaxForm’);
someSubmitButton.setAttribute(’name’, ’submitAjaxForm’);
someSubmitButton.setAttribute(’value’, ‘Submit’);
//this is a browser detect script because IE uses different event handlers than does FF
if(typeof someSubmitButton.addEventListener != ‘undefined’) {
someSubmitButton.addEventListener(’click’, submitFCKform, false);
}
else if(typeof someSubmitButton.addEventListener != ‘undefined’) {
someSubmitButton.addEventListener(’click’, submitFCKform, false);
}
else if(typeof someSubmitButton.attachEvent != ‘undefined’) {
someSubmitButton.attachEvent(’onclick’, submitFCKform);
}
//create a cancel button
var someCancelButton = document.createElement(’button’);
someCancelButton.setAttribute(’id’, ‘cancelAjaxForm’);
someCancelButton.setAttribute(’name’, ‘cancelAjaxForm’);
someCancelButton.setAttribute(’value’, ‘Cancel’);
//again, use the browser detect script because IE uses different event stuffs than FF
if(typeof someSubmitButton.addEventListener != ‘undefined’) {
someCancelButton.addEventListener(’click’, cancelFCKform, false);
}
else if(typeof someSubmitButton.addEventListener != ‘undefined’) {
someCancelButton.addEventListener(’click’, cancelFCKform, false);
}
else if(typeof someSubmitButton.attachEvent != ‘undefined’) {
someCancelButton.attachEvent(’onclick’, cancelFCKform);
}
//we now use the <div id=”story”> layer as the target point for where
// we are gonna put the textarea
targetLayer.appendChild(textarea);
targetLayer.parentNode.appendChild(someSubmitButton);
targetLayer.parentNode.appendChild(someCancelButton);
//now we use the strText we grabbed to set the value of the textarea
textarea.value = strText;
//lastly, we create fckeditor
var oFCKeditor = new FCKeditor(editorname);
oFCKeditor.BasePath = ‘/somepath/FCKeditor/’ ;
//using the ReplaceTextarea() allows us to create the FCKeditor in the place where
// we dynamically created the textarea
oFCKeditor.ReplaceTextarea();
// now hide the original text layer - we want to see it vanish and the editing area
// seemingly replace it… just use a standard layer visibility=none routine
hideContentLayer(’story-content’);
}
};
http_request.open(’POST’, url, true);
http_request.setRequestHeader(”Content-type”, “application/x-www-form-urlencoded”);
http_request.setRequestHeader(”Content-length”, parameters.length);
http_request.setRequestHeader(”Connection”, “close”);
http_request.send(parameters);
}
Now, all I have to do is build the routine to send off the content … save it into the database … and replace the content on this page.
You could reuse/tweak the above AJAX call so that it could send off the request for updating content to the database. The form itself should just echo a message (the content you sent) back to this page so that the response becomes the new content, replacing that inside <div id=”story”>
…I’ll leave that one til next time…
M









