I've added basic 'pluggability' to the containers. I have tested it with several plugged containers that I am using but I'm sure it could use some additional testing (for example I'm not sure about the "TH" container logic as I'm currently not using it). Hopefully this can provide the basis for pluggable containers in the next version (if it's not being done already)...
The pluggable containers work simply by adding a customizable 'injector' callback function to each
containerItem object. For most normal containers (P,H1,H2 etc), this function doesn;t need to be implemented, and the
container() function simply switches to the new container (with switchTo()) - theres no custom injection. For containers with custom injection functionality (such as 'BLOCKQOUTE, and 'TH'), the 'injector' is implemented to perform the custom injection logic (such as they already were in the container() method). Basically, this is simply modularizing what was already being done in the container() method and allowing you to add your own. This means that the 'containersItems' object now looks like:
- Code: Select all
containersItems: [
{'name': 'P', 'title': 'Paragraph', 'css': 'wym_containers_p'},
{'name': 'H1', 'title': 'Heading_1', 'css': 'wym_containers_h1'},
{'name': 'H2', 'title': 'Heading_2', 'css': 'wym_containers_h2'},
{'name': 'H3', 'title': 'Heading_3', 'css': 'wym_containers_h3'},
{'name': 'H4', 'title': 'Heading_4', 'css': 'wym_containers_h4'},
{'name': 'H5', 'title': 'Heading_5', 'css': 'wym_containers_h5'},
{'name': 'H6', 'title': 'Heading_6', 'css': 'wym_containers_h6'},
{'name': 'PRE', 'title': 'Preformatted', 'css': 'wym_containers_pre'},
{'name': 'BLOCKQUOTE', 'title': 'Blockquote','css': 'wym_containers_blockquote', 'injector' : function(wym, container) {
var blockquote = wym.findUp(wym.container(), WYMeditor.BLOCKQUOTE);
if(blockquote == null) {
newNode = wym._doc.createElement('BLOCKQUOTE');
container.parentNode.insertBefore(newNode,container);
newNode.appendChild(container);
wym.setFocusToNode(newNode.firstChild);
} else {
var nodes = blockquote.childNodes;
var lgt = nodes.length;
var firstNode = null;
if(lgt > 0) firstNode = nodes.item(0);
for(var x=0; x<lgt; x++) {
blockquote.parentNode.insertBefore(nodes.item(0),blockquote);
}
blockquote.parentNode.removeChild(blockquote);
if(firstNode) wym.setFocusToNode(firstNode);
}
return true;
}},
{'name': 'TH', 'title': 'Table_Header', 'css': 'wym_containers_th', 'injector': function(wym, container) {
//find the TD or TH container
container = wym.container();
switch(container.tagName.toLowerCase()) {
case WYMeditor.TD: case WYMeditor.TH:
break;
default:
var aTypes = new Array(WYMeditor.TD,WYMeditor.TH);
container = wym.findUp(wym.container(), aTypes);
break;
}
//if it exists, switch
if(container!=null) {
sType = (container.tagName.toLowerCase() == WYMeditor.TD)? WYMeditor.TH: WYMeditor.TD;
wym.switchTo(container,'TH');
return true;
}
return false;
}}
],
Implement the pluggable containers as follows:
1. Add the following editor protoype function- Code: Select all
/*
* injector is a callback function that should be implemented to perform container-specific injection logic
* injector = function(wym,container) is passed reference to the wym editor as arg 1 and reference to container as arg 2
* returns true if successful (if editor should be updated) or false if not.
*/
WYMeditor.editor.prototype.registerContainer = function(name, injector) {
if(!this._containers) { this._containers = []; }
if(name && jQuery.isFunction(injector)) {
this._containers[name.toLowerCase()] = injector;
}
}
2. Replace the container() prototype function with the following- Code: Select all
/* @name container
* @description Get/Set the selected container
*/
WYMeditor.editor.prototype.container = function(sType) {
if(sType) {
var container = this.findUp(this.container(), WYMeditor.MAIN_CONTAINERS);
if(container) {
var injector = this._containers[sType.toLowerCase()];
var isUpdate = true;
if(injector) {
isUpdate = injector(this, container);
} else {
this.switchTo(container,sType);
}
if(isUpdate) {
this.update();
//Note, I use the following code below (eliminating the xhtml() parser for performance and some parser issues since we're in control of the validity of the HTML injected anyway
//var html = this.html();
//jQuery(this._element).val(html);
//jQuery(this._box).find(this._options.htmlValSelector).val(html);
}
}
} else return(this.selected());
}
(Note I'm using WYMeditor.MAIN_CONTAINERS as the list of valid containers.
I suppose this is fine for now but it should be made into an option as custom container code may need to specify custom container types to allow for cutomized container nesting - I do)
3. Add the following line to the init function where it constructs the containers list- Code: Select all
[b]add new line:[/b]
this.registerContainer(oContainer.name, oContainer.injector);
[b]after existing lines:[/b]
sContainer = h.replaceAll(sContainer, WYMeditor.CONTAINER_CLASS, oContainer.css);
sContainers += sContainer;
4. Update the containersItems object as I described earlier to: - Code: Select all
containersItems: [
{'name': 'P', 'title': 'Paragraph', 'css': 'wym_containers_p'},
{'name': 'H1', 'title': 'Heading_1', 'css': 'wym_containers_h1'},
{'name': 'H2', 'title': 'Heading_2', 'css': 'wym_containers_h2'},
{'name': 'H3', 'title': 'Heading_3', 'css': 'wym_containers_h3'},
{'name': 'H4', 'title': 'Heading_4', 'css': 'wym_containers_h4'},
{'name': 'H5', 'title': 'Heading_5', 'css': 'wym_containers_h5'},
{'name': 'H6', 'title': 'Heading_6', 'css': 'wym_containers_h6'},
{'name': 'PRE', 'title': 'Preformatted', 'css': 'wym_containers_pre'},
{'name': 'BLOCKQUOTE', 'title': 'Blockquote','css': 'wym_containers_blockquote', 'injector' : function(wym, container) { //blockquotes must contain a block level element
var blockquote = wym.findUp(wym.container(), WYMeditor.BLOCKQUOTE);
if(blockquote == null) {
newNode = wym._doc.createElement('BLOCKQUOTE');
container.parentNode.insertBefore(newNode,container);
newNode.appendChild(container);
wym.setFocusToNode(newNode.firstChild);
} else {
var nodes = blockquote.childNodes;
var lgt = nodes.length;
var firstNode = null;
if(lgt > 0) firstNode = nodes.item(0);
for(var x=0; x<lgt; x++) {
blockquote.parentNode.insertBefore(nodes.item(0),blockquote);
}
blockquote.parentNode.removeChild(blockquote);
if(firstNode) wym.setFocusToNode(firstNode);
}
return true;
}},
{'name': 'TH', 'title': 'Table_Header', 'css': 'wym_containers_th', 'injector': function(wym, container) {
//find the TD or TH container
container = wym.container();
switch(container.tagName.toLowerCase()) {
case WYMeditor.TD: case WYMeditor.TH:
break;
default:
var aTypes = new Array(WYMeditor.TD,WYMeditor.TH);
container = wym.findUp(wym.container(), aTypes);
break;
}
//if it exists, switch
if(container!=null) {
sType = (container.tagName.toLowerCase() == WYMeditor.TD)? WYMeditor.TH: WYMeditor.TD;
wym.switchTo(container,'TH');
return true;
}
return false;
}}
],
(note: 'TH' injector function not tested)
That's it! (hope i haven't forgotten something)
Now, we can add any additional containers with custom injector logic in the
preInit () function. For example I could have:
- Code: Select all
preInit: function(wym) {
wym._options.containersItems = wym._options.containersItems.concat(
[
{'name': 'CUSTOM_CONTAINER', 'title': 'Custom_Container', 'css': 'wym_containers_cutom', 'injector' : function(wym, container) {
var jContainer = jQuery(container);
var jNode = jQuery("<div class='customContainer'><a id='interactive'>My container link</a></div>");
var html = jContainer.html();
jContainer.replaceWith(jNode);
jNode.find("div.interactive").append(html);
wym.setFocusToNode(jNode [0]);
}},
]);
}
As I said, not very well tested. But a start and all I have time for at the moment...
- Eric