editor-base.js revision 8c208655578fa8136ffc7395672918b72abe633c
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * Base class for Editor. Handles the business logic of Editor, no GUI involved only utility methods and events.
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @module editor
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @submodule editor-base
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * Base class for Editor. Handles the business logic of Editor, no GUI involved only utility methods and events.
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @class EditorBase
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @for EditorBase
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @extends Base
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @constructor
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass var EditorBase = function() {
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass EditorBase.superclass.constructor.apply(this, arguments);
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * Internal reference to the Y.Frame instance
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @property frame
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass initializer: function() {
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass frame.after('ready', Y.bind(this._afterFrameReady, this));
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass destructor: function() {
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass * Copy certain styles from one node instance to another (used for new paragraph creation mainly)
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass * @method copyStyles
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass * @param {Node} from The Node instance to copy the styles from
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass * @param {Node} to The Node instance to copy the styles to
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass //Don't carry the A styles
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass var styles = ['color', 'fontSize', 'fontFamily', 'backgroundColor', 'fontStyle' ],
0523d0a8daaa474f0214203f8cbb0bc4a88e2964Dav Glass * Holder for the selection bookmark in IE.
5432371fbb6d790a76159481f0dd16e806812153Dav Glass * @property _lastBookmark
5432371fbb6d790a76159481f0dd16e806812153Dav Glass * Resolves the e.changedNode in the nodeChange event if it comes from the document. If
162527ab925c04aa8d6bbf78d0484a133a8076f1Dav Glass * the event came from the document, it will get the last child of the last child of the document
5432371fbb6d790a76159481f0dd16e806812153Dav Glass * and return that instead.
5432371fbb6d790a76159481f0dd16e806812153Dav Glass * @method _resolveChangedNode
5432371fbb6d790a76159481f0dd16e806812153Dav Glass * @param {Node} n The node to resolve
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * The default handler for the nodeChange event.
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @method _defNodeChangeFn
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * @param {Event} e The event
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass //Y.log('Default nodeChange function: ' + e.changedType, 'info', 'editor');
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass } catch (ie) {}
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass e.changedNode = this._resolveChangedNode(e.changedNode);
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * This whole method needs to be fixed and made more dynamic.
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * Maybe static functions for the e.changeType and an object bag
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass * to walk through and filter to pass off the event to before firing..
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass case 'keydown':
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass //inst.later(100, inst, inst.Selection.cleanCursor);
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass if (!e.changedNode.test('li, li *') && !e.changedEvent.shiftKey) {
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass Y.log('Overriding TAB key to insert HTML: HALTING', 'info', 'editor');
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass case 'enter-up':
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass var para = ((this._lastPara) ? this._lastPara : e.changedNode),
d2a5a45ff58ab15a8ee0339edcd03f0243373d59Dav Glass var prev = para.previous(), lc, lc2, found = false;
if (lc) {
if (lc2) {
found = true;
found = true;
if (lc) {
this._lastPara = p;
if (e.commands) {
if (cmd) {
if (family2) {
if (family) {
if (!e.fontFamily) {
if (!e.fontSize) {
if (!e.fontColor) {
if (!e.backgroundColor) {
while (domNode !== null) {
if ((domNode === inst.config.doc.documentElement) || (domNode === inst.config.doc) || !domNode.tagName) {
domNode = null;
domNode = null;
domNode = null;
if (nodeList) {
_afterFrameReady: function() {
_onFrameActivate: function() {
if (this._lastBookmark) {
this._lastBookmark = null;
_onFrameMouseUp: function(e) {
this.fire('nodeChange', { changedNode: e.frameTarget, changedType: 'mouseup', changedEvent: e.frameEvent });
_onFrameMouseDown: function(e) {
this.fire('nodeChange', { changedNode: e.frameTarget, changedType: 'mousedown', changedEvent: e.frameEvent });
_currentSelection: null,
_currentSelectionTimer: null,
_currentSelectionClear: null,
_onFrameKeyDown: function(e) {
if (!this._currentSelection) {
if (this._currentSelectionTimer) {
this._currentSelectionClear = true;
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keydown', changedEvent: e.frameEvent });
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: EditorBase.NC_KEYS[e.keyCode], changedEvent: e.frameEvent });
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: EditorBase.NC_KEYS[e.keyCode] + '-down', changedEvent: e.frameEvent });
_onFrameKeyPress: function(e) {
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keypress', changedEvent: e.frameEvent });
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: EditorBase.NC_KEYS[e.keyCode] + '-press', changedEvent: e.frameEvent });
_onFrameKeyUp: function(e) {
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keyup', selection: sel, changedEvent: e.frameEvent });
this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: EditorBase.NC_KEYS[e.keyCode] + '-up', selection: sel, changedEvent: e.frameEvent });
if (this._currentSelectionClear) {
* @return {Node/NodeList} The Node or Nodelist affected by the command. Only returns on override commands, not browser defined commands.
switch (cmd) {
return ret;
getInstance: function() {
* @param {Selector/HTMLElement/Node} node The node to append the Editor to
show: function() {
hide: function() {
getContent: function() {
return html;
NORMALIZE_FONTSIZE: function(n) {
switch (size) {
return size;
* @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00
var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
return css;
TAG2CMD: {
NC_KEYS: {
STRINGS: {
ATTRS: {
content: {
getter: function() {
dir: {
writeOnce: true,
linkedcss: {
if (this.frame) {
return css;
extracss: {
value: false,
if (this.frame) {
return css;
defaultblock: {
* <dt>changedType</dt><dd>The type of change: mousedown, mouseup, right, left, backspace, tab, enter, etc..</dd>
* <dt>commands</dt><dd>The list of execCommands that belong to this change and the dompath that's associated with the changedNode</dd>
* <dt>classNames</dt><dd>An array of classNames that are applied to the changedNode and all of it's parents</dd>