diff --git a/modules/editor/skins/xquared/doc/api/_01.html b/modules/editor/skins/xquared/doc/api/_01.html deleted file mode 100644 index bd7000e14..000000000 --- a/modules/editor/skins/xquared/doc/api/_01.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: Browser.js - - - - -
-
- -
Library: Browser.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - -
Functions
- - -
Objects
- -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_02.html b/modules/editor/skins/xquared/doc/api/_02.html deleted file mode 100644 index bc396fa0a..000000000 --- a/modules/editor/skins/xquared/doc/api/_02.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - JsDoc: - - - - -
-
- -
Library: Controls.js
-
-
- Overview -
-
-
xq.controls provides common UI elements such as dialog.
-
- -
-
-
- -
Constructors
- - - - - - - - -
Functions
- - -
-
- - - - this.form.onsubmit() - -
- - - - - - - - - - -
- - - -
-
- - - - cancelButton.onclick() - -
- - - - - - - - - - -
- - - -
-
- - - - this.param.renderItem(item) - -
- - - - - - -
parameters
- - - - - - - - -
- - - item - - -
- - - - - -
- - - -
Objects
- - - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:20 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_03.html b/modules/editor/skins/xquared/doc/api/_03.html deleted file mode 100644 index 527f10740..000000000 --- a/modules/editor/skins/xquared/doc/api/_03.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - JsDoc: DomTree.js - - - - -
-
- -
Library: DomTree.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - - - - - -
Functions
- - - - -
-
- - - - findLeft(el) - -
- - - - - - -
parameters
- - - - - - - - -
- - - el - - -
- - - - - -
- - - -
-
- - - - findRight(el) - -
- - - - - - -
parameters
- - - - - - - - -
- - - el - - -
- - - - - -
- - - -
Objects
- - -
-
- - - - - xq.DomTree - -
- - -
Provide various tree operations. - -TODO: Add specs
- - - - - -
- - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_04.html b/modules/editor/skins/xquared/doc/api/_04.html deleted file mode 100644 index 080339233..000000000 --- a/modules/editor/skins/xquared/doc/api/_04.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: - - - - -
-
- -
Library: EditHistory.js
-
-
- Overview -
-
-
xq.EditHistory manages editing history and performs UNDO/REDO.
-
- -
-
-
- -
Constructors
- - -
Functions
- - -
Objects
- -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:21 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_05.html b/modules/editor/skins/xquared/doc/api/_05.html deleted file mode 100644 index 4b8bee6a9..000000000 --- a/modules/editor/skins/xquared/doc/api/_05.html +++ /dev/null @@ -1,796 +0,0 @@ - - - - - - JsDoc: - - - - -
-
- -
Library: Editor.js
-
-
- Overview -
-
-
xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
-
- -
-
-
- -
Constructors
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - criteria(text) - -
- - - - - - -
parameters
- - - - - - - - -
- - - text - - -
- - - - - -
- - - -
-
- - - - criteria(text) - -
- - - - - - -
parameters
- - - - - - - - -
- - - text - - -
- - - - - -
- - - -
-
- - - - this.contentElement.form.onsubmit() - -
- - - - - - - - - - -
- - - -
-
- - - - cancelMousedown(e) - -
- - - - - - -
parameters
- - - - - - - - -
- - - e - - -
- - - - - -
- - - -
-
- - - - finder(node) - -
- - - - - - -
parameters
- - - - - - - - -
- - - node - - -
- - - - - -
- - - -
-
- - - - exitCondition(node) - -
- - - - - - -
parameters
- - - - - - - - -
- - - node - - -
- - - - - -
- - - -
Objects
- - -
-
- - - object - - - - this.config - -
- - -
Editor's configuration
- - - - - -
- - - - -
-
- - - Element - - - - this.contentElement - -
- - -
Original content element
- - - - - -
- - - - -
-
- - - Document - - - - this.doc - -
- - -
Owner document of content element
- - - - - -
- - - - -
-
- - - Element - - - - this.body - -
- - -
Body of content element
- - - - - -
- - - - -
-
- - - Object - - - - this.currentEditMode - -
- - -
False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
- - - - - -
- - - - -
-
- - - xq.RichDom - - - - this.rdom - -
- - -
RichDom instance
- - - - - -
- - - - -
-
- - - xq.Validator - - - - this.validator - -
- - -
Validator instance
- - - - - -
- - - - -
-
- - - Element - - - - this.outmostWrapper - -
- - -
Outmost wrapper div
- - - - - -
- - - - -
-
- - - Element - - - - this.sourceEditorDiv - -
- - -
Source editor container
- - - - - -
- - - - -
-
- - - Element - - - - this.sourceEditorTextarea - -
- - -
Source editor textarea
- - - - - -
- - - - -
-
- - - Element - - - - this.wysiwygEditorDiv - -
- - -
WYSIWYG editor container
- - - - - -
- - - - -
-
- - - IFrame - - - - this.editorFrame - -
- - -
Design mode iframe
- - - - - -
- - - - -
-
- - - Window - - - - this.editorWin - -
- - -
Window that contains design mode iframe
- - - - - -
- - - - -
-
- - - Document - - - - this.editorDoc - -
- - -
Document that contained by design mode iframe
- - - - - -
- - - - -
-
- - - Element - - - - this.editorBody - -
- - -
Body that contained by design mode iframe
- - - - - -
- - - - -
-
- - - Element - - - - this.toolbarContainer - -
- - -
Toolbar container
- - - - - -
- - - - -
-
- - - Array - - - - this.toolbarButtons - -
- - -
Toolbar buttons
- - - - - -
- - - - -
-
- - - xq.EditHistory - - - - this.editHistory - -
- - -
Undo/redo manager
- - - - - -
- - - - - - - - - - - - - - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:34 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_06.html b/modules/editor/skins/xquared/doc/api/_06.html deleted file mode 100644 index 3aa42a640..000000000 --- a/modules/editor/skins/xquared/doc/api/_06.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - JsDoc: RichDom.js - - - - -
-
- -
Library: RichDom.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - - - - - - - - - -
Functions
- - - - - - -
-
- - - - finder(node) - -
- - - - - - -
parameters
- - - - - - - - -
- - - node - - -
- - - - - -
- - - -
-
- - - - exitCondition(node) - -
- - - - - - -
parameters
- - - - - - - - -
- - - node - - -
- - - - - -
- - - -
-
- - - - xq.RichDom.createInstance() - -
- - -
Creates and returns instance of browser specific implementation.
- - - - - - - - - -
- - - -
Objects
- - -
-
- - - - - xq.RichDom - -
- - -
Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API. - -RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
- - - - - -
- - - - -
-
- - - - - this.tree - -
- - -
instance of DomTree
- - - - - -
- - - - - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_07.html b/modules/editor/skins/xquared/doc/api/_07.html deleted file mode 100644 index 58e74f9aa..000000000 --- a/modules/editor/skins/xquared/doc/api/_07.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomGecko.js - - - - -
-
- -
Library: RichDomGecko.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.RichDomGecko - -
- - -
RichDom for Gecko
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_08.html b/modules/editor/skins/xquared/doc/api/_08.html deleted file mode 100644 index 56f0609f3..000000000 --- a/modules/editor/skins/xquared/doc/api/_08.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomTrident.js - - - - -
-
- -
Library: RichDomTrident.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.RichDomTrident - -
- - -
RichDom for Internet Explorer 6 and 7
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:48 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_09.html b/modules/editor/skins/xquared/doc/api/_09.html deleted file mode 100644 index 5a3a1fe0f..000000000 --- a/modules/editor/skins/xquared/doc/api/_09.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomW3.js - - - - -
-
- -
Library: RichDomW3.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.RichDomW3 - -
- - -
RichDom for W3C Standard Engine
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_10.html b/modules/editor/skins/xquared/doc/api/_10.html deleted file mode 100644 index 9c4670246..000000000 --- a/modules/editor/skins/xquared/doc/api/_10.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: RichDomWebkit.js - - - - -
-
- -
Library: RichDomWebkit.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.RichDomWebkit - -
- - -
RichDom for Webkit
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_11.html b/modules/editor/skins/xquared/doc/api/_11.html deleted file mode 100644 index c5409a591..000000000 --- a/modules/editor/skins/xquared/doc/api/_11.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - JsDoc: RichTable.js - - - - -
-
- -
Library: RichTable.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - -
-
- - - - xq.RichTable.create(rdom, cols, rows, headerPositions) - -
- - - - - - -
parameters
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - rdom - - -
- - - cols - - -
- - - rows - - -
- - - headerPositions - - -
- - - - - -
- - - -
Objects
- - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_12.html b/modules/editor/skins/xquared/doc/api/_12.html deleted file mode 100644 index 2d0bff85a..000000000 --- a/modules/editor/skins/xquared/doc/api/_12.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - JsDoc: Shortcut.js - - - - -
-
- -
Library: Shortcut.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - - - - - -
Functions
- - -
-
- - - - xq.Shortcut.interprete(expression) - -
- - - - - - -
parameters
- - - - - - - - -
- - - expression - - -
- - - - - -
- - - -
-
- - - - xq.Shortcut._interpreteModifier(expression, modifierName) - -
- - - - - - -
parameters
- - - - - - - - - - - - - - -
- - - expression - - -
- - - modifierName - - -
- - - - - -
- - - -
-
- - - - xq.Shortcut._interpreteWhich(keyName) - -
- - - - - - -
parameters
- - - - - - - - -
- - - keyName - - -
- - - - - -
- - - -
Objects
- - - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_13.html b/modules/editor/skins/xquared/doc/api/_13.html deleted file mode 100644 index 46fe53499..000000000 --- a/modules/editor/skins/xquared/doc/api/_13.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - JsDoc: Validator.js - - - - -
-
- -
Library: Validator.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - - - -
Functions
- - - - -
-
- - - - xq.Validator.createInstance(curUrl, urlValidationMode, allowedTags, allowedAttrs) - -
- - -
Creates and returns instance of browser specific implementation.
- - - - - -
parameters
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - curUrl - - -
- - - urlValidationMode - - -
- - - allowedTags - - -
- - - allowedAttrs - - -
- - - - - -
- - - -
Objects
- - -
-
- - - - - xq.Validator - -
- - -
Validates and invalidates designmode contents
- - - - - -
- - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_14.html b/modules/editor/skins/xquared/doc/api/_14.html deleted file mode 100644 index 3a15872b4..000000000 --- a/modules/editor/skins/xquared/doc/api/_14.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorGecko.js - - - - -
-
- -
Library: ValidatorGecko.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.ValidatorGecko - -
- - -
Validator for Gecko Engine
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:49 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_15.html b/modules/editor/skins/xquared/doc/api/_15.html deleted file mode 100644 index ee41915a5..000000000 --- a/modules/editor/skins/xquared/doc/api/_15.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorTrident.js - - - - -
-
- -
Library: ValidatorTrident.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.ValidatorTrident - -
- - -
Validator for Internet Explorer 6 and 7
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_16.html b/modules/editor/skins/xquared/doc/api/_16.html deleted file mode 100644 index 5b7576800..000000000 --- a/modules/editor/skins/xquared/doc/api/_16.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorW3.js - - - - -
-
- -
Library: ValidatorW3.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.ValidatorW3 - -
- - -
Validator for W3C Standard Engine
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_17.html b/modules/editor/skins/xquared/doc/api/_17.html deleted file mode 100644 index b4e3818df..000000000 --- a/modules/editor/skins/xquared/doc/api/_17.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - JsDoc: ValidatorWebkit.js - - - - -
-
- -
Library: ValidatorWebkit.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - -
Functions
- - - - -
Objects
- - -
-
- - - - - xq.ValidatorWebkit - -
- - -
Validator for Webkit
- - - - - -
- - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_18.html b/modules/editor/skins/xquared/doc/api/_18.html deleted file mode 100644 index 88d060871..000000000 --- a/modules/editor/skins/xquared/doc/api/_18.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - JsDoc: XQuared.js - - - - -
-
- -
Library: XQuared.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Functions
- - - - -
-
- - - - xq.asEventSource(object, prefix, events) - -
- - -
Make given object as event source
- - - - - -
parameters
- - - - - - - - - - - - - - - - - - - - -
- Object - - object - - target object -
- String - - prefix - - prefix for generated functions -
- Array - - events - - array of string which contains name of events -
- - - - - -
- - - -
-
- - - Array.indexOf(n) - - -
- - -
Returns the index of given element
- - - - - -
parameters
- - - - - - - - -
- - - n - - -
- - - -
returns
- - - - - - - -
- Number - - index or -1 -
- - - -
- - - -
-
- - - - Date.pass(msec) - -
- - - - - - -
parameters
- - - - - - - - -
- - - msec - - -
- - - - - -
- - - -
-
- - - - Date.get() - -
- - - - - - - - - - -
- - - -
-
- - - Date.elapsed(msec) - - -
- - - - - - -
parameters
- - - - - - - - -
- - - msec - - -
- - - - - -
- - - -
-
- - - String.merge(data) - - -
- - - - - - -
parameters
- - - - - - - - -
- - - data - - -
- - - - - -
- - - -
-
- - - String.parseURL() - - -
- - - - - - - - - - -
- - - -
-
- - - - xq.findXquaredScript() - -
- - - - - - - - - - -
- - - -
-
- - - - xq.shouldLoadOthers() - -
- - - - - - - - - - -
- - - -
-
- - - - xq.loadScript(url) - -
- - - - - - -
parameters
- - - - - - - - -
- - - url - - -
- - - - - -
- - - -
-
- - - - xq.loadOthers() - -
- - - - - - - - - - -
- - - -
Objects
- - -
-
- - - - - xq - -
- - -
Namespace for entire Xquared classes
- - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/_19.html b/modules/editor/skins/xquared/doc/api/_19.html deleted file mode 100644 index 4616b926c..000000000 --- a/modules/editor/skins/xquared/doc/api/_19.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - JsDoc: _ui_templates.js - - - - -
-
- -
Library: _ui_templates.js
-
-
- Overview -
-
-
-
- -
-
-
- -
Constructors
- - -
Functions
- - -
Objects
- -
-
-
- Generated by JsDoc Toolkit 1.3.1 on Wed, 21 Nov 2007 09:57:50 GMT. -
- - diff --git a/modules/editor/skins/xquared/doc/api/constructor.gif b/modules/editor/skins/xquared/doc/api/constructor.gif deleted file mode 100644 index ba779972c..000000000 Binary files a/modules/editor/skins/xquared/doc/api/constructor.gif and /dev/null differ diff --git a/modules/editor/skins/xquared/doc/api/default.css b/modules/editor/skins/xquared/doc/api/default.css deleted file mode 100644 index cfe837beb..000000000 --- a/modules/editor/skins/xquared/doc/api/default.css +++ /dev/null @@ -1,116 +0,0 @@ -body,a -{ - color: #000; - font: 12px verdana; -} - -ul -{ - list-style-type: none; - margin-left: 10px; - padding-left: 10px; -} - -.content { } -.docs { } -.signature { font-weight: normal; } -.code { - font: 11px monaco,monospace; - padding: 4px; - margin-left: 18px; - border: 1px dashed #ccc; -} - -.itemTitle -{ - font-size: 12px; - font-weight: bold; - height: 16px; -} - -.item { } - -.sectionHead -{ - font-size: 18px; - font-weight: bold; - background-color: #C0C1DE; - color: #fff; - margin-top: 18px; - padding: 2px 4px 2px 4px; -} - -.section -{ - padding: 8px; - border: 1px #8A92BC solid; - margin: 4px; -} - -.detailHead -{ - border-bottom: 1px #8FB685 dotted; - font-size: 12px; - font-weight: bold; - color: #798E73; - margin-top: 18px; -} - -.desc { padding: 8px; } - -.fileHead -{ - background-image: url(file.gif); - background-repeat: no-repeat; - padding-left: 20px; - font-weight: bold; - font-size: 14px; - line-height: 20px; -} - -.overview .itemTitle -{ - background-image: url(overview.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.constructor .itemTitle -{ - background-image: url(constructor.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.function .itemTitle -{ - background-image: url(function.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.object .itemTitle -{ - background-image: url(object.gif); - background-repeat: no-repeat; - padding-left: 20px; -} - -.type -{ - font-style: italic; - color: #999; - font-weight: normal; -} - -.itemTitle a.type { font-weight: bold; } - -.finePrint -{ - color: #878787; - font-family: verdana; - font-size: 10px; - text-align: right; -} - -.params td { padding-right: 10px; } \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/file.gif b/modules/editor/skins/xquared/doc/api/file.gif deleted file mode 100644 index 9c7446e41..000000000 Binary files a/modules/editor/skins/xquared/doc/api/file.gif and /dev/null differ diff --git a/modules/editor/skins/xquared/doc/api/file_list.html b/modules/editor/skins/xquared/doc/api/file_list.html deleted file mode 100644 index f6c3a20f5..000000000 --- a/modules/editor/skins/xquared/doc/api/file_list.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - JsDoc - - - - -
File Index
- - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/function.gif b/modules/editor/skins/xquared/doc/api/function.gif deleted file mode 100644 index be00b964b..000000000 Binary files a/modules/editor/skins/xquared/doc/api/function.gif and /dev/null differ diff --git a/modules/editor/skins/xquared/doc/api/index.html b/modules/editor/skins/xquared/doc/api/index.html deleted file mode 100644 index 3df8e5bfc..000000000 --- a/modules/editor/skins/xquared/doc/api/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - JsDoc - - - - - - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/object.gif b/modules/editor/skins/xquared/doc/api/object.gif deleted file mode 100644 index 409b58e33..000000000 Binary files a/modules/editor/skins/xquared/doc/api/object.gif and /dev/null differ diff --git a/modules/editor/skins/xquared/doc/api/overview.gif b/modules/editor/skins/xquared/doc/api/overview.gif deleted file mode 100644 index 241c2574e..000000000 Binary files a/modules/editor/skins/xquared/doc/api/overview.gif and /dev/null differ diff --git a/modules/editor/skins/xquared/doc/api/splash.html b/modules/editor/skins/xquared/doc/api/splash.html deleted file mode 100644 index 8c7495195..000000000 --- a/modules/editor/skins/xquared/doc/api/splash.html +++ /dev/null @@ -1,7 +0,0 @@ - - - JsDoc - - - - \ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_01.html b/modules/editor/skins/xquared/doc/api/src_01.html deleted file mode 100644 index 4d8272800..000000000 --- a/modules/editor/skins/xquared/doc/api/src_01.html +++ /dev/null @@ -1,24 +0,0 @@ -
  1 xq.Browser = {
-  2 	// By Layout Engines
-  3 	isTrident: navigator.appName == "Microsoft Internet Explorer",
-  4 	isWebkit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
-  5 	isGecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
-  6 	isKHTML: navigator.userAgent.indexOf('KHTML') != -1,
-  7 	isPresto: navigator.appName == "Opera",
-  8 	
-  9 	// By Platforms
- 10 	isMac: navigator.userAgent.indexOf("Macintosh") != -1,
- 11 	isUbuntu: navigator.userAgent.indexOf('Ubuntu') != -1,
- 12 
- 13 	// By Browsers
- 14 	isIE: navigator.appName == "Microsoft Internet Explorer",
- 15 	isIE6: navigator.userAgent.indexOf('MSIE 6') != -1,
- 16 	isIE7: navigator.userAgent.indexOf('MSIE 7') != -1
- 17 };
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_02.html b/modules/editor/skins/xquared/doc/api/src_02.html deleted file mode 100644 index 7d1de91f7..000000000 --- a/modules/editor/skins/xquared/doc/api/src_02.html +++ /dev/null @@ -1,344 +0,0 @@ -
  1 /**
-  2  * @fileOverview xq.controls provides common UI elements such as dialog.
-  3  */
-  4 xq.controls = {};
-  5 
-  6 
-  7 
-  8 xq.controls.FormDialog = Class.create({
-  9 	/**
- 10      * @constructor
- 11      *
- 12      * @param {String} html HTML string which contains FORM
- 13      * @param {Function} [onLoadHandler] callback function to be called when the form is loaded
- 14 	 */
- 15 	initialize: function(xed, html, onLoadHandler, onCloseHandler) {
- 16 		this.xed = xed;
- 17 		this.html = html;
- 18 		this.onLoadHandler = onLoadHandler || function() {};
- 19 		this.onCloseHandler = onCloseHandler || function() {};
- 20 		this.form = null;
- 21 	},
- 22 	/**
- 23 	 * Show dialog
- 24 	 *
- 25 	 * @param {Object} [options] collection of options
- 26 	 */
- 27 	show: function(options) {
- 28 		options = options || {};
- 29 		options.position = options.position || 'centerOfWindow';
- 30 		options.mode = options.mode || 'modal';
- 31 		options.cancelOnEsc = options.cancelOnEsc || true;
- 32 		
- 33 		var self = this;
- 34 		
- 35 		// create and append container
- 36 		var container = $(document.createElement('DIV'));
- 37 		container.style.display = 'none';
- 38 		document.body.appendChild(container);
- 39 		
- 40 		// initialize form
- 41 		container.innerHTML = this.html;
- 42 		this.form = $(container.getElementsByTagName('FORM')[0]);
- 43 		
- 44 		this.form.onsubmit = function() {
- 45 			self.onCloseHandler($(this).serialize(true));
- 46 			self.close();
- 47 			return false;
- 48 		};
- 49 		
- 50 		var cancelButton = this.form.getElementsByClassName('cancel')[0];
- 51 		cancelButton.onclick = function() {
- 52 			self.onCloseHandler();
- 53 			self.close();
- 54 		};
- 55 		
- 56 		// append dialog
- 57 		document.body.appendChild(this.form);
- 58 		container.parentNode.removeChild(container);
- 59 		
- 60 		// place dialog to center of window
- 61 		this.setPosition(options.position);
- 62 		
- 63 		// give focus
- 64 		var elementToFocus = this.form.getElementsByClassName('initialFocus');
- 65 		if(elementToFocus.length > 0) elementToFocus[0].focus();
- 66 		
- 67 		// handle cancelOnEsc option
- 68 		if(options.cancelOnEsc) {
- 69 			Event.observe(this.form, 'keydown', function(e) {
- 70 				if(e.keyCode == 27) {
- 71 					this.onCloseHandler();
- 72 					this.close();
- 73 				}
- 74 				return false;
- 75 			}.bind(this));
- 76 		}
- 77 		
- 78 		this.onLoadHandler(this);
- 79 	},
- 80 	close: function() {
- 81 		this.form.parentNode.removeChild(this.form);
- 82 	},
- 83 	setPosition: function(target) {
- 84 		var targetElement;
- 85 		
- 86 		if(target == 'centerOfWindow') {
- 87 			targetElement = document.documentElement;
- 88 		} else if(target == 'centerOfEditor') {
- 89 			targetElement = this.xed.getDoc()[xq.Browser.isTrident ? "body" : "documentElement"];
- 90 		} else if(target == 'nearbyCaret') {
- 91 			throw "Not implemented yet";
- 92 		} else {
- 93 			throw "Invalid argument: " + target;
- 94 		}
- 95 		
- 96 		var targetWidth = targetElement.clientWidth;
- 97 		var targetHeight = targetElement.clientHeight;
- 98 		var dialogWidth = this.form.clientWidth;
- 99 		var dialogHeight = this.form.clientHeight;
-100 		
-101 		var x = parseInt((targetWidth - dialogWidth) / 2);
-102 		var y = parseInt((targetHeight - dialogHeight) / 2);
-103 		
-104 		this.form.style.left = x + "px";
-105 		this.form.style.top = y + "px";
-106 	}
-107 })
-108 
-109 
-110 
-111 xq.controls.QuickSearchDialog = Class.create({
-112 	/**
-113      * @constructor
-114 	 */
-115 	initialize: function(xed, param) {
-116 		this.xed = xed;
-117 		
-118 		this.rdom = xq.RichDom.createInstance();
-119 		this.rdom.setRoot(document.body);
-120 		
-121 		this.param = param;
-122 		if(!this.param.renderItem) this.param.renderItem = function(item) {
-123 			return this.rdom.getInnerText(item);
-124 		}.bind(this);
-125 		
-126 		this.container = null;
-127 	},
-128 	
-129 	getQuery: function() {
-130 		if(!this.container) return "";
-131 		return this._getInputField().value;
-132 	},
-133 	
-134 	onSubmit: function(e) {
-135 		if(this.matchCount() > 0) {
-136 			this.param.onSelect(this.xed, this.list[this._getSelectedIndex()]);
-137 		}
-138 		
-139 		this.close();
-140 		Event.stop(e);
-141 		return false;
-142 	},
-143 	
-144 	onCancel: function(e) {
-145 		if(this.param.onCancel) this.param.onCancel(this.xed);
-146 		this.close();
-147 	},
-148 	
-149 	onBlur: function(e) {
-150 		// TODO: Ugly
-151 		setTimeout(function() {this.onCancel(e)}.bind(this), 400);
-152 	},
-153 	
-154 	onKey: function(e) {
-155 		var esc = new xq.Shortcut("ESC");
-156 		var enter = new xq.Shortcut("ENTER");
-157 		var up = new xq.Shortcut("UP");
-158 		var down = new xq.Shortcut("DOWN");
-159 		
-160 		if(esc.matches(e)) {
-161 			this.onCancel(e);
-162 		} else if(enter.matches(e)) {
-163 			this.onSubmit(e);
-164 		} else if(up.matches(e)) {
-165 			this._moveSelectionUp();
-166 		} else if(down.matches(e)) {
-167 			this._moveSelectionDown();
-168 		} else {
-169 			this.updateList();
-170 		}
-171 	},
-172 	
-173 	onClick: function(e) {
-174 		var target = e.srcElement || e.target;
-175 		if(target.nodeName == "LI") {
-176 			
-177 			var index = this._getIndexOfLI(target);
-178 			this.param.onSelect(this.xed, this.list[index]);
-179 		}
-180 	},
-181 	
-182 	onList: function(list) {
-183 		this.list = list;
-184 		this.renderList(list);
-185 	},
-186 	
-187 	updateList: function() {
-188 		window.setTimeout(function() {
-189 			this.param.listProvider(this.getQuery(), this.xed, this.onList.bind(this));
-190 		}.bind(this), 0);
-191 	},
-192 	
-193 	renderList: function(list) 
-194 	{
-195 		var ol = this._getListContainer();
-196 		ol.innerHTML = "";
-197 		
-198 		for(var i = 0; i < list.length; i++) {
-199 			var li = this.rdom.createElement('LI');
-200 			li.innerHTML = this.param.renderItem(list[i]);
-201 			ol.appendChild(li);
-202 		}
-203 		
-204 		if(ol.hasChildNodes()) {
-205 			ol.firstChild.className = "selected";
-206 		}
-207 	},
-208 	
-209 	show: function() {
-210 		if(!this.container) this.container = this._create();
-211 		
-212 		var dialog = this.rdom.insertNodeAt(this.container, this.rdom.getRoot(), "end");
-213 		this.setPosition('centerOfEditor');
-214 		this.updateList();
-215 		this.focus();
-216 	},
-217 	
-218 	close: function() {
-219 		this.rdom.deleteNode(this.container);
-220 	},
-221 	
-222 	focus: function() {
-223 		this._getInputField().focus();
-224 	},
-225 	
-226 	setPosition: function(target) {
-227 		var targetElement;
-228 		
-229 		if(target == 'centerOfWindow') {
-230 			targetElement = document.documentElement;
-231 		} else if(target == 'centerOfEditor') {
-232 			targetElement = this.xed.getDoc().documentElement;
-233 		} else if(target == 'nearbyCaret') {
-234 			throw "Not implemented yet";
-235 		} else {
-236 			throw "Invalid argument: " + target;
-237 		}
-238 		
-239 		var targetWidth = targetElement.clientWidth;
-240 		var targetHeight = targetElement.clientHeight;
-241 		var dialogWidth = this.container.clientWidth;
-242 		var dialogHeight = this.container.clientHeight;
-243 		
-244 		var x = parseInt((targetWidth - dialogWidth) / 2);
-245 		var y = parseInt((targetHeight - dialogHeight) / 2);
-246 		this.container.style.left = x + "px";
-247 		this.container.style.top = y + "px";
-248 	},
-249 	
-250 	matchCount: function() {
-251 		return this.list ? this.list.length : 0;
-252 	},
-253 	
-254 	_create: function() {
-255 		// make container
-256 		var container = this.rdom.createElement("DIV");
-257 		container.className = "xqQuickSearch";
-258 		
-259 		// make title
-260 		if(this.param.title) {
-261 			var title = this.rdom.createElement("H1");
-262 			title.innerHTML = this.param.title;
-263 			container.appendChild(title);
-264 		}
-265 		
-266 		// make input field
-267 		var inputWrapper = this.rdom.createElement("DIV");
-268 		inputWrapper.className = "input";
-269 		var form = this.rdom.createElement("FORM");
-270 		var input = this.rdom.createElement("INPUT");
-271 		input.type = "text";
-272 		input.value = "";
-273     	form.appendChild(input);
-274 		inputWrapper.appendChild(form);
-275 		container.appendChild(inputWrapper);
-276 		
-277 		// make list
-278 		var list = this.rdom.createElement("OL");
-279 
-280 	    Event.observe(input, 'blur', this.onBlur.bindAsEventListener(this));
-281     	Event.observe(input, 'keypress', this.onKey.bindAsEventListener(this));
-282     	Event.observe(list, 'click', this.onClick.bindAsEventListener(this), true);
-283     	Event.observe(form, 'submit', this.onSubmit.bindAsEventListener(this));
-284     	Event.observe(form, 'reset', this.onCancel.bindAsEventListener(this));
-285 
-286 		container.appendChild(list);
-287 		return container;
-288 	},
-289 	
-290 	_getInputField: function() {
-291 		return this.container.getElementsByTagName('INPUT')[0];
-292 	},
-293 	
-294 	_getListContainer: function() {
-295 		return this.container.getElementsByTagName('OL')[0];
-296 	},
-297 	
-298 	_getSelectedIndex: function() {
-299 		var ol = this._getListContainer();
-300 		for(var i = 0; i < ol.childNodes.length; i++) {
-301 			if(ol.childNodes[i].className == 'selected') return i;
-302 		}
-303 	},
-304 	
-305 	_getIndexOfLI: function(li) {
-306 		var ol = this._getListContainer();
-307 		for(var i = 0; i < ol.childNodes.length; i++) {
-308 			if(ol.childNodes[i] == li) return i;
-309 		}
-310 	},
-311 	
-312 	_moveSelectionUp: function() {
-313 		var count = this.matchCount();
-314 		if(count == 0) return;
-315 		var index = this._getSelectedIndex();
-316 		var ol = this._getListContainer();
-317 		ol.childNodes[index].className = "";
-318 		
-319 		index--;
-320 		if(index < 0) index = count - 1;
-321 
-322 		ol.childNodes[index].className = "selected";
-323 	},
-324 	
-325 	_moveSelectionDown: function() {
-326 		var count = this.matchCount();
-327 		if(count == 0) return;
-328 		var index = this._getSelectedIndex();
-329 		var ol = this._getListContainer();
-330 		ol.childNodes[index].className = "";
-331 
-332 		index++;
-333 		if(index >= count) index = 0;
-334 		
-335 		ol.childNodes[index].className = "selected";
-336 	}
-337 });
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_03.html b/modules/editor/skins/xquared/doc/api/src_03.html deleted file mode 100644 index 076de09f1..000000000 --- a/modules/editor/skins/xquared/doc/api/src_03.html +++ /dev/null @@ -1,325 +0,0 @@ -
  1 /**
-  2  * Provide various tree operations.
-  3  *
-  4  * TODO: Add specs
-  5  */
-  6 xq.DomTree = Class.create({
-  7 	initialize: function() {
-  8 		this._blockTags = ["DIV", "DD", "LI", "ADDRESS", "CAPTION", "DT", "H1", "H2", "H3", "H4", "H5", "H6", "HR", "P", "BODY", "BLOCKQUOTE", "PRE", "PARAM", "DL", "OL", "UL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
-  9 		this._blockContainerTags = ["DIV", "DD", "LI", "BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR", "TH", "TD"];
- 10 		this._listContainerTags = ["OL", "UL", "DL"];
- 11 		this._tableCellTags = ["TH", "TD"];
- 12 		this._blockOnlyContainerTags = ["BODY", "BLOCKQUOTE", "UL", "OL", "DL", "TABLE", "THEAD", "TBODY", "TR"];
- 13 		this._atomicTags = ["IMG", "OBJECT", "BR", "HR"];
- 14 	},
- 15 	
- 16 	getBlockTags: function() {
- 17 		return this._blockTags;
- 18 	},
- 19 	
- 20 	/**
- 21 	 * Find common ancestor(parent) and his immediate children(left and right).
- 22 	 *
- 23 	 * A --- B -+- C -+- D -+- E
- 24 	 *          |
- 25 	 *          +- F -+- G
- 26 	 *
- 27 	 * For example:
- 28 	 * > findCommonAncestorAndImmediateChildrenOf("E", "G")
- 29 	 *
- 30 	 * will return
- 31 	 *
- 32 	 * > {parent:"B", left:"C", right:"F"}
- 33 	 */
- 34 	findCommonAncestorAndImmediateChildrenOf: function(left, right) {
- 35 		if(left.parentNode == right.parentNode) {
- 36 			return {
- 37 				left:left,
- 38 				right:right,
- 39 				parent:left.parentNode
- 40 			};
- 41 		} else {
- 42 			var parentsOfLeft = this.collectParentsOf(left, true);
- 43 			var parentsOfRight = this.collectParentsOf(right, true);
- 44 			var ca = this.getCommonAncestor(parentsOfLeft, parentsOfRight);
- 45 	
- 46 			var leftAncestor = parentsOfLeft.find(function(node) {return node.parentNode == ca});
- 47 			var rightAncestor = parentsOfRight.find(function(node) {return node.parentNode == ca});
- 48 			
- 49 			return {
- 50 				left:leftAncestor,
- 51 				right:rightAncestor,
- 52 				parent:ca
- 53 			};
- 54 		}
- 55 	},
- 56 	
- 57 	/**
- 58 	 * Find leaves at edge.
- 59 	 *
- 60 	 * A --- B -+- C -+- D -+- E
- 61 	 *          |
- 62 	 *          +- F -+- G
- 63 	 *
- 64 	 * For example:
- 65 	 * > getLeavesAtEdge("A")
- 66 	 *
- 67 	 * will return
- 68 	 *
- 69 	 * > ["E", "G"]
- 70 	 */
- 71 	getLeavesAtEdge: function(element) {
- 72 		if(!element.hasChildNodes()) return [null, null];
- 73 		
- 74 		var findLeft = function(el) {
- 75 			for (var i = 0; i < el.childNodes.length; i++) {
- 76 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findLeft(el.childNodes[i]);
- 77 			}
- 78 			return el;
- 79 		}.bind(this);
- 80 		
- 81 		var findRight=function(el) {
- 82 			for (var i = el.childNodes.length; i--;) {
- 83 				if (el.childNodes[i].nodeType == 1 && this.isBlock(el.childNodes[i])) return findRight(el.childNodes[i]);
- 84 			}
- 85 			return el;
- 86 		}.bind(this);
- 87 		
- 88 		var left = findLeft(element);
- 89 		var right = findRight(element);
- 90 		return [left == element ? null : left, right == element ? null : right];
- 91 	},
- 92 	
- 93 	getCommonAncestor: function(parents1, parents2) {
- 94 		for(var i = 0; i < parents1.length; i++) {
- 95 			for(var j = 0; j < parents2.length; j++) {
- 96 				if(parents1[i] == parents2[j]) return parents1[i];
- 97 			}
- 98 		}
- 99 	},
-100 	
-101 	collectParentsOf: function(node, includeSelf, exitCondition) {
-102 		var parents = [];
-103 		if(includeSelf) parents.push(node);
-104 		
-105 		while((node = node.parentNode) && (node.nodeName != "HTML") && !(typeof exitCondition == "function" && exitCondition(node))) parents.push(node);
-106 		return parents;
-107 	},
-108 	
-109 	isDescendantOf: function(parent, child) {
-110 		if(parent.length > 0) {
-111 			for(var i = 0; i < parent.length; i++) {
-112 				if(this.isDescendantOf(parent[i], child)) return true;
-113 			}
-114 			return false;
-115 		}
-116 		
-117 		if(parent == child) return false;
-118 		
-119 	    while (child = child.parentNode)
-120 	      if (child == parent) return true;
-121 	    return false;
-122 	},
-123 	
-124 	/**
-125 	 * Perform tree walking (foreward)
-126 	 */
-127 	walkForward: function(node) {
-128 		if(node.hasChildNodes()) return node.firstChild;
-129 		if(node.nextSibling) return node.nextSibling;
-130 		
-131 		while(node = node.parentNode) {
-132 			if(node.nextSibling) return node.nextSibling;
-133 		}
-134 		
-135 		return null;
-136 	},
-137 	
-138 	/**
-139 	 * Perform tree walking (backward)
-140 	 */
-141 	walkBackward: function(node) {
-142 		if(node.previousSibling) {
-143 			node = node.previousSibling;
-144 			while(node.hasChildNodes()) {node = node.lastChild;}
-145 			return node;
-146 		}
-147 		
-148 		return node.parentNode;
-149 	},
-150 	
-151 	/**
-152 	 * Perform tree walking (to next siblings)
-153 	 */
-154 	walkNext: function(node) {return node.nextSibling},
-155 	
-156 	/**
-157 	 * Perform tree walking (to next siblings)
-158 	 */
-159 	walkPrev: function(node) {return node.previousSibling},
-160 	
-161 	/**
-162 	 * Returns true if target is followed by start
-163 	 */
-164 	checkTargetForward: function(start, target) {
-165 		return this._check(start, this.walkForward, target);
-166 	},
-167 
-168 	/**
-169 	 * Returns true if start is followed by target
-170 	 */
-171 	checkTargetBackward: function(start, target) {
-172 		return this._check(start, this.walkBackward, target);
-173 	},
-174 	
-175 	findForward: function(start, condition, exitCondition) {
-176 		return this._find(start, this.walkForward, condition, exitCondition);
-177 	},
-178 	
-179 	findBackward: function(start, condition, exitCondition) {
-180 		return this._find(start, this.walkBackward, condition, exitCondition);
-181 	},
-182 	
-183 	/** @private */
-184 	_check: function(start, direction, target) {
-185 		if(start == target) return false;
-186 		
-187 		while(start = direction(start)) {
-188 			if(start == target) return true;
-189 		}
-190 		return false;
-191 	},
-192 	
-193 	/** @private */
-194 	_find: function(start, direction, condition, exitCondition) {
-195 		while(start = direction(start)) {
-196 			if(exitCondition && exitCondition(start)) return null;
-197 			if(condition(start)) return start;
-198 		}
-199 		return null;
-200 	},
-201 
-202 	/**
-203 	 * Walks Forward through DOM tree from start to end, and collects all nodes that matches with a filter.
-204 	 * If no filter provided, it just collects all nodes.
-205 	 *
-206 	 * @param function filter a filter function
-207 	 */
-208 	collectNodesBetween: function(start, end, filter) {
-209 		if(start == end) return [start, end].findAll(filter || function() {return true});
-210 		
-211 		var nodes = this.collectForward(start, function(node) {return node == end}, filter);
-212 		if(
-213 			start != end &&
-214 			typeof filter == "function" &&
-215 			filter(end)
-216 		) nodes.push(end);
-217 		
-218 		return nodes;
-219 	},
-220 
-221 	collectForward: function(start, exitCondition, filter) {
-222 		return this.collect(start, this.walkForward, exitCondition, filter);
-223 	},
-224 	
-225 	collectBackward: function(start, exitCondition, filter) {
-226 		return this.collect(start, this.walkBackward, exitCondition, filter);
-227 	},
-228 	
-229 	collectNext: function(start, exitCondition, filter) {
-230 		return this.collect(start, this.walkNext, exitCondition, filter);
-231 	},
-232 	
-233 	collectPrev: function(start, exitCondition, filter) {
-234 		return this.collect(start, this.walkPrev, exitCondition, filter);
-235 	},
-236 	
-237 	collect: function(start, next, exitCondition, filter) {
-238 		var nodes = [start];
-239 
-240 		while(true) {
-241 			start = next(start);
-242 			if(
-243 				(start == null) ||
-244 				(typeof exitCondition == "function" && exitCondition(start))
-245 			) break;
-246 			
-247 			nodes.push(start);
-248 		}
-249 
-250 		return (typeof filter == "function") ? nodes.findAll(filter) : nodes;
-251 	},
-252 
-253 
-254 	hasBlocks: function(element) {
-255 		var nodes = element.childNodes;
-256 		for(var i = 0; i < nodes.length; i++) {
-257 			if(this.isBlock(nodes[i])) return true;
-258 		}
-259 		return false;
-260 	},
-261 	
-262 	hasMixedContents: function(element) {
-263 		if(!this.isBlock(element)) return false;
-264 		if(!this.isBlockContainer(element)) return false;
-265 		
-266 		var hasTextOrInline = false;
-267 		var hasBlock = false;
-268 		for(var i = 0; i < element.childNodes.length; i++) {
-269 			var node = element.childNodes[i];
-270 			if(!hasTextOrInline && this.isTextOrInlineNode(node)) hasTextOrInline = true;
-271 			if(!hasBlock && this.isBlock(node)) hasBlock = true;
-272 			
-273 			if(hasTextOrInline && hasBlock) break;
-274 		}
-275 		if(!hasTextOrInline || !hasBlock) return false;
-276 		
-277 		return true;
-278 	},
-279 	
-280 	isBlockOnlyContainer: function(element) {
-281 		if(!element) return false;
-282 		return this._blockOnlyContainerTags.include(typeof element == 'string' ? element : element.nodeName);
-283 	},
-284 	
-285 	isTableCell: function(element) {
-286 		if(!element) return false;
-287 		return this._tableCellTags.include(typeof element == 'string' ? element : element.nodeName);
-288 	},
-289 	
-290 	isBlockContainer: function(element) {
-291 		if(!element) return false;
-292 		return this._blockContainerTags.include(typeof element == 'string' ? element : element.nodeName);
-293 	},
-294 	
-295 	isHeading: function(element) {
-296 		if(!element) return false;
-297 		return (typeof element == 'string' ? element : element.nodeName).match(/H\d/);
-298 	},
-299 	
-300 	isBlock: function(element) {
-301 		if(!element) return false;
-302 		return this._blockTags.include(typeof element == 'string' ? element : element.nodeName);
-303 	},
-304 	
-305 	isAtomic: function(element) {
-306 		if(!element) return false;
-307 		return this._atomicTags.include(typeof element == 'string' ? element : element.nodeName);
-308 	},
-309 	
-310 	isListContainer: function(element) {
-311 		if(!element) return false;
-312 		return this._listContainerTags.include(typeof element == 'string' ? element : element.nodeName);
-313 	},
-314 	
-315 	isTextOrInlineNode: function(node) {
-316 		return node && (node.nodeType == 3 || !this.isBlock(node));
-317 	}
-318 });
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_04.html b/modules/editor/skins/xquared/doc/api/src_04.html deleted file mode 100644 index 50db4821a..000000000 --- a/modules/editor/skins/xquared/doc/api/src_04.html +++ /dev/null @@ -1,163 +0,0 @@ -
  1 /**
-  2  * @fileOverview xq.EditHistory manages editing history and performs UNDO/REDO.
-  3  */
-  4 xq.EditHistory = Class.create({
-  5     /**
-  6 	 * Initializer
-  7 	 *
-  8      * @constructor
-  9 	 * @param {xq.RichDom} rdom RichDom instance
- 10 	 * @param {Number} [max] maximum UNDO buffer size(default value is 100).
- 11 	 */
- 12 	initialize: function(rdom, max) {
- 13 		if (!rdom) throw "IllegalArgumentException";
- 14 
- 15 		this.disabled = false;
- 16 		this.max = max || 100;
- 17 		this.rdom = rdom;
- 18 		this.root = rdom.getRoot();
- 19 		this.clear();
- 20 		
- 21 		this.lastModified = Date.get();
- 22 	},
- 23 	getLastModifiedDate: function() {
- 24 		return this.lastModified;
- 25 	},
- 26 	isUndoable: function() {
- 27 		return this.queue.length > 0 && this.index > 0;
- 28 	},
- 29 	isRedoable: function() {
- 30 		return this.queue.length > 0 && this.index < this.queue.length - 1;
- 31 	},
- 32 	disable: function() {
- 33 		this.disabled = true;
- 34 	},
- 35 	enable: function() {
- 36 		this.disabled = false;
- 37 	},
- 38 	undo: function() {
- 39 		this.pushContent();
- 40 		
- 41 		if (this.isUndoable()) {
- 42 			this.index--;
- 43 			this.popContent();
- 44 			return true;
- 45 		} else {
- 46 			return false;
- 47 		}
- 48 	},
- 49 	redo: function() {
- 50 		if (this.isRedoable()) {
- 51 			this.index++;
- 52 			this.popContent();
- 53 			return true;
- 54 		} else {
- 55 			return false;
- 56 		}
- 57 	},
- 58 	onCommand: function() {
- 59 		this.lastModified = Date.get();
- 60 		if(this.disabled) return false;
- 61 
- 62 		return this.pushContent();
- 63 	},
- 64 	onEvent: function(event) {
- 65 		this.lastModified = Date.get();
- 66 		if(this.disabled) return false;
- 67 
- 68 		// ignore normal keys
- 69 		if('keydown' == event.type && !(event.ctrlKey || event.metaKey)) return false;
- 70 		if(['keydown', 'keyup', 'keypress'].include(event.type) && !event.ctrlKey && !event.altKey && !event.metaKey && ![33,34,35,36,37,38,39,40].include(event.keyCode)) return false;
- 71 		if(['keydown', 'keyup', 'keypress'].include(event.type) && (event.ctrlKey || event.metaKey) && [89,90].include(event.keyCode)) return false;
- 72 		
- 73 		// ignore ctrl/shift/alt/meta keys
- 74 		if([16,17,18,224].include(event.keyCode)) return false;
- 75 		
- 76 		return this.pushContent();
- 77 	},
- 78 	popContent: function() {
- 79 		this.lastModified = Date.get();
- 80 		var entry = this.queue[this.index];
- 81 		if (entry.caret > 0) {
- 82 			var html=entry.html.substring(0, entry.caret) + '<span id="caret_marker_00700"></span>' + entry.html.substring(entry.caret);
- 83 			this.root.innerHTML = html;
- 84 		} else {
- 85 			this.root.innerHTML = entry.html;
- 86 		}
- 87 		this.restoreCaret();
- 88 	},
- 89 	pushContent: function(ignoreCaret) {
- 90 		if(xq.Browser.isTrident && !ignoreCaret && !this.rdom.hasFocus()) return false;
- 91 		if(!this.rdom.getCurrentElement()) return false;
- 92 		
- 93 		var html = this.root.innerHTML;
- 94 		if(html == (this.queue[this.index] ? this.queue[this.index].html : null)) return false;
- 95 		var caret = ignoreCaret ? -1 : this.saveCaret();
- 96 		
- 97 		if(this.queue.length >= this.max) {
- 98 			this.queue.shift();
- 99 		} else {
-100 			this.index++;
-101 		}
-102 		
-103 		this.queue.splice(this.index, this.queue.length - this.index, {html:html, caret:caret});
-104 		return true;
-105 	},
-106 	clear: function() {
-107 		this.index = -1;
-108 		this.queue = [];
-109 		this.pushContent(true);
-110 	},
-111 	saveCaret: function() {
-112 		if(this.rdom.hasSelection()) return null;
-113 
-114 		// FF on Mac has a caret problem with these lines. --2007/11/19
-115 		var marker = this.rdom.pushMarker();
-116 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
-117 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
-118 		this.rdom.popMarker(true);
-119 
-120 		return caret;
-121 
-122 /*
-123 		// This is old code. It also has same problem.
-124 		
-125 		if(this.rdom.hasSelection()) return null;
-126 		
-127 		var bookmark = this.rdom.saveSelection();
-128 		var marker = this.rdom.pushMarker();
-129 		
-130 		var str = xq.Browser.isTrident ? '<SPAN class='+marker.className : '<span class="'+marker.className+'"';
-131 		var caret = this.rdom.getRoot().innerHTML.indexOf(str);
-132 		
-133 		this.rdom.popMarker();
-134 		this.rdom.restoreSelection(bookmark);
-135 		
-136 		return caret;
-137 */
-138 	},
-139 	restoreCaret: function() {
-140 		var marker = this.rdom.$('caret_marker_00700');
-141 		
-142 		if(marker) {
-143 			this.rdom.selectElement(marker, true);
-144 			this.rdom.collapseSelection(false);
-145 			this.rdom.deleteNode(marker);
-146 		} else {
-147 			var node = this.rdom.tree.findForward(this.rdom.getRoot(), function(node) {
-148 				return this.isBlock(node) && !this.hasBlocks(node);
-149 			}.bind(this.rdom.tree));
-150 			this.rdom.selectElement(node, false);
-151 			this.rdom.collapseSelection(false);
-152 			
-153 		}
-154 	}
-155 });
-156 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_05.html b/modules/editor/skins/xquared/doc/api/src_05.html deleted file mode 100644 index c8bbff96a..000000000 --- a/modules/editor/skins/xquared/doc/api/src_05.html +++ /dev/null @@ -1,2216 +0,0 @@ -
  1 /**
-  2  * @fileOverview xq.Editor manages configurations such as autocompletion and autocorrection, edit mode/normal mode switching, handles editing commands, keyboard shortcuts and other events.
-  3  */
-  4 xq.Editor = Class.create({
-  5 	/**
-  6 	 * Initialize editor but it doesn't automatically start designMode. setEditMode should be called after initialization.
-  7 	 *
-  8      * @constructor
-  9 	 * @param {Element} contentElement HTML element(TEXTAREA or normal block element such as DIV) to be replaced with editable area
- 10 	 * @param {Element} toolbarContainer HTML element which contains toolbar icons
- 11 	 */
- 12 	initialize: function(contentElement, toolbarContainer) {
- 13 		if(!contentElement) throw "[contentElement] is null";
- 14 		if(contentElement.nodeType != 1) throw "[contentElement] is not an element";
- 15 		
- 16 		xq.asEventSource(this, "Editor", ["ElementChanged", "BeforeEvent", "AfterEvent", "CurrentContentChanged", "StaticContentChanged", "CurrentEditModeChanged"]);
- 17 		
- 18 		/**
- 19 		 * Editor's configuration
- 20 		 * @type object
- 21 		 */
- 22 		this.config = {};
- 23 		this.config.enableLinkClick = false;
- 24 		this.config.changeCursorOnLink = false;
- 25 		this.config.generateDefaultToolbar = true;
- 26 		this.config.defaultToolbarButtonMap = [
- 27 			[
- 28 				{className:"foregroundColor", title:"Foreground color", handler:"xed.handleForegroundColor()"},
- 29 				{className:"backgroundColor", title:"Background color", handler:"xed.handleBackgroundColor()"}
- 30 			],
- 31 			[
- 32 				{className:"link", title:"Link", handler:"xed.handleLink()"},
- 33 				{className:"strongEmphasis", title:"Strong emphasis", handler:"xed.handleStrongEmphasis()"},
- 34 				{className:"emphasis", title:"Emphasis", handler:"xed.handleEmphasis()"},
- 35 				{className:"underline", title:"Underline", handler:"xed.handleUnderline()"},
- 36 				{className:"strike", title:"Strike", handler:"xed.handleStrike()"},
- 37 				{className:"superscription", title:"Superscription", handler:"xed.handleSuperscription()"},
- 38 				{className:"subscription", title:"Subscription", handler:"xed.handleSubscription()"}
- 39 			],
- 40 			[
- 41 				{className:"removeFormat", title:"Remove format", handler:"xed.handleRemoveFormat()"}
- 42 			],
- 43 			[
- 44 				{className:"justifyLeft", title:"Justify left", handler:"xed.handleJustify('left')"},
- 45 				{className:"justifyCenter", title:"Justify center", handler:"xed.handleJustify('center')"},
- 46 				{className:"justifyRight", title:"Justify right", handler:"xed.handleJustify('right')"},
- 47 				{className:"justifyBoth", title:"Justify both", handler:"xed.handleJustify('both')"}
- 48 			],
- 49 			[
- 50 				{className:"indent", title:"Indent", handler:"xed.handleIndent()"},
- 51 				{className:"outdent", title:"Outdent", handler:"xed.handleOutdent()"}
- 52 			],
- 53 			[
- 54 				{className:"unorderedList", title:"Unordered list", handler:"xed.handleList('UL')"},
- 55 				{className:"orderedList", title:"Ordered list", handler:"xed.handleList('OL')"}
- 56 			],
- 57 			[
- 58 				{className:"paragraph", title:"Paragraph", handler:"xed.handleApplyBlock('P')"},
- 59 				{className:"heading1", title:"Heading 1", handler:"xed.handleApplyBlock('H1')"},
- 60 				{className:"blockquote", title:"Blockquote", handler:"xed.handleApplyBlock('BLOCKQUOTE')"},
- 61 				{className:"code", title:"Code", handler:"xed.handleList('CODE')"},
- 62 				{className:"division", title:"Division", handler:"xed.handleApplyBlock('DIV')"}
- 63 			],
- 64 			[
- 65 				{className:"table", title:"Table", handler:"xed.handleTable(3,3,'tl')"},
- 66 				{className:"separator", title:"Separator", handler:"xed.handleSeparator()"}
- 67 			],
- 68 			[
- 69 				{className:"html", title:"Edit source", handler:"xed.toggleSourceAndWysiwygMode()"}
- 70 			],
- 71 			[
- 72 				{className:"undo", title:"Undo", handler:"xed.handleUndo()"},
- 73 				{className:"redo", title:"Redo", handler:"xed.handleRedo()"}
- 74 			]
- 75 		];
- 76 		
- 77 		this.config.imagePathForDefaultToobar = 'img/toolbar/';
- 78 		
- 79 		// relative | host_relative | absolute | browser_default
- 80 		this.config.urlValidationMode = 'absolute';
- 81 		
- 82 		this.config.automaticallyHookSubmitEvent = true;
- 83 		
- 84 		this.config.allowedTags = ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var'];
- 85 		this.config.allowedAttributes = ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width'];
- 86 		
- 87 		this.config.shortcuts = {};
- 88 		this.config.autocorrections = {};
- 89 		this.config.autocompletions = {};
- 90 		this.config.templateProcessors = {};
- 91 		this.config.contextMenuHandlers = {};
- 92 		
- 93 		/**
- 94 		 * Original content element
- 95 		 * @type Element
- 96 		 */
- 97 		this.contentElement = contentElement;
- 98 		
- 99 		/**
-100 		 * Owner document of content element
-101 		 * @type Document
-102 		 */
-103 		this.doc = this.contentElement.ownerDocument;
-104 		
-105 		/**
-106 		 * Body of content element
-107 		 * @type Element
-108 		 */
-109 		this.body = this.doc.body;
-110 		
-111 		/**
-112 		 * False or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
-113 		 * @type Object
-114 		 */
-115 		this.currentEditMode = 'readonly';
-116 		
-117 		/**
-118 		 * RichDom instance
-119 		 * @type xq.RichDom
-120 		 */
-121 		this.rdom = xq.RichDom.createInstance();
-122 		
-123 		/**
-124 		 * Validator instance
-125 		 * @type xq.Validator
-126 		 */
-127 		this.validator = null;
-128 		
-129 		/**
-130 		 * Outmost wrapper div
-131 		 * @type Element
-132 		 */
-133 		this.outmostWrapper = null;
-134 		
-135 		/**
-136 		 * Source editor container
-137 		 * @type Element
-138 		 */
-139 		this.sourceEditorDiv = null;
-140 		
-141 		/**
-142 		 * Source editor textarea
-143 		 * @type Element
-144 		 */
-145 		this.sourceEditorTextarea = null;
-146 		
-147 		/**
-148 		 * WYSIWYG editor container
-149 		 * @type Element
-150 		 */
-151 		this.wysiwygEditorDiv = null;
-152 		
-153 		/**
-154 		 * Design mode iframe
-155 		 * @type IFrame
-156 		 */
-157 		this.editorFrame = null;
-158 		
-159 		/**
-160 		 * Window that contains design mode iframe
-161 		 * @type Window
-162 		 */
-163 		this.editorWin = null;
-164 		
-165 		/**
-166 		 * Document that contained by design mode iframe
-167 		 * @type Document
-168 		 */
-169 		this.editorDoc = null;
-170 		
-171 		/**
-172 		 * Body that contained by design mode iframe
-173 		 * @type Element
-174 		 */
-175 		this.editorBody = null;
-176 		
-177 		/**
-178 		 * Toolbar container
-179 		 * @type Element
-180 		 */
-181 		this.toolbarContainer = toolbarContainer;
-182 		
-183 		/**
-184 		 * Toolbar buttons
-185 		 * @type Array
-186 		 */
-187 		this.toolbarButtons = null;
-188 		
-189 		/**
-190 		 * Undo/redo manager
-191 		 * @type xq.EditHistory
-192 		 */
-193 		this.editHistory = null;
-194 		
-195 		this._contextMenuContainer = null;
-196 		this._contextMenuItems = null;
-197 		
-198 		this._validContentCache = null;
-199 		this._lastModified = null;
-200 		
-201 		this.addShortcuts(this._getDefaultShortcuts());
-202 		this.addTemplateProcessors(this._getDefaultTemplateProcessors());
-203 		
-204 		this.addListener({
-205 			onEditorCurrentContentChanged: function(xed) {
-206 				var curFocusElement = xed.rdom.getCurrentElement();
-207 				if(!curFocusElement) return;
-208 				
-209 				if(xed._lastFocusElement != curFocusElement) {
-210 					if(!xed.rdom.tree.isBlockOnlyContainer(xed._lastFocusElement) && xed.rdom.tree.isBlock(xed._lastFocusElement)) {
-211 						xed.rdom.removeTrailingWhitespace(xed._lastFocusElement);
-212 					}
-213 					xed._fireOnElementChanged(xed._lastFocusElement, curFocusElement);
-214 					xed._lastFocusElement = curFocusElement;
-215 				}
-216 
-217 				xed.updateAllToolbarButtonsStatus(curFocusElement);
-218 			}
-219 		});
-220 	},
-221 	
-222 	
-223 	
-224 	/////////////////////////////////////////////
-225 	// Configuration Management
-226 	
-227 	_getDefaultShortcuts: function() {
-228 		if(xq.Browser.isMac) {
-229 			// Mac FF & Safari
-230 			return [
-231 				{event:"Ctrl+Shift+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
-232 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
-233 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
-234 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
-235 				{event:"TAB", handler:"this.handleTab()"},
-236 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
-237 				{event:"DELETE", handler:"this.handleDelete()"},
-238 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
-239 				
-240 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
-241 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
-242 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
-243 				{event:"Ctrl+K", handler:"this.handleStrike()"},
-244 				{event:"Meta+Z", handler:"this.handleUndo()"},
-245 				{event:"Meta+Shift+Z", handler:"this.handleRedo()"},
-246 				{event:"Meta+Y", handler:"this.handleRedo()"}
-247 			];
-248 		} else if(xq.Browser.isUbuntu) {
-249 			//  Ubunto FF
-250 			return [
-251 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
-252 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
-253 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
-254 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
-255 				{event:"TAB", handler:"this.handleTab()"},
-256 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
-257 				{event:"DELETE", handler:"this.handleDelete()"},
-258 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
-259 			
-260 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
-261 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
-262 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
-263 				{event:"Ctrl+K", handler:"this.handleStrike()"},
-264 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
-265 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
-266 			];
-267 		} else {
-268 			// Win IE & FF
-269 			return [
-270 				{event:"Ctrl+SPACE", handler:"this.handleAutocompletion(); stop = true;"},
-271 				{event:"ENTER", handler:"this.handleEnter(false, false)"},
-272 				{event:"Ctrl+ENTER", handler:"this.handleEnter(true, false)"},
-273 				{event:"Ctrl+Shift+ENTER", handler:"this.handleEnter(true, true)"},
-274 				{event:"TAB", handler:"this.handleTab()"},
-275 				{event:"Shift+TAB", handler:"this.handleShiftTab()"},
-276 				{event:"DELETE", handler:"this.handleDelete()"},
-277 				{event:"BACKSPACE", handler:"this.handleBackspace()"},
-278 			
-279 				{event:"Ctrl+B", handler:"this.handleStrongEmphasis()"},
-280 				{event:"Ctrl+I", handler:"this.handleEmphasis()"},
-281 				{event:"Ctrl+U", handler:"this.handleUnderline()"},
-282 				{event:"Ctrl+K", handler:"this.handleStrike()"},
-283 				{event:"Ctrl+Z", handler:"this.handleUndo()"},
-284 				{event:"Ctrl+Y", handler:"this.handleRedo()"}
-285 			];
-286 		}
-287 	},
-288 	
-289 	_getDefaultTemplateProcessors: function() {
-290 		return [
-291 			{
-292 				id:"predefinedKeywordProcessor",
-293 				handler:function(html) {
-294 					var today = Date.get();
-295 					var keywords = {
-296 						year: today.getFullYear(),
-297 						month: today.getMonth() + 1,
-298 						date: today.getDate(),
-299 						hour: today.getHours(),
-300 						min: today.getMinutes(),
-301 						sec: today.getSeconds()
-302 					};
-303 					
-304 					return html.replace(/\{xq:(year|month|date|hour|min|sec)\}/img, function(text, keyword) {
-305 						return keywords[keyword] || keyword;
-306 					});
-307 				}
-308 			}
-309 		];
-310 	},
-311 	
-312 	/**
-313 	 * Adds or replaces keyboard shortcut.
-314 	 *
-315 	 * @param {String} shortcut keymap expression like "CTRL+Space"
-316 	 * @param {Object} handler string or function to be evaluated or called
-317 	 */
-318 	addShortcut: function(shortcut, handler) {
-319 		this.config.shortcuts[shortcut] = {"event":new xq.Shortcut(shortcut), "handler":handler};
-320 	},
-321 	
-322 	/**
-323 	 * Adds several keyboard shortcuts at once.
-324 	 *
-325 	 * @param {Array} list of shortcuts. each element should have following structure: {event:"keymap expression", handler:handler}
-326 	 */
-327 	addShortcuts: function(list) {
-328 		list.each(function(shortcut) {
-329 			this.addShortcut(shortcut.event, shortcut.handler);
-330 		}.bind(this));
-331 	},
-332 
-333 	/**
-334 	 * Returns keyboard shortcut matches with given keymap expression.
-335 	 *
-336 	 * @param {String} shortcut keymap expression like "CTRL+Space"
-337 	 */
-338 	getShortcut: function(shortcut) {return this.config.shortcuts[shortcut];},
-339 
-340 	/**
-341 	 * Returns entire keyboard shortcuts' map
-342 	 */
-343 	getShortcuts: function() {return this.config.shortcuts;},
-344 	
-345 	/**
-346 	 * Remove keyboard shortcut matches with given keymap expression.
-347 	 *
-348 	 * @param {String} shortcut keymap expression like "CTRL+Space"
-349 	 */
-350 	removeShortcut: function(shortcut) {delete this.config.shortcuts[shortcut];},
-351 	
-352 	/**
-353 	 * Adds or replaces autocorrection handler.
-354 	 *
-355 	 * @param {String} id unique identifier
-356 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
-357 	 * @param {Object} handler string or function to be evaluated or called when criteria met
-358 	 */
-359 	addAutocorrection: function(id, criteria, handler) {
-360 		if(criteria.exec) {
-361 			var pattern = criteria;
-362 			criteria = function(text) {return text.match(pattern)};
-363 		}
-364 		this.config.autocorrections[id] = {"criteria":criteria, "handler":handler};
-365 	},
-366 	
-367 	/**
-368 	 * Adds several autocorrection handlers at once.
-369 	 *
-370 	 * @param {Array} list of autocorrection. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
-371 	 */
-372 	addAutocorrections: function(list) {
-373 		list.each(function(ac) {
-374 			this.addAutocorrection(ac.id, ac.criteria, ac.handler);
-375 		}.bind(this));
-376 	},
-377 	
-378 	/**
-379 	 * Returns autocorrection handler matches with given id
-380 	 *
-381 	 * @param {String} id unique identifier
-382 	 */
-383 	getAutocorrection: function(id) {return this.config.autocorrection[id];},
-384 	
-385 	/**
-386 	 * Returns entire autocorrections' map
-387 	 */
-388 	getAutocorrections: function() {return this.config.autocorrections;},
-389 	
-390 	/**
-391 	 * Removes autocorrection handler matches with given id
-392 	 *
-393 	 * @param {String} id unique identifier
-394 	 */
-395 	removeAutocorrection: function(id) {delete this.config.autocorrections[id];},
-396 	
-397 	/**
-398 	 * Adds or replaces autocompletion handler.
-399 	 *
-400 	 * @param {String} id unique identifier
-401 	 * @param {Object} criteria regex pattern or function to be used as a criterion for match
-402 	 * @param {Object} handler string or function to be evaluated or called when criteria met
-403 	 */
-404 	addAutocompletion: function(id, criteria, handler) {
-405 		if(criteria.exec) {
-406 			var pattern = criteria;
-407 			criteria = function(text) {
-408 				var m = pattern.exec(text);
-409 				return m ? m.index : -1;
-410 			};
-411 		}
-412 		this.config.autocompletions[id] = {"criteria":criteria, "handler":handler};
-413 	},
-414 	
-415 	/**
-416 	 * Adds several autocompletion handlers at once.
-417 	 *
-418 	 * @param {Array} list of autocompletion. each element should have following structure: {id:"identifier", criteria:criteria, handler:handler}
-419 	 */
-420 	addAutocompletions: function(list) {
-421 		list.each(function(ac) {
-422 			this.addAutocompletion(ac.id, ac.criteria, ac.handler);
-423 		}.bind(this));
-424 	},
-425 	
-426 	/**
-427 	 * Returns autocompletion handler matches with given id
-428 	 *
-429 	 * @param {String} id unique identifier
-430 	 */
-431 	getAutocompletion: function(id) {return this.config.autocompletions[id];},
-432 	
-433 	/**
-434 	 * Returns entire autocompletions' map
-435 	 */
-436 	getAutocompletions: function() {return this.config.autocompletions;},
-437 	
-438 	/**
-439 	 * Removes autocompletion handler matches with given id
-440 	 *
-441 	 * @param {String} id unique identifier
-442 	 */
-443 	removeAutocompletion: function(id) {delete this.config.autocompletions[id];},
-444 	
-445 	/**
-446 	 * Adds or replaces template processor.
-447 	 *
-448 	 * @param {String} id unique identifier
-449 	 * @param {Object} handler string or function to be evaluated or called when template inserted
-450 	 */
-451 	addTemplateProcessor: function(id, handler) {
-452 		this.config.templateProcessors[id] = {"handler":handler};
-453 	},
-454 	
-455 	/**
-456 	 * Adds several template processors at once.
-457 	 *
-458 	 * @param {Array} list of template processors. Each element should have following structure: {id:"identifier", handler:handler}
-459 	 */
-460 	addTemplateProcessors: function(list) {
-461 		list.each(function(tp) {
-462 			this.addTemplateProcessor(tp.id, tp.handler);
-463 		}.bind(this));
-464 	},
-465 	
-466 	/**
-467 	 * Returns template processor matches with given id
-468 	 *
-469 	 * @param {String} id unique identifier
-470 	 */
-471 	getTemplateProcessor: function(id) {return this.config.templateProcessors[id];},
-472 
-473 	/**
-474 	 * Returns entire template processors' map
-475 	 */
-476 	getTemplateProcessors: function() {return this.config.templateProcessors;},
-477 
-478 	/**
-479 	 * Removes template processor matches with given id
-480 	 *
-481 	 * @param {String} id unique identifier
-482 	 */
-483 	removeTemplateProcessor: function(id) {delete this.config.templateProcessors[id];},
-484 
-485 
-486 
-487 	/**
-488 	 * Adds or replaces context menu handler.
-489 	 *
-490 	 * @param {String} id unique identifier
-491 	 * @param {Object} handler string or function to be evaluated or called when onContextMenu occured
-492 	 */
-493 	addContextMenuHandler: function(id, handler) {
-494 		this.config.contextMenuHandlers[id] = {"handler":handler};
-495 	},
-496 	
-497 	/**
-498 	 * Adds several context menu handlers at once.
-499 	 *
-500 	 * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler}
-501 	 */
-502 	addContextMenuHandlers: function(list) {
-503 		list.each(function(mh) {
-504 			this.addContextMenuHandler(mh.id, mh.handler);
-505 		}.bind(this));
-506 	},
-507 	
-508 	/**
-509 	 * Returns context menu handler matches with given id
-510 	 *
-511 	 * @param {String} id unique identifier
-512 	 */
-513 	getContextMenuHandler: function(id) {return this.config.contextMenuHandlers[id];},
-514 
-515 	/**
-516 	 * Returns entire context menu handlers' map
-517 	 */
-518 	getContextMenuHandlers: function() {return this.config.contextMenuHandlers;},
-519 
-520 	/**
-521 	 * Removes context menu handler matches with given id
-522 	 *
-523 	 * @param {String} id unique identifier
-524 	 */
-525 	removeContextMenuHandler: function(id) {delete this.config.contextMenuHandlers[id];},
-526 	
-527 	
-528 	
-529 	/////////////////////////////////////////////
-530 	// Edit mode management
-531 	
-532 	/**
-533 	 * Returns current edit mode - readonly, wysiwyg, source
-534 	 */
-535 	getCurrentEditMode: function() {
-536 		return this.currentEditMode;
-537 	},
-538 	
-539 	toggleSourceAndWysiwygMode: function() {
-540 		var mode = this.getCurrentEditMode();
-541 		if(mode == 'readonly') return;
-542 		this.setEditMode(mode == 'wysiwyg' ? 'source' : 'wysiwyg');
-543 		
-544 		return true;
-545 	},
-546 	
-547 	/**
-548 	 * Switches between edit-mode/normal mode.
-549 	 *
-550 	 * @param {Object} mode false or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode.
-551 	 */
-552 	setEditMode: function(mode) {
-553 		if(this.currentEditMode == mode) return;
-554 		
-555 		var firstCall = mode != false && mode != 'readonly' && !this.outmostWrapper;
-556 		if(firstCall) {
-557 			// Create editor element if needed
-558 			this._createEditorFrame();
-559 			this._registerEventHandlers();
-560 			
-561 			this.loadCurrentContentFromStaticContent();
-562 			this.editHistory = new xq.EditHistory(this.rdom);
-563 		}
-564 		
-565 		if(mode == 'wysiwyg') {
-566 			// Update contents
-567 			if(this.currentEditMode == 'source') this.setStaticContent(this.getSourceContent());
-568 			this.loadCurrentContentFromStaticContent();
-569 			
-570 			// Make static content invisible
-571 			this.contentElement.style.display = "none";
-572 			
-573 			// Make WYSIWYG editor visible
-574 			this.sourceEditorDiv.style.display = "none";
-575 			this.wysiwygEditorDiv.style.display = "block";
-576 			this.outmostWrapper.style.display = "block";
-577 			
-578 			this.currentEditMode = mode;
-579 			
-580 			if(!xq.Browser.isTrident) {
-581 				window.setTimeout(function() {
-582 					if(this.getDoc().designMode == 'On') return;
-583 					
-584 					// Without it, Firefox doesn't display embedded SWF
-585 					this.getDoc().designMode = 'On';
-586 					
-587 					// turn off Firefox's table editing feature
-588 					try {this.getDoc().execCommand("enableInlineTableEditing", false, "false")} catch(ignored) {}
-589 				}.bind(this), 0);
-590 			}
-591 			
-592 			this.enableToolbarButtons();
-593 			if(!firstCall) this.focus();
-594 		} else if(mode == 'source') {
-595 			// Update contents
-596 			if(this.currentEditMode == 'wysiwyg') this.setStaticContent(this.getWysiwygContent());
-597 			this.loadCurrentContentFromStaticContent();
-598 			
-599 			// Make static content invisible
-600 			this.contentElement.style.display = "none";
-601 			
-602 			// Make source editor visible
-603 			this.sourceEditorDiv.style.display = "block";
-604 			this.wysiwygEditorDiv.style.display = "none";
-605 			this.outmostWrapper.style.display = "block";
-606 			
-607 			this.currentEditMode = mode;
-608 
-609 			this.disableToolbarButtons(['html']);
-610 			if(!firstCall) this.focus();
-611 		} else {
-612 			// Update contents
-613 			this.setStaticContent(this.getCurrentContent());
-614 			this.loadCurrentContentFromStaticContent();
-615 
-616 			// Make editor and toolbar invisible
-617 			this.outmostWrapper.style.display = "none";
-618 			
-619 			// Make static content visible
-620 			this.contentElement.style.display = "block";
-621 			
-622 			this.currentEditMode = mode;
-623 		}
-624 		
-625 		this._fireOnCurrentEditModeChanged(this, mode);
-626 	},
-627 	
-628 	/**
-629 	 * Load CSS into editing-mode document
-630 	 *
-631 	 * @param {string} path URL
-632 	 */
-633 	loadStylesheet: function(path) {
-634 		var head = this.editorDoc.getElementsByTagName("HEAD")[0];
-635 		var link = this.editorDoc.createElement("LINK");
-636 		link.rel = "Stylesheet";
-637 		link.type = "text/css";
-638 		link.href = path;
-639 		head.appendChild(link);
-640 	},
-641 	
-642 	/**
-643 	 * Sets editor's dynamic content from static content
-644 	 */
-645 	loadCurrentContentFromStaticContent: function() {
-646 		// update WYSIWYG editor
-647 		var html = this.validator.invalidate(this.getStaticContentAsDOM());
-648 		html = this.removeUnnecessarySpaces(html);
-649 		
-650 		if(html.blank()) {
-651 			this.rdom.clearRoot();
-652 		} else {
-653 			this.rdom.getRoot().innerHTML = html;
-654 		}
-655 		this.rdom.wrapAllInlineOrTextNodesAs("P", this.rdom.getRoot(), true);
-656 		
-657 		// update source editor
-658 		var source = this.getWysiwygContent(true, true);
-659 		
-660 		this.sourceEditorTextarea.value = source;
-661 		if(xq.Browser.isWebkit) {
-662 			this.sourceEditorTextarea.innerHTML = source;
-663 		}
-664 		
-665 		this._fireOnCurrentContentChanged(this);
-666 	},
-667 	
-668 	/**
-669 	 * Enables all toolbar buttons
-670 	 *
-671 	 * @param {Array} [exceptions] array of string containing classnames to exclude
-672 	 */
-673 	enableToolbarButtons: function(exceptions) {
-674 		if(!this.toolbarContainer) return;
-675 		
-676 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
-677 			li.firstChild.className = !exception ? '' : 'disabled';
-678 		});
-679 		
-680 		// Toolbar image icon disappears without following code:
-681 		if(xq.Browser.isIE6) {
-682 			this.toolbarContainer.style.display = 'none';
-683 			setTimeout(function() {this.toolbarContainer.style.display = 'block';}.bind(this), 0);
-684 		}
-685 	},
-686 	
-687 	/**
-688 	 * Disables all toolbar buttons
-689 	 *
-690 	 * @param {Array} [exceptions] array of string containing classnames to exclude
-691 	 */
-692 	disableToolbarButtons: function(exceptions) {
-693 		this._execForAllToolbarButtons(exceptions, function(li, exception) {
-694 			li.firstChild.className = exception ? '' : 'disabled';
-695 		});
-696 	},
-697 	
-698 	_execForAllToolbarButtons: function(exceptions, exec) {
-699 		if(!this.toolbarContainer) return;
-700 		exceptions = exceptions || [];
-701 		
-702 		$(this.toolbarContainer).select('li').each(function(li) {
-703 			var buttonsClassName = li.classNames().find(function(name) {return name != 'xq_separator'});
-704 			var exception = exceptions.include(buttonsClassName);
-705 			exec(li, exception);
-706 		});
-707 	},
-708 
-709 	_updateToolbarButtonStatus: function(buttonClassName, selected) {
-710 		var button = this.toolbarButtons.get(buttonClassName);
-711 		if(button) button.firstChild.firstChild.className = selected ? 'selected' : '';
-712 	},
-713 	
-714 	updateAllToolbarButtonsStatus: function(element) {
-715 		if(!this.toolbarContainer) return;
-716 		if(!this.toolbarButtons) {
-717 			var classNames = [
-718 				"emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription",
-719 				"justifyLeft", "justifyCenter", "justifyRight", "justifyBoth",
-720 				"unorderedList", "orderedList", "code",
-721 				"paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6"
-722 			];
-723 			
-724 			this.toolbarButtons = $H({});
-725 			
-726 			classNames.each(function(className) {
-727 				var found = $(this.toolbarContainer).getElementsBySelector("." + className);
-728 				var button = found && found.length > 0 ? found[0] : null;
-729 				if(button) this.toolbarButtons.set(className, button);
-730 			}.bind(this));
-731 		}
-732 		
-733 		var buttons = this.toolbarButtons;
-734 		
-735 		var info = this.rdom.collectStructureAndStyle(element);
-736 		
-737 		this._updateToolbarButtonStatus('emphasis', info.em);
-738 		this._updateToolbarButtonStatus('strongEmphasis', info.strong);
-739 		this._updateToolbarButtonStatus('underline', info.underline);
-740 		this._updateToolbarButtonStatus('strike', info.strike);
-741 		this._updateToolbarButtonStatus('superscription', info.superscription);
-742 		this._updateToolbarButtonStatus('subscription', info.subscription);
-743 		
-744 		this._updateToolbarButtonStatus('justifyLeft', info.justification == 'left');
-745 		this._updateToolbarButtonStatus('justifyCenter', info.justification == 'center');
-746 		this._updateToolbarButtonStatus('justifyRight', info.justification == 'right');
-747 		this._updateToolbarButtonStatus('justifyBoth', info.justification == 'justify');
-748 		
-749 		this._updateToolbarButtonStatus('orderedList', info.list == 'OL');
-750 		this._updateToolbarButtonStatus('unorderedList', info.list == 'UL');
-751 		this._updateToolbarButtonStatus('code', info.list == 'CODE');
-752 		
-753 		this._updateToolbarButtonStatus('paragraph', info.block == 'P');
-754 		this._updateToolbarButtonStatus('heading1', info.block == 'H1');
-755 		this._updateToolbarButtonStatus('heading2', info.block == 'H2');
-756 		this._updateToolbarButtonStatus('heading3', info.block == 'H3');
-757 		this._updateToolbarButtonStatus('heading4', info.block == 'H4');
-758 		this._updateToolbarButtonStatus('heading5', info.block == 'H5');
-759 		this._updateToolbarButtonStatus('heading6', info.block == 'H6');
-760 	},
-761 	
-762 	removeUnnecessarySpaces: function(html) {
-763 		var blocks = this.rdom.tree.getBlockTags().join("|");
-764 		var regex = new RegExp("\\s*<(/?)(" + blocks + ")>\\s*", "img");
-765 		return html.replace(regex, '<$1$2>');
-766 	},
-767 	
-768 	/**
-769 	 * Gets editor's dynamic content from current editor(source or WYSIWYG)
-770 	 * 
-771 	 * @return {Object} HTML String
-772 	 */
-773 	getCurrentContent: function(performFullValidation) {
-774 		if(this.getCurrentEditMode() == 'source') {
-775 			return this.getSourceContent(performFullValidation);
-776 		} else {
-777 			return this.getWysiwygContent(performFullValidation);
-778 		}
-779 	},
-780 	
-781 	/**
-782 	 * Gets editor's dynamic content from WYSIWYG editor
-783 	 * 
-784 	 * @return {Object} HTML String
-785 	 */
-786 	getWysiwygContent: function(performFullValidation, dontUseCache) {
-787 		if(dontUseCache || !performFullValidation) return this.validator.validate(this.rdom.getRoot(), performFullValidation);
-788 		
-789 		var lastModified = this.editHistory.getLastModifiedDate();
-790 		if(this._lastModified != lastModified) {
-791 			this._validContentCache = this.validator.validate(this.rdom.getRoot(), performFullValidation);
-792 			this._lastModified = lastModified;
-793 		}
-794 		return this._validContentCache;
-795 	},
-796 	
-797 	/**
-798 	 * Gets editor's dynamic content from source editor
-799 	 * 
-800 	 * @return {Object} HTML String
-801 	 */
-802 	getSourceContent: function(performFullValidation) {
-803 		var raw = this.sourceEditorTextarea[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
-804 		var tempDiv = document.createElement('div');
-805 		tempDiv.innerHTML = this.removeUnnecessarySpaces(raw);
-806 
-807 		var rdom = xq.RichDom.createInstance();
-808 		rdom.setRoot(document.body);
-809 		rdom.wrapAllInlineOrTextNodesAs("P", tempDiv, true);
-810 		
-811 		return this.validator.validate(tempDiv, performFullValidation);
-812 	},
-813 	
-814 	/**
-815 	 * Sets editor's original content
-816 	 *
-817 	 * @param {Object} content HTML String
-818 	 */
-819 	setStaticContent: function(content) {
-820 		if(this.contentElement.nodeName == 'TEXTAREA') {
-821 			this.contentElement.value = content;
-822 			if(xq.Browser.isWebkit) {
-823 				this.contentElement.innerHTML = content;
-824 			}
-825 		} else {
-826 			this.contentElement.innerHTML = content;
-827 		}
-828 		this._fireOnStaticContentChanged(this, content);
-829 	},
-830 	
-831 	/**
-832 	 * Gets editor's original content
-833 	 *
-834 	 * @return {Object} HTML String
-835 	 */
-836 	getStaticContent: function() {
-837 		var content;
-838 		if(this.contentElement.nodeName == 'TEXTAREA') {
-839 			content = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
-840 		} else {
-841 			content = this.contentElement.innerHTML;
-842 		}
-843 		return content;
-844 	},
-845 	
-846 	/**
-847 	 * Gets editor's original content as DOM node
-848 	 *
-849 	 * @return {Object} HTML String
-850 	 */
-851 	getStaticContentAsDOM: function() {
-852 		if(this.contentElement.nodeName == 'TEXTAREA') {
-853 			var div = this.doc.createElement('DIV');
-854 			div.innerHTML = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value'];
-855 			return div;
-856 		} else {
-857 			return this.contentElement;
-858 		}
-859 	},
-860 	
-861 	/**
-862 	 * Gives focus to editor
-863 	 */
-864 	focus: function() {
-865 		if(this.getCurrentEditMode() == 'wysiwyg') {
-866 			this.rdom.focus();
-867 			window.setTimeout(function() {
-868 				this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement());
-869 			}.bind(this), 0);
-870 		} else if(this.getCurrentEditMode() == 'source') {
-871 			this.sourceEditorTextarea.focus();
-872 		}
-873 	},
-874 	
-875 	/**
-876 	 * Returns designmode iframe object
-877 	 */
-878 	getFrame: function() {
-879 		return this.editorFrame;
-880 	},
-881 	
-882 	/**
-883 	 * Returns designmode window object
-884 	 */
-885 	getWin: function() {
-886 		return this.editorWin;
-887 	},
-888 	
-889 	/**
-890 	 * Returns designmode document object
-891 	 */
-892 	getDoc: function() {
-893 		return this.editorDoc;
-894 	},
-895 	
-896 	/**
-897 	 * Returns outmost wrapper element
-898 	 */
-899 	getOutmostWrapper: function() {
-900 		return this.outmostWrapper;
-901 	},
-902 	
-903 	/**
-904 	 * Returns designmode body object
-905 	 */
-906 	getBody: function() {
-907 		return this.editorBody;
-908 	},
-909 	
-910 	_createEditorFrame: function() {
-911 		// create outer DIV
-912 		this.outmostWrapper = this.doc.createElement('div');
-913 		this.outmostWrapper.className = "xquared";
-914 		
-915 		this.contentElement.parentNode.insertBefore(this.outmostWrapper, this.contentElement);
-916 		
-917 		// create toolbar is needed
-918 		if(!this.toolbarContainer && this.config.generateDefaultToolbar) {
-919 			this.toolbarContainer = this._generateDefaultToolbar();
-920 			this.outmostWrapper.appendChild(this.toolbarContainer);
-921 		}
-922 		
-923 		// create source editor div
-924 		this.sourceEditorDiv = this.doc.createElement('div');
-925 		this.sourceEditorDiv.className = "editor source_editor"; //TODO: remove editor
-926 		this.sourceEditorDiv.style.display = "none";
-927 		this.outmostWrapper.appendChild(this.sourceEditorDiv);
-928 		
-929 		// create TEXTAREA for source editor
-930 		this.sourceEditorTextarea = this.doc.createElement('textarea');
-931 		this.sourceEditorDiv.appendChild(this.sourceEditorTextarea);
-932 		
-933 		// create WYSIWYG editor div
-934 		this.wysiwygEditorDiv = this.doc.createElement('div');
-935 		this.wysiwygEditorDiv.className = "editor wysiwyg_editor"; //TODO: remove editor
-936 		this.wysiwygEditorDiv.style.display = "none";
-937 		this.outmostWrapper.appendChild(this.wysiwygEditorDiv);
-938 		
-939 		// create designmode iframe for WYSIWYG editor
-940 		this.editorFrame = this.doc.createElement('iframe');
-941 		this.rdom.setAttributes(this.editorFrame, {
-942 			"frameBorder": "0",
-943 			"marginWidth": "0",
-944 			"marginHeight": "0",
-945 			"leftMargin": "0",
-946 			"topMargin": "0",
-947 			"allowTransparency": "true"
-948 		});
-949 		this.wysiwygEditorDiv.appendChild(this.editorFrame);
-950 		
-951 		var doc = this.editorFrame.contentWindow.document;
-952 		if(xq.Browser.isTrident) doc.designMode = 'On';
-953 		
-954 		doc.open();
-955 		doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">');
-956 		doc.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko">');
-957 		doc.write('<head>');
-958 		
-959 		// it is needed to force href of pasted content to be an absolute url
-960 		if(!xq.Browser.isTrident) doc.write('<base href="./" />');
-961 		
-962 		doc.write('<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />');
-963 		doc.write('<title>XQuared</title>');
-964 		if(this.config.changeCursorOnLink) doc.write('<style>.xed a {cursor: pointer !important;}</style>');
-965 		doc.write('</head>');
-966 		doc.write('<body><p>' + this.rdom.makePlaceHolderString() + '</p></body>');
-967 		doc.write('</html>');
-968 		doc.close();
-969 		
-970 		this.editorWin = this.editorFrame.contentWindow;
-971 		this.editorDoc = this.editorWin.document;
-972 		this.editorBody = this.editorDoc.body;
-973 		this.editorBody.className = "xed";
-974 		
-975 		// it is needed to fix IE6 horizontal scrollbar problem
-976 		if(xq.Browser.isIE6) {
-977 			this.editorDoc.documentElement.style.overflowY='auto';
-978 			this.editorDoc.documentElement.style.overflowX='hidden';
-979 		}
-980 		
-981 		this.rdom.setWin(this.editorWin);
-982 		this.rdom.setRoot(this.editorBody);
-983 		this.validator = xq.Validator.createInstance(this.doc.location.href, this.config.urlValidationMode, this.config.allowedTags, this.config.allowedAttributes);
-984 		
-985 		// hook onsubmit of form
-986 		if(this.config.automaticallyHookSubmitEvent && this.contentElement.nodeName == 'TEXTAREA' && this.contentElement.form) {
-987 			var original = this.contentElement.form.onsubmit;
-988 			
-989 			this.contentElement.form.onsubmit = function() {
-990 				this.contentElement.value = this.getCurrentContent(true);
-991 				if(original) {
-992 					return original();
-993 				} else {
-994 					return true;
-995 				}
-996 			}.bind(this);
-997 		}
-998 	},
-999 	
-1000 	_addStyleRule: function(selector, rule) {
-1001 		if(!this.dynamicStyle) {
-1002 			if(xq.Browser.isTrident) {
-1003 			    this.dynamicStyle = this.doc.createStyleSheet();
-1004 			} else {
-1005 	    		var style = this.doc.createElement('style');
-1006 	    		this.doc.body.appendChild(style);
-1007 		    	this.dynamicStyle = $A(this.doc.styleSheets).last();
-1008 			}
-1009 		}
-1010 		
-1011 		if(xq.Browser.isTrident) {
-1012 			this.dynamicStyle.addRule(selector, rule);
-1013 		} else {
-1014 	    	this.dynamicStyle.insertRule(selector + " {" + rule + "}", this.dynamicStyle.cssRules.length);
-1015     	}
-1016 	},
-1017 	
-1018 	_generateDefaultToolbar: function() {
-1019 		// override image path
-1020 		this._addStyleRule(".xquared div.toolbar", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarBg.gif)");
-1021 		this._addStyleRule(".xquared ul.buttons li", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarButtonBg.gif)");
-1022 		this._addStyleRule(".xquared ul.buttons li.xq_separator", "background-image: url(" + this.config.imagePathForDefaultToobar + "toolbarSeparator.gif)");
-1023 		
-1024 		// outmost container
-1025 		var container = this.doc.createElement('div');
-1026 		container.className = 'toolbar';
-1027 		
-1028 		// button container
-1029 		var buttons = this.doc.createElement('ul');
-1030 		buttons.className = 'buttons';
-1031 		container.appendChild(buttons);
-1032 		
-1033 		// Generate buttons from map and append it to button container
-1034 		var cancelMousedown = function(e) {Event.stop(e); return false};
-1035 		var map = this.config.defaultToolbarButtonMap;
-1036 		for(var i = 0; i < map.length; i++) {
-1037 			for(var j = 0; j < map[i].length; j++) {
-1038 				var buttonConfig = map[i][j];
-1039 
-1040 				var li = this.doc.createElement('li');
-1041 				buttons.appendChild(li);
-1042 				li.className = buttonConfig.className;
-1043 				
-1044 				var span = this.doc.createElement('span');
-1045 				li.appendChild(span);
-1046 				
-1047 				var a = this.doc.createElement('a');
-1048 				span.appendChild(a);
-1049 				a.href = '#';
-1050 				a.title = buttonConfig.title;
-1051 				a.handler = buttonConfig.handler;
-1052 				a.xed = this;
-1053 				Event.observe(a, 'mousedown', cancelMousedown);
-1054 				Event.observe(a, 'click', function(e) {
-1055 					var xed = this.xed;
-1056 					
-1057 					if($(this.parentNode).hasClassName('disabled') || xed.toolbarContainer.hasClassName('disabled')) {
-1058 						Event.stop(e);
-1059 						return false;
-1060 					}
-1061 					
-1062 					if(xq.Browser.isTrident) xed.focus();
-1063 					
-1064 					var handler = this.handler;
-1065 					var stop = (typeof handler == "function") ? handler(xed) : eval(handler);
-1066 					if(stop) {
-1067 						Event.stop(e);
-1068 						return false;
-1069 					} else {
-1070 						return true;
-1071 					}
-1072 				}.bind(a));
-1073 				
-1074 				var img = this.doc.createElement('img');
-1075 				a.appendChild(img);
-1076 				img.src = this.config.imagePathForDefaultToobar + buttonConfig.className + '.gif';
-1077 
-1078 				if(j == 0 && i != 0) li.className += ' xq_separator';
-1079 			}
-1080 		}
-1081 		
-1082 		return container;
-1083 	},
-1084 	
-1085 	
-1086 	
-1087 	/////////////////////////////////////////////
-1088 	// Event Management
-1089 	
-1090 	_registerEventHandlers: function() {
-1091 		var events = ['keydown', 'click', 'keyup', 'mouseup', 'contextmenu', 'scroll'];
-1092 		
-1093 		if(xq.Browser.isTrident && this.config.changeCursorOnLink) events.push('mousemove');
-1094 		if(xq.Browser.isMac && xq.Browser.isGecko) events.push('keypress');
-1095 		
-1096 		for(var i = 0; i < events.length; i++) {
-1097 			Event.observe(this.getDoc(), events[i], this._handleEvent.bindAsEventListener(this));
-1098 		}
-1099 	},
-1100 	
-1101 	_handleEvent: function(e) {
-1102 		this._fireOnBeforeEvent(this, e);
-1103 		
-1104 		var stop = false;
-1105 		
-1106 		var modifiedByCorrection = false;
-1107 		
-1108 		if(e.type == 'mousemove' && this.config.changeCursorOnLink) {
-1109 			// Trident only
-1110 			var link = !!this.rdom.getParentElementOf(e.srcElement, ["A"]);
-1111 			if(this.editorBody.contentEditable != link && !this.rdom.hasSelection()) this.editorBody.contentEditable = !link;
-1112 		} else if(e.type == 'click' && e.button == 0 && this.config.enableLinkClick) {
-1113 			var a = this.rdom.getParentElementOf(e.target || e.srcElement, ["A"]);
-1114 			if(a) stop = this.handleClick(e, a);
-1115 		} else if(e.type == (xq.Browser.isMac && xq.Browser.isGecko ? "keypress" : "keydown")) {
-1116 			var undoPerformed = false;
-1117 			
-1118 			modifiedByCorrection = this.rdom.correctParagraph();
-1119 			for(var key in this.config.shortcuts) {
-1120 				if(!this.config.shortcuts[key].event.matches(e)) continue;
-1121 				
-1122 				var handler = this.config.shortcuts[key].handler;
-1123 				var xed = this;
-1124 				stop = (typeof handler == "function") ? handler(this) : eval(handler);
-1125 				
-1126 				if(key == "undo") undoPerformed = true;
-1127 			}
-1128 		} else if(["mouseup", "keyup"].include(e.type)) {
-1129 			modifiedByCorrection = this.rdom.correctParagraph();
-1130 		} else if(["contextmenu"].include(e.type)) {
-1131 			this._handleContextMenu(e);
-1132 		}
-1133 		
-1134 		if(stop) Event.stop(e);
-1135 		
-1136 		this._fireOnCurrentContentChanged(this);
-1137 		this._fireOnAfterEvent(this, e);
-1138 		
-1139 		if(!undoPerformed && !modifiedByCorrection) this.editHistory.onEvent(e);
-1140 		
-1141 		return !stop;
-1142 	},
-1143 
-1144 	/**
-1145 	 * TODO: remove dup with handleAutocompletion
-1146 	 */
-1147 	handleAutocorrection: function() {
-1148 		var block = this.rdom.getCurrentBlockElement();
-1149 		
-1150 		// TODO: use complete unescape algorithm
-1151 		var text = this.rdom.getInnerText(block).replace(/ /gi, " ");
-1152 		
-1153 		var acs = this.config.autocorrections;
-1154 		var performed = false;
-1155 		
-1156 		var stop = false;
-1157 		for(var key in acs) {
-1158 			var ac = acs[key];
-1159 			if(ac.criteria(text)) {
-1160 				try {
-1161 					this.editHistory.onCommand();
-1162 					this.editHistory.disable();
-1163 					if(typeof ac.handler == "String") {
-1164 						var xed = this;
-1165 						var rdom = this.rdom;
-1166 						eval(ac.handler);
-1167 					} else {
-1168 						stop = ac.handler(this, this.rdom, block, text);
-1169 					}
-1170 					this.editHistory.enable();
-1171 				} catch(ignored) {}
-1172 				
-1173 				block = this.rdom.getCurrentBlockElement();
-1174 				text = this.rdom.getInnerText(block);
-1175 				
-1176 				performed = true;
-1177 				if(stop) break;
-1178 			}
-1179 		}
-1180 		
-1181 		return stop;
-1182 	},
-1183 	
-1184 	/**
-1185 	 * TODO: remove dup with handleAutocorrection
-1186 	 */
-1187 	handleAutocompletion: function() {
-1188 		var acs = $H(this.config.autocompletions);
-1189 		if(acs.size() == 0) return;
-1190 
-1191 		if(this.rdom.hasSelection()) {
-1192 			var text = this.rdom.getSelectionAsText();
-1193 			this.rdom.deleteSelection();
-1194 			var wrapper = this.rdom.insertNode(this.rdom.createElement("SPAN"));
-1195 			wrapper.innerHTML = text;
-1196 			
-1197 			var marker = this.rdom.pushMarker();
-1198 
-1199 			var filtered = 
-1200 				acs.map(function(pair) {
-1201 					return [pair.key, pair.value.criteria(text)];
-1202 				}.bind(this)).findAll(function(elem) {
-1203 					return elem[1] != -1;
-1204 				}).sortBy(function(elem) {
-1205 					return elem[1];
-1206 				});
-1207 			
-1208 			if(filtered.length == 0) {
-1209 				this.rdom.popMarker(true);
-1210 				return;
-1211 			}
-1212 			var ac = acs.get(filtered[0][0]);
-1213 			
-1214 			this.editHistory.disable();
-1215 		} else {
-1216 			var marker = this.rdom.pushMarker();
-1217 			
-1218 			var filtered = 
-1219 				acs.map(function(pair) {
-1220 					return [pair.key, this.rdom.testSmartWrap(marker, pair.value.criteria).textIndex];
-1221 				}.bind(this)).findAll(function(elem) {
-1222 					return elem[1] != -1;
-1223 				}).sortBy(function(elem) {
-1224 					return elem[1];
-1225 				});
-1226 			
-1227 			if(filtered.length == 0) {
-1228 				this.rdom.popMarker(true);
-1229 				return;
-1230 			}
-1231 			
-1232 			var ac = acs.get(filtered[0][0]);
-1233 			
-1234 			this.editHistory.disable();
-1235 			
-1236 			var wrapper = this.rdom.smartWrap(marker, "SPAN", ac.criteria);
-1237 		}
-1238 		
-1239 		var block = this.rdom.getCurrentBlockElement();
-1240 		
-1241 		// TODO: use complete unescape algorithm
-1242 		var text = this.rdom.getInnerText(wrapper).replace(/ /gi, " ");
-1243 		
-1244 		try {
-1245 			// call handler
-1246 			if(typeof ac.handler == "String") {
-1247 				var xed = this;
-1248 				var rdom = this.rdom;
-1249 				eval(ac.handler);
-1250 			} else {
-1251 				ac.handler(this, this.rdom, block, wrapper, text);
-1252 			}
-1253 		} catch(ignored) {}
-1254 		
-1255 		try {
-1256 			this.rdom.unwrapElement(wrapper);
-1257 		} catch(ignored) {}
-1258 
-1259 		
-1260 		if(this.rdom.isEmptyBlock(block)) this.rdom.correctEmptyElement(block);
-1261 		
-1262 		this.editHistory.enable();
-1263 		this.editHistory.onCommand();
-1264 		
-1265 		this.rdom.popMarker(true);
-1266 	},
-1267 
-1268 	/**
-1269 	 * Handles click event
-1270 	 *
-1271 	 * @param {Event} e click event
-1272 	 * @param {Element} target target element(usually has A tag)
-1273 	 */
-1274 	handleClick: function(e, target) {
-1275 		var href = decodeURI(target.href);
-1276 		if(!xq.Browser.isTrident) {
-1277 			if(!e.ctrlKey && !e.shiftKey && e.button != 1) {
-1278 				window.location.href = href;
-1279 				return true;
-1280 			}
-1281 		} else {
-1282 			if(e.shiftKey) {
-1283 				window.open(href, "_blank");
-1284 			} else {
-1285 				window.location.href = href;
-1286 			}
-1287 			return true;
-1288 		}
-1289 		
-1290 		return false;
-1291 	},
-1292 
-1293 	/**
-1294 	 * Show link dialog
-1295 	 *
-1296 	 * TODO: should support modify/unlink
-1297 	 */
-1298 	handleLink: function() {
-1299 		var text = this.rdom.getSelectionAsText() || '';
-1300 		var dialog = new xq.controls.FormDialog(
-1301 			this,
-1302 			xq.ui_templates.basicLinkDialog,
-1303 			function(dialog) {
-1304 				if(text) {
-1305 					dialog.form.text.value = text;
-1306 					dialog.form.url.focus();
-1307 					dialog.form.url.select();
-1308 				}
-1309 			},
-1310 			function(data) {
-1311 				this.focus();
-1312 				
-1313 				if(xq.Browser.isTrident) {
-1314 					var rng = this.rdom.rng();
-1315 					rng.moveToBookmark(bm);
-1316 					rng.select();
-1317 				}
-1318 				
-1319 				if(!data) return;
-1320 				this.handleInsertLink(false, data.url, data.text, data.text);
-1321 			}.bind(this)
-1322 		);
-1323 		
-1324 		if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
-1325 		
-1326 		dialog.show({position: 'centerOfEditor'});
-1327 		
-1328 		return true;
-1329 	},
-1330 	
-1331 	/**
-1332 	 * Inserts link or apply link into selected area
-1333 	 * 
-1334 	 * @param {boolean} autoSelection if set true and there's no selection, automatically select word to link(if possible)
-1335 	 * @param {String} url url
-1336 	 * @param {String} title title of link
-1337 	 * @param {String} text text of link. If there's a selection(manually or automatically), it will be replaced with this text
-1338 	 *
-1339 	 * @returns {Element} created element
-1340 	 */
-1341 	handleInsertLink: function(autoSelection, url, title, text) {
-1342 		if(autoSelection && !this.rdom.hasSelection()) {
-1343 			var marker = this.rdom.pushMarker();
-1344 			var a = this.rdom.smartWrap(marker, "A", function(text) {
-1345 				var index = text.lastIndexOf(" ");
-1346 				return index == -1 ? index : index + 1;
-1347 			});
-1348 			a.href = url;
-1349 			a.title = title;
-1350 			if(text) {
-1351 				a.innerHTML = ""
-1352 				a.appendChild(this.rdom.createTextNode(text));
-1353 			} else if(!a.hasChildNodes()) {
-1354 				this.rdom.deleteNode(a);
-1355 			}
-1356 			this.rdom.popMarker(true);
-1357 		} else {
-1358 			text = text || (this.rdom.hasSelection() ? this.rdom.getSelectionAsText() : null);
-1359 			if(!text) return;
-1360 			
-1361 			this.rdom.deleteSelection();
-1362 			
-1363 			var a = this.rdom.createElement('A');
-1364 			a.href = url;
-1365 			a.title = title;
-1366 			a.appendChild(this.rdom.createTextNode(text));
-1367 			this.rdom.insertNode(a);
-1368 		}
-1369 		
-1370 		var historyAdded = this.editHistory.onCommand();
-1371 		this._fireOnCurrentContentChanged(this);
-1372 		
-1373 		return true;
-1374 	},
-1375 	
-1376 	/**
-1377 	 * Called when enter key pressed.
-1378 	 *
-1379 	 * @param {boolean} skipAutocorrection if set true, skips autocorrection
-1380 	 * @param {boolean} forceInsertParagraph if set true, inserts paragraph
-1381 	 */
-1382 	handleEnter: function(skipAutocorrection, forceInsertParagraph) {
-1383 		// If it has selection, perform default action.
-1384 		if(this.rdom.hasSelection()) return false;
-1385 		
-1386 		// Perform autocorrection
-1387 		if(!skipAutocorrection && this.handleAutocorrection()) return true;
-1388 		
-1389 		var atEmptyBlock = this.rdom.isCaretAtEmptyBlock();
-1390 		var atStart = atEmptyBlock || this.rdom.isCaretAtBlockStart();
-1391 		var atEnd = atEmptyBlock || (!atStart && this.rdom.isCaretAtBlockEnd());
-1392 		var atEdge = atEmptyBlock || atStart || atEnd;
-1393 		
-1394 		if(!atEdge) {
-1395 			var block = this.rdom.getCurrentBlockElement();
-1396 			var marker = this.rdom.pushMarker();
-1397 			
-1398 			if(this.rdom.isFirstLiWithNestedList(block) && !forceInsertParagraph) {
-1399 				var parent = block.parentNode;
-1400 				this.rdom.unwrapElement(block);
-1401 				block = parent;
-1402 			} else if(block.nodeName != "LI" && this.rdom.tree.isBlockContainer(block)) {
-1403 				block = this.rdom.wrapAllInlineOrTextNodesAs("P", block, true).first();
-1404 			}
-1405 			this.rdom.splitElementUpto(marker, block);
-1406 			
-1407 			this.rdom.popMarker(true);
-1408 		} else if(atEmptyBlock) {
-1409 			this._handleEnterAtEmptyBlock();
-1410 		} else {
-1411 			this._handleEnterAtEdge(atStart, forceInsertParagraph);
-1412 		}
-1413 		
-1414 		return true;
-1415 	},
-1416 	
-1417 	/**
-1418 	 * Moves current block upward or downward
-1419 	 *
-1420 	 * @param {boolean} up moves current block upward
-1421 	 */
-1422 	handleMoveBlock: function(up) {
-1423 		var block = this.rdom.moveBlock(this.rdom.getCurrentBlockElement(), up);
-1424 		if(block) {
-1425 			this.rdom.selectElement(block, false);
-1426 			block.scrollIntoView(false);
-1427 			
-1428 			var historyAdded = this.editHistory.onCommand();
-1429 			this._fireOnCurrentContentChanged(this);
-1430 		}
-1431 		return true;
-1432 	},
-1433 	
-1434 	/**
-1435 	 * Called when tab key pressed
-1436 	 */
-1437 	handleTab: function() {
-1438 		var hasSelection = this.rdom.hasSelection();
-1439 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
-1440 		
-1441 		if(hasSelection) {
-1442 			this.handleIndent();
-1443 		} else if (table && table.className == "datatable") {
-1444 			this.handleMoveToNextCell();
-1445 		} else if (this.rdom.isCaretAtBlockStart()) {
-1446 			this.handleIndent();
-1447 		} else {
-1448 			this.handleInsertTab();
-1449 		}
-1450 
-1451 		return true;
-1452 	},
-1453 	
-1454 	/**
-1455 	 * Called when shift+tab key pressed
-1456 	 */
-1457 	handleShiftTab: function() {
-1458 		var hasSelection = this.rdom.hasSelection();
-1459 		var table = this.rdom.getParentElementOf(this.rdom.getCurrentBlockElement(), ["TABLE"]);
-1460 		
-1461 		if(hasSelection) {
-1462 			this.handleOutdent();
-1463 		} else if (table && table.className == "datatable") {
-1464 			this.handleMoveToPreviousCell();
-1465 		} else {
-1466 			this.handleOutdent();
-1467 		}
-1468 		
-1469 		return true;
-1470 	},
-1471 	
-1472 	/**
-1473 	 * Inserts three non-breaking spaces
-1474 	 */
-1475 	handleInsertTab: function() {
-1476 		this.rdom.insertHtml(' ');
-1477 		this.rdom.insertHtml(' ');
-1478 		this.rdom.insertHtml(' ');
-1479 		
-1480 		return true;
-1481 	},
-1482 	
-1483 	/**
-1484 	 * Called when delete key pressed
-1485 	 */
-1486 	handleDelete: function() {
-1487 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockEnd()) return false;
-1488 		return this._handleMerge(true);
-1489 	},
-1490 	
-1491 	/**
-1492 	 * Called when backspace key pressed
-1493 	 */
-1494 	handleBackspace: function() {
-1495 		if(this.rdom.hasSelection() || !this.rdom.isCaretAtBlockStart()) return false;
-1496 		return this._handleMerge(false);
-1497 	},
-1498 	
-1499 	_handleMerge: function(withNext) {
-1500 		var block = this.rdom.getCurrentBlockElement();
-1501 		
-1502 		// save caret position;
-1503 		var marker = this.rdom.pushMarker();
-1504 		
-1505 		// perform merge
-1506 		var merged = this.rdom.mergeElement(block, withNext, withNext);
-1507 		if(!merged && !withNext) this.rdom.extractOutElementFromParent(block);
-1508 		
-1509 		// restore caret position
-1510 		this.rdom.popMarker(true);
-1511 		if(merged) this.rdom.correctEmptyElement(merged);
-1512 		
-1513 		var historyAdded = this.editHistory.onCommand();
-1514 		this._fireOnCurrentContentChanged(this);
-1515 		
-1516 		return !!merged;
-1517 	},
-1518 	
-1519 	/**
-1520 	 * (in table) Moves caret to the next cell
-1521 	 */
-1522 	handleMoveToNextCell: function() {
-1523 		this._handleMoveToCell("next");
-1524 	},
-1525 
-1526 	/**
-1527 	 * (in table) Moves caret to the previous cell
-1528 	 */
-1529 	handleMoveToPreviousCell: function() {
-1530 		this._handleMoveToCell("prev");
-1531 	},
-1532 
-1533 	/**
-1534 	 * (in table) Moves caret to the above cell
-1535 	 */
-1536 	handleMoveToAboveCell: function() {
-1537 		this._handleMoveToCell("above");
-1538 	},
-1539 
-1540 	/**
-1541 	 * (in table) Moves caret to the below cell
-1542 	 */
-1543 	handleMoveToBelowCell: function() {
-1544 		this._handleMoveToCell("below");
-1545 	},
-1546 
-1547 	_handleMoveToCell: function(dir) {
-1548 		var block = this.rdom.getCurrentBlockElement();
-1549 		var cell = this.rdom.getParentElementOf(block, ["TD", "TH"]);
-1550 		var table = this.rdom.getParentElementOf(cell, ["TABLE"]);
-1551 		var rtable = new xq.RichTable(this.rdom, table);
-1552 		var target = null;
-1553 		
-1554 		if(["next", "prev"].include(dir)) {
-1555 			var toNext = dir == "next";
-1556 			target = toNext ? rtable.getNextCellOf(cell) : rtable.getPreviousCellOf(cell);
-1557 		} else {
-1558 			var toBelow = dir == "below";
-1559 			target = toBelow ? rtable.getBelowCellOf(cell) : rtable.getAboveCellOf(cell);
-1560 		}
-1561 
-1562 		if(!target) {
-1563 			var finder = function(node) {return !['TD', 'TH'].include(node.nodeName) && this.tree.isBlock(node) && !this.tree.hasBlocks(node);}.bind(this.rdom);
-1564 			var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this.rdom);
-1565 			
-1566 			target = (toNext || toBelow) ? 
-1567 				this.rdom.tree.findForward(cell, finder, exitCondition) :
-1568 				this.rdom.tree.findBackward(table, finder, exitCondition);
-1569 		}
-1570 		
-1571 		if(target) this.rdom.placeCaretAtStartOf(target);
-1572 	},
-1573 	
-1574 	/**
-1575 	 * Applies STRONG tag
-1576 	 */
-1577 	handleStrongEmphasis: function() {
-1578 		this.rdom.applyStrongEmphasis();
-1579 		
-1580 		var historyAdded = this.editHistory.onCommand();
-1581 		this._fireOnCurrentContentChanged(this);
-1582 		
-1583 		return true;
-1584 	},
-1585 	
-1586 	/**
-1587 	 * Applies EM tag
-1588 	 */
-1589 	handleEmphasis: function() {
-1590 		this.rdom.applyEmphasis();
-1591 		
-1592 		var historyAdded = this.editHistory.onCommand();
-1593 		this._fireOnCurrentContentChanged(this);
-1594 		
-1595 		return true;
-1596 	},
-1597 	
-1598 	/**
-1599 	 * Applies EM.underline tag
-1600 	 */
-1601 	handleUnderline: function() {
-1602 		this.rdom.applyUnderline();
-1603 		
-1604 		var historyAdded = this.editHistory.onCommand();
-1605 		this._fireOnCurrentContentChanged(this);
-1606 		
-1607 		return true;
-1608 	},
-1609 	
-1610 	/**
-1611 	 * Applies SPAN.strike tag
-1612 	 */
-1613 	handleStrike: function() {
-1614 		this.rdom.applyStrike();
-1615 
-1616 		var historyAdded = this.editHistory.onCommand();
-1617 		this._fireOnCurrentContentChanged(this);
-1618 
-1619 		return true;
-1620 	},
-1621 	
-1622 	/**
-1623 	 * Removes all style
-1624 	 */
-1625 	handleRemoveFormat: function() {
-1626 		this.rdom.applyRemoveFormat();
-1627 
-1628 		var historyAdded = this.editHistory.onCommand();
-1629 		this._fireOnCurrentContentChanged(this);
-1630 
-1631 		return true;
-1632 	},
-1633 	
-1634 	/**
-1635 	 * Inserts table
-1636 	 *
-1637 	 * @param {Number} cols number of columns
-1638 	 * @param {Number} rows number of rows
-1639 	 * @param {String} headerPosition position of THs. "T" or "L" or "TL". "T" means top, "L" means left.
-1640 	 */
-1641 	handleTable: function(cols, rows, headerPositions) {
-1642 		var cur = this.rdom.getCurrentBlockElement();
-1643 		if(this.rdom.getParentElementOf(cur, ["TABLE"])) return true;
-1644 		
-1645 		var rtable = xq.RichTable.create(this.rdom, cols, rows, headerPositions);
-1646 		if(this.rdom.tree.isBlockContainer(cur)) {
-1647 			var wrappers = this.rdom.wrapAllInlineOrTextNodesAs("P", cur, true);
-1648 			cur = wrappers.last();
-1649 		}
-1650 		var tableDom = this.rdom.insertNodeAt(rtable.getDom(), cur, "after");
-1651 		this.rdom.placeCaretAtStartOf(rtable.getCellAt(0, 0));
-1652 		
-1653 		if(this.rdom.isEmptyBlock(cur)) this.rdom.deleteNode(cur, true);
-1654 		
-1655 		var historyAdded = this.editHistory.onCommand();
-1656 		this._fireOnCurrentContentChanged(this);
-1657 		
-1658 		return true;
-1659 	},
-1660 	
-1661 	handleInsertNewRowAt: function(where) {
-1662 		var cur = this.rdom.getCurrentBlockElement();
-1663 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
-1664 		if(!tr) return true;
-1665 		
-1666 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
-1667 		var rtable = new xq.RichTable(this.rdom, table);
-1668 		var row = rtable.insertNewRowAt(tr, where);
-1669 		
-1670 		this.rdom.placeCaretAtStartOf(row.cells[0]);
-1671 		return true;
-1672 	},
-1673 	handleInsertNewColumnAt: function(where) {
-1674 		var cur = this.rdom.getCurrentBlockElement();
-1675 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
-1676 		if(!td) return true;
-1677 		
-1678 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
-1679 		var rtable = new xq.RichTable(this.rdom, table);
-1680 		rtable.insertNewCellAt(td, where);
-1681 		
-1682 		this.rdom.placeCaretAtStartOf(cur);
-1683 		return true;
-1684 	},
-1685 	
-1686 	handleDeleteRow: function() {
-1687 		var cur = this.rdom.getCurrentBlockElement();
-1688 		var tr = this.rdom.getParentElementOf(cur, ["TR"]);
-1689 		if(!tr) return true;
-1690 
-1691 		var table = this.rdom.getParentElementOf(tr, ["TABLE"]);
-1692 		var rtable = new xq.RichTable(this.rdom, table);
-1693 		var blockToMove = rtable.deleteRow(tr);
-1694 		
-1695 		this.rdom.placeCaretAtStartOf(blockToMove);
-1696 		return true;
-1697 	},
-1698 	
-1699 	handleDeleteColumn: function() {
-1700 		var cur = this.rdom.getCurrentBlockElement();
-1701 		var td = this.rdom.getParentElementOf(cur, ["TD"], true);
-1702 		if(!td) return true;
-1703 
-1704 		var table = this.rdom.getParentElementOf(td, ["TABLE"]);
-1705 		var rtable = new xq.RichTable(this.rdom, table);
-1706 		rtable.deleteCell(td);
-1707 
-1708 		return true;
-1709 	},
-1710 	
-1711 	/**
-1712 	 * Performs block indentation
-1713 	 */
-1714 	handleIndent: function() {
-1715 		if(this.rdom.hasSelection()) {
-1716 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
-1717 			if(blocks.first() != blocks.last()) {
-1718 				var affected = this.rdom.indentElements(blocks.first(), blocks.last());
-1719 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
-1720 				
-1721 				var historyAdded = this.editHistory.onCommand();
-1722 				this._fireOnCurrentContentChanged(this);
-1723 				
-1724 				return true;
-1725 			}
-1726 		}
-1727 		
-1728 		var block = this.rdom.getCurrentBlockElement();
-1729 		var affected = this.rdom.indentElement(block);
-1730 		
-1731 		if(affected) {
-1732 			this.rdom.placeCaretAtStartOf(affected);
-1733 			
-1734 			var historyAdded = this.editHistory.onCommand();
-1735 			this._fireOnCurrentContentChanged(this);
-1736 		}
-1737 		
-1738 		return true;
-1739 	},
-1740 
-1741 	/**
-1742 	 * Performs block outdentation
-1743 	 */
-1744 	handleOutdent: function() {
-1745 		if(this.rdom.hasSelection()) {
-1746 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
-1747 			if(blocks.first() != blocks.last()) {
-1748 				var affected = this.rdom.outdentElements(blocks.first(), blocks.last());
-1749 				this.rdom.selectBlocksBetween(affected.first(), affected.last());
-1750 				
-1751 				var historyAdded = this.editHistory.onCommand();
-1752 				this._fireOnCurrentContentChanged(this);
-1753 				
-1754 				return true;
-1755 			}
-1756 		}
-1757 		
-1758 		var block = this.rdom.getCurrentBlockElement();
-1759 		var affected = this.rdom.outdentElement(block);
-1760 		
-1761 		if(affected) {
-1762 			this.rdom.placeCaretAtStartOf(affected);
-1763 
-1764 			var historyAdded = this.editHistory.onCommand();
-1765 			this._fireOnCurrentContentChanged(this);
-1766 		}
-1767 		
-1768 		return true;
-1769 	},
-1770 	
-1771 	/**
-1772 	 * Applies list.
-1773 	 *
-1774 	 * @param {String} type "UL" or "OL" or "CODE". CODE generates OL.code
-1775 	 */
-1776 	handleList: function(type) {
-1777 		if(this.rdom.hasSelection()) {
-1778 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
-1779 			if(blocks.first() != blocks.last()) {
-1780 				blocks = this.rdom.applyLists(blocks.first(), blocks.last(), type);
-1781 			} else {
-1782 				blocks[0] = blocks[1] = this.rdom.applyList(blocks.first(), type);
-1783 			}
-1784 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
-1785 		} else {
-1786 			var block = this.rdom.applyList(this.rdom.getCurrentBlockElement(), type);
-1787 			this.rdom.placeCaretAtStartOf(block);
-1788 		}
-1789 		var historyAdded = this.editHistory.onCommand();
-1790 		this._fireOnCurrentContentChanged(this);
-1791 		
-1792 		return true;
-1793 	},
-1794 	
-1795 	/**
-1796 	 * Applies justification
-1797 	 *
-1798 	 * @param {String} dir "left", "center", "right" or "both"
-1799 	 */
-1800 	handleJustify: function(dir) {
-1801 		var block = this.rdom.getCurrentBlockElement();
-1802 		var dir = (dir == "left" || dir == "both") && (block.style.textAlign == "left" || block.style.textAlign == "") ? "both" : dir;
-1803 		
-1804 		if(this.rdom.hasSelection()) {
-1805 			var blocks = this.rdom.getSelectedBlockElements();
-1806 			this.rdom.justifyBlocks(blocks, dir);
-1807 			this.rdom.selectBlocksBetween(blocks.first(), blocks.last());
-1808 		} else {
-1809 			this.rdom.justifyBlock(block, dir);
-1810 		}
-1811 		var historyAdded = this.editHistory.onCommand();
-1812 		this._fireOnCurrentContentChanged(this);
-1813 		
-1814 		return true;
-1815 	},
-1816 	
-1817 	/**
-1818 	 * Removes current block element
-1819 	 */
-1820 	handleRemoveBlock: function() {
-1821 		var block = this.rdom.getCurrentBlockElement();
-1822 		var blockToMove = this.rdom.removeBlock(block);
-1823 		this.rdom.placeCaretAtStartOf(blockToMove);
-1824 		blockToMove.scrollIntoView(false);
-1825 	},
-1826 	
-1827 	/**
-1828 	 * Applies background color
-1829 	 *
-1830 	 * @param {String} color CSS color string
-1831 	 */
-1832 	handleBackgroundColor: function(color) {
-1833 		if(color) {
-1834 			this.rdom.applyBackgroundColor(color);
-1835 
-1836 			var historyAdded = this.editHistory.onCommand();
-1837 			this._fireOnCurrentContentChanged(this);
-1838 		} else {
-1839 			var dialog = new xq.controls.FormDialog(
-1840 				this,
-1841 				xq.ui_templates.basicColorPickerDialog,
-1842 				function(dialog) {},
-1843 				function(data) {
-1844 					this.focus();
-1845 					
-1846 					if(xq.Browser.isTrident) {
-1847 						var rng = this.rdom.rng();
-1848 						rng.moveToBookmark(bm);
-1849 						rng.select();
-1850 					}
-1851 					
-1852 					if(!data) return;
-1853 					
-1854 					this.handleBackgroundColor(data.color);
-1855 				}.bind(this)
-1856 			);
-1857 			
-1858 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
-1859 			
-1860 			dialog.show({position: 'centerOfEditor'});
-1861 		}
-1862 		return true;
-1863 	},
-1864 	
-1865 	/**
-1866 	 * Applies foreground color
-1867 	 *
-1868 	 * @param {String} color CSS color string
-1869 	 */
-1870 	handleForegroundColor: function(color) {
-1871 		if(color) {
-1872 			this.rdom.applyForegroundColor(color);
-1873 
-1874 			var historyAdded = this.editHistory.onCommand();
-1875 			this._fireOnCurrentContentChanged(this);
-1876 		} else {
-1877 			var dialog = new xq.controls.FormDialog(
-1878 				this,
-1879 				xq.ui_templates.basicColorPickerDialog,
-1880 				function(dialog) {},
-1881 				function(data) {
-1882 					this.focus();
-1883 					
-1884 					if(xq.Browser.isTrident) {
-1885 						var rng = this.rdom.rng();
-1886 						rng.moveToBookmark(bm);
-1887 						rng.select();
-1888 					}
-1889 					
-1890 					if(!data) return;
-1891 					
-1892 					this.handleForegroundColor(data.color);
-1893 				}.bind(this)
-1894 			);
-1895 			
-1896 			if(xq.Browser.isTrident) var bm = this.rdom.rng().getBookmark();
-1897 			
-1898 			dialog.show({position: 'centerOfEditor'});
-1899 		}
-1900 		return true;
-1901 	},
-1902 
-1903 	/**
-1904 	 * Applies superscription
-1905 	 */	
-1906 	handleSuperscription: function() {
-1907 		this.rdom.applySuperscription();
-1908 
-1909 		var historyAdded = this.editHistory.onCommand();
-1910 		this._fireOnCurrentContentChanged(this);
-1911 
-1912 		return true;
-1913 	},
-1914 	
-1915 	/**
-1916 	 * Applies subscription
-1917 	 */	
-1918 	handleSubscription: function() {
-1919 		this.rdom.applySubscription();
-1920 
-1921 		var historyAdded = this.editHistory.onCommand();
-1922 		this._fireOnCurrentContentChanged(this);
-1923 
-1924 		return true;
-1925 	},
-1926 	
-1927 	/**
-1928 	 * Change of wrap current block's tag
-1929 	 */	
-1930 	handleApplyBlock: function(tagName) {
-1931 		if(this.rdom.hasSelection()) {
-1932 			var blocks = this.rdom.getBlockElementsAtSelectionEdge(true, true);
-1933 			if(blocks.first() != blocks.last()) {
-1934 				var applied = this.rdom.applyTagIntoElements(tagName, blocks.first(), blocks.last());
-1935 				this.rdom.selectBlocksBetween(applied.first(), applied.last());
-1936 				
-1937 				var historyAdded = this.editHistory.onCommand();
-1938 				this._fireOnCurrentContentChanged(this);
-1939 				
-1940 				return true;
-1941 			}
-1942 		}
-1943 		
-1944 		var block = this.rdom.getCurrentBlockElement();
-1945 		this.rdom.pushMarker();
-1946 		var applied =
-1947 			this.rdom.applyTagIntoElement(tagName, block) ||
-1948 			block;
-1949 		this.rdom.popMarker(true);
-1950 
-1951 		if(this.rdom.isEmptyBlock(applied)) {
-1952 			this.rdom.correctEmptyElement(applied);
-1953 			this.rdom.placeCaretAtStartOf(applied);
-1954 		}
-1955 		
-1956 		var historyAdded = this.editHistory.onCommand();
-1957 		this._fireOnCurrentContentChanged(this);
-1958 		
-1959 		return true;
-1960 	},
-1961 
-1962 	/**
-1963 	 * Inserts seperator (HR)
-1964 	 */
-1965 	handleSeparator: function() {
-1966 		this.rdom.collapseSelection();
-1967 		
-1968 		var curBlock = this.rdom.getCurrentBlockElement();
-1969 		var atStart = this.rdom.isCaretAtBlockStart();
-1970 		if(this.rdom.tree.isBlockContainer(curBlock)) curBlock = this.rdom.wrapAllInlineOrTextNodesAs("P", curBlock, true)[0];
-1971 		
-1972 		this.rdom.insertNodeAt(this.rdom.createElement("HR"), curBlock, atStart ? "before" : "after");
-1973 		this.rdom.placeCaretAtStartOf(curBlock);
-1974 
-1975 		// add undo history
-1976 		var historyAdded = this.editHistory.onCommand();
-1977 		this._fireOnCurrentContentChanged(this);
-1978 		
-1979 		return true;
-1980 	},
-1981 	
-1982 	/**
-1983 	 * Performs UNDO
-1984 	 */
-1985 	handleUndo: function() {
-1986 		var performed = this.editHistory.undo();
-1987 		this._fireOnCurrentContentChanged(this);
-1988 		
-1989 		var curBlock = this.rdom.getCurrentBlockElement();
-1990 		if(!xq.Browser.isTrident && curBlock) {
-1991 			curBlock.scrollIntoView(false);
-1992 		}
-1993 		return true;
-1994 	},
-1995 	
-1996 	/**
-1997 	 * Performs REDO
-1998 	 */
-1999 	handleRedo: function() {
-2000 		var performed = this.editHistory.redo();
-2001 		this._fireOnCurrentContentChanged(this);
-2002 		
-2003 		var curBlock = this.rdom.getCurrentBlockElement();
-2004 		if(!xq.Browser.isTrident && curBlock) {
-2005 			curBlock.scrollIntoView(false);
-2006 		}
-2007 		return true;
-2008 	},
-2009 	
-2010 	
-2011 	
-2012 	_handleContextMenu: function(e) {
-2013 		if (xq.Browser.isWebkit) {
-2014 			if (e.metaKey || Event.isLeftClick(e)) return false;
-2015 		} else if (e.shiftKey || e.ctrlKey || e.altKey) {
-2016 			return false;
-2017 		}
-2018 		
-2019 		var x=Event.pointerX(e);
-2020 		var y=Event.pointerY(e);
-2021 		var pos=Position.cumulativeOffset(this.getFrame());
-2022 		x+=pos[0];
-2023 		y+=pos[1];
-2024 		this._contextMenuTargetElement = e.target || e.srcElement;
-2025 		
-2026 		//TODO: Safari on Windows doesn't work with context key(app key)
-2027 		if (!x || !y || xq.Browser.isTrident) {
-2028 			var pos = Position.cumulativeOffset(this._contextMenuTargetElement);
-2029 			var posFrame = Position.cumulativeOffset(this.getFrame());
-2030 			x = pos[0] + posFrame[0] - this.getDoc().documentElement.scrollLeft;
-2031 			y = pos[1] + posFrame[1] - this.getDoc().documentElement.scrollTop;
-2032 		}
-2033 		
-2034 		if (!xq.Browser.isTrident) {
-2035 			var doc = this.getDoc();
-2036 			var body = this.getBody();
-2037 			
-2038 			x -= doc.documentElement.scrollLeft;
-2039 			y -= doc.documentElement.scrollTop;
-2040 			
-2041 			if (doc != body) {
-2042 				x -= body.scrollLeft;
-2043 				y -= body.scrollTop;
-2044 			}
-2045 		}
-2046 		
-2047 		for(var cmh in this.config.contextMenuHandlers) {
-2048 			var stop = this.config.contextMenuHandlers[cmh].handler(this, this._contextMenuTargetElement, x, y);
-2049 			if(stop) {
-2050 				Event.stop(e);
-2051 				return true;
-2052 			}
-2053 		}
-2054 		
-2055 		return false;
-2056 	},
-2057 	
-2058 	showContextMenu: function(menuItems, x, y) {
-2059 		if (!menuItems || menuItems.length <= 0) return;
-2060 		
-2061 		if (!this._contextMenuContainer) {
-2062 			this._contextMenuContainer = this.doc.createElement('UL');
-2063 			this._contextMenuContainer.className = 'xqContextMenu';
-2064 			this._contextMenuContainer.style.display='none';
-2065 			
-2066 			Event.observe(this.doc, 'click', this._contextMenuClicked.bindAsEventListener(this));
-2067 			Event.observe(this.rdom.getDoc(), 'click', this.hideContextMenu.bindAsEventListener(this));
-2068 			
-2069 			this.body.appendChild(this._contextMenuContainer);
-2070 		} else {
-2071 			while (this._contextMenuContainer.childNodes.length > 0)
-2072 				this._contextMenuContainer.removeChild(this._contextMenuContainer.childNodes[0]);
-2073 		}
-2074 		
-2075 		for (var i=0; i < menuItems.length; i++) {
-2076 			menuItems[i]._node = this._addContextMenuItem(menuItems[i]);
-2077 		}
-2078 
-2079 		this._contextMenuContainer.style.display='block';
-2080 		this._contextMenuContainer.style.left=Math.min(Math.max(this.doc.body.scrollWidth, this.doc.documentElement.clientWidth)-this._contextMenuContainer.offsetWidth, x)+'px';
-2081 		this._contextMenuContainer.style.top=Math.min(Math.max(this.doc.body.scrollHeight, this.doc.documentElement.clientHeight)-this._contextMenuContainer.offsetHeight, y)+'px';
-2082 
-2083 		this._contextMenuItems = menuItems;
-2084 	},
-2085 	
-2086 	hideContextMenu: function() {
-2087 		if (this._contextMenuContainer)
-2088 			this._contextMenuContainer.style.display='none';
-2089 	},
-2090 	
-2091 	_addContextMenuItem: function(item) {
-2092 		if (!this._contextMenuContainer) throw "No conext menu container exists";
-2093 		
-2094 		var node = this.doc.createElement('LI');
-2095 		if (item.disabled) node.className += ' disabled'; 
-2096 		
-2097 		if (item.title == '----') {
-2098 			node.innerHTML = ' ';
-2099 			node.className = 'separator';
-2100 		} else {
-2101 			if(item.handler) {
-2102 				node.innerHTML = '<a href="javascript:;" onclick="return false;">'+(item.title.toString().escapeHTML())+'</a>';
-2103 			} else {
-2104 				node.innerHTML = (item.title.toString().escapeHTML());
-2105 			}
-2106 		}
-2107 		
-2108 		if(item.className) node.className = item.className;
-2109 		
-2110 		this._contextMenuContainer.appendChild(node);
-2111 		
-2112 		return node;
-2113 	},
-2114 	
-2115 	_contextMenuClicked: function(e) {
-2116 		this.hideContextMenu();
-2117 		
-2118 		if (!this._contextMenuContainer) return;
-2119 		
-2120 		var node = Event.findElement(e, 'LI');
-2121 		if (!node || !this.rdom.tree.isDescendantOf(this._contextMenuContainer, node)) return;
-2122 
-2123 		for (var i=0; i < this._contextMenuItems.length; i++) {
-2124 			if (this._contextMenuItems[i]._node == node) {
-2125 				var handler = this._contextMenuItems[i].handler;
-2126 				if (!this._contextMenuItems[i].disabled && handler) {
-2127 					var xed = this;
-2128 					var element = this._contextMenuTargetElement;
-2129 					if(typeof handler == "function") {
-2130 						handler(xed, element);
-2131 					} else {
-2132 						eval(handler);
-2133 					}
-2134 				}
-2135 				break;
-2136 			}
-2137 		}
-2138 	},
-2139 	
-2140 	/**
-2141 	 * Inserts HTML template
-2142 	 *
-2143 	 * @param {String} html Template string. It should have single root element
-2144 	 * @returns {Element} inserted element
-2145 	 */
-2146 	insertTemplate: function(html) {
-2147 		return this.rdom.insertHtml(this._processTemplate(html));
-2148 	},
-2149 	
-2150 	/**
-2151 	 * Places given HTML template nearby target.
-2152 	 *
-2153 	 * @param {String} html Template string. It should have single root element
-2154 	 * @param {Node} target Target node.
-2155 	 * @param {String} where Possible values: "before", "start", "end", "after"
-2156 	 *
-2157 	 * @returns {Element} Inserted element.
-2158 	 */
-2159 	insertTemplateAt: function(html, target, where) {
-2160 		return this.rdom.insertHtmlAt(this._processTemplate(html), target, where);
-2161 	},
-2162 	
-2163 	_processTemplate: function(html) {
-2164 		// apply template processors
-2165 		var tps = $H(this.getTemplateProcessors()).values();
-2166 		for(var i = 0; i < tps.length; i++) {
-2167 			html = tps[i].handler(html);
-2168 		}
-2169 		
-2170 		// remove all whitespace characters between block tags
-2171 		return html = this.removeUnnecessarySpaces(html);
-2172 	},
-2173 	
-2174 	
-2175 	
-2176 	/** @private */
-2177 	_handleEnterAtEmptyBlock: function() {
-2178 		var block = this.rdom.getCurrentBlockElement();
-2179 		if(this.rdom.tree.isTableCell(block) && this.rdom.isFirstBlockOfBody(block)) {
-2180 			block = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
-2181 		} else {
-2182 			block = 
-2183 				this.rdom.outdentElement(block) ||
-2184 				this.rdom.extractOutElementFromParent(block) ||
-2185 				this.rdom.replaceTag("P", block) ||
-2186 				this.rdom.insertNewBlockAround(block);
-2187 		}
-2188 		
-2189 		this.rdom.placeCaretAtStartOf(block);
-2190 		if(!xq.Browser.isTrident) block.scrollIntoView(false);
-2191 	},
-2192 	
-2193 	/** @private */
-2194 	_handleEnterAtEdge: function(atStart, forceInsertParagraph) {
-2195 		var block = this.rdom.getCurrentBlockElement();
-2196 		var blockToPlaceCaret;
-2197 		
-2198 		if(atStart && this.rdom.isFirstBlockOfBody(block)) {
-2199 			blockToPlaceCaret = this.rdom.insertNodeAt(this.rdom.makeEmptyParagraph(), this.rdom.getRoot(), "start");
-2200 		} else {
-2201 			if(this.rdom.tree.isTableCell(block)) forceInsertParagraph = true;
-2202 			var newBlock = this.rdom.insertNewBlockAround(block, atStart, forceInsertParagraph ? "P" : null);
-2203 			blockToPlaceCaret = !atStart ? newBlock : newBlock.nextSibling;
-2204 		}
-2205 		
-2206 		this.rdom.placeCaretAtStartOf(blockToPlaceCaret);
-2207 		if(!xq.Browser.isTrident) blockToPlaceCaret.scrollIntoView(false);
-2208 	}
-2209 });
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_06.html b/modules/editor/skins/xquared/doc/api/src_06.html deleted file mode 100644 index 32b20a15b..000000000 --- a/modules/editor/skins/xquared/doc/api/src_06.html +++ /dev/null @@ -1,2262 +0,0 @@ -
  1 /**
-  2  * Encapsulates browser incompatibility problem and provides rich set of DOM manipulation API.
-  3  *
-  4  * RichDom provides basic CRUD + Advanced DOM manipulation API, various query methods and caret/selection management API
-  5  */
-  6 xq.RichDom = Class.create({
-  7 	/**
-  8 	 * Initialize RichDom. Target window and root element should be set after initialization. See setWin and setRoot.
-  9 	 *
- 10      * @constructor
- 11 	 */
- 12 	initialize: function() {
- 13 		/**
- 14 		 * {xq.DomTree} instance of DomTree
- 15 		 */
- 16 		this.tree = new xq.DomTree();
- 17 		
- 18 		this._lastMarkerId = 0;
- 19 	},
- 20 	
- 21 	
- 22 	
- 23 	/**
- 24 	 * @param {Window} win Browser's window object
- 25 	 */
- 26 	setWin: function(win) {
- 27 		if(!win) throw "[win] is null";
- 28 		this.win = win;
- 29 	},
- 30 	
- 31 	/**
- 32 	 * @param {Element} root Root element
- 33 	 */
- 34 	setRoot: function(root) {
- 35 		if(!root) throw "[root] is null";
- 36 		if(this.win && (root.ownerDocument != this.win.document)) throw "root.ownerDocument != this.win.document";
- 37 		this.root = root;
- 38 		this.doc = this.root.ownerDocument;
- 39 	},
- 40 	
- 41 	/**
- 42 	 * @returns Browser's window object.
- 43 	 */
- 44 	getWin: function() {return this.win},
- 45 	
- 46 	/**
- 47 	 * @returns Document object of root element.
- 48 	 */
- 49 	getDoc: function() {return this.doc},
- 50 	
- 51 	/**
- 52 	 * @returns Root element.
- 53 	 */
- 54 	getRoot: function() {return this.root},
- 55 	
- 56 	
- 57 	
- 58 	/////////////////////////////////////////////
- 59 	// CRUDs
- 60 	
- 61 	clearRoot: function() {
- 62 		this.root.innerHTML = "";
- 63 		this.root.appendChild(this.makeEmptyParagraph());
- 64 	},
- 65 	
- 66 	/**
- 67 	 * Removes place holders and empty text nodes of given element.
- 68 	 *
- 69 	 * @param {Element} element target element
- 70 	 */
- 71 	removePlaceHoldersAndEmptyNodes: function(element) {
- 72 		var children = element.childNodes;
- 73 		if(!children) return;
- 74 		var stopAt = this.getBottommostLastChild(element);
- 75 		if(!stopAt) return;
- 76 		stopAt = this.tree.walkForward(stopAt);
- 77 		
- 78 		while(true) {
- 79 			if(!element || element == stopAt) break;
- 80 			
- 81 			if(
- 82 				this.isPlaceHolder(element) ||
- 83 				(element.nodeType == 3 && element.nodeValue == "") ||
- 84 				(!this.getNextSibling(element) && element.nodeType == 3 && element.nodeValue.strip() == "")
- 85 			) {
- 86 				var deleteTarget = element;
- 87 				element = this.tree.walkForward(element);
- 88 				
- 89 				this.deleteNode(deleteTarget);
- 90 			} else {
- 91 				element = this.tree.walkForward(element);
- 92 			}
- 93 		}
- 94 	},
- 95 	
- 96 	/**
- 97 	 * Sets multiple attributes into element at once
- 98 	 *
- 99 	 * @param {Element} element target element
-100 	 * @param {Object} map key-value pairs
-101 	 */
-102 	setAttributes: function(element, map) {
-103 		for(key in map) element.setAttribute(key, map[key]);
-104 	},
-105 
-106 	/**
-107 	 * Creates textnode by given node value.
-108 	 *
-109 	 * @param {String} value value of textnode
-110 	 * @returns {Node} Created text node
-111 	 */	
-112 	createTextNode: function(value) {return this.doc.createTextNode(value);},
-113 
-114 	/**
-115 	 * Creates empty element by given tag name.
-116 	 *
-117 	 * @param {String} tagName name of tag
-118 	 * @returns {Element} Created element
-119 	 */	
-120 	createElement: function(tagName) {return this.doc.createElement(tagName);},
-121 
-122 	/**
-123 	 * Creates element from HTML string
-124 	 * 
-125 	 * @param {String} html HTML string
-126 	 * @returns {Element} Created element
-127 	 */
-128 	createElementFromHtml: function(html) {
-129 		var node = this.createElement("div");
-130 		node.innerHTML = html;
-131 		if(node.childNodes.length != 1) {
-132 			throw "Illegal HTML fragment";
-133 		}
-134 		return this.getFirstChild(node);
-135 	},
-136 	
-137 	/**
-138 	 * Deletes node from DOM tree.
-139 	 *
-140 	 * @param {Node} node Target node which should be deleted
-141 	 * @param {boolean} deleteEmptyParentsRecursively Recursively delete empty parent elements
-142 	 * @param {boolean} correctEmptyParent Call #correctEmptyElement on empty parent element after deletion
-143 	 */	
-144 	deleteNode: function(node, deleteEmptyParentsRecursively, correctEmptyParent) {
-145 		if(!node || !node.parentNode) return;
-146 		
-147 		var parent = node.parentNode;
-148 		parent.removeChild(node);
-149 		
-150 		if(deleteEmptyParentsRecursively) {
-151 			while(!parent.hasChildNodes()) {
-152 				node = parent;
-153 				parent = node.parentNode;
-154 				if(!parent || this.getRoot() == node) break;
-155 				parent.removeChild(node);
-156 			}
-157 		}
-158 		
-159 		if(correctEmptyParent && this.isEmptyBlock(parent)) {
-160 			parent.innerHTML = "";
-161 			this.correctEmptyElement(parent);
-162 		}
-163 	},
-164 
-165 	/**
-166 	 * Inserts given node into current caret position
-167 	 *
-168 	 * @param {Node} node Target node
-169 	 * @returns {Node} Inserted node. It could be different with given node.
-170 	 */
-171 	insertNode: function(node) {throw "Not implemented"},
-172 
-173 	/**
-174 	 * Inserts given html into current caret position
-175 	 *
-176 	 * @param {String} html HTML string
-177 	 * @returns {Node} Inserted node. It could be different with given node.
-178 	 */
-179 	insertHtml: function(html) {
-180 		return this.insertNode(this.createElementFromHtml(html));
-181 	},
-182 	
-183 	/**
-184 	 * Creates textnode from given text and inserts it into current caret position
-185 	 *
-186 	 * @param {String} text Value of textnode
-187 	 * @returns {Node} Inserted node
-188 	 */
-189 	insertText: function(text) {
-190 		this.insertNode(this.createTextNode(text));
-191 	},
-192 	
-193 	/**
-194 	 * Places given node nearby target.
-195 	 *
-196 	 * @param {Node} node Node to be inserted.
-197 	 * @param {Node} target Target node.
-198 	 * @param {String} where Possible values: "before", "start", "end", "after"
-199 	 * @param {boolean} performValidation Validate node if needed. For example when P placed into UL, its tag name automatically replaced with LI
-200 	 *
-201 	 * @returns {Node} Inserted node. It could be different with given node.
-202 	 */
-203 	insertNodeAt: function(node, target, where, performValidation) {
-204 		if(
-205 			["HTML", "HEAD"].include(target.nodeName) ||
-206 			["BODY"].include(target.nodeName) && ["before", "after"].include(where)
-207 		) throw "Illegal argument. Cannot move node[" + node.nodeName + "] to '" + where + "' of target[" + target.nodeName + "]"
-208 		
-209 		var object;
-210 		var message;
-211 		var secondParam;
-212 		
-213 		switch(where.toLowerCase()) {
-214 			case "before":
-215 				object = target.parentNode;
-216 				message = 'insertBefore';
-217 				secondParam = target;
-218 				break
-219 			case "start":
-220 				if(target.firstChild) {
-221 					object = target;
-222 					message = 'insertBefore';
-223 					secondParam = target.firstChild;
-224 				} else {
-225 					object = target;
-226 					message = 'appendChild';
-227 				}
-228 				break
-229 			case "end":
-230 				object = target;
-231 				message = 'appendChild';
-232 				break
-233 			case "after":
-234 				if(target.nextSibling) {
-235 					object = target.parentNode;
-236 					message = 'insertBefore';
-237 					secondParam = target.nextSibling;
-238 				} else {
-239 					object = target.parentNode;
-240 					message = 'appendChild';
-241 				}
-242 				break
-243 		}
-244 
-245 		if(performValidation && this.tree.isListContainer(object) && node.nodeName != "LI") {
-246 			var li = this.createElement("LI");
-247 			li.appendChild(node);
-248 			node = li;
-249 			object[message](node, secondParam);		
-250 		} else if(performValidation && !this.tree.isListContainer(object) && node.nodeName == "LI") {
-251 			this.wrapAllInlineOrTextNodesAs("P", node, true);
-252 			var div = this.createElement("DIV");
-253 			this.moveChildNodes(node, div);
-254 			this.deleteNode(node);
-255 			object[message](div, secondParam);
-256 			node = this.unwrapElement(div, true);
-257 		} else {
-258 			object[message](node, secondParam);
-259 		}
-260 		
-261 		return node;
-262 	},
-263 
-264 	/**
-265 	 * Creates textnode from given text and places given node nearby target.
-266 	 *
-267 	 * @param {String} text Text to be inserted.
-268 	 * @param {Node} target Target node.
-269 	 * @param {String} where Possible values: "before", "start", "end", "after"
-270 	 *
-271 	 * @returns {Node} Inserted node.
-272 	 */
-273 	insertTextAt: function(text, target, where) {
-274 		return this.insertNodeAt(this.createTextNode(text), target, where);
-275 	},
-276 
-277 	/**
-278 	 * Creates element from given HTML string and places given it nearby target.
-279 	 *
-280 	 * @param {String} html HTML to be inserted.
-281 	 * @param {Node} target Target node.
-282 	 * @param {String} where Possible values: "before", "start", "end", "after"
-283 	 *
-284 	 * @returns {Node} Inserted node.
-285 	 */
-286 	insertHtmlAt: function(html, target, where) {
-287 		return this.insertNodeAt(this.createElementFromHtml(html), target, where);
-288 	},
-289 
-290 	/**
-291 	 * Replaces element's tag by removing current element and creating new element by given tag name.
-292 	 *
-293 	 * @param {String} tag New tag name
-294 	 * @param {Element} element Target element
-295 	 *
-296 	 * @returns {Element} Replaced element
-297 	 */	
-298 	replaceTag: function(tag, element) {
-299 		if(element.nodeName == tag) return null;
-300 		if(this.tree.isTableCell(element)) return null;
-301 		
-302 		var newElement = this.createElement(tag);
-303 		this.moveChildNodes(element, newElement);
-304 		this.copyAttributes(element, newElement, true);
-305 		element.parentNode.replaceChild(newElement, element);
-306 		
-307 		if(!newElement.hasChildNodes()) this.correctEmptyElement(newElement);
-308 		
-309 		return newElement;
-310 	},
-311 
-312 	/**
-313 	 * Unwraps unnecessary paragraph.
-314 	 *
-315 	 * Unnecessary paragraph is P which is the only child of given container element.
-316 	 * For example, P which is contained by LI and is the only child is the unnecessary paragraph.
-317 	 * But if given container element is a block-only-container(BLOCKQUOTE, BODY), this method does nothing.
-318 	 *
-319 	 * @param {Element} element Container element
-320 	 * @returns {boolean} True if unwrap performed.
-321 	 */
-322 	unwrapUnnecessaryParagraph: function(element) {
-323 		if(!element) return false;
-324 		
-325 		if(!this.tree.isBlockOnlyContainer(element) && element.childNodes.length == 1 && element.firstChild.nodeName == "P" && !this.hasImportantAttributes(element.firstChild)) {
-326 			var p = element.firstChild;
-327 			this.moveChildNodes(p, element);
-328 			this.deleteNode(p);
-329 			return true;
-330 		}
-331 		return false;
-332 	},
-333 	
-334 	/**
-335 	 * Unwraps element by extracting all children out and removing the element.
-336 	 *
-337 	 * @param {Element} element Target element
-338 	 * @param {boolean} wrapInlineAndTextNodes Wrap all inline and text nodes with P before unwrap
-339 	 * @returns {Node} First child of unwrapped element
-340 	 */
-341 	unwrapElement: function(element, wrapInlineAndTextNodes) {
-342 		if(wrapInlineAndTextNodes) this.wrapAllInlineOrTextNodesAs("P", element);
-343 		
-344 		var nodeToReturn = element.firstChild;
-345 		
-346 		while(element.firstChild) this.insertNodeAt(element.firstChild, element, "before");
-347 		this.deleteNode(element);
-348 		
-349 		return nodeToReturn;
-350 	},
-351 	
-352 	/**
-353 	 * Wraps element by given tag
-354 	 *
-355 	 * @param {String} tag tag name
-356 	 * @param {Element} element target element to wrap
-357 	 * @returns {Element} wrapper
-358 	 */
-359 	wrapElement: function(tag, element) {
-360 		var wrapper = this.insertNodeAt(this.createElement(tag), element, "before");
-361 		wrapper.appendChild(element);
-362 		return wrapper;
-363 	},
-364 	
-365 	/**
-366 	 * Tests #smartWrap with given criteria but doesn't change anything
-367 	 */
-368 	testSmartWrap: function(endElement, criteria) {
-369 		return this.smartWrap(endElement, null, criteria, true);
-370 	},
-371 	
-372 	/**
-373 	 * Create inline element with given tag name and wraps nodes nearby endElement by given criteria
-374 	 *
-375 	 * @param {Element} endElement Boundary(end point, exclusive) of wrapper.
-376 	 * @param {String} tag Tag name of wrapper.
-377 	 * @param {Object} function which returns text index of start boundary.
-378 	 * @param {boolean} testOnly just test boundary and do not perform actual wrapping.
-379 	 *
-380 	 * @returns {Element} wrapper
-381 	 */
-382 	smartWrap: function(endElement, tag, criteria, testOnly) {
-383 		var block = this.getParentBlockElementOf(endElement);
-384 
-385 		tag = tag || "SPAN";
-386 		criteria = criteria || function(text) {return -1};
-387 		
-388 		// check for empty wrapper
-389 		if(!testOnly && (!endElement.previousSibling || this.isEmptyBlock(block))) {
-390 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
-391 			return wrapper;
-392 		}
-393 		
-394 		// collect all textnodes
-395 		var textNodes = this.tree.collectForward(block, function(node) {return node == endElement}, function(node) {return node.nodeType == 3});
-396 		
-397 		// find textnode and break-point
-398 		var nodeIndex = 0;
-399 		var nodeValues = textNodes.pluck("nodeValue");
-400 		var textToWrap = nodeValues.join("");
-401 		var textIndex = criteria(textToWrap)
-402 		var breakPoint = textIndex;
-403 		
-404 		if(breakPoint == -1) {
-405 			breakPoint = 0;
-406 		} else {
-407 			textToWrap = textToWrap.substring(breakPoint);
-408 		}
-409 		
-410 		for(var i = 0; i < textNodes.length; i++) {
-411 			if(breakPoint > nodeValues[i].length) {
-412 				breakPoint -= nodeValues[i].length;
-413 			} else {
-414 				nodeIndex = i;
-415 				break;
-416 			}
-417 		}
-418 		
-419 		if(testOnly) return {text:textToWrap, textIndex:textIndex, nodeIndex:nodeIndex, breakPoint:breakPoint};
-420 		
-421 		// break textnode if necessary 
-422 		if(breakPoint != 0) {
-423 			var splitted = textNodes[nodeIndex].splitText(breakPoint);
-424 			nodeIndex++;
-425 			textNodes.splice(nodeIndex, 0, splitted);
-426 		}
-427 		var startElement = textNodes[nodeIndex] || block.firstChild;
-428 		
-429 		// split inline elements up to parent block if necessary
-430 		var family = this.tree.findCommonAncestorAndImmediateChildrenOf(startElement, endElement);
-431 		var ca = family.parent;
-432 		if(ca) {
-433 			if(startElement.parentNode != ca) startElement = this.splitElementUpto(startElement, ca, true);
-434 			if(endElement.parentNode != ca) endElement = this.splitElementUpto(endElement, ca, true);
-435 			
-436 			var prevStart = startElement.previousSibling;
-437 			var nextEnd = endElement.nextSibling;
-438 			
-439 			// remove empty inline elements
-440 			if(prevStart && prevStart.nodeType == 1 && this.isEmptyBlock(prevStart)) this.deleteNode(prevStart);
-441 			if(nextEnd && nextEnd.nodeType == 1 && this.isEmptyBlock(nextEnd)) this.deleteNode(nextEnd);
-442 			
-443 			// wrap
-444 			var wrapper = this.insertNodeAt(this.createElement(tag), startElement, "before");
-445 			while(wrapper.nextSibling != endElement) wrapper.appendChild(wrapper.nextSibling);
-446 			return wrapper;
-447 		} else {
-448 			// wrap
-449 			var wrapper = this.insertNodeAt(this.createElement(tag), endElement, "before");
-450 			return wrapper;
-451 		}
-452 	},
-453 	
-454 	/**
-455 	 * Wraps all adjust inline elements and text nodes into block element.
-456 	 *
-457 	 * TODO: empty element should return empty array when it is not forced and (at least) single item array when forced
-458 	 *
-459 	 * @param {String} tag Tag name of wrapper
-460 	 * @param {Element} element Target element
-461 	 * @param {boolean} force Force wrapping. If it is set to false, this method do not makes unnecessary wrapper.
-462 	 *
-463 	 * @returns {Array} Array of wrappers. If nothing performed it returns empty array
-464 	 */
-465 	wrapAllInlineOrTextNodesAs: function(tag, element, force) {
-466 		var wrappers = [];
-467 		
-468 		if(!force && !this.tree.hasMixedContents(element)) return wrappers;
-469 		
-470 		var node = element.firstChild;
-471 		while(node) {
-472 			if(this.tree.isTextOrInlineNode(node)) {
-473 				var wrapper = this.wrapInlineOrTextNodesAs(tag, node);
-474 				wrappers.push(wrapper);
-475 				node = wrapper.nextSibling;
-476 			} else {
-477 				node = node.nextSibling;
-478 			}
-479 		}
-480 
-481 		return wrappers;
-482 	},
-483 
-484 	/**
-485 	 * Wraps node and its adjust next siblings into an element
-486 	 */
-487 	wrapInlineOrTextNodesAs: function(tag, node) {
-488 		var wrapper = this.createElement(tag);
-489 		var from = node;
-490 
-491 		from.parentNode.replaceChild(wrapper, from);
-492 		wrapper.appendChild(from);
-493 
-494 		// move nodes into wrapper
-495 		while(wrapper.nextSibling && this.tree.isTextOrInlineNode(wrapper.nextSibling)) wrapper.appendChild(wrapper.nextSibling);
-496 
-497 		return wrapper;
-498 	},
-499 	
-500 	/**
-501 	 * Turns block element into list item
-502 	 *
-503 	 * @param {Element} element Target element
-504 	 * @param {String} type One of "UL", "OL", "CODE". "CODE" is same with "OL" but it gives "OL" a class name "code"
-505 	 *
-506 	 * @return {Element} LI element
-507 	 */
-508 	turnElementIntoListItem: function(element, type) {
-509 		type = type.toUpperCase();
-510 		
-511 		var container = this.createElement(type == "UL" ? "UL" : "OL");
-512 		if(type == "CODE") container.className = "code";
-513 		
-514 		if(this.tree.isTableCell(element)) {
-515 			var p = this.wrapAllInlineOrTextNodesAs("P", element, true)[0];
-516 			container = this.insertNodeAt(container, element, "start");
-517 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
-518 			li.appendChild(p);
-519 		} else {
-520 			container = this.insertNodeAt(container, element, "after");
-521 			var li = this.insertNodeAt(this.createElement("LI"), container, "start");
-522 			li.appendChild(element);
-523 		}
-524 		
-525 		this.unwrapUnnecessaryParagraph(li);
-526 		this.mergeAdjustLists(container);
-527 		
-528 		return li;
-529 	},
-530 	
-531 	/**
-532 	 * Extracts given element out from its parent element.
-533 	 * 
-534 	 * @param {Element} element Target element
-535 	 */
-536 	extractOutElementFromParent: function(element) {
-537 		if(element == this.root || this.root == element.parentNode || !element.offsetParent) return null;
-538 		
-539 		if(element.nodeName == "LI") {
-540 			this.wrapAllInlineOrTextNodesAs("P", element, true);
-541 			element = element.firstChild;
-542 		}
-543 
-544 		var container = element.parentNode;
-545 		var nodeToReturn = null;
-546 		
-547 		if(container.nodeName == "LI" && container.parentNode.parentNode.nodeName == "LI") {
-548 			// nested list item
-549 			if(element.previousSibling) {
-550 				this.splitContainerOf(element, true);
-551 				this.correctEmptyElement(element);
-552 			}
-553 			
-554 			this.outdentListItem(element);
-555 			nodeToReturn = element;
-556 		} else if(container.nodeName == "LI") {
-557 			// not-nested list item
-558 			
-559 			if(this.tree.isListContainer(element.nextSibling)) {
-560 				// 1. split listContainer
-561 				var listContainer = container.parentNode;
-562 				this.splitContainerOf(container, true);
-563 				this.correctEmptyElement(element);
-564 				
-565 				// 2. extract out LI's children
-566 				nodeToReturn = container.firstChild;
-567 				while(container.firstChild) {
-568 					this.insertNodeAt(container.firstChild, listContainer, "before");
-569 				}
-570 				
-571 				// 3. remove listContainer and merge adjust lists
-572 				var prevContainer = listContainer.previousSibling;
-573 				this.deleteNode(listContainer);
-574 				if(prevContainer && this.tree.isListContainer(prevContainer)) this.mergeAdjustLists(prevContainer);
-575 			} else {
-576 				// 1. split LI
-577 				this.splitContainerOf(element, true);
-578 				this.correctEmptyElement(element);
-579 				
-580 				// 2. split list container
-581 				var listContainer = this.splitContainerOf(container);
-582 				
-583 				// 3. extract out
-584 				this.insertNodeAt(element, listContainer.parentNode, "before");
-585 				this.deleteNode(listContainer.parentNode);
-586 				
-587 				nodeToReturn = element;
-588 			}
-589 		} else if(this.tree.isTableCell(container) || this.tree.isTableCell(element)) {
-590 			// do nothing
-591 		} else {
-592 			// normal block
-593 			this.splitContainerOf(element, true);
-594 			this.correctEmptyElement(element);
-595 			nodeToReturn = this.insertNodeAt(element, container, "before");
-596 			
-597 			this.deleteNode(container);
-598 		}
-599 		
-600 		return nodeToReturn;
-601 	},
-602 	
-603 	/**
-604 	 * Insert new block above or below given element.
-605 	 *
-606 	 * @param {Element} block Target block
-607 	 * @param {boolean} before Insert new block above(before) target block
-608 	 * @param {String} forceTag New block's tag name. If omitted, target block's tag name will be used.
-609 	 *
-610 	 * @returns {Element} Inserted block
-611 	 */
-612 	insertNewBlockAround: function(block, before, forceTag) {
-613 		var isListItem = block.nodeName == "LI" || block.parentNode.nodeName == "LI";
-614 		
-615 		this.removeTrailingWhitespace(block);
-616 		if(this.isFirstLiWithNestedList(block) && !forceTag && before) {
-617 			var li = this.getParentElementOf(block, ["LI"]);
-618 			var newBlock = this._insertNewBlockAround(li, before);
-619 			return newBlock;
-620 		} else if(isListItem && !forceTag) {
-621 			var li = this.getParentElementOf(block, ["LI"]);
-622 			var newBlock = this._insertNewBlockAround(block, before);
-623 			if(li != block) newBlock = this.splitContainerOf(newBlock, false, "prev");
-624 			return newBlock;
-625 		} else if(this.tree.isBlockContainer(block)) {
-626 			this.wrapAllInlineOrTextNodesAs("P", block, true);
-627 			return this._insertNewBlockAround(block.firstChild, before, forceTag);
-628 		} else {
-629 			return this._insertNewBlockAround(block, before, this.tree.isHeading(block) ? "P" : forceTag);
-630 		}
-631 	},
-632 	
-633 	/**
-634 	 * @private
-635 	 *
-636 	 * TODO: Rename
-637 	 */
-638 	_insertNewBlockAround: function(element, before, tagName) {
-639 		var newElement = this.createElement(tagName || element.nodeName);
-640 		this.copyAttributes(element, newElement, false);
-641 		this.correctEmptyElement(newElement);
-642 		newElement = this.insertNodeAt(newElement, element, before ? "before" : "after");
-643 		return newElement;
-644 	},
-645 	
-646 	/**
-647 	 * Wrap or replace element with given tag name.
-648 	 *
-649 	 * @param {String} tag Tag name
-650 	 * @param {Element} element Target element
-651 	 *
-652 	 * @return {Element} wrapper element or replaced element.
-653 	 */
-654 	applyTagIntoElement: function(tag, element) {
-655 		if(this.tree.isBlockOnlyContainer(tag)) {
-656 			return this.wrapBlock(tag, element);
-657 		} else if(this.tree.isBlockContainer(element)) {
-658 			var wrapper = this.createElement(tag);
-659 			this.moveChildNodes(element, wrapper);
-660 			return this.insertNodeAt(wrapper, element, "start");
-661 		} else {
-662 			if(this.tree.isBlockContainer(tag) && this.hasImportantAttributes(element)) {
-663 				return this.wrapBlock(tag, element);
-664 			} else {
-665 				return this.replaceTag(tag, element);
-666 			}
-667 		}
-668 		
-669 		throw "IllegalArgumentException - [" + tag + ", " + element + "]";
-670 	},
-671 	
-672 	/**
-673 	 * Wrap or replace elements with given tag name.
-674 	 *
-675 	 * @param {String} tag Tag name
-676 	 * @param {Element} from Start boundary (inclusive)
-677 	 * @param {Element} to End boundary (inclusive)
-678 	 *
-679 	 * @returns {Array} Array of wrappers or replaced elements
-680 	 */
-681 	applyTagIntoElements: function(tagName, from, to) {
-682 		var applied = [];
-683 		
-684 		if(this.tree.isBlockContainer(tagName)) {
-685 			var family = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
-686 			var node = family.left;
-687 			var wrapper = this.insertNodeAt(this.createElement(tagName), node, "before");
-688 			
-689 			var coveringWholeList =
-690 				family.parent.nodeName == "LI" &&
-691 				family.parent.parentNode.childNodes.length == 1 &&
-692 				!family.left.previousSilbing &&
-693 				!family.right.nextSibling;
-694 				
-695 			if(coveringWholeList) {
-696 				var ul = node.parentNode.parentNode;
-697 				this.insertNodeAt(wrapper, ul, "before");
-698 				wrapper.appendChild(ul);
-699 			} else {
-700 				while(node != family.right) {
-701 					next = node.nextSibling;
-702 					wrapper.appendChild(node);
-703 					node = next;
-704 				}
-705 				wrapper.appendChild(family.right);
-706 			}
-707 			applied.push(wrapper);
-708 		} else {
-709 			// is normal tagName
-710 			var elements = this.getBlockElementsBetween(from, to);
-711 			for(var i = 0; i < elements.length; i++) {
-712 				if(this.tree.isBlockContainer(elements[i])) {
-713 					applied.push(this.wrapAllInlineOrTextNodesAs(tagName, elements[i], true));
-714 				} else {
-715 					applied.push(this.replaceTag(tagName, elements[i]));
-716 				}
-717 			}
-718 		}
-719 		return applied.flatten();
-720 	},
-721 	
-722 	/**
-723 	 * Moves block up or down
-724 	 *
-725 	 * @param {Element} block Target block
-726 	 * @param {boolean} up Move up if true
-727 	 * 
-728 	 * @returns {Element} Moved block. It could be different with given block.
-729 	 */
-730 	moveBlock: function(block, up) {
-731 		// if block is table cell or contained by table cell, select its row as mover
-732 		block = this.getParentElementOf(block, ["TR"]) || block;
-733 		
-734 		// if block is only child, select its parent as mover
-735 		while(block.nodeName != "TR" && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
-736 			block = block.parentNode;
-737 		}
-738 		
-739 		// find target and where
-740 		var target, where;
-741 		if (up) {
-742 			target = block.previousSibling;
-743 			
-744 			if(target) {
-745 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
-746 				var table = ['TABLE', 'TR'].include(target.nodeName);
-747 
-748 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "end" : "before";
-749 			} else if(block.parentNode != this.getRoot()) {
-750 				target = block.parentNode;
-751 				where = "before";
-752 			}
-753 		} else {
-754 			target = block.nextSibling;
-755 			
-756 			if(target) {
-757 				var singleNodeLi = target.nodeName == 'LI' && ((target.childNodes.length == 1 && this.tree.isBlock(target.firstChild)) || !this.tree.hasBlocks(target));
-758 				var table = ['TABLE', 'TR'].include(target.nodeName);
-759 				
-760 				where = this.tree.isBlockContainer(target) && !singleNodeLi && !table ? "start" : "after";
-761 			} else if(block.parentNode != this.getRoot()) {
-762 				target = block.parentNode;
-763 				where = "after";
-764 			}
-765 		}
-766 		
-767 		
-768 		// no way to go?
-769 		if(!target) return null;
-770 		if(["TBODY", "THEAD"].include(target.nodeName)) return null;
-771 		
-772 		// normalize
-773 		this.wrapAllInlineOrTextNodesAs("P", target, true);
-774 		
-775 		// make placeholder if needed
-776 		if(this.isFirstLiWithNestedList(block)) {
-777 			this.insertNewBlockAround(block, false, "P");
-778 		}
-779 		
-780 		// perform move
-781 		var parent = block.parentNode;
-782 		var moved = this.insertNodeAt(block, target, where, true);
-783 		
-784 		// cleanup
-785 		if(!parent.hasChildNodes()) this.deleteNode(parent, true);
-786 		this.unwrapUnnecessaryParagraph(moved);
-787 		this.unwrapUnnecessaryParagraph(target);
-788 
-789 		// remove placeholder
-790 		if(up) {
-791 			if(moved.previousSibling && this.isEmptyBlock(moved.previousSibling) && !moved.previousSibling.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling)) {
-792 				this.deleteNode(moved.previousSibling);
-793 			}
-794 		} else {
-795 			if(moved.nextSibling && this.isEmptyBlock(moved.nextSibling) && !moved.previousSibling && moved.parentNode.nodeName == "LI" && this.tree.isListContainer(moved.nextSibling.nextSibling)) {
-796 				this.deleteNode(moved.nextSibling);
-797 			}
-798 		}
-799 		
-800 		return moved;
-801 	},
-802 	
-803 	/**
-804 	 * Remove given block
-805 	 *
-806 	 * @param {Element} block Target block
-807 	 * @returns {Element} Nearest block of remove element
-808 	 */
-809 	removeBlock: function(block) {
-810 		var blockToMove;
-811 
-812 		// if block is only child, select its parent as mover
-813 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
-814 			block = block.parentNode;
-815 		}
-816 		
-817 		var finder = function(node) {return this.tree.isBlock(node) && !this.tree.isAtomic(node) && !this.tree.isDescendantOf(block, node) && !this.tree.hasBlocks(node);}.bind(this);
-818 		var exitCondition = function(node) {return this.tree.isBlock(node) && !this.tree.isDescendantOf(this.getRoot(), node)}.bind(this);
-819 		
-820 		if(this.isFirstLiWithNestedList(block)) {
-821 			blockToMove = this.outdentListItem(block.nextSibling.firstChild);
-822 			this.deleteNode(blockToMove.previousSibling, true);
-823 		} else if(this.tree.isTableCell(block)) {
-824 			var rtable = new xq.RichTable(this, this.getParentElementOf(block, ["TABLE"]));
-825 			blockToMove = rtable.getBelowCellOf(block);
-826 			
-827 			// should not delete row when there's thead and the row is the only child of tbody
-828 			if(
-829 				block.parentNode.parentNode.nodeName == "TBODY" &&
-830 				rtable.hasHeadingAtTop() &&
-831 				rtable.getDom().tBodies[0].rows.length == 1) return blockToMove;
-832 			
-833 			blockToMove = blockToMove ||
-834 				this.tree.findForward(block, finder, exitCondition) ||
-835 				this.tree.findBackward(block, finder, exitCondition);
-836 			
-837 			this.deleteNode(block.parentNode, true);
-838 		} else {
-839 			blockToMove = blockToMove ||
-840 				this.tree.findForward(block, finder, exitCondition) ||
-841 				this.tree.findBackward(block, finder, exitCondition);
-842 			
-843 			if(!blockToMove) blockToMove = this.insertNodeAt(this.makeEmptyParagraph(), block, "after");
-844 			
-845 			this.deleteNode(block, true);
-846 		}
-847 		if(!this.getRoot().hasChildNodes()) {
-848 			blockToMove = this.createElement("P");
-849 			this.getRoot().appendChild(blockToMove);
-850 			this.correctEmptyElement(blockToMove);
-851 		}
-852 		
-853 		return blockToMove;
-854 	},
-855 	
-856 	/**
-857 	 * Removes trailing whitespaces of given block
-858 	 *
-859 	 * @param {Element} block Target block
-860 	 */
-861 	removeTrailingWhitespace: function(block) {throw "Not implemented"},
-862 	
-863 	/**
-864 	 * Extract given list item out and change its container's tag
-865 	 *
-866 	 * @param {Element} element LI or P which is a child of LI
-867 	 * @param {String} type "OL", "UL", or "CODE"
-868 	 *
-869 	 * @returns {Element} changed element
-870 	 */
-871 	changeListTypeTo: function(element, type) {
-872 		type = type.toUpperCase();
-873 		
-874 		var li = this.getParentElementOf(element, ["LI"]);
-875 		if(!li) throw "IllegalArgumentException";
-876 		
-877 		var container = li.parentNode;
-878 
-879 		this.splitContainerOf(li);
-880 		
-881 		var newContainer = this.insertNodeAt(this.createElement(type == "UL" ? "UL" : "OL"), container, "before");
-882 		if(type == "CODE") newContainer.className = "code";
-883 		
-884 		this.insertNodeAt(li, newContainer, "start");
-885 		this.deleteNode(container);
-886 		
-887 		this.mergeAdjustLists(newContainer);
-888 		
-889 		return element;
-890 	},
-891 	
-892 	/**
-893 	 * Split container of element into (maxium) three pieces.
-894 	 */
-895 	splitContainerOf: function(element, preserveElementItself, dir) {
-896 		if([element, element.parentNode].include(this.getRoot())) return element;
-897 
-898 		var container = element.parentNode;
-899 		if(element.previousSibling && (!dir || dir.toLowerCase() == "prev")) {
-900 			var prev = this.createElement(container.nodeName);
-901 			this.copyAttributes(container, prev);
-902 			while(container.firstChild != element) {
-903 				prev.appendChild(container.firstChild);
-904 			}
-905 			this.insertNodeAt(prev, container, "before");
-906 			this.unwrapUnnecessaryParagraph(prev);
-907 		}
-908 		
-909 		if(element.nextSibling && (!dir || dir.toLowerCase() == "next")) {
-910 			var next = this.createElement(container.nodeName);
-911 			this.copyAttributes(container, next);
-912 			while(container.lastChild != element) {
-913 				this.insertNodeAt(container.lastChild, next, "start");
-914 			}
-915 			this.insertNodeAt(next, container, "after");
-916 			this.unwrapUnnecessaryParagraph(next);
-917 		}
-918 		
-919 		if(!preserveElementItself) element = this.unwrapUnnecessaryParagraph(container) ? container : element;
-920 		return element;
-921 	},
-922 
-923 	/**
-924 	 * TODO: Add specs
-925 	 */
-926 	splitParentElement: function(seperator) {
-927 		var parent = seperator.parentNode;
-928 		if(["HTML", "HEAD", "BODY"].include(parent.nodeName)) throw "Illegal argument. Cannot seperate element[" + parent.nodeName + "]";
-929 
-930 		var previousSibling = seperator.previousSibling;
-931 		var nextSibling = seperator.nextSibling;
-932 		
-933 		var newElement = this.insertNodeAt(this.createElement(parent.nodeName), parent, "after");
-934 		
-935 		var next;
-936 		while(next = seperator.nextSibling) newElement.appendChild(next);
-937 		
-938 		this.insertNodeAt(seperator, newElement, "start");
-939 		this.copyAttributes(parent, newElement);
-940 		
-941 		return newElement;
-942 	},
-943 	
-944 	/**
-945 	 * TODO: Add specs
-946 	 */
-947 	splitElementUpto: function(seperator, element, excludeElement) {
-948 		while(seperator.previousSibling != element) {
-949 			if(excludeElement && seperator.parentNode == element) break;
-950 			seperator = this.splitParentElement(seperator);
-951 		}
-952 		return seperator;
-953 	},
-954 	
-955 	/**
-956 	 * Merges two adjust elements
-957 	 *
-958 	 * @param {Element} element base element
-959 	 * @param {boolean} withNext merge base element with next sibling
-960 	 * @param {boolean} skip skip merge steps
-961 	 */
-962 	mergeElement: function(element, withNext, skip) {
-963 		this.wrapAllInlineOrTextNodesAs("P", element.parentNode, true);
-964 		
-965 		// find two block
-966 		if(withNext) {
-967 			var prev = element;
-968 			var next = this.tree.findForward(
-969 				element,
-970 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
-971 			);
-972 		} else {
-973 			var next = element;
-974 			var prev = this.tree.findBackward(
-975 				element,
-976 				function(node) {return this.tree.isBlock(node) && !this.tree.isListContainer(node) && node != element.parentNode}.bind(this)
-977 			);
-978 		}
-979 		
-980 		// normalize next block
-981 		if(next && this.tree.isDescendantOf(this.getRoot(), next)) {
-982 			var nextContainer = next.parentNode;
-983 			if(this.tree.isBlockContainer(next)) {
-984 				nextContainer = next;
-985 				this.wrapAllInlineOrTextNodesAs("P", nextContainer, true);
-986 				next = nextContainer.firstChild;
-987 			}
-988 		} else {
-989 			next = null;
-990 		}
-991 		
-992 		// normalize prev block
-993 		if(prev && this.tree.isDescendantOf(this.getRoot(), prev)) {
-994 			var prevContainer = prev.parentNode;
-995 			if(this.tree.isBlockContainer(prev)) {
-996 				prevContainer = prev;
-997 				this.wrapAllInlineOrTextNodesAs("P", prevContainer, true);
-998 				prev = prevContainer.lastChild;
-999 			}
-1000 		} else {
-1001 			prev = null;
-1002 		}
-1003 		
-1004 		try {
-1005 			var containersAreTableCell =
-1006 				prevContainer && (this.tree.isTableCell(prevContainer) || ['TR', 'THEAD', 'TBODY'].include(prevContainer.nodeName)) &&
-1007 				nextContainer && (this.tree.isTableCell(nextContainer) || ['TR', 'THEAD', 'TBODY'].include(nextContainer.nodeName));
-1008 			
-1009 			if(containersAreTableCell && prevContainer != nextContainer) return null;
-1010 			
-1011 			// if next has margin, perform outdent
-1012 			if((!skip || !prev) && next && this.outdentElement(next)) return element;
-1013 
-1014 			// nextContainer is first li and next of it is list container
-1015 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(next.nextSibling)) {
-1016 				this.extractOutElementFromParent(nextContainer);
-1017 				return prev;
-1018 			}
-1019 			
-1020 			// merge two list containers
-1021 			if(nextContainer && nextContainer.nodeName == 'LI' && this.tree.isListContainer(nextContainer.parentNode.previousSibling)) {
-1022 				this.mergeAdjustLists(nextContainer.parentNode.previousSibling, true, "next");
-1023 				return prev;
-1024 			}
-1025 
-1026 			if(next && !containersAreTableCell && prevContainer && prevContainer.nodeName == 'LI' && nextContainer && nextContainer.nodeName == 'LI' && prevContainer.parentNode.nextSibling == nextContainer.parentNode) {
-1027 				var nextContainerContainer = nextContainer.parentNode;
-1028 				this.moveChildNodes(nextContainer.parentNode, prevContainer.parentNode);
-1029 				this.deleteNode(nextContainerContainer);
-1030 				return prev;
-1031 			}
-1032 			
-1033 			// merge two containers
-1034 			if(next && !containersAreTableCell && prevContainer && prevContainer.nextSibling == nextContainer && ((skip && prevContainer.nodeName != "LI") || (!skip && prevContainer.nodeName == "LI"))) {
-1035 				this.moveChildNodes(nextContainer, prevContainer);
-1036 				return prev;
-1037 			}
-1038 
-1039 			// unwrap container
-1040 			if(nextContainer && nextContainer.nodeName != "LI" && !this.getParentElementOf(nextContainer, ["TABLE"]) && !this.tree.isListContainer(nextContainer) && nextContainer != this.getRoot() && !next.previousSibling) {
-1041 				return this.unwrapElement(nextContainer, true);
-1042 			}
-1043 			
-1044 			// delete table
-1045 			if(withNext && nextContainer && nextContainer.nodeName == "TABLE") {
-1046 				this.deleteNode(nextContainer, true);
-1047 				return prev;
-1048 			} else if(!withNext && prevContainer && this.tree.isTableCell(prevContainer) && !this.tree.isTableCell(nextContainer)) {
-1049 				this.deleteNode(this.getParentElementOf(prevContainer, ["TABLE"]), true);
-1050 				return next;
-1051 			}
-1052 			
-1053 			// if prev is same with next, do nothing
-1054 			if(prev == next) return null;
-1055 
-1056 			// if there is a null block, do nothing
-1057 			if(!prev || !next || !prevContainer || !nextContainer) return null;
-1058 			
-1059 			// if two blocks are not in the same table cell, do nothing
-1060 			if(this.getParentElementOf(prev, ["TD", "TH"]) != this.getParentElementOf(next, ["TD", "TH"])) return null;
-1061 			
-1062 			var prevIsEmpty = false;
-1063 			
-1064 			// cleanup empty block before merge
-1065 
-1066 			// 1. cleanup prev node which ends with marker +  
-1067 			if(
-1068 				xq.Browser.isTrident &&
-1069 				prev.childNodes.length >= 2 &&
-1070 				this.isMarker(prev.lastChild.previousSibling) &&
-1071 				prev.lastChild.nodeType == 3 &&
-1072 				prev.lastChild.nodeValue.length == 1 &&
-1073 				prev.lastChild.nodeValue.charCodeAt(0) == 160
-1074 			) {
-1075 				this.deleteNode(prev.lastChild);
-1076 			}
-1077 
-1078 			// 2. cleanup prev node (if prev is empty, then replace prev's tag with next's)
-1079 			this.removePlaceHoldersAndEmptyNodes(prev);
-1080 			if(this.isEmptyBlock(prev)) {
-1081 				// replace atomic block with normal block so that following code don't need to care about atomic block
-1082 				if(this.tree.isAtomic(prev)) prev = this.replaceTag("P", prev);
-1083 				
-1084 				prev = this.replaceTag(next.nodeName, prev) || prev;
-1085 				prev.innerHTML = "";
-1086 			} else if(prev.firstChild == prev.lastChild && this.isMarker(prev.firstChild)) {
-1087 				prev = this.replaceTag(next.nodeName, prev) || prev;
-1088 			}
-1089 			
-1090 			// 3. cleanup next node
-1091 			if(this.isEmptyBlock(next)) {
-1092 				// replace atomic block with normal block so that following code don't need to care about atomic block
-1093 				if(this.tree.isAtomic(next)) next = this.replaceTag("P", next);
-1094 				
-1095 				next.innerHTML = "";
-1096 			}
-1097 			
-1098 			// perform merge
-1099 			this.moveChildNodes(next, prev);
-1100 			this.deleteNode(next);
-1101 			return prev;
-1102 		} finally {
-1103 			// cleanup
-1104 			if(prevContainer && this.isEmptyBlock(prevContainer)) this.deleteNode(prevContainer, true);
-1105 			if(nextContainer && this.isEmptyBlock(nextContainer)) this.deleteNode(nextContainer, true);
-1106 			
-1107 			if(prevContainer) this.unwrapUnnecessaryParagraph(prevContainer);
-1108 			if(nextContainer) this.unwrapUnnecessaryParagraph(nextContainer);
-1109 		}
-1110 	},
-1111 	
-1112 	/**
-1113 	 * Merges adjust list containers which has same tag name
-1114 	 *
-1115 	 * @param {Element} container target list container
-1116 	 * @param {boolean} force force adjust list container even if they have different list type
-1117 	 * @param {String} dir Specify merge direction: PREV or NEXT. If not supplied it will be merged with both direction.
-1118 	 */
-1119 	mergeAdjustLists: function(container, force, dir) {
-1120 		var prev = container.previousSibling;
-1121 		var isPrevSame = prev && (prev.nodeName == container.nodeName && prev.className == container.className);
-1122 		if((!dir || dir.toLowerCase() == 'prev') && (isPrevSame || (force && this.tree.isListContainer(prev)))) {
-1123 			while(prev.lastChild) {
-1124 				this.insertNodeAt(prev.lastChild, container, "start");
-1125 			}
-1126 			this.deleteNode(prev);
-1127 		}
-1128 		
-1129 		var next = container.nextSibling;
-1130 		var isNextSame = next && (next.nodeName == container.nodeName && next.className == container.className);
-1131 		if((!dir || dir.toLowerCase() == 'next') && (isNextSame || (force && this.tree.isListContainer(next)))) {
-1132 			while(next.firstChild) {
-1133 				this.insertNodeAt(next.firstChild, container, "end");
-1134 			}
-1135 			this.deleteNode(next);
-1136 		}
-1137 	},
-1138 	
-1139 	/**
-1140 	 * Moves child nodes from one element into another.
-1141 	 *
-1142 	 * @param {Elemet} from source element
-1143 	 * @param {Elemet} to target element
-1144 	 */
-1145 	moveChildNodes: function(from, to) {
-1146 		if(this.tree.isDescendantOf(from, to) || ["HTML", "HEAD"].include(to.nodeName))
-1147 			throw "Illegal argument. Cannot move children of element[" + from.nodeName + "] to element[" + to.nodeName + "]";
-1148 		
-1149 		if(from == to) return;
-1150 		
-1151 		while(from.firstChild) to.appendChild(from.firstChild);
-1152 	},
-1153 	
-1154 	/**
-1155 	 * Copies attributes from one element into another.
-1156 	 *
-1157 	 * @param {Element} from source element
-1158 	 * @param {Element} to target element
-1159 	 * @param {boolean} copyId copy ID attribute of source element
-1160 	 */
-1161 	copyAttributes: function(from, to, copyId) {
-1162 		// IE overrides this
-1163 		
-1164 		var attrs = from.attributes;
-1165 		if(!attrs) return;
-1166 		
-1167 		for(var i = 0; i < attrs.length; i++) {
-1168 			if(attrs[i].nodeName == "class" && attrs[i].nodeValue) {
-1169 				to.className = attrs[i].nodeValue;
-1170 			} else if((copyId || !["id"].include(attrs[i].nodeName)) && attrs[i].nodeValue) {
-1171 				to.setAttribute(attrs[i].nodeName, attrs[i].nodeValue);
-1172 			}
-1173 		}
-1174 	},
-1175 
-1176 	_indentElements: function(node, blocks, affect) {
-1177 		for (var i=0; i < affect.length; i++) {
-1178 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
-1179 				return;
-1180 		}
-1181 		leaves = this.tree.getLeavesAtEdge(node);
-1182 		
-1183 		if (blocks.include(leaves[0])) {
-1184 			var affected = this.indentElement(node, true);
-1185 			if (affected) {
-1186 				affect.push(affected);
-1187 				return;
-1188 			}
-1189 		}
-1190 		
-1191 		if (blocks.include(node)) {
-1192 			var affected = this.indentElement(node, true);
-1193 			if (affected) {
-1194 				affect.push(affected);
-1195 				return;
-1196 			}
-1197 		}
-1198 
-1199 		var children=$A(node.childNodes);
-1200 		for (var i=0; i < children.length; i++)
-1201 			this._indentElements(children[i], blocks, affect);
-1202 		return;
-1203 	},
-1204 
-1205 	indentElements: function(from, to) {
-1206 		var blocks = this.getBlockElementsBetween(from, to);
-1207 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
-1208 		
-1209 		var affect = [];
-1210 		
-1211 		leaves = this.tree.getLeavesAtEdge(top.parent);
-1212 		if (blocks.include(leaves[0])) {
-1213 			var affected = this.indentElement(top.parent);
-1214 			if (affected)
-1215 				return [affected];
-1216 		}
-1217 		
-1218 		var children = $A(top.parent.childNodes);
-1219 		for (var i=0; i < children.length; i++) {
-1220 			this._indentElements(children[i], blocks, affect);
-1221 		}
-1222 		
-1223 		affect = affect.flatten()
-1224 		return affect.length > 0 ? affect : blocks;
-1225 	},
-1226 	
-1227 	outdentElementsCode: function(node) {
-1228 		if (node.tagName == 'LI')
-1229 			node = node.parentNode;
-1230 		if (node.tagName == 'OL' && node.className == 'code')
-1231 			return true;
-1232 		return false;
-1233 	},
-1234 	
-1235 	_outdentElements: function(node, blocks, affect) {
-1236 		for (var i=0; i < affect.length; i++) {
-1237 			if (affect[i] == node || this.tree.isDescendantOf(affect[i], node))
-1238 				return;
-1239 		}
-1240 		leaves = this.tree.getLeavesAtEdge(node);
-1241 		
-1242 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(leaves[0])) {
-1243 			var affected = this.outdentElement(node, true);
-1244 			if (affected) {
-1245 				affect.push(affected);
-1246 				return;
-1247 			}
-1248 		}
-1249 		
-1250 		if (blocks.include(node)) {
-1251 			var children = $A(node.parentNode.childNodes);
-1252 			var isCode = this.outdentElementsCode(node);
-1253 			var affected = this.outdentElement(node, true, isCode);
-1254 			if (affected) {
-1255 				if (children.include(affected) && this.tree.isListContainer(node.parentNode) && !isCode) {
-1256 					for (var i=0; i < children.length; i++) {
-1257 						if (blocks.include(children[i]) && !affect.include(children[i]))
-1258 							affect.push(children[i]);
-1259 					}
-1260 				}else
-1261 					affect.push(affected);
-1262 				return;
-1263 			}
-1264 		}
-1265 
-1266 		var children=$A(node.childNodes);
-1267 		for (var i=0; i < children.length; i++)
-1268 			this._outdentElements(children[i], blocks, affect);
-1269 		return;
-1270 	},
-1271 
-1272 	outdentElements: function(from, to) {
-1273 		var start, end;
-1274 		
-1275 		if (from.parentNode.tagName == 'LI') start=from.parentNode;
-1276 		if (to.parentNode.tagName == 'LI') end=to.parentNode;
-1277 		
-1278 		var blocks = this.getBlockElementsBetween(from, to);
-1279 		var top = this.tree.findCommonAncestorAndImmediateChildrenOf(from, to);
-1280 		
-1281 		var affect = [];
-1282 		
-1283 		leaves = this.tree.getLeavesAtEdge(top.parent);
-1284 		if (blocks.include(leaves[0]) && !this.outdentElementsCode(top.parent)) {
-1285 			var affected = this.outdentElement(top.parent);
-1286 			if (affected)
-1287 				return [affected];
-1288 		}
-1289 		
-1290 		var children = $A(top.parent.childNodes);
-1291 		for (var i=0; i < children.length; i++) {
-1292 			this._outdentElements(children[i], blocks, affect);
-1293 		}
-1294 
-1295 		if (from.offsetParent && to.offsetParent) {
-1296 			start = from;
-1297 			end = to;
-1298 		}else if (blocks.first().offsetParent && blocks.last().offsetParent) {
-1299 			start = blocks.first();
-1300 			end = blocks.last();
-1301 		}
-1302 		
-1303 		affect = affect.flatten()
-1304 		if (!start || !start.offsetParent)
-1305 			start = affect.first();
-1306 		if (!end || !end.offsetParent)
-1307 			end = affect.last();
-1308 		
-1309 		return this.getBlockElementsBetween(start, end);
-1310 	},
-1311 	
-1312 	/**
-1313 	 * Performs indent by increasing element's margin-left
-1314 	 */	
-1315 	indentElement: function(element, noParent, forceMargin) {
-1316 		if(
-1317 			!forceMargin &&
-1318 			(element.nodeName == "LI" || (!this.tree.isListContainer(element) && !element.previousSibling && element.parentNode.nodeName == "LI"))
-1319 		) return this.indentListItem(element, noParent);
-1320 		
-1321 		var root = this.getRoot();
-1322 		if(!element || element == root) return null;
-1323 		
-1324 		if (element.parentNode != root && !element.previousSibling && !noParent) element=element.parentNode;
-1325 		
-1326 		var margin = element.style.marginLeft;
-1327 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
-1328 		
-1329 		cssValue.value += 2;
-1330 		element.style.marginLeft = cssValue.value + cssValue.unit;
-1331 		
-1332 		return element;
-1333 	},
-1334 	
-1335 	/**
-1336 	 * Performs outdent by decreasing element's margin-left
-1337 	 */	
-1338 	outdentElement: function(element, noParent, forceMargin) {
-1339 		if(!forceMargin && element.nodeName == "LI") return this.outdentListItem(element, noParent);
-1340 		
-1341 		var root = this.getRoot();
-1342 		if(!element || element == root) return null;
-1343 		
-1344 		var margin = element.style.marginLeft;
-1345 		
-1346 		var cssValue = margin ? this._getCssValue(margin, "px") : {value:0, unit:"em"};
-1347 		if(cssValue.value == 0) {
-1348 			return element.previousSibling || forceMargin ?
-1349 				null :
-1350 				this.outdentElement(element.parentNode, noParent);
-1351 		}
-1352 		
-1353 		cssValue.value -= 2;
-1354 		element.style.marginLeft = cssValue.value <= 0 ? "" : cssValue.value + cssValue.unit;
-1355 		if(element.style.cssText == "") element.removeAttribute("style");
-1356 		
-1357 		return element;
-1358 	},
-1359 	
-1360 	/**
-1361 	 * Performs indent for list item
-1362 	 */
-1363 	indentListItem: function(element, treatListAsNormalBlock) {
-1364 		var li = this.getParentElementOf(element, ["LI"]);
-1365 		var container = li.parentNode;
-1366 		var prev = li.previousSibling;
-1367 		if(!li.previousSibling) return this.indentElement(container);
-1368 		
-1369 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.indentElement(li, treatListAsNormalBlock, true);
-1370 		
-1371 		if(!prev.lastChild) prev.appendChild(this.makePlaceHolder());
-1372 		
-1373 		var targetContainer = 
-1374 			this.tree.isListContainer(prev.lastChild) ?
-1375 			// if there's existing list container, select it as target container
-1376 			prev.lastChild :
-1377 			// if there's nothing, create new one
-1378 			this.insertNodeAt(this.createElement(container.nodeName), prev, "end");
-1379 		
-1380 		this.wrapAllInlineOrTextNodesAs("P", prev, true);
-1381 		
-1382 		// perform move
-1383 		targetContainer.appendChild(li);
-1384 		
-1385 		// flatten nested list
-1386 		if(!treatListAsNormalBlock && li.lastChild && this.tree.isListContainer(li.lastChild)) {
-1387 			var childrenContainer = li.lastChild;
-1388 			var child;
-1389 			while(child = childrenContainer.lastChild) {
-1390 				this.insertNodeAt(child, li, "after");
-1391 			}
-1392 			this.deleteNode(childrenContainer);
-1393 		}
-1394 		
-1395 		this.unwrapUnnecessaryParagraph(li);
-1396 		
-1397 		return li;
-1398 	},
-1399 	
-1400 	/**
-1401 	 * Performs outdent for list item
-1402 	 *
-1403 	 * @return {Element} outdented list item or null if no outdent performed
-1404 	 */
-1405 	outdentListItem: function(element, treatListAsNormalBlock) {
-1406 		var li = this.getParentElementOf(element, ["LI"]);
-1407 		var container = li.parentNode;
-1408 
-1409 		if(!li.previousSibling) {
-1410 			var performed = this.outdentElement(container);
-1411 			if(performed) return performed;
-1412 		}
-1413 
-1414 		if(li.parentNode.nodeName == "OL" && li.parentNode.className == "code") return this.outdentElement(li, treatListAsNormalBlock, true);
-1415 		
-1416 		var parentLi = container.parentNode;
-1417 		if(parentLi.nodeName != "LI") return null;
-1418 		
-1419 		if(treatListAsNormalBlock) {
-1420 			while(container.lastChild != li) {
-1421 				this.insertNodeAt(container.lastChild, parentLi, "after");
-1422 			}
-1423 		} else {
-1424 			// make next siblings as children
-1425 			if(li.nextSibling) {
-1426 				var targetContainer =
-1427 					li.lastChild && this.tree.isListContainer(li.lastChild) ?
-1428 						// if there's existing list container, select it as target container
-1429 						li.lastChild :
-1430 						// if there's nothing, create new one
-1431 						this.insertNodeAt(this.createElement(container.nodeName), li, "end");
-1432 				
-1433 				this.copyAttributes(container, targetContainer);
-1434 				
-1435 				var sibling;
-1436 				while(sibling = li.nextSibling) {
-1437 					targetContainer.appendChild(sibling);
-1438 				}
-1439 			}
-1440 		}
-1441 		
-1442 		// move current LI into parent LI's next sibling
-1443 		li = this.insertNodeAt(li, parentLi, "after");
-1444 		
-1445 		// remove empty container
-1446 		if(container.childNodes.length == 0) this.deleteNode(container);
-1447 		
-1448 		if(li.firstChild && this.tree.isListContainer(li.firstChild)) {
-1449 			this.insertNodeAt(this.makePlaceHolder(), li, "start");
-1450 		}
-1451 		
-1452 		this.wrapAllInlineOrTextNodesAs("P", li);
-1453 		this.unwrapUnnecessaryParagraph(parentLi);
-1454 		
-1455 		return li;
-1456 	},
-1457 	
-1458 	/**
-1459 	 * Performs justification
-1460 	 *
-1461 	 * @param {Element} block target element
-1462 	 * @param {String} dir one of "LEFT", "CENTER", "RIGHT", "BOTH"
-1463 	 */
-1464 	justifyBlock: function(block, dir) {
-1465 		// if block is only child, select its parent as mover
-1466 		while(block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
-1467 			block = block.parentNode;
-1468 		}
-1469 		
-1470 		var styleValue = dir.toLowerCase() == "both" ? "justify" : dir;
-1471 		if(styleValue == "left") {
-1472 			block.style.textAlign = "";
-1473 			if(block.style.cssText == "") block.removeAttribute("style");
-1474 		} else {
-1475 			block.style.textAlign = styleValue;
-1476 		}
-1477 		return block;
-1478 	},
-1479 	
-1480 	justifyBlocks: function(blocks, dir) {
-1481 		blocks.each(function(block) {
-1482 			this.justifyBlock(block, dir);
-1483 		}.bind(this));
-1484 		
-1485 		return blocks;
-1486 	},
-1487 	
-1488 	/**
-1489      * Turn given element into list. If the element is a list already, it will be reversed into normal element.
-1490 	 *
-1491 	 * @param {Element} element target element
-1492 	 * @param {String} type one of "UL", "OL"
-1493 	 * @returns {Element} affected element
-1494 	 */
-1495 	applyList: function(element, type) {
-1496 		type = type.toUpperCase();
-1497 		var containerTag = type == "UL" ? "UL" : "OL";
-1498 		
-1499 		if(element.nodeName == "LI" || (element.parentNode.nodeName == "LI" && !element.previousSibling)) {
-1500 			var element = this.getParentElementOf(element, ["LI"]);
-1501 			var container = element.parentNode;
-1502 			if(container.nodeName == containerTag) {
-1503 				return this.extractOutElementFromParent(element);
-1504 			} else {
-1505 				return this.changeListTypeTo(element, type);
-1506 			}
-1507 		} else {
-1508 			return this.turnElementIntoListItem(element, type);
-1509 		}
-1510 	},
-1511 	
-1512 	applyLists: function(from, to, type) {
-1513 		type = type.toUpperCase();
-1514 		var containerTag = type == "UL" ? "UL" : "OL";
-1515 		var blocks = this.getBlockElementsBetween(from, to);
-1516 		
-1517 		// LIs or Non-containing blocks
-1518 		var whole = blocks.findAll(function(e) {
-1519 			return e.nodeName == "LI" || !this.tree.isBlockContainer(e);
-1520 		}.bind(this));
-1521 		
-1522 		// LIs
-1523 		var listItems = whole.findAll(function(e) {return e.nodeName == "LI"}.bind(this));
-1524 		
-1525 		// Non-containing blocks which is not a descendant of any LIs selected above(listItems).
-1526 		var normalBlocks = whole.findAll(function(e) {
-1527 			return e.nodeName != "LI" &&
-1528 				!(e.parentNode.nodeName == "LI" && !e.previousSibling && !e.nextSibling) &&
-1529 				!this.tree.isDescendantOf(listItems, e)
-1530 		}.bind(this));
-1531 		
-1532 		var diffListItems = listItems.findAll(function(e) {
-1533 			return e.parentNode.nodeName != containerTag;
-1534 		}.bind(this));
-1535 		
-1536 		// Conditions needed to determine mode
-1537 		var hasNormalBlocks = normalBlocks.length > 0;
-1538 		var hasDifferentListStyle = diffListItems.length > 0;
-1539 		
-1540 		var blockToHandle = null;
-1541 		
-1542 		if(hasNormalBlocks) {
-1543 			blockToHandle = normalBlocks;
-1544 		} else if(hasDifferentListStyle) {
-1545 			blockToHandle = diffListItems;
-1546 		} else {
-1547 			blockToHandle = listItems;
-1548 		}
-1549 		
-1550 		// perform operation
-1551 		for(var i = 0; i < blockToHandle.length; i++) {
-1552 			var block = blockToHandle[i];
-1553 			
-1554 			// preserve original index to restore selection
-1555 			var originalIndex = blocks.indexOf(block);
-1556 			blocks[originalIndex] = this.applyList(block, type);
-1557 		}
-1558 		
-1559 		return blocks;
-1560 	},
-1561 
-1562 	/**
-1563 	 * Insert place-holder for given empty element. Empty element does not displayed and causes many editing problems.
-1564 	 *
-1565 	 * @param {Element} element empty element
-1566 	 */
-1567 	correctEmptyElement: function(element) {throw "Not implemented"},
-1568 
-1569 	/**
-1570 	 * Corrects current block-only-container to do not take any non-block element or node.
-1571 	 */
-1572 	correctParagraph: function() {throw "Not implemented"},
-1573 	
-1574 	/**
-1575 	 * Makes place-holder for empty element.
-1576 	 *
-1577 	 * @returns {Node} Platform specific place holder
-1578 	 */
-1579 	makePlaceHolder: function() {throw "Not implemented"},
-1580 	
-1581 	/**
-1582 	 * Makes place-holder string.
-1583 	 *
-1584 	 * @returns {String} Platform specific place holder string
-1585 	 */
-1586 	makePlaceHolderString: function() {throw "Not implemented"},
-1587 	
-1588 	/**
-1589 	 * Makes empty paragraph which contains only one place-holder
-1590 	 */
-1591 	makeEmptyParagraph: function() {throw "Not implemented"},
-1592 
-1593 	/**
-1594 	 * Applies background color to selected area
-1595 	 *
-1596 	 * @param {Object} color valid CSS color value
-1597 	 */
-1598 	applyBackgroundColor: function(color) {throw "Not implemented";},
-1599 
-1600 	/**
-1601 	 * Applies foreground color to selected area
-1602 	 *
-1603 	 * @param {Object} color valid CSS color value
-1604 	 */
-1605 	applyForegroundColor: function(color) {
-1606 		this.execCommand("forecolor", color);
-1607 	},
-1608 	
-1609 	execCommand: function(commandId, param) {throw "Not implemented";},
-1610 	
-1611 	applyRemoveFormat: function() {throw "Not implemented";},
-1612 	applyEmphasis: function() {throw "Not implemented";},
-1613 	applyStrongEmphasis: function() {throw "Not implemented";},
-1614 	applyStrike: function() {throw "Not implemented";},
-1615 	applyUnderline: function() {throw "Not implemented";},
-1616 	applySuperscription: function() {
-1617 		this.execCommand("superscript");
-1618 	},
-1619 	applySubscription: function() {
-1620 		this.execCommand("subscript");
-1621 	},
-1622 	indentBlock: function(element, treatListAsNormalBlock) {
-1623 		return (!element.previousSibling && element.parentNode.nodeName == "LI") ?
-1624 			this.indentListItem(element, treatListAsNormalBlock) :
-1625 			this.indentElement(element);
-1626 	},
-1627 	outdentBlock: function(element, treatListAsNormalBlock) {
-1628 		while(true) {
-1629 			if(!element.previousSibling && element.parentNode.nodeName == "LI") {
-1630 				element = this.outdentListItem(element, treatListAsNormalBlock);
-1631 				return element;
-1632 			} else {
-1633 				var performed = this.outdentElement(element);
-1634 				if(performed) return performed;
-1635 				
-1636 				// first-child can outdent container
-1637 				if(!element.previousSibling) {
-1638 					element = element.parentNode;
-1639 				} else {
-1640 					break;
-1641 				}
-1642 			}
-1643 		}
-1644 		
-1645 		return null;
-1646 	},
-1647 	wrapBlock: function(tag, start, end) {
-1648 		if(!this.tree._blockTags.include(tag)) throw "Unsuppored block container: [" + tag + "]";
-1649 		if(!start) start = this.getCurrentBlockElement();
-1650 		if(!end) end = start;
-1651 		
-1652 		// Check if the selection captures valid fragement
-1653 		var validFragment = false;
-1654 		
-1655 		if(start == end) {
-1656 			// are they same block?
-1657 			validFragment = true;
-1658 		} else if(start.parentNode == end.parentNode && !start.previousSibling && !end.nextSibling) {
-1659 			// are they covering whole parent?
-1660 			validFragment = true;
-1661 			start = end = start.parentNode;
-1662 		} else {
-1663 			// are they siblings of non-LI blocks?
-1664 			validFragment =
-1665 				(start.parentNode == end.parentNode) &&
-1666 				(start.nodeName != "LI");
-1667 		}
-1668 		
-1669 		if(!validFragment) return null;
-1670 		
-1671 		var wrapper = this.createElement(tag);
-1672 		
-1673 		if(start == end) {
-1674 			// They are same.
-1675 			if(this.tree.isBlockContainer(start) && !this.tree.isListContainer(start)) {
-1676 				// It's a block container. Wrap its contents.
-1677 				if(this.tree.isBlockOnlyContainer(wrapper)) {
-1678 					this.correctEmptyElement(start);
-1679 					this.wrapAllInlineOrTextNodesAs("P", start, true);
-1680 				}
-1681 				this.moveChildNodes(start, wrapper);
-1682 				start.appendChild(wrapper);
-1683 			} else {
-1684 				// It's not a block container. Wrap itself.
-1685 				wrapper = this.insertNodeAt(wrapper, start, "after");
-1686 				wrapper.appendChild(start);
-1687 			}
-1688 			
-1689 			this.correctEmptyElement(wrapper);
-1690 		} else {
-1691 			// They are siblings. Wrap'em all.
-1692 			wrapper = this.insertNodeAt(wrapper, start, "before");
-1693 			var node = start;
-1694 			
-1695 			while(node != end) {
-1696 				next = node.nextSibling;
-1697 				wrapper.appendChild(node);
-1698 				node = next;
-1699 			}
-1700 			wrapper.appendChild(node);
-1701 		}
-1702 		
-1703 		return wrapper;
-1704 	},
-1705 
-1706 
-1707 	
-1708 	/////////////////////////////////////////////
-1709 	// Focus/Caret/Selection
-1710 	
-1711 	/**
-1712 	 * Gives focus to root element's window
-1713 	 */
-1714 	focus: function() {throw "Not implemented";},
-1715 
-1716 	/**
-1717 	 * Returns selection object
-1718 	 */
-1719 	sel: function() {throw "Not implemented";},
-1720 	
-1721 	/**
-1722 	 * Returns range object
-1723 	 */
-1724 	rng: function() {throw "Not implemented";},
-1725 	
-1726 	/**
-1727 	 * Returns true if DOM has selection
-1728 	 */
-1729 	hasSelection: function() {throw "Not implemented";},
-1730 
-1731 	/**
-1732 	 * Returns true if root element's window has selection
-1733 	 */
-1734 	hasFocus: function() {
-1735 		var cur = this.getCurrentElement();
-1736 		return (cur && cur.ownerDocument == this.getDoc());
-1737 	},
-1738 	
-1739 	/**
-1740 	 * Adjust scrollbar to make the element visible in current viewport.
-1741 	 *
-1742 	 * @param {Element} element Target element
-1743 	 * @param {boolean} toTop Align element to top of the viewport
-1744 	 * @param {boolean} moveCaret Move caret to the element
-1745 	 */
-1746 	scrollIntoView: function(element, toTop, moveCaret) {
-1747 		element.scrollIntoView(toTop);
-1748 		if(moveCaret) this.placeCaretAtStartOf(element);
-1749 	},
-1750 	
-1751 	/**
-1752 	 * Select all document
-1753 	 */
-1754 	selectAll: function() {
-1755 		return this.execCommand('selectall');
-1756 	},
-1757 	
-1758 	/**
-1759 	 * Select specified element.
-1760 	 *
-1761 	 * @param {Element} element element to select
-1762 	 * @param {boolean} entireElement true to select entire element, false to select inner content of element 
-1763 	 */
-1764 	selectElement: function(node, entireElement) {throw "Not implemented"},
-1765 	
-1766 	/**
-1767 	 * Select all elements between two blocks(inclusive).
-1768 	 *
-1769 	 * @param {Element} start start of selection
-1770 	 * @param {Element} end end of selection
-1771 	 */
-1772 	selectBlocksBetween: function(start, end) {throw "Not implemented"},
-1773 	
-1774 	/**
-1775 	 * Delete selected area
-1776 	 */
-1777 	deleteSelection: function() {throw "Not implemented"},
-1778 	
-1779 	/**
-1780 	 * Collapses current selection.
-1781 	 *
-1782 	 * @param {boolean} toStart true to move caret to start of selected area.
-1783 	 */
-1784 	collapseSelection: function(toStart) {throw "Not implemented"},
-1785 	
-1786 	/**
-1787 	 * Returns selected area as HTML string
-1788 	 */
-1789 	getSelectionAsHtml: function() {throw "Not implemented"},
-1790 	
-1791 	/**
-1792 	 * Returns selected area as text string
-1793 	 */
-1794 	getSelectionAsText: function() {throw "Not implemented"},
-1795 	
-1796 	/**
-1797 	 * Places caret at start of the element
-1798 	 *
-1799 	 * @param {Element} element Target element
-1800 	 */
-1801 	placeCaretAtStartOf: function(element) {throw "Not implemented"},
-1802 	
-1803 	/**
-1804 	 * Checks if the node is empty-text-node or not
-1805 	 */
-1806 	isEmptyTextNode: function(node) {
-1807 		return node.nodeType == 3 && node.nodeValue.length == 0;
-1808 	},
-1809 	
-1810 	/**
-1811 	 * Checks if the caret is place in empty block element
-1812 	 */
-1813 	isCaretAtEmptyBlock: function() {
-1814 		return this.isEmptyBlock(this.getCurrentBlockElement());
-1815 	},
-1816 	
-1817 	/**
-1818 	 * Checks if the caret is place at start of the block
-1819 	 */
-1820 	isCaretAtBlockStart: function() {throw "Not implemented"},
-1821 
-1822 	/**
-1823 	 * Checks if the caret is place at end of the block
-1824 	 */
-1825 	isCaretAtBlockEnd: function() {throw "Not implemented"},
-1826 	
-1827 	/**
-1828 	 * Saves current selection info
-1829 	 *
-1830 	 * @returns {Object} Bookmark for selection
-1831 	 */
-1832 	saveSelection: function() {throw "Not implemented"},
-1833 	
-1834 	/**
-1835 	 * Restores current selection info
-1836 	 *
-1837 	 * @param {Object} bookmark Bookmark
-1838 	 */
-1839 	restoreSelection: function(bookmark) {throw "Not implemented"},
-1840 	
-1841 	/**
-1842 	 * Create marker
-1843 	 */
-1844 	createMarker: function() {
-1845 		var marker = this.createElement("SPAN");
-1846 		marker.id = "xquared_marker_" + (this._lastMarkerId++);
-1847 		marker.className = "xquared_marker";
-1848 		return marker;
-1849 	},
-1850 
-1851 	/**
-1852 	 * Create and insert marker into current caret position.
-1853 	 * Marker is an inline element which has no child nodes. It can be used with many purposes.
-1854 	 * For example, You can push marker to mark current caret position.
-1855 	 *
-1856 	 * @returns {Element} marker
-1857 	 */
-1858 	pushMarker: function() {
-1859 		var marker = this.createMarker();
-1860 		return this.insertNode(marker);
-1861 	},
-1862 	
-1863 	/**
-1864 	 * Removes last marker
-1865 	 *
-1866 	 * @params {boolean} moveCaret move caret into marker before delete.
-1867 	 */
-1868 	popMarker: function(moveCaret) {
-1869 		var id = "xquared_marker_" + (--this._lastMarkerId);
-1870 		var marker = this.$(id);
-1871 		if(!marker) return;
-1872 		
-1873 		if(moveCaret) {
-1874 			this.selectElement(marker, true);
-1875 			this.collapseSelection(false);
-1876 		}
-1877 		
-1878 		this.deleteNode(marker);
-1879 	},
-1880 	
-1881 	
-1882 	
-1883 	/////////////////////////////////////////////
-1884 	// Query methods
-1885 	
-1886 	isMarker: function(node) {
-1887 		return (node.nodeType == 1 && node.nodeName == "SPAN" && node.className == "xquared_marker");
-1888 	},
-1889 	
-1890 	isFirstBlockOfBody: function(block) {
-1891 		var root = this.getRoot();
-1892 		var found = this.tree.findBackward(
-1893 			block,
-1894 			function(node) {return (node == root) || node.previousSibling;}.bind(this)
-1895 		);
-1896 		
-1897 		return found == root;
-1898 	},
-1899 	
-1900 	/**
-1901 	 * Returns outer HTML of given element
-1902 	 */
-1903 	getOuterHTML: function(element) {throw "Not implemented"},
-1904 	
-1905 	/**
-1906 	 * Returns inner text of given element
-1907 	 * 
-1908 	 * @param {Element} element Target element
-1909 	 * @returns {String} Text string
-1910 	 */
-1911 	getInnerText: function(element) {
-1912 		return element.innerHTML.stripTags();
-1913 	},
-1914 
-1915 	/**
-1916 	 * Checks if given node is place holder or not.
-1917 	 * 
-1918 	 * @param {Node} node DOM node
-1919 	 */
-1920 	isPlaceHolder: function(node) {throw "Not implemented"},
-1921 	
-1922 	/**
-1923 	 * Checks if given block is the first LI whose next sibling is a nested list.
-1924 	 *
-1925 	 * @param {Element} block Target block
-1926 	 */
-1927 	isFirstLiWithNestedList: function(block) {
-1928 		return !block.previousSibling &&
-1929 			block.parentNode.nodeName == "LI" &&
-1930 			this.tree.isListContainer(block.nextSibling);
-1931 	},
-1932 	
-1933 	/**
-1934 	 * Search all links within given element
-1935 	 *
-1936 	 * @param {Element} [element] Container element. If not given, the root element will be used.
-1937 	 * @param {Array} [found] if passed, links will be appended into this array.
-1938 	 * @returns {Array} Array of anchors. It returns empty array if there's no links.
-1939 	 */
-1940 	searchAnchors: function(element, found) {
-1941 		if(!element) element = this.getRoot();
-1942 		if(!found) found = [];
-1943 
-1944 		var anchors = element.getElementsByTagName("A");
-1945 		for(var i = 0; i < anchors.length; i++) {
-1946 			found.push(anchors[i]);
-1947 		}
-1948 
-1949 		return found;
-1950 	},
-1951 	
-1952 	/**
-1953 	 * Search all headings within given element
-1954 	 *
-1955 	 * @param {Element} [element] Container element. If not given, the root element will be used.
-1956 	 * @param {Array} [found] if passed, headings will be appended into this array.
-1957 	 * @returns {Array} Array of headings. It returns empty array if there's no headings.
-1958 	 */
-1959 	searchHeadings: function(element, found) {
-1960 		if(!element) element = this.getRoot();
-1961 		if(!found) found = [];
-1962 
-1963 		var regexp = /^h[1-6]/ig;
-1964 
-1965 		if (!element.childNodes) return [];
-1966 		$A(element.childNodes).each(function(child) {
-1967 			var isContainer = child && this.tree._blockContainerTags.include(child.nodeName);
-1968 			var isHeading = child && child.nodeName.match(regexp);
-1969 
-1970 			if (isContainer) {
-1971 				this.searchHeadings(child, found);
-1972 			} else if (isHeading) {
-1973 				found.push(child);
-1974 			}
-1975 		}.bind(this));
-1976 
-1977 		return found;
-1978 	},
-1979 	
-1980 	/**
-1981 	 * Collect structure and style informations of given element.
-1982 	 *
-1983 	 * @param {Element} element target element
-1984 	 * @returns {Object} object that contains information: {em: true, strong: false, block: "p", list: "ol", ...}
-1985 	 */
-1986 	collectStructureAndStyle: function(element) {
-1987 		if(!element || element.nodeName == "#document") return {};
-1988 
-1989 		var block = this.getParentBlockElementOf(element);
-1990 		var parents = this.tree.collectParentsOf(element, true, function(node) {return block.parentNode == node});
-1991 		var blockName = block.nodeName;
-1992 
-1993 		var info = {};
-1994 		
-1995 		var doc = this.getDoc();
-1996 		var em = doc.queryCommandState("Italic");
-1997 		var strong = doc.queryCommandState("Bold");
-1998 		var strike = doc.queryCommandState("Strikethrough");
-1999 		var underline = doc.queryCommandState("Underline") && !this.getParentElementOf(element, ["A"]);
-2000 		var superscription = doc.queryCommandState("superscript");
-2001 		var subscription = doc.queryCommandState("subscript");
-2002 		
-2003 		// if block is only child, select its parent
-2004 		while(block.parentNode && block.parentNode != this.getRoot() && !block.previousSibling && !block.nextSibling && !this.tree.isListContainer(block.parentNode)) {
-2005 			block = block.parentNode;
-2006 		}
-2007 
-2008 		var list = false;
-2009 		if(block.nodeName == "LI") {
-2010 			var parent = block.parentNode;
-2011 			var isCode = parent.nodeName == "OL" && parent.className == "code";
-2012 			list = isCode ? "CODE" : parent.nodeName;
-2013 		}
-2014 		
-2015 		var justification = block.style.textAlign || "left";
-2016 		
-2017 		return {
-2018 			block:blockName,
-2019 			em: em,
-2020 			strong: strong,
-2021 			strike: strike,
-2022 			underline: underline,
-2023 			superscription: superscription,
-2024 			subscription: subscription,
-2025 			list: list,
-2026 			justification: justification
-2027 		};
-2028 	},
-2029 	
-2030 	/**
-2031 	 * Find elements by CSS selector.
-2032 	 *
-2033 	 * WARNING: Use this method carefully since prototype.js doesn't work well with designMode DOM.
-2034 	 */
-2035 	findBySelector: function(selector) {
-2036 		return Element.getElementsBySelector(this.root, selector);
-2037 	},
-2038 	
-2039 	/**
-2040 	 * Find elements by attribute.
-2041 	 * 
-2042 	 * This method will be deprecated when findBySelector get stabilized.
-2043 	 */
-2044 	findByAttribute: function(name, value) {
-2045 		var nodes = [];
-2046 		this._findByAttribute(nodes, this.root, name, value);
-2047 		return nodes;
-2048 	},
-2049 	
-2050 	/** @private */
-2051 	_findByAttribute: function(nodes, element, name, value) {
-2052 		if(element.getAttribute(name) == value) nodes.push(element);
-2053 		if(!element.hasChildNodes()) return;
-2054 		
-2055 		var children = element.childNodes;
-2056 		for(var i = 0; i < children.length; i++) {
-2057 			if(children[i].nodeType == 1) this._findByAttribute(nodes, children[i], name, value);
-2058 		}
-2059 	},
-2060 	
-2061 	/**
-2062 	 * Checks if the element has one or more important attributes: id, class, style
-2063 	 *
-2064 	 * @param {Element} element Target element
-2065 	 */
-2066 	hasImportantAttributes: function(element) {throw "Not implemented"},
-2067 	
-2068 	/**
-2069 	 * Checks if the element is empty or not. Place-holder is not counted as a child.
-2070 	 *
-2071 	 * @param {Element} element Target element
-2072 	 */
-2073 	isEmptyBlock: function(element) {throw "Not implemented"},
-2074 	
-2075 	/**
-2076 	 * Returns element that contains caret.
-2077 	 */
-2078 	getCurrentElement: function() {throw "Not implemented"},
-2079 	
-2080 	/**
-2081 	 * Returns block element that contains caret.
-2082 	 */
-2083 	getCurrentBlockElement: function() {
-2084 		var cur = this.getCurrentElement();
-2085 		if(!cur) return null;
-2086 		
-2087 		var block = this.getParentBlockElementOf(cur);
-2088 		if(!block) return null;
-2089 		
-2090 		return (block.nodeName == "BODY") ? null : block;
-2091 	},
-2092 	
-2093 	/**
-2094 	 * Returns parent block element of parameter.
-2095 	 * If the parameter itself is a block, it will be returned.
-2096 	 *
-2097 	 * @param {Element} element Target element
-2098 	 *
-2099 	 * @returns {Element} Element or null
-2100 	 */
-2101 	getParentBlockElementOf: function(element) {
-2102 		while(element) {
-2103 			if(this.tree._blockTags.include(element.nodeName)) return element;
-2104 			element = element.parentNode;
-2105 		}
-2106 		return null;
-2107 	},
-2108 	
-2109 	/**
-2110 	 * Returns parent element of parameter which has one of given tag name.
-2111 	 * If the parameter itself has the same tag name, it will be returned.
-2112 	 *
-2113 	 * @param {Element} element Target element
-2114 	 * @param {Array} tagNames Array of string which contains tag names
-2115 	 *
-2116 	 * @returns {Element} Element or null
-2117 	 */
-2118 	getParentElementOf: function(element, tagNames) {
-2119 		while(element) {
-2120 			if(tagNames.include(element.nodeName)) return element;
-2121 			element = element.parentNode;
-2122 		}
-2123 		return null;
-2124 	},
-2125 	
-2126 	/**
-2127 	 * Collects all block elements between two elements
-2128 	 *
-2129 	 * @param {Element} from Start element(inclusive)
-2130 	 * @param {Element} to End element(inclusive)
-2131 	 */
-2132 	getBlockElementsBetween: function(from, to) {
-2133 		return this.tree.collectNodesBetween(from, to, function(node) {
-2134 			return node.nodeType == 1 && this.tree.isBlock(node);
-2135 		}.bind(this));
-2136 	},
-2137 	
-2138 	/**
-2139 	 * Returns block element that contains selection start.
-2140 	 *
-2141 	 * This method will return exactly same result with getCurrentBlockElement method
-2142 	 * when there's no selection.
-2143 	 */
-2144 	getBlockElementAtSelectionStart: function() {throw "Not implemented"},
-2145 	
-2146 	/**
-2147 	 * Returns block element that contains selection end.
-2148 	 *
-2149 	 * This method will return exactly same result with getCurrentBlockElement method
-2150 	 * when there's no selection.
-2151 	 */
-2152 	getBlockElementAtSelectionEnd: function() {throw "Not implemented"},
-2153 	
-2154 	/**
-2155 	 * Returns blocks at each edge of selection(start and end).
-2156 	 *
-2157 	 * TODO: implement ignoreEmptyEdges for FF
-2158 	 *
-2159 	 * @param {boolean} naturalOrder Mak the start element always comes before the end element
-2160 	 * @param {boolean} ignoreEmptyEdges Prevent some browser(Gecko) from selecting one more block than expected
-2161 	 */
-2162 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {throw "Not implemented"},
-2163 	
-2164 	/**
-2165 	 * Returns array of selected block elements
-2166 	 */
-2167 	getSelectedBlockElements: function() {
-2168 		var selectionEdges = this.getBlockElementsAtSelectionEdge(true, true);
-2169 		var start = selectionEdges[0];
-2170 		var end = selectionEdges[1];
-2171 		
-2172 		return this.tree.collectNodesBetween(start, end, function(node) {
-2173 			return node.nodeType == 1 && this.tree.isBlock(node);
-2174 		}.bind(this));
-2175 	},
-2176 	
-2177 	/**
-2178 	 * Get element by ID
-2179 	 *
-2180 	 * @param {String} id Element's ID
-2181 	 * @returns {Element} element or null
-2182 	 */
-2183 	getElementById: function(id) {return this.doc.getElementById(id)},
-2184 	
-2185 	/**
-2186 	 * Shortcut for #getElementById
-2187 	 */
-2188 	$: function(id) {return this.getElementById(id)},
-2189 	
-2190 	/**
-2191 	  * Returns first "valid" child of given element. It ignores empty textnodes.
-2192 	  *
-2193 	  * @param {Element} element Target element
-2194 	  * @returns {Node} first child node or null
-2195 	  */
-2196 	getFirstChild: function(element) {
-2197 		if(!element) return null;
-2198 		
-2199 		var nodes = $A(element.childNodes);
-2200 		for(var i = 0; i < nodes.length; i++) {
-2201 			if(!this.isEmptyTextNode(nodes[i])) return nodes[i];
-2202 		}
-2203 		return null;
-2204 	},
-2205 	
-2206 	/**
-2207 	  * Returns last "valid" child of given element. It ignores empty textnodes and place-holders.
-2208 	  *
-2209 	  * @param {Element} element Target element
-2210 	  * @returns {Node} last child node or null
-2211 	  */
-2212 	getLastChild: function(element) {throw "Not implemented"},
-2213 
-2214 	getNextSibling: function(node) {
-2215 		while(node = node.nextSibling) {
-2216 			if(node.nodeType != 3 || node.nodeValue.strip() != "") break;
-2217 		}
-2218 		return node;
-2219 	},
-2220 
-2221 	getBottommostFirstChild: function(node) {
-2222 		while(node.firstChild && node.nodeType == 1) node = node.firstChild;
-2223 		return node;
-2224 	},
-2225 	
-2226 	getBottommostLastChild: function(node) {
-2227 		while(node.lastChild && node.nodeType == 1) node = node.lastChild;
-2228 		return node;
-2229 	},
-2230 
-2231 	/** @private */
-2232 	_getCssValue: function(str, defaultUnit) {
-2233 		if(!str || str.length == 0) return {value:0, unit:defaultUnit};
-2234 		
-2235 		var tokens = str.match(/(\d+)(.*)/);
-2236 		return {
-2237 			value:parseInt(tokens[1]),
-2238 			unit:tokens[2] || defaultUnit
-2239 		};
-2240 	}
-2241 });
-2242 
-2243 /**
-2244  * Creates and returns instance of browser specific implementation.
-2245  */
-2246 xq.RichDom.createInstance = function() {
-2247 	if(xq.Browser.isTrident) {
-2248 		return new xq.RichDomTrident();
-2249 	} else if(xq.Browser.isWebkit) {
-2250 		return new xq.RichDomWebkit();
-2251 	} else {
-2252 		return new xq.RichDomGecko();
-2253 	}
-2254 }
-2255 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_07.html b/modules/editor/skins/xquared/doc/api/src_07.html deleted file mode 100644 index 6b89ca0d2..000000000 --- a/modules/editor/skins/xquared/doc/api/src_07.html +++ /dev/null @@ -1,54 +0,0 @@ -
  1 /**
-  2  * RichDom for Gecko
-  3  */
-  4 xq.RichDomGecko = Class.create(xq.RichDomW3, {
-  5 	makePlaceHolder: function() {
-  6 		var holder = this.createElement("BR");
-  7 		holder.setAttribute("type", "_moz");
-  8 		return holder;
-  9 	},
- 10 	
- 11 	makePlaceHolderString: function() {
- 12 		return '<br type="_moz" />';
- 13 	},
- 14 	
- 15 	makeEmptyParagraph: function() {
- 16 		return this.createElementFromHtml('<p><br type="_moz" /></p>');
- 17 	},
- 18 
- 19 	isPlaceHolder: function(node) {
- 20 		if(node.nodeType != 1) return false;
- 21 		
- 22 		var typeMatches = node.nodeName == "BR" && node.getAttribute("type") == "_moz";
- 23 		if(typeMatches) return true;
- 24 		
- 25 		var positionMatches = node.nodeName == "BR" && !this.getNextSibling(node);
- 26 		if(positionMatches) return true;
- 27 		
- 28 		return false;
- 29 	},
- 30 
- 31 	selectElement: function(element, entireElement) {
- 32 		if(!element) throw "[element] is null";
- 33 		if(element.nodeType != 1) throw "[element] is not an element";
- 34 
- 35 		// required to avoid Windows FF selection bug.
- 36 		try {
- 37 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
- 38 		} catch(ignored) {}
- 39 		
- 40 		if(entireElement) {
- 41 			this.rng().selectNode(element);
- 42 		} else {
- 43 			this.rng().selectNodeContents(element);
- 44 		}
- 45 	}
- 46 });
- 47 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_08.html b/modules/editor/skins/xquared/doc/api/src_08.html deleted file mode 100644 index ce19b8514..000000000 --- a/modules/editor/skins/xquared/doc/api/src_08.html +++ /dev/null @@ -1,369 +0,0 @@ -
  1 /**
-  2  * RichDom for Internet Explorer 6 and 7
-  3  */
-  4 xq.RichDomTrident = Class.create(xq.RichDom, {
-  5 	makePlaceHolder: function() {
-  6 		return this.createTextNode(" ");
-  7 	},
-  8 	
-  9 	makePlaceHolderString: function() {
- 10 		return ' ';
- 11 	},
- 12 	
- 13 	makeEmptyParagraph: function() {
- 14 		return this.createElementFromHtml("<p> </p>");
- 15 	},
- 16 
- 17 	isPlaceHolder: function(node) {
- 18 		return false;
- 19 	},
- 20 
- 21 	getOuterHTML: function(element) {
- 22 		return element.outerHTML;
- 23 	},
- 24 	
- 25 	insertNode: function(node) {
- 26 		if(this.hasSelection()) this.collapseSelection(true);
- 27 		
- 28 		this.rng().pasteHTML('<span id="xquared_temp"></span>');
- 29 		var marker = this.$('xquared_temp');
- 30 		if(node.id == 'xquared_temp') return marker;
- 31 		
- 32 		marker.replaceNode(node);
- 33 		return node;
- 34 	},
- 35 	
- 36 	removeTrailingWhitespace: function(block) {
- 37 		if(!block) return;
- 38 		
- 39 		// TODO: reimplement to handle atomic tags and so on. (use DomTree)
- 40 		if(this.tree.isBlockContainer(block)) return;
- 41 		if(this.isEmptyBlock(block)) return;
- 42 		
- 43 		var text = block.innerText;
- 44 		var lastCharCode = text.charCodeAt(text.length - 1);
- 45 		if(text.length <= 1 || ![32,160].include(lastCharCode)) return;
- 46 		
- 47 		var node = block;
- 48 		
- 49 		while(node && node.nodeType != 3) node = node.lastChild;
- 50 		
- 51 		if(!node) return;
- 52 		
- 53 		// DO NOT REMOVE OR MODIFY FOLLOWING CODE:
- 54 		//
- 55 		// Modifying following code crash IE7
- 56 		var nodeValue = node.nodeValue;
- 57 		if(nodeValue.length <= 1) {
- 58 			this.deleteNode(node, true);
- 59 		} else {
- 60 			node.nodeValue = nodeValue.substring(0, nodeValue.length - 1);
- 61 		}
- 62 	},
- 63 	
- 64 	correctEmptyElement: function(element) {
- 65 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
- 66 		
- 67 		if(element.firstChild) {
- 68 			this.correctEmptyElement(element.firstChild);
- 69 		} else {
- 70 			element.innerHTML = " ";
- 71 		}
- 72 	},
- 73 
- 74 	copyAttributes: function(from, to, copyId) {
- 75 		to.mergeAttributes(from, !copyId);
- 76 	},
- 77 
- 78 	correctParagraph: function() {
- 79 		if(!this.hasFocus()) return false;
- 80 		if(this.hasSelection()) return false;
- 81 		
- 82 		var block = this.getCurrentElement();
- 83 		
- 84 		if(block.nodeName == "BODY") {
- 85 			// check for atomic block element such as HR
- 86 			block = this.insertNode(this.makeEmptyParagraph());
- 87 			var next = block.nextSibling;
- 88 			if(this.tree.isAtomic(next)) {
- 89 				block = this.insertNodeAt(block, next, "after");
- 90 				this.placeCaretAtStartOf(block);
- 91 				
- 92 				var nextBlock = this.tree.findForward(
- 93 					block,
- 94 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
- 95 				);
- 96 				if(nextBlock) {
- 97 					this.deleteNode(block);
- 98 					this.placeCaretAtStartOf(nextBlock);
- 99 				}
-100 				return true;
-101 			} else {
-102 				var nextBlock = this.tree.findForward(
-103 					block,
-104 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
-105 				);
-106 				if(nextBlock) {
-107 					this.deleteNode(block);
-108 					this.placeCaretAtStartOf(nextBlock);
-109 				}
-110 				return true;
-111 			}
-112 		} else {
-113 			block = this.getCurrentBlockElement();
-114 			if(block.nodeType == 3) block = block.parentNode;
-115 			
-116 			if(this.tree.hasMixedContents(block)) {
-117 				var marker = this.pushMarker();
-118 				this.wrapAllInlineOrTextNodesAs("P", block, true);
-119 				this.popMarker(true);
-120 				return true;
-121 			} else if((this.tree.isTextOrInlineNode(block.previousSibling) || this.tree.isTextOrInlineNode(block.nextSibling)) && this.tree.hasMixedContents(block.parentNode)) {
-122 				// IE?서??Block?Inline/Text??접??경우 getCurrentElement ?이 ?작?한??
-123 				// ?라???재 Block 주?까? ?번???아주어???다.
-124 				this.wrapAllInlineOrTextNodesAs("P", block.parentNode, true);
-125 				return true;
-126 			} else {
-127 				return false;
-128 			}
-129 		}
-130 	},
-131 	
-132 	
-133 	
-134 	//////
-135 	// Commands
-136 	execCommand: function(commandId, param) {
-137 		return this.doc.execCommand(commandId, false, param);
-138 	},
-139 	
-140 	applyBackgroundColor: function(color) {
-141 		this.execCommand("BackColor", color);
-142 	},
-143 	
-144 	applyEmphasis: function() {
-145 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
-146 		this.execCommand("Italic");
-147 	},
-148 	applyStrongEmphasis: function() {
-149 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
-150 		this.execCommand("Bold");
-151 	},
-152 	applyStrike: function() {
-153 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
-154 		this.execCommand("strikethrough");
-155 	},
-156 	applyUnderline: function() {
-157 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
-158 		this.execCommand("underline");
-159 	},
-160 	applyRemoveFormat: function() {
-161 		this.execCommand("RemoveFormat");
-162 		this.execCommand("Unlink");
-163 	},
-164 	execHeading: function(level) {
-165 		this.execCommand("FormatBlock", "<H" + level + ">");
-166 	},
-167 
-168 
-169 
-170 	//////
-171 	// Focus/Caret/Selection
-172 	
-173 	focus: function() {
-174 		this.win.focus();
-175 		
-176 		// ?게 ?으?초기??caret??P 밖에 ?치?면??		// getCurrentElement??면 P?리턴?는 기이???상??발생.
-177 		if(!this._focusedBefore) {
-178 			this.correctParagraph();
-179 			this.placeCaretAtStartOf(this.getCurrentBlockElement());
-180 			this._focusedBefore = true;
-181 		}
-182 	},
-183 
-184 	sel: function() {
-185 		return this.doc.selection;
-186 	},
-187 	
-188 	rng: function() {
-189 		try {
-190 			var sel = this.sel();
-191 			return (sel == null) ? null : sel.createRange();
-192 		} catch(ignored) {
-193 			// IE often fails
-194 			return null;
-195 		}
-196 	},
-197 	
-198 	hasSelection: function() {
-199 		var selectionType = this.sel().type.toLowerCase();
-200 		if("none" == selectionType) return false;
-201 		if("text" == selectionType && this.getSelectionAsHtml().length == 0) return false;
-202 		return true;
-203 	},
-204 	deleteSelection: function() {
-205 		if(this.getSelectionAsText() != "") this.sel().clear();
-206 	},
-207 	
-208 	placeCaretAtStartOf: function(element) {
-209 		// If there's no empty span, caret sometimes moves into a previous node.
-210 		var ph = this.insertNodeAt(this.createElement("SPAN"), element, "start");
-211 		this.selectElement(ph);
-212 		this.collapseSelection(false);
-213 		this.deleteNode(ph);
-214 	},
-215 	
-216 	selectElement: function(element, entireElement) {
-217 		if(!element) throw "[element] is null";
-218 		if(element.nodeType != 1) throw "[element] is not an element";
-219 		
-220 		var rng = this.rng();
-221 		rng.moveToElementText(element);
-222 		rng.select();
-223 	},
-224 
-225 	selectBlocksBetween: function(start, end) {
-226 		var rng = this.rng();
-227 		var rngTemp = this.rng();
-228 
-229 		rngTemp.moveToElementText(start);
-230 		rng.setEndPoint("StartToStart", rngTemp);
-231 		
-232 		rngTemp.moveToElementText(end);
-233 		rng.setEndPoint("EndToEnd", rngTemp);
-234 		
-235 		rng.select();
-236 	},
-237 	
-238 	collapseSelection: function(toStart) {
-239 		var rng = this.rng();
-240 		rng.collapse(toStart);
-241 		rng.select();
-242 	},
-243 	
-244 	getSelectionAsHtml: function() {
-245 		var rng = this.rng()
-246 		return rng && rng.htmlText ? rng.htmlText : ""
-247 	},
-248 	
-249 	getSelectionAsText: function() {
-250 		var rng = this.rng();
-251 		return rng && rng.text ? rng.text : "";
-252 	},
-253 	
-254 	hasImportantAttributes: function(element) {
-255 		return !!(element.id || element.className || element.style.cssText);
-256 	},
-257 
-258 	isEmptyBlock: function(element) {
-259 		if(!element.hasChildNodes()) return true;
-260 		if(element.nodeType == 3 && !element.nodeValue) return true;
-261 		if([" ", " ", ""].include(element.innerHTML)) return true;
-262 		
-263 		return false;
-264 	},
-265 	
-266 	getLastChild: function(element) {
-267 		if(!element || !element.hasChildNodes()) return null;
-268 		
-269 		var nodes = $A(element.childNodes).reverse();
-270 		
-271 		for(var i = 0; i < nodes.length; i++) {
-272 			if(nodes[i].nodeType != 3 || nodes[i].nodeValue.length != 0) return nodes[i];
-273 		}
-274 		
-275 		return null;
-276 	},
-277 	
-278 	getCurrentElement: function() {
-279 		if(this.sel().type.toLowerCase() == "control") return this.rng().item(0);
-280 		return this.rng().parentElement();
-281 	},
-282 	
-283 	getBlockElementAtSelectionStart: function() {
-284 		var rng = this.rng();
-285 		var dup = rng.duplicate();
-286 		dup.collapse(true);
-287 		
-288 		var result = this.getParentBlockElementOf(dup.parentElement());
-289 		if(result.nodeName == "BODY") result = result.firstChild;
-290 		
-291 		return result;
-292 	},
-293 	
-294 	getBlockElementAtSelectionEnd: function() {
-295 		var rng = this.rng();
-296 		var dup = rng.duplicate();
-297 		dup.collapse(false);
-298 		
-299 		var result = this.getParentBlockElementOf(dup.parentElement());
-300 		if(result.nodeName == "BODY") result = result.lastChild;
-301 
-302 		return result;
-303 	},
-304 	
-305 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
-306 		return [
-307 			this.getBlockElementAtSelectionStart(),
-308 			this.getBlockElementAtSelectionEnd()
-309 		];
-310 	},
-311 	
-312 	isCaretAtBlockStart: function() {
-313 		if(this.isCaretAtEmptyBlock()) return true;
-314 		if(this.hasSelection()) return false;
-315 		var node = this.getCurrentBlockElement();
-316 		var marker = this.pushMarker();
-317 		
-318 		var isTrue = false;
-319 		while (node = this.getFirstChild(node)) {
-320 			if (node == marker) {
-321 				isTrue = true;
-322 				break;
-323 			}
-324 		}
-325 		
-326 		this.popMarker();
-327 		
-328 		return isTrue;
-329 	},
-330 	isCaretAtBlockEnd: function() {
-331 		if(this.isCaretAtEmptyBlock()) return true;
-332 		if(this.hasSelection()) return false;
-333 		var node = this.getCurrentBlockElement();
-334 		var marker = this.pushMarker();
-335 		var isTrue = false;
-336 		while (node = this.getLastChild(node)) {
-337 			var nodeValue = node.nodeValue;
-338 			
-339 			if (node == marker) {
-340 				isTrue = true;
-341 				break;
-342 			} else if(
-343 				node.nodeType == 3 &&
-344 				node.previousSibling == marker &&
-345 				(nodeValue == " " || (nodeValue.length == 1 && nodeValue.charCodeAt(0) == 160))
-346 			) {
-347 				isTrue = true;
-348 				break;
-349 			}
-350 		}
-351 		
-352 		this.popMarker();
-353 		return isTrue;
-354 	},
-355 	saveSelection: function() {
-356 		return this.rng();
-357 	},
-358 	restoreSelection: function(bookmark) {
-359 		bookmark.select();
-360 	}
-361 });
-362 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_09.html b/modules/editor/skins/xquared/doc/api/src_09.html deleted file mode 100644 index 030d7b252..000000000 --- a/modules/editor/skins/xquared/doc/api/src_09.html +++ /dev/null @@ -1,382 +0,0 @@ -
  1 /**
-  2  * RichDom for W3C Standard Engine
-  3  */
-  4 xq.RichDomW3 = Class.create(xq.RichDom, {
-  5 	insertNode: function(node) {
-  6 		var rng = this.rng();
-  7 		rng.insertNode(node);
-  8 		rng.selectNode(node);
-  9 		rng.collapse(false);
- 10 		return node;
- 11 	},
- 12 
- 13 	removeTrailingWhitespace: function(block) {
- 14 		// TODO: do nothing
- 15 	},
- 16 
- 17 	getOuterHTML: function(element) {
- 18 		var div = element.ownerDocument.createElement("div");
- 19 		div.appendChild(element.cloneNode(true));
- 20 		return div.innerHTML;
- 21 	},
- 22 	
- 23 	correctEmptyElement: function(element) {
- 24 		if(!element || element.nodeType != 1 || this.tree.isAtomic(element)) return;
- 25 		
- 26 		if(element.firstChild)
- 27 			this.correctEmptyElement(element.firstChild);
- 28 		else
- 29 			element.appendChild(this.makePlaceHolder());
- 30 	},
- 31 	
- 32 	correctParagraph: function() {
- 33 		if(this.hasSelection()) return false;
- 34 		
- 35 		var block = this.getCurrentElement();
- 36 		var modified = false;
- 37 		
- 38 		if(this.tree.isBlockOnlyContainer(block)) {
- 39 			this.execCommand("InsertParagraph");
- 40 			
- 41 			// check for atomic block element such as HR
- 42 			var newBlock = this.getCurrentElement();
- 43 			if(this.tree.isAtomic(newBlock.previousSibling)) {
- 44 				var nextBlock = this.tree.findForward(
- 45 					newBlock,
- 46 					function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this)
- 47 				);
- 48 				if(nextBlock) {
- 49 					this.deleteNode(newBlock);
- 50 					this.placeCaretAtStartOf(nextBlock);
- 51 				}
- 52 			}
- 53 			modified = true;
- 54 		} else if(this.tree.hasMixedContents(block)) {
- 55 			this.wrapAllInlineOrTextNodesAs("P", block, true);
- 56 			modified = true;
- 57 		}
- 58 		
- 59 		block = this.getCurrentElement();
- 60 		if(this.tree.isBlock(block) && !this._hasPlaceHolderAtEnd(block)) {
- 61 			block.appendChild(this.makePlaceHolder());
- 62 			modified = true;
- 63 		}
- 64 		
- 65 		if(this.tree.isBlock(block)) {
- 66 			var parentsLastChild = block.parentNode.lastChild;
- 67 			if(this.isPlaceHolder(parentsLastChild)) {
- 68 				this.deleteNode(parentsLastChild);
- 69 				modified = true;
- 70 			}
- 71 		}
- 72 		
- 73 		return modified;
- 74 	},
- 75 	
- 76 	_hasPlaceHolderAtEnd: function(block) {
- 77 		if(!block.hasChildNodes()) return false;
- 78 		return this.isPlaceHolder(block.lastChild) || this._hasPlaceHolderAtEnd(block.lastChild);
- 79 	},
- 80 	
- 81 	applyBackgroundColor: function(color) {
- 82 		this.execCommand("styleWithCSS", "true");
- 83 		this.execCommand("hilitecolor", color);
- 84 		this.execCommand("styleWithCSS", "false");
- 85 		
- 86 		// 0. Save current selection
- 87 		var bookmark = this.saveSelection();
- 88 		
- 89 		// 1. Get selected blocks
- 90 		var blocks = this.getSelectedBlockElements();
- 91 		if(blocks.length == 0) return;
- 92 		
- 93 		// 2. Apply background-color to all adjust inline elements
- 94 		// 3. Remove background-color from blocks
- 95 		for(var i = 0; i < blocks.length; i++) {
- 96 			if((i == 0 || i == blocks.length-1) && !blocks[i].style.backgroundColor) continue;
- 97 			
- 98 			var spans = this.wrapAllInlineOrTextNodesAs("SPAN", blocks[i], true);
- 99 			for(var j = 0; j < spans.length; j++) {
-100 				spans[j].style.backgroundColor = color;
-101 			}
-102 			blocks[i].style.backgroundColor = "";
-103 		}
-104 		
-105 		// 4. Restore selection
-106 		this.restoreSelection(bookmark);
-107 	},
-108 	
-109 	
-110 	
-111 	
-112 	//////
-113 	// Commands
-114 	execCommand: function(commandId, param) {
-115 		return this.doc.execCommand(commandId, false, param || null);
-116 	},
-117 	
-118 	saveSelection: function() {
-119 		var rng = this.rng();
-120 		return [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
-121 	},
-122 	
-123 	restoreSelection: function(bookmark) {
-124 		var rng = this.rng();
-125 		rng.setStart(bookmark[0], bookmark[1]);
-126 		rng.setEnd(bookmark[2], bookmark[3]);
-127 	},
-128 	
-129 	applyRemoveFormat: function() {
-130 		this.execCommand("RemoveFormat");
-131 		this.execCommand("Unlink");
-132 	},
-133 	applyEmphasis: function() {
-134 		// Generate <i> tag. It will be replaced with <emphasis> tag during cleanup phase.
-135 		this.execCommand("styleWithCSS", "false");
-136 		this.execCommand("italic");
-137 	},
-138 	applyStrongEmphasis: function() {
-139 		// Generate <b> tag. It will be replaced with <strong> tag during cleanup phase.
-140 		this.execCommand("styleWithCSS", "false");
-141 		this.execCommand("bold");
-142 	},
-143 	applyStrike: function() {
-144 		// Generate <strike> tag. It will be replaced with <style class="strike"> tag during cleanup phase.
-145 		this.execCommand("styleWithCSS", "false");
-146 		this.execCommand("strikethrough");
-147 	},
-148 	applyUnderline: function() {
-149 		// Generate <u> tag. It will be replaced with <em class="underline"> tag during cleanup phase.
-150 		this.execCommand("styleWithCSS", "false");
-151 		this.execCommand("underline");
-152 	},
-153 	execHeading: function(level) {
-154 		this.execCommand("Heading", "H" + level);
-155 	},
-156 
-157 
-158 
-159 	//////
-160 	// Focus/Caret/Selection
-161 	
-162 	focus: function() {
-163 		setTimeout(this._focus.bind(this), 0);
-164 	},
-165 	
-166 	/** @private */
-167 	_focus: function() {
-168 		this.win.focus();
-169 		if(!this.hasSelection() && this.getCurrentElement().nodeName == "HTML") {
-170 			this.selectElement(this.doc.body.firstChild);
-171 			this.collapseSelection(true);
-172 		}
-173 	},
-174 
-175 	sel: function() {
-176 		return this.win.getSelection();
-177 	},
-178 	
-179 	rng: function() {
-180 		var sel = this.sel();
-181 		return (sel == null || sel.rangeCount == 0) ? null : sel.getRangeAt(0);
-182 	},
-183 
-184 	hasSelection: function() {
-185 		var sel = this.sel();
-186 		return sel && !sel.isCollapsed;
-187 	},
-188 	
-189 	deleteSelection: function() {
-190 		this.rng().deleteContents();
-191 		this.sel().collapseToStart();
-192 	},
-193 	
-194 	selectElement: function(element, entireElement) {throw "Not implemented yet"},
-195 
-196 	selectBlocksBetween: function(start, end) {
-197 		// required to avoid FF selection bug.
-198 		try {
-199 			if(!xq.Browser.isMac) this.doc.execCommand("SelectAll", false, null);
-200 		} catch(ignored) {}
-201 		
-202 		var rng = this.rng();
-203 		rng.setStart(start.firstChild, 0);
-204 		rng.setEnd(end, end.childNodes.length);
-205 	},
-206 
-207 	collapseSelection: function(toStart) {
-208 		this.rng().collapse(toStart);
-209 	},
-210 	
-211 	placeCaretAtStartOf: function(element) {
-212 		while(this.tree.isBlock(element.firstChild)) {
-213 			element = element.firstChild;
-214 		}
-215 		this.selectElement(element, false);
-216 		this.collapseSelection(true);
-217 	},
-218 	
-219 	getSelectionAsHtml: function() {
-220 		var container = document.createElement("div");
-221 		container.appendChild(this.rng().cloneContents());
-222 		return container.innerHTML;
-223 	},
-224 	
-225 	getSelectionAsText: function() {
-226 		return this.rng().toString()
-227 	},
-228 	
-229 	hasImportantAttributes: function(element) {
-230 		return !!(element.id || element.className || element.style.cssText);
-231 	},
-232 	
-233 	isEmptyBlock: function(element) {
-234 		if(!element.hasChildNodes()) return true;
-235 		var children = element.childNodes;
-236 		for(var i = 0; i < children.length; i++) {
-237 			if(!this.isPlaceHolder(children[i]) && !this.isEmptyTextNode(children[i])) return false;
-238 		}
-239 		return true;
-240 	},
-241 	
-242 	getLastChild: function(element) {
-243 		if(!element || !element.hasChildNodes()) return null;
-244 		
-245 		var nodes = $A(element.childNodes).reverse();
-246 		
-247 		for(var i = 0; i < nodes.length; i++) {
-248 			if(!this.isPlaceHolder(nodes[i]) && !this.isEmptyTextNode(nodes[i])) return nodes[i];
-249 		}
-250 		return null;
-251 	},
-252 	
-253 	getCurrentElement: function() {
-254 		var rng = this.rng();
-255 		if(!rng) return null;
-256 		
-257 		var container = rng.startContainer;
-258 		return container.nodeType == 3 ? container.parentNode : container;
-259 	},
-260 
-261 	getBlockElementsAtSelectionEdge: function(naturalOrder, ignoreEmptyEdges) {
-262 		var start = this.getBlockElementAtSelectionStart();
-263 		var end = this.getBlockElementAtSelectionEnd();
-264 		
-265 		var reversed = false;
-266 		
-267 		if(naturalOrder && start != end && this.tree.checkTargetBackward(start, end)) {
-268 			var temp = start;
-269 			start = end;
-270 			end = temp;
-271 			
-272 			reversed = true;
-273 		}
-274 		
-275 		if(ignoreEmptyEdges && start != end) {
-276 			// TODO - Firefox sometimes selects one more block.
-277 /*
-278 			
-279 			var sel = this.sel();
-280 			if(reversed) {
-281 				if(sel.focusNode.nodeType == 1) start = start.nextSibling;
-282 				if(sel.anchorNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
-283 			} else {
-284 				if(sel.anchorNode.nodeType == 1) start = start.nextSibling;
-285 				if(sel.focusNode.nodeType == 3 && sel.focusOffset == 0) end = end.previousSibling;
-286 			}
-287 */
-288 		}
-289 		
-290 		return [start, end];
-291 	},
-292 	
-293 	getBlockElementAtSelectionStart: function() {
-294 		var block = this.getParentBlockElementOf(this.sel().anchorNode);
-295 		
-296 		// find bottom-most first block child
-297 		while(this.tree.isBlockContainer(block) && block.firstChild && this.tree.isBlock(block.firstChild)) {
-298 			block = block.firstChild;
-299 		}
-300 		
-301 		return block;
-302 	},
-303 	
-304 	getBlockElementAtSelectionEnd: function() {
-305 		var block = this.getParentBlockElementOf(this.sel().focusNode);
-306 		
-307 		// find bottom-most last block child
-308 		while(this.tree.isBlockContainer(block) && block.lastChild && this.tree.isBlock(block.lastChild)) {
-309 			block = block.lastChild;
-310 		}
-311 		
-312 		return block;
-313 	},
-314 
-315 	isCaretAtBlockStart: function() {
-316 		if(this.isCaretAtEmptyBlock()) return true;
-317 		if(this.hasSelection()) return false;
-318 		var rng = this.rng();
-319 		var node = this.getCurrentBlockElement();
-320 		var isTrue = false;
-321 		
-322 		if(node == rng.startContainer) {
-323 			var marker = this.pushMarker();
-324 			while (node = this.getFirstChild(node)) {
-325 				if (node == marker) {
-326 					isTrue = true;
-327 					break;
-328 				}
-329 			}
-330 			this.popMarker();
-331 		} else {
-332 			while (node = node.firstChild) {
-333 				if (node == rng.startContainer && rng.startOffset == 0) {
-334 					isTrue = true;
-335 					break;
-336 				}
-337 			}
-338 		}
-339 		
-340 		return isTrue;
-341 	},
-342 	
-343 	isCaretAtBlockEnd: function() {
-344 		if(this.isCaretAtEmptyBlock()) return true;
-345 		if(this.hasSelection()) return false;
-346 		
-347 		var rng = this.rng();
-348 		var node = this.getCurrentBlockElement();
-349 		var isTrue = false;
-350 		
-351 		if(node == rng.startContainer) {
-352 			var marker = this.pushMarker();
-353 			while (node = this.getLastChild(node)) {
-354 				if ((node == marker) || (this.isPlaceHolder(node) && node.previousSibling == marker)) {
-355 					isTrue = true;
-356 					break;
-357 				}
-358 			}
-359 			this.popMarker();
-360 		} else {
-361 			while (node = this.getLastChild(node)) {
-362 				if (node == rng.endContainer && rng.endContainer.nodeType == 1) {
-363 					isTrue = true;
-364 					break;
-365 				} else if (node == rng.endContainer && rng.endOffset == node.nodeValue.length) {
-366 					isTrue = true;
-367 					break;
-368 				}
-369 			}
-370 		}
-371 		
-372 		return isTrue;
-373 	}
-374 });
-375 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_10.html b/modules/editor/skins/xquared/doc/api/src_10.html deleted file mode 100644 index 9eb4955a5..000000000 --- a/modules/editor/skins/xquared/doc/api/src_10.html +++ /dev/null @@ -1,91 +0,0 @@ -
  1 /**
-  2  * RichDom for Webkit
-  3  */
-  4 xq.RichDomWebkit = Class.create(xq.RichDomW3, {
-  5 	makePlaceHolder: function() {
-  6 		var holder = this.createElement("BR");
-  7 		holder.className = "webkit-block-placeholder";
-  8 		return holder;
-  9 	},
- 10 	
- 11 	makePlaceHolderString: function() {
- 12 		return '<br class="webkit-block-placeholder" />';
- 13 	},
- 14 	
- 15 	makeEmptyParagraph: function() {
- 16 		return this.createElementFromHtml('<p><br class="webkit-block-placeholder" /></p>');
- 17 	},
- 18 	
- 19 	isPlaceHolder: function(node) {
- 20 		return node.nodeName == "BR" && node.className == "webkit-block-placeholder";
- 21 	},
- 22 
- 23 	rng: function() {
- 24 		var sel = this.sel();
- 25 		var rng = this.doc.createRange();
- 26 		if (!this._rng ||
- 27 			this._anchorNode != sel.anchorNode ||
- 28 			this._anchorOffset != sel.anchorOffset ||
- 29 			this._focusNode != sel.focusNode ||
- 30 			this._focusOffset != sel.focusOffset ) {
- 31 
- 32 			if (sel.type != 'None') {
- 33 				rng.setStart(sel.anchorNode, sel.anchorOffset);
- 34 				rng.setEnd(sel.focusNode, sel.focusOffset);
- 35 			}
- 36 			this._anchorNode = sel.anchorNode;
- 37 			this._anchorOffset = sel.anchorOffset;
- 38 			this._focusNode = sel.focusNode;
- 39 			this._focusOffset = sel.focusOffset;
- 40 			this._rng = rng;
- 41 		}
- 42 		return this._rng;
- 43 	},
- 44 
- 45 	selectElement: function(element, entireElement) {
- 46 		if(!element) throw "[element] is null";
- 47 		if(element.nodeType != 1) throw "[element] is not an element";
- 48 		
- 49 		var rng = this.rng();
- 50 		if(entireElement) {
- 51 			rng.selectNode(element);
- 52 		} else {
- 53 			rng.selectNodeContents(element);
- 54 		}
- 55 		this._setSelectionByRange(rng);
- 56 	},
- 57 
- 58 	deleteSelection: function() {
- 59 		this.rng().deleteContents();
- 60 	},
- 61 
- 62 	collapseSelection: function(toStart) {
- 63 		var rng = this.rng();
- 64 		rng.collapse(toStart);
- 65 		this._setSelectionByRange(rng);
- 66 	},
- 67 
- 68 	getSelectionAsHtml: function() {
- 69 		var container = this.createElement("div");
- 70 		var rng = this.rng();
- 71 		var contents = this.rng().cloneContents();
- 72 		if(contents) container.appendChild(contents);
- 73 		return container.innerHTML;
- 74 	},
- 75 	
- 76 	_setSelectionByRange: function(rng) {
- 77 		var sel = this.sel();
- 78 		sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
- 79 		this._anchorNode = sel.anchorNode;
- 80 		this._anchorOffset = sel.anchorOffset;
- 81 		this._focusNode = sel.focusNode;
- 82 		this._focusOffset = sel.focusOffset;
- 83 	}
- 84 });
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_11.html b/modules/editor/skins/xquared/doc/api/src_11.html deleted file mode 100644 index 58f5fb053..000000000 --- a/modules/editor/skins/xquared/doc/api/src_11.html +++ /dev/null @@ -1,209 +0,0 @@ -
  1 xq.RichTable = Class.create({
-  2 	initialize: function(rdom, table) {
-  3 		this.rdom = rdom;
-  4 		this.table = table;
-  5 	},
-  6 	insertNewRowAt: function(tr, where) {
-  7 		var row = this.rdom.createElement("TR");
-  8 		var cells = tr.cells;
-  9 		for(var i = 0; i < cells.length; i++) {
- 10 			var cell = this.rdom.createElement(cells[i].nodeName);
- 11 			this.rdom.correctEmptyElement(cell);
- 12 			row.appendChild(cell);
- 13 		}
- 14 		return this.rdom.insertNodeAt(row, tr, where);
- 15 	},
- 16 	insertNewCellAt: function(cell, where) {
- 17 		// collect cells;
- 18 		var cells = [];
- 19 		var x = this.getXIndexOf(cell);
- 20 		var y = 0;
- 21 		while(true) {
- 22 			var cur = this.getCellAt(x, y);
- 23 			if(!cur) break;
- 24 			cells.push(cur);
- 25 			y++;
- 26 		}
- 27 		
- 28 		// insert new cells
- 29 		for(var i = 0; i < cells.length; i++) {
- 30 			var cell = this.rdom.createElement(cells[i].nodeName);
- 31 			this.rdom.correctEmptyElement(cell);
- 32 			this.rdom.insertNodeAt(cell, cells[i], where);
- 33 		}
- 34 	},
- 35 	deleteRow: function(tr) {
- 36 		return this.rdom.removeBlock(tr);
- 37 	},
- 38 	deleteCell: function(cell) {
- 39 		if(!cell.previousSibling && !cell.nextSibling) {
- 40 			this.rdom.deleteNode(this.table);
- 41 			return;
- 42 		}
- 43 		
- 44 		// collect cells;
- 45 		var cells = [];
- 46 		var x = this.getXIndexOf(cell);
- 47 		var y = 0;
- 48 		while(true) {
- 49 			var cur = this.getCellAt(x, y);
- 50 			if(!cur) break;
- 51 			cells.push(cur);
- 52 			y++;
- 53 		}
- 54 		
- 55 		for(var i = 0; i < cells.length; i++) {
- 56 			this.rdom.deleteNode(cells[i]);
- 57 		}
- 58 	},
- 59 	getPreviousCellOf: function(cell) {
- 60 		if(cell.previousSibling) return cell.previousSibling;
- 61 		var adjRow = this.getPreviousRowOf(cell.parentNode);
- 62 		if(adjRow) return adjRow.lastChild;
- 63 		return null;
- 64 	},
- 65 	getNextCellOf: function(cell) {
- 66 		if(cell.nextSibling) return cell.nextSibling;
- 67 		var adjRow = this.getNextRowOf(cell.parentNode);
- 68 		if(adjRow) return adjRow.firstChild;
- 69 		return null;
- 70 	},
- 71 	getPreviousRowOf: function(row) {
- 72 		if(row.previousSibling) return row.previousSibling;
- 73 		var rowContainer = row.parentNode;
- 74 		if(rowContainer.previousSibling && rowContainer.previousSibling.lastChild) return rowContainer.previousSibling.lastChild;
- 75 		return null;
- 76 	},
- 77 	getNextRowOf: function(row) {
- 78 		if(row.nextSibling) return row.nextSibling;
- 79 		var rowContainer = row.parentNode;
- 80 		if(rowContainer.nextSibling && rowContainer.nextSibling.firstChild) return rowContainer.nextSibling.firstChild;
- 81 		return null;
- 82 	},
- 83 	getAboveCellOf: function(cell) {
- 84 		var row = this.getPreviousRowOf(cell.parentNode);
- 85 		if(!row) return null;
- 86 		
- 87 		var x = this.getXIndexOf(cell);
- 88 		return row.cells[x];
- 89 	},
- 90 	getBelowCellOf: function(cell) {
- 91 		var row = this.getNextRowOf(cell.parentNode);
- 92 		if(!row) return null;
- 93 		
- 94 		var x = this.getXIndexOf(cell);
- 95 		return row.cells[x];
- 96 	},
- 97 	getXIndexOf: function(cell) {
- 98 		var row = cell.parentNode;
- 99 		for(var i = 0; i < row.cells.length; i++) {
-100 			if(row.cells[i] == cell) return i;
-101 		}
-102 		
-103 		return -1;
-104 	},
-105 	getYIndexOf: function(cell) {
-106 		var y = -1;
-107 		
-108 		// find y
-109 		var group = row.parentNode;
-110 		for(var i = 0; i <group.rows.length; i++) {
-111 			if(group.rows[i] == row) {
-112 				y = i;
-113 				break;
-114 			}
-115 		}
-116 		if(this.hasHeadingAtTop() && group.nodeName == "TBODY") y = y + 1;
-117 		
-118 		return y;
-119 	},
-120 	/**
-121 	 * TODO: Not used. Delete or not?
-122 	 */
-123 	getLocationOf: function(cell) {
-124 		var x = this.getXIndexOf(cell);
-125 		var y = this.getYIndexOf(cell);
-126 		return {x:x, y:y};
-127 	},
-128 	getCellAt: function(col, row) {
-129 		var row = this.getRowAt(row);
-130 		return (row && row.cells.length > col) ? row.cells[col] : null;
-131 	},
-132 	getRowAt: function(index) {
-133 		if(this.hasHeadingAtTop()) {
-134 			return index == 0 ? this.table.tHead.rows[0] : this.table.tBodies[0].rows[index - 1];
-135 		} else {
-136 			var rows = this.table.tBodies[0].rows;
-137 			return (rows.length > index) ? rows[index] : null;
-138 		}
-139 	},
-140 	getDom: function() {
-141 		return this.table;
-142 	},
-143 	hasHeadingAtTop: function() {
-144 		return !!(this.table.tHead && this.table.tHead.rows[0]);
-145 	},
-146 	hasHeadingAtLeft: function() {
-147 		return this.table.tBodies[0].rows[0].cells[0].nodeName == "TH";
-148 	},
-149 	correctEmptyCells: function() {
-150 		var cells = $A(this.table.getElementsByTagName("TH"));
-151 		cells.push($A(this.table.getElementsByTagName("TD")));
-152 		cells = cells.flatten();
-153 		
-154 		for(var i = 0; i < cells.length; i++) {
-155 			if(this.rdom.isEmptyBlock(cells[i])) this.rdom.correctEmptyElement(cells[i])
-156 		}
-157 	}
-158 });
-159 
-160 xq.RichTable.create = function(rdom, cols, rows, headerPositions) {
-161 	if(["t", "tl", "lt"].include(headerPositions)) var headingAtTop = true
-162 	if(["l", "tl", "lt"].include(headerPositions)) var headingAtLeft = true
-163 
-164 	var sb = []
-165 	sb.push('<table class="datatable">')
-166 	
-167 	// thead
-168 	if(headingAtTop) {
-169 		sb.push('<thead><tr>')
-170 		for(var i = 0; i < cols; i++) sb.push('<th></th>')
-171 		sb.push('</tr></thead>')
-172 		rows -= 1
-173 	}
-174 		
-175 	// tbody
-176 	sb.push('<tbody>')
-177 	for(var i = 0; i < rows; i++) {
-178 		sb.push('<tr>')
-179 		
-180 		for(var j = 0; j < cols; j++) {
-181 			if(headingAtLeft && j == 0) {
-182 				sb.push('<th></th>')
-183 			} else {
-184 				sb.push('<td></td>')
-185 			}
-186 		}
-187 		
-188 		sb.push('</tr>')
-189 	}
-190 	sb.push('</tbody>')
-191 	
-192 	sb.push('</table>')
-193 	
-194 	// create DOM element
-195 	var container = rdom.createElement("div");
-196 	container.innerHTML = sb.join("");
-197 	
-198 	// correct empty cells and return
-199 	var rtable = new xq.RichTable(rdom, container.firstChild);
-200 	rtable.correctEmptyCells();
-201 	return rtable;
-202 }
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_12.html b/modules/editor/skins/xquared/doc/api/src_12.html deleted file mode 100644 index 72b700cd4..000000000 --- a/modules/editor/skins/xquared/doc/api/src_12.html +++ /dev/null @@ -1,135 +0,0 @@ -
  1 xq.Shortcut = Class.create({
-  2 	initialize: function(keymapOrExpression) {
-  3 		this.keymap = (typeof keymapOrExpression == "string") ?
-  4 			xq.Shortcut.interprete(keymapOrExpression).keymap :
-  5 			keymapOrExpression;
-  6 	},
-  7 	matches: function(e) {
-  8 		var which = xq.Browser.isGecko && xq.Browser.isMac ? (e.keyCode + "_" + e.charCode) : e.keyCode;
-  9 		
- 10 		var keyMatches =
- 11 			(this.keymap.which == which) ||
- 12 			(this.keymap.which == 32 && which == 25); // 25 is SPACE in Type-3 keyboard.
- 13 		
- 14 		if(typeof e.metaKey == "undefined") e.metaKey = false;
- 15 		
- 16 		var modifierMatches = 
- 17 			(typeof this.keymap.shiftKey == "undefined" || this.keymap.shiftKey == e.shiftKey) &&
- 18 			(typeof this.keymap.altKey == "undefined" || this.keymap.altKey == e.altKey) &&
- 19 			(typeof this.keymap.ctrlKey == "undefined" || this.keymap.ctrlKey == e.ctrlKey) &&
- 20 			(typeof this.keymap.metaKey == "undefined" || this.keymap.metaKey == e.metaKey)
- 21 		
- 22 		return modifierMatches && keyMatches;
- 23 	}
- 24 });
- 25 
- 26 xq.Shortcut.interprete = function(expression) {
- 27 	expression = expression.toUpperCase();
- 28 	
- 29 	var which = xq.Shortcut._interpreteWhich(expression.split("+").pop());
- 30 	var ctrlKey = xq.Shortcut._interpreteModifier(expression, "CTRL");
- 31 	var altKey = xq.Shortcut._interpreteModifier(expression, "ALT");
- 32 	var shiftKey = xq.Shortcut._interpreteModifier(expression, "SHIFT");
- 33 	var metaKey = xq.Shortcut._interpreteModifier(expression, "META");
- 34 	
- 35 	var keymap = {};
- 36 	
- 37 	keymap.which = which;
- 38 	if(typeof ctrlKey != "undefined") keymap.ctrlKey = ctrlKey;
- 39 	if(typeof altKey != "undefined") keymap.altKey = altKey;
- 40 	if(typeof shiftKey != "undefined") keymap.shiftKey = shiftKey;
- 41 	if(typeof metaKey != "undefined") keymap.metaKey = metaKey;
- 42 	
- 43 	return new xq.Shortcut(keymap);
- 44 }
- 45 
- 46 xq.Shortcut._interpreteModifier = function(expression, modifierName) {
- 47 	return expression.match("\\(" + modifierName + "\\)") ?
- 48 		undefined :
- 49 			expression.match(modifierName) ?
- 50 			true : false;
- 51 }
- 52 xq.Shortcut._interpreteWhich = function(keyName) {
- 53 	var which = keyName.length == 1 ?
- 54 		((xq.Browser.isMac && xq.Browser.isGecko) ? "0_" + keyName.toLowerCase().charCodeAt(0) : keyName.charCodeAt(0)) :
- 55 		xq.Shortcut._keyNames[keyName];
- 56 	
- 57 	if(typeof which == "undefined") throw "Unknown special key name: [" + keyName + "]"
- 58 	
- 59 	return which;
- 60 }
- 61 xq.Shortcut._keyNames =
- 62 	xq.Browser.isMac && xq.Browser.isGecko ?
- 63 	{
- 64 		BACKSPACE: "8_0",
- 65 		TAB: "9_0",
- 66 		RETURN: "13_0",
- 67 		ENTER: "13_0",
- 68 		ESC: "27_0",
- 69 		SPACE: "0_32",
- 70 		LEFT: "37_0",
- 71 		UP: "38_0",
- 72 		RIGHT: "39_0",
- 73 		DOWN: "40_0",
- 74 		DELETE: "46_0",
- 75 		HOME: "36_0",
- 76 		END: "35_0",
- 77 		PAGEUP: "33_0",
- 78 		PAGEDOWN: "34_0",
- 79 		COMMA: "0_44",
- 80 		HYPHEN: "0_45",
- 81 		EQUAL: "0_61",
- 82 		PERIOD: "0_46",
- 83 		SLASH: "0_47",
- 84 		F1: "112_0",
- 85 		F2: "113_0",
- 86 		F3: "114_0",
- 87 		F4: "115_0",
- 88 		F5: "116_0",
- 89 		F6: "117_0",
- 90 		F7: "118_0",
- 91 		F8: "119_0"
- 92 	}
- 93 	:
- 94 	{
- 95 		BACKSPACE: 8,
- 96 		TAB: 9,
- 97 		RETURN: 13,
- 98 		ENTER: 13,
- 99 		ESC: 27,
-100 		SPACE: 32,
-101 		LEFT: 37,
-102 		UP: 38,
-103 		RIGHT: 39,
-104 		DOWN: 40,
-105 		DELETE: 46,
-106 		HOME: 36,
-107 		END: 35,
-108 		PAGEUP: 33,
-109 		PAGEDOWN: 34,
-110 		COMMA: 188,
-111 		HYPHEN: xq.Browser.isTrident ? 189 : 109,
-112 		EQUAL: xq.Browser.isTrident ? 187 : 61,
-113 		PERIOD: 190,
-114 		SLASH: 191,
-115 		F1:112,
-116 		F2:113,
-117 		F3:114,
-118 		F4:115,
-119 		F5:116,
-120 		F6:117,
-121 		F7:118,
-122 		F8:119,
-123 		F9:120,
-124 		F10:121,
-125 		F11:122,
-126 		F12:123
-127 	}
-128 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_13.html b/modules/editor/skins/xquared/doc/api/src_13.html deleted file mode 100644 index e2311e8a9..000000000 --- a/modules/editor/skins/xquared/doc/api/src_13.html +++ /dev/null @@ -1,235 +0,0 @@ -
  1 /**
-  2  * Validates and invalidates designmode contents
-  3  */
-  4 xq.Validator = Class.create({
-  5 	initialize: function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
-  6 		this.allowedTags = (allowedTags || ['a', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'caption', 'cite', 'code', 'dd', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'img', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'span', 'sup', 'sub', 'strong', 'table', 'thead', 'tbody', 'td', 'th', 'tr', 'ul', 'var']).join(' ') + ' ';
-  7 		this.allowedAttrs = (allowedAttrs || ['alt', 'cite', 'class', 'datetime', 'height', 'href', 'id', 'rel', 'rev', 'src', 'style', 'title', 'width']).join(' ') + ' ';
-  8 		
-  9 		this.curUrl = curUrl;
- 10 		this.curUrlParts = curUrl ? curUrl.parseURL() : null;
- 11 		this.urlValidationMode = urlValidationMode;
- 12 	},
- 13 	
- 14 	/**
- 15 	 * Perform validation on given element
- 16 	 *
- 17 	 * @param {Element} element Target element. It is not affected by validation.
- 18 	 * @param {boolean} fullValidation Perform full validation. If you just want to use the result to assign innerHTML, set it false
- 19 	 *
- 20 	 * @returns {String} Validated HTML string
- 21 	 */
- 22 	validate: function(element, fullValidation) {throw "Not implemented"},
- 23 	
- 24 	/**
- 25 	 * Perform invalidation on given element to make the designmode works well.
- 26 	 *
- 27 	 * @param {Element} element Target element.
- 28 	 * @returns {String} Invalidated HTML string
- 29 	 */
- 30 	invalidate: function(element) {throw "Not implemented"},
- 31 	
- 32 	validateStrike: function(content) {
- 33 		content = content.replace(/<strike(>|\s+[^>]*>)/ig, "<span class=\"strike\"$1");
- 34 		content = content.replace(/<\/strike>/ig, "</span>");
- 35 		return content;
- 36 	},
- 37 	
- 38 	validateUnderline: function(content) {
- 39 		content = content.replace(/<u(>|\s+[^>]*>)/ig, "<em class=\"underline\"$1");
- 40 		content = content.replace(/<\/u>/ig, "</em>");
- 41 		return content;
- 42 	},
- 43 	
- 44 	replaceTag: function(content, from, to) {
- 45 		return content.replace(new RegExp("(</?)" + from + "(>|\\s+[^>]*>)", "ig"), "$1" + to + "$2");
- 46 	},
- 47 	
- 48 	validateSelfClosingTags: function(content) {
- 49 		return content.replace(/<(br|hr|img)([^>]*?)>/img, function(str, tag, attrs) {
- 50 			return "<" + tag + attrs + " />"
- 51 		});
- 52 	},
- 53 	
- 54 	removeComments: function(content) {
- 55 		return content.replace(/<!--.*?-->/img, '');
- 56 	},
- 57 	
- 58 	removeDangerousElements: function(element) {
- 59 		var scripts = $A(element.getElementsByTagName('SCRIPT')).reverse();
- 60 		for(var i = 0; i < scripts.length; i++) {
- 61 			scripts[i].parentNode.removeChild(scripts[i]);
- 62 		}
- 63 	},
- 64 
- 65 	// TODO: very slow
- 66 	applyWhitelist: function(content) {
- 67 		var allowedTags = this.allowedTags;
- 68 		var allowedAttrs = this.allowedAttrs;
- 69 		
- 70 		return content.replace(new RegExp("(</?)([^>]+?)(>|\\s+([^>]*?)(\\s?/?)>)", "g"), function(str, head, tag, tail, attrs, selfClosing) {
- 71 			if(allowedTags.indexOf(tag) == -1) return '';
- 72 			
- 73 			if(attrs) {
- 74 				attrs = attrs.replace(/(^|\s")([^"=]+)(\s|$)/g, '$1$2="$2"$3'); // for IE
- 75 				
- 76 				var sb = [];
- 77 				var m = attrs.match(/([^=]+)="[^"]*?"/g);
- 78 				for(var i = 0; i < m.length; i++) {
- 79 					m[i] = m[i].strip();
- 80 					var name = m[i].split('=')[0];
- 81 					if(allowedAttrs.indexOf(name) != -1) sb.push(m[i]);
- 82 				}
- 83 				attrs = sb.join(' ');
- 84 				if(attrs != '') attrs = ' ' + attrs;
- 85 				return head + tag + attrs + selfClosing + '>';
- 86 			} else {
- 87 				return str;
- 88 			}
- 89 		});
- 90 	},
- 91 	
- 92 	makeUrlsRelative: function(content) {
- 93 		var curUrl = this.curUrl;
- 94 		var urlParts = this.curUrlParts;
- 95 		
- 96 		// 1. find attributes and...
- 97 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
- 98 			if(attrs) {
- 99 				// 2. validate URL part
-100 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
-101 					// 3. first, make it absolute
-102 					var abs = null;
-103 					if(url.charAt(0) == '#') {
-104 						abs = urlParts.includeQuery + url;
-105 					} else if(url.charAt(0) == '?') {
-106 						abs = urlParts.includePath + url;
-107 					} else if(url.charAt(0) == '/') {
-108 						abs = urlParts.includeHost + url;
-109 					} else if(url.match(/^\w+:\/\//)) {
-110 						abs = url;
-111 					} else {
-112 						abs = urlParts.includeBase + url;
-113 					}
-114 					
-115 					// 4. make it relative by removing same part
-116 					var rel = abs;
-117 					
-118 					if(abs.indexOf(urlParts.includeQuery) == 0) {
-119 						rel = abs.substring(urlParts.includeQuery.length);
-120 					} else if(abs.indexOf(urlParts.includePath) == 0) {
-121 						rel = abs.substring(urlParts.includePath.length);
-122 					} else if(abs.indexOf(urlParts.includeBase) == 0) {
-123 						rel = abs.substring(urlParts.includeBase.length);
-124 					} else if(abs.indexOf(urlParts.includeHost) == 0) {
-125 						rel = abs.substring(urlParts.includeHost.length);
-126 					}
-127 					if(rel == '') rel = '#';
-128 					
-129 					return name + '="' + rel + '"';
-130 				});
-131 				
-132 				return head + attrs + tail + '>';
-133 			} else {
-134 				return str;
-135 			}
-136 		});
-137 		
-138 		return content;
-139 	},
-140 	
-141 	makeUrlsHostRelative: function(content) {
-142 		var curUrl = this.curUrl;
-143 		var urlParts = this.curUrlParts;
-144 		
-145 		// 1. find attributes and...
-146 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
-147 			if(attrs) {
-148 				// 2. validate URL part
-149 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
-150 					// 3. first, make it absolute
-151 					var abs = null;
-152 					if(url.charAt(0) == '#') {
-153 						abs = urlParts.includeQuery + url;
-154 					} else if(url.charAt(0) == '?') {
-155 						abs = urlParts.includePath + url;
-156 					} else if(url.charAt(0) == '/') {
-157 						abs = urlParts.includeHost + url;
-158 					} else if(url.match(/^\w+:\/\//)) {
-159 						abs = url;
-160 					} else {
-161 						abs = urlParts.includeBase + url;
-162 					}
-163 					
-164 					// 4. make it relative by removing same part
-165 					var rel = abs;
-166 					if(abs.indexOf(urlParts.includeHost) == 0) {
-167 						rel = abs.substring(urlParts.includeHost.length);
-168 					}
-169 					if(rel == '') rel = '#';
-170 					
-171 					return name + '="' + rel + '"';
-172 				});
-173 				
-174 				return head + attrs + tail + '>';
-175 			} else {
-176 				return str;
-177 			}
-178 		});
-179 		
-180 		return content;
-181 	},
-182 	
-183 	makeUrlsAbsolute: function(content) {
-184 		var curUrl = this.curUrl;
-185 		var urlParts = this.curUrlParts;
-186 		
-187 		// 1. find attributes and...
-188 		return content.replace(/(<\w+\s+)(\/|([^>]+?)(\/?))>/g, function(str, head, ignored, attrs, tail) {
-189 			if(attrs) {
-190 				// 2. validate URL part
-191 				attrs = attrs.replace(/(href|src)="([^"]+)"/g, function(str, name, url) {
-192 					var abs = null;
-193 					if(url.charAt(0) == '#') {
-194 						abs = urlParts.includeQuery + url;
-195 					} else if(url.charAt(0) == '?') {
-196 						abs = urlParts.includePath + url;
-197 					} else if(url.charAt(0) == '/') {
-198 						abs = urlParts.includeHost + url;
-199 					} else if(url.match(/^\w+:\/\//)) {
-200 						abs = url;
-201 					} else {
-202 						abs = urlParts.includeBase + url;
-203 					}
-204 
-205 					return name + '="' + abs + '"';
-206 				});
-207 				
-208 				return head + attrs + tail + '>';
-209 			} else {
-210 				return str;
-211 			}
-212 		});
-213 	}
-214 });
-215 
-216 /**
-217  * Creates and returns instance of browser specific implementation.
-218  */
-219 xq.Validator.createInstance = function(curUrl, urlValidationMode, allowedTags, allowedAttrs) {
-220 	if(xq.Browser.isTrident) {
-221 		return new xq.ValidatorTrident(curUrl, urlValidationMode, allowedTags, allowedAttrs);
-222 	} else if(xq.Browser.isWebkit) {
-223 		return new xq.ValidatorWebkit(curUrl, urlValidationMode, allowedTags, allowedAttrs);
-224 	} else {
-225 		return new xq.ValidatorGecko(curUrl, urlValidationMode, allowedTags, allowedAttrs);
-226 	}
-227 }
-228 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_14.html b/modules/editor/skins/xquared/doc/api/src_14.html deleted file mode 100644 index 9de6a044d..000000000 --- a/modules/editor/skins/xquared/doc/api/src_14.html +++ /dev/null @@ -1,12 +0,0 @@ -
  1 /**
-  2  * Validator for Gecko Engine
-  3  */
-  4 xq.ValidatorGecko = Class.create(xq.ValidatorW3, {
-  5 });
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_15.html b/modules/editor/skins/xquared/doc/api/src_15.html deleted file mode 100644 index a67012aa6..000000000 --- a/modules/editor/skins/xquared/doc/api/src_15.html +++ /dev/null @@ -1,147 +0,0 @@ -
  1 /**
-  2  * Validator for Internet Explorer 6 and 7
-  3  */
-  4 xq.ValidatorTrident = Class.create(xq.Validator, {
-  5 	validate: function(element, fullValidation) {
-  6 		element = element.cloneNode(true);
-  7 		
-  8 		this.removeDangerousElements(element);
-  9 		this.validateFontColor(element);
- 10 		this.validateBackgroundColor(element);
- 11 		
- 12 		var content = element.innerHTML;
- 13 		
- 14 		try {
- 15 			content = this.validateStrike(content);
- 16 			content = this.validateUnderline(content);
- 17 			
- 18 			if(fullValidation) content = this.performFullValidation(content);
- 19 		} catch(ignored) {}
- 20 		
- 21 		return content;
- 22 	},
- 23 	
- 24 	invalidate: function(element) {
- 25 		var rdom = xq.RichDom.createInstance();
- 26 		rdom.setRoot(element);
- 27 		
- 28 		this.invalidateFontColor(element);
- 29 		this.invalidateBackgroundColor(element);
- 30 		
- 31 		// <span class="strike"> -> <strike>
- 32 		var strikes = rdom.findByAttribute("className", "strike");
- 33 		for(var i = 0; i < strikes.length; i++) {
- 34 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("className");
- 35 		}
- 36 		
- 37 		// <em|i class="underline"> -> <u>
- 38 		var underlines = rdom.findByAttribute("className", "underline");
- 39 		for(var i = 0; i < underlines.length; i++) {
- 40 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("className");
- 41 		}
- 42 
- 43 		var content = rdom.getRoot().innerHTML;
- 44 
- 45 		content = this.removeComments(content);
- 46 		
- 47 		return content;
- 48 	},
- 49 	
- 50 	performFullValidation: function(content) {
- 51 		content = this.lowerTagNamesAndUniformizeQuotation(content);
- 52 		content = this.validateSelfClosingTags(content);
- 53 		content = this.applyWhitelist(content);
- 54 		
- 55 		if(this.urlValidationMode == 'relative') {
- 56 			content = this.makeUrlsRelative(content);
- 57 		} else if(this.urlValidationMode == 'host_relative') {
- 58 			content = this.makeUrlsHostRelative(content);
- 59 		} else if(this.urlValidationMode == 'absolute') {
- 60 			// Trident always use absolute URL so we don't need to do anything.
- 61 			//
- 62 			// content = this.makeUrlsAbsolute(content);
- 63 		}
- 64 		
- 65 		return content;
- 66 	},
- 67 	
- 68 	validateFontColor: function(element) {
- 69 		var rdom = xq.RichDom.createInstance();
- 70 		rdom.setRoot(element);
- 71 		
- 72 		// It should be reversed to deal with nested elements
- 73 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
- 74 		for(var i = 0; i < fonts.length; i++) {
- 75 			var font = fonts[i];
- 76 			var color = font.getAttribute('color');
- 77 			
- 78 			if(color) {
- 79 				var span = rdom.replaceTag("span", font);
- 80 				span.removeAttribute('color');
- 81 				span.style.color = color;
- 82 			}
- 83 		}
- 84 	},
- 85 
- 86 	invalidateFontColor: function(element) {
- 87 		var rdom = xq.RichDom.createInstance();
- 88 		rdom.setRoot(element);
- 89 
- 90 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
- 91 		for(var i = 0; i < spans.length; i++) {
- 92 			var span = spans[i];
- 93 			var color = span.style.color;
- 94 			
- 95 			if(color) {
- 96 				var font = rdom.replaceTag("font", span);
- 97 				font.style.color = "";
- 98 				font.setAttribute('color', color);
- 99 			}
-100 		}
-101 	},
-102 
-103 	validateBackgroundColor: function(element) {
-104 		var rdom = xq.RichDom.createInstance();
-105 		rdom.setRoot(element);
-106 
-107 		// It should be reversed to deal with nested elements
-108 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
-109 		for(var i = 0; i < fonts.length; i++) {
-110 			if(fonts[i].style.color || fonts[i].style.backgroundColor) rdom.replaceTag("span", fonts[i]);
-111 		}
-112 	},
-113 
-114 	invalidateBackgroundColor: function(element) {
-115 		var rdom = xq.RichDom.createInstance();
-116 		rdom.setRoot(element);
-117 
-118 		// It should be reversed to deal with nested elements
-119 		var spans = $A(element.getElementsByTagName('SPAN')).reverse();
-120 		for(var i = 0; i < spans.length; i++) {
-121 			if(spans[i].style.color || spans[i].style.backgroundColor) rdom.replaceTag("font", spans[i]);
-122 		}
-123 	},
-124 	
-125 	lowerTagNamesAndUniformizeQuotation: function(content) {
-126 		// Uniformize quotation, turn tag names and attribute names into lower case
-127 		content = content.replace(/<(\/?)(\w+)([^>]*?)>/img, function(str, closingMark, tagName, attrs) {
-128 			return "<" + closingMark + tagName.toLowerCase() + this.correctHtmlAttrQuotation(attrs) + ">";
-129 		}.bind(this));
-130 		
-131 		return content;
-132 	},
-133 	
-134 	correctHtmlAttrQuotation: function(html) {
-135 		html = html.replace(/\s(\w+?)=\s+"([^"]+)"/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
-136 		html = html.replace(/\s(\w+?)=([^ "]+)/mg,function (str, name, value) {return " " + name.toLowerCase() + '=' + '"' + value + '"'});
-137 		return html;
-138 	}
-139 });
-140 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_16.html b/modules/editor/skins/xquared/doc/api/src_16.html deleted file mode 100644 index eacdef1b9..000000000 --- a/modules/editor/skins/xquared/doc/api/src_16.html +++ /dev/null @@ -1,112 +0,0 @@ -
  1 /**
-  2  * Validator for W3C Standard Engine
-  3  */
-  4 xq.ValidatorW3 = Class.create(xq.Validator, {
-  5 	validate: function(element, fullValidation) {
-  6 		element = element.cloneNode(true);
-  7 
-  8 		var rdom = xq.RichDom.createInstance();
-  9 		rdom.setRoot(element);
- 10 		rdom.removePlaceHoldersAndEmptyNodes(element);
- 11 		this.removeDangerousElements(element);
- 12 		this.validateFontColor(element);
- 13 
- 14 		var content = element.innerHTML;
- 15 		
- 16 		try {
- 17 			content = this.replaceTag(content, "b", "strong");
- 18 			content = this.replaceTag(content, "i", "em");
- 19 			
- 20 			content = this.validateStrike(content);
- 21 			content = this.validateUnderline(content);
- 22 			content = this.addNbspToEmptyBlocks(content);
- 23 			
- 24 			if(fullValidation) content = this.performFullValidation(content);
- 25 		} catch(ignored) {}
- 26 
- 27 		// insert newline between block-tags
- 28 		var blocks = rdom.tree.getBlockTags().join("|");
- 29 		var regex = new RegExp("</(" + blocks + ")>([^\n])", "img");
- 30 		content = content.replace(regex, '</$1>\n$2');
- 31 		
- 32 		return content;
- 33 	},
- 34 	invalidate: function(element) {
- 35 		var rdom = xq.RichDom.createInstance();
- 36 		rdom.setRoot(element);
- 37 		
- 38 		// <span class="strike"> -> <strike>
- 39 		var strikes = rdom.findByAttribute("class", "strike");
- 40 		for(var i = 0; i < strikes.length; i++) {
- 41 			if("SPAN" == strikes[i].nodeName) rdom.replaceTag("strike", strikes[i]).removeAttribute("class");
- 42 		}
- 43 		
- 44 		// <em|i class="underline"> -> <u>
- 45 		var underlines = rdom.findByAttribute("class", "underline");
- 46 		for(var i = 0; i < underlines.length; i++) {
- 47 			if(["EM", "I"].include(underlines[i].nodeName)) rdom.replaceTag("u", underlines[i]).removeAttribute("class");
- 48 		}
- 49 		
- 50 		var content = rdom.getRoot().innerHTML;
- 51 		
- 52 		content = this.replaceTag(content, "strong", "b");
- 53 		content = this.replaceTag(content, "em", "i");
- 54 		content = this.removeComments(content);
- 55 		content = this.replaceNbspToBr(content);
- 56 		
- 57 		return content;
- 58 	},
- 59 	
- 60 	performFullValidation: function(content) {
- 61 		content = this.validateSelfClosingTags(content);
- 62 		content = this.applyWhitelist(content);
- 63 		
- 64 		if(this.urlValidationMode == 'relative') {
- 65 			content = this.makeUrlsRelative(content);
- 66 		} else if(this.urlValidationMode == 'host_relative') {
- 67 			content = this.makeUrlsHostRelative(content);
- 68 		} else if(this.urlValidationMode == 'absolute') {
- 69 			content = this.makeUrlsAbsolute(content);
- 70 		}
- 71 
- 72 		return content;
- 73 	},
- 74 	
- 75 	validateFontColor: function(element) {
- 76 		var rdom = xq.RichDom.createInstance();
- 77 		rdom.setRoot(element);
- 78 
- 79 		var fonts = $A(element.getElementsByTagName('FONT')).reverse();
- 80 		for(var i = 0; i < fonts.length; i++) {
- 81 			var font = fonts[i];
- 82 			var color = font.getAttribute('color');
- 83 			
- 84 			if(color) {
- 85 				var span = rdom.replaceTag("span", font);
- 86 				span.removeAttribute('color');
- 87 				span.style.color = color;
- 88 			}
- 89 		}
- 90 	},
- 91 	
- 92 	addNbspToEmptyBlocks: function(content) {
- 93 		var blocks = new xq.DomTree().getBlockTags().join("|");
- 94 		var regex = new RegExp("<(" + blocks + ")>\\s*?</(" + blocks + ")>", "img");
- 95 		return content.replace(regex, '<$1> </$2>');
- 96 	},
- 97 	
- 98 	replaceNbspToBr: function(content) {
- 99 		var blocks = new xq.DomTree().getBlockTags().join("|");
-100 		var regex = new RegExp("<(" + blocks + ")>( )?</(" + blocks + ")>", "img");
-101 		var rdom = xq.RichDom.createInstance();
-102 		return content.replace(regex, '<$1>' + rdom.makePlaceHolderString() + '</$3>');
-103 	}
-104 });
-105 
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_17.html b/modules/editor/skins/xquared/doc/api/src_17.html deleted file mode 100644 index b07ebbc67..000000000 --- a/modules/editor/skins/xquared/doc/api/src_17.html +++ /dev/null @@ -1,21 +0,0 @@ -
  1 /**
-  2  * Validator for Webkit
-  3  */
-  4 xq.ValidatorWebkit = Class.create(xq.ValidatorW3, {
-  5 });
-  6 
-  7 /*
-  8 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontStyle == "italic") em = true;
-  9 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.fontWeight == "bold") strong = true;
- 10 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "line-through") strike = true;
- 11 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.textDecoration == "underline") underline = true;
- 12 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: super;") != -1) superscription = true;
- 13 if(node.nodeName == "SPAN" && node.className == "Apple-style-span" && node.style.cssText.indexOf("vertical-align: sub;") != -1) subscription = true;
- 14 */
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_18.html b/modules/editor/skins/xquared/doc/api/src_18.html deleted file mode 100644 index 5fa6b1885..000000000 --- a/modules/editor/skins/xquared/doc/api/src_18.html +++ /dev/null @@ -1,157 +0,0 @@ -
  1 /**
-  2  * Namespace for entire Xquared classes
-  3  */
-  4 var xq = {
-  5 	majorVersion: '0.1',
-  6 	minorVersion: '2007119'
-  7 };
-  8 
-  9 /**
- 10  * Make given object as event source
- 11  *
- 12  * @param {Object} object target object
- 13  * @param {String} prefix prefix for generated functions
- 14  * @param {Array} events array of string which contains name of events
- 15  */
- 16 xq.asEventSource = function(object, prefix, events) {
- 17 	object._listeners = []
- 18 	object._registerEventFirer = function(prefix, name) {
- 19 		this["_fireOn" + name] = function() {
- 20 			for(var i = 0; i < this._listeners.length; i++) {
- 21 				var listener = this._listeners[i];
- 22 				var func = listener["on" + prefix + name];
- 23 				if(func) func.apply(listener, $A(arguments));
- 24 			}
- 25 		}
- 26 	}
- 27 	object.addListener = function(l) {
- 28 		this._listeners.push(l);
- 29 	}
- 30 	
- 31 	for(var i = 0; i < events.length; i++) {
- 32 		object._registerEventFirer(prefix, events[i]);
- 33 	}
- 34 }
- 35 
- 36 /**
- 37  * Returns the index of given element
- 38  *
- 39  * @returns {Number} index or -1
- 40  */
- 41 Array.prototype.indexOf = function(n) {
- 42 	for(var i = 0; i < this.length; i++) {
- 43 		if(this[i] == n) return i;
- 44 	}
- 45 	
- 46 	return -1;
- 47 }
- 48 
- 49 Date.preset = null;
- 50 Date.pass = function(msec) {
- 51 	if(Date.preset == null) return;
- 52 	Date.preset = new Date(Date.preset.getTime() + msec);
- 53 }
- 54 Date.get = function() {
- 55 	return Date.preset == null ? new Date() : Date.preset;
- 56 }
- 57 Date.prototype.elapsed = function(msec) {
- 58 	return Date.get().getTime() - this.getTime() >= msec;
- 59 }
- 60 
- 61 String.prototype.merge = function(data) {
- 62 	var newString = this;
- 63 	for(k in data) {
- 64 		newString = newString.replace("{" + k + "}", data[k]);
- 65 	}
- 66 	return newString;
- 67 }
- 68 
- 69 String.prototype.parseURL = function() {
- 70 	var m = this.match(/((((\w+):\/\/(((([^@:]+)(:([^@]+))?)@)?([^:\/\?#]+)?(:(\d+))?))?([^\?#]+)?)(\?([^#]+))?)(#(.+))?/);
- 71 	
- 72 	var includeAnchor = m[0];
- 73 	var includeQuery = m[1] || undefined;
- 74 	var includePath = m[2] || undefined;
- 75 	var includeHost = m[3] || undefined;
- 76 	var includeBase = null;
- 77 	var protocol = m[4] || undefined;
- 78 	var user = m[8] || undefined;
- 79 	var password = m[10] || undefined;
- 80 	var domain = m[11] || undefined;
- 81 	var port = m[13] || undefined;
- 82 	var path = m[14] || undefined;
- 83 	var query = m[16] || undefined;
- 84 	var anchor = m[18] || undefined;
- 85 	
- 86 	if(!path || path == '/') {
- 87 		includeBase = includeHost + '/';
- 88 	} else {
- 89 		var index = path.lastIndexOf('/');
- 90 		includeBase = includeHost + path.substring(0, index + 1);
- 91 	}
- 92 	
- 93 	return {
- 94 		includeAnchor: includeAnchor,
- 95 		includeQuery: includeQuery,
- 96 		includePath: includePath,
- 97 		includeBase: includeBase,
- 98 		includeHost: includeHost,
- 99 		protocol: protocol,
-100 		user: user,
-101 		password: password,
-102 		domain: domain,
-103 		port: port,
-104 		path: path,
-105 		query: query,
-106 		anchor: anchor
-107 	};
-108 }
-109 
-110 xq.findXquaredScript = function() {
-111     return $A(document.getElementsByTagName("script")).find(function(script) {
-112     	return script.src && script.src.match(/xquared\.js/i);
-113     });
-114 }
-115 xq.shouldLoadOthers = function() {
-116 	var script = xq.findXquaredScript();
-117     return script && !!script.src.match(/xquared\.js\?load_others=1/i);
-118 }
-119 xq.loadScript = function(url) {
-120     document.write('<script type="text/javascript" src="' + url + '"></script>');
-121 }
-122 xq.loadOthers = function() {
-123 	var script = xq.findXquaredScript();
-124 	var basePath = script.src.match(/(.*\/)xquared\.js.*/i)[1];
-125 	var others = [
-126 		'Editor.js',
-127 		'Browser.js',
-128 		'Shortcut.js',
-129 		'DomTree.js',
-130 		'RichDom.js',
-131 		'RichDomW3.js',
-132 		'RichDomGecko.js',
-133 		'RichDomWebkit.js',
-134 		'RichDomTrident.js',
-135 		'RichTable.js',
-136 		'Validator.js',
-137 		'ValidatorW3.js',
-138 		'ValidatorGecko.js',
-139 		'ValidatorWebkit.js',
-140 		'ValidatorTrident.js',
-141 		'EditHistory.js',
-142 		'Controls.js',
-143 		'_ui_templates.js'
-144 	];
-145 	others.each(function(name) {
-146 		xq.loadScript(basePath + name);
-147 	});
-148 }
-149 
-150 if(xq.shouldLoadOthers()) xq.loadOthers();
\ No newline at end of file diff --git a/modules/editor/skins/xquared/doc/api/src_19.html b/modules/editor/skins/xquared/doc/api/src_19.html deleted file mode 100644 index feb2f6a4e..000000000 --- a/modules/editor/skins/xquared/doc/api/src_19.html +++ /dev/null @@ -1,16 +0,0 @@ -
  1 if(!xq) xq = {};
-  2 if(!xq.ui_templates) xq.ui_templates = {};
-  3 
-  4 xq.ui_templates.basicColorPickerDialog='<form action="#" class="xqFormDialog xqBasicColorPickerDialog">\n		<div>\n			<label>\n				<input type="radio" class="initialFocus" name="color" value="black" checked="checked" />\n				<span style="color: black;">Black</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="red" />\n				<span style="color: red;">Red</span>\n			</label>\n				<input type="radio" name="color" value="yellow" />\n				<span style="color: yellow;">Yellow</span>\n			</label>\n			</label>\n				<input type="radio" name="color" value="pink" />\n				<span style="color: pink;">Pink</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="blue" />\n				<span style="color: blue;">Blue</span>\n			</label>\n			<label>\n				<input type="radio" name="color" value="green" />\n				<span style="color: green;">Green</span>\n			</label>\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
-  5 if(!xq) xq = {};
-  6 if(!xq.ui_templates) xq.ui_templates = {};
-  7 
-  8 xq.ui_templates.basicLinkDialog='<form action="#" class="xqFormDialog xqBasicLinkDialog">\n		<h3>Link</h3>\n		<div>\n			<input type="text" class="initialFocus" name="text" value="" />\n			<input type="text" name="url" value="http://" />\n			\n			<input type="submit" value="Ok" />\n			<input type="button" class="cancel" value="Cancel" />\n		</div>\n	</form>';
-  9 
\ No newline at end of file