mirror of
https://gitea.psi.ch/ELOG/elog.git
synced 2026-09-08 17:13:56 +00:00
Upgraded CKEditor to version 4.5.1
This commit is contained in:
parent
b8e058934e
commit
5a8547bd99
1509
scripts/ckeditor/CHANGES.md
Executable file → Normal file
1509
scripts/ckeditor/CHANGES.md
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
2690
scripts/ckeditor/LICENSE.md
Executable file → Normal file
2690
scripts/ckeditor/LICENSE.md
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
0
scripts/ckeditor/README.md
Executable file → Normal file
0
scripts/ckeditor/README.md
Executable file → Normal file
10
scripts/ckeditor/adapters/jquery.js
vendored
Normal file
10
scripts/ckeditor/adapters/jquery.js
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
|
||||||
|
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
|
*/
|
||||||
|
(function(a){if("undefined"==typeof a)throw Error("jQuery should be loaded before CKEditor jQuery adapter.");if("undefined"==typeof CKEDITOR)throw Error("CKEditor should be loaded before CKEditor jQuery adapter.");CKEDITOR.config.jqueryOverrideVal="undefined"==typeof CKEDITOR.config.jqueryOverrideVal?!0:CKEDITOR.config.jqueryOverrideVal;a.extend(a.fn,{ckeditorGet:function(){var a=this.eq(0).data("ckeditorInstance");if(!a)throw"CKEditor is not initialized yet, use ckeditor() with a callback.";return a},
|
||||||
|
ckeditor:function(g,d){if(!CKEDITOR.env.isCompatible)throw Error("The environment is incompatible.");if(!a.isFunction(g))var k=d,d=g,g=k;var i=[],d=d||{};this.each(function(){var b=a(this),c=b.data("ckeditorInstance"),f=b.data("_ckeditorInstanceLock"),h=this,j=new a.Deferred;i.push(j.promise());if(c&&!f)g&&g.apply(c,[this]),j.resolve();else if(f)c.once("instanceReady",function(){setTimeout(function(){c.element?(c.element.$==h&&g&&g.apply(c,[h]),j.resolve()):setTimeout(arguments.callee,100)},0)},null,
|
||||||
|
null,9999);else{if(d.autoUpdateElement||"undefined"==typeof d.autoUpdateElement&&CKEDITOR.config.autoUpdateElement)d.autoUpdateElementJquery=!0;d.autoUpdateElement=!1;b.data("_ckeditorInstanceLock",!0);c=a(this).is("textarea")?CKEDITOR.replace(h,d):CKEDITOR.inline(h,d);b.data("ckeditorInstance",c);c.on("instanceReady",function(d){var e=d.editor;setTimeout(function(){if(e.element){d.removeListener();e.on("dataReady",function(){b.trigger("dataReady.ckeditor",[e])});e.on("setData",function(a){b.trigger("setData.ckeditor",
|
||||||
|
[e,a.data])});e.on("getData",function(a){b.trigger("getData.ckeditor",[e,a.data])},999);e.on("destroy",function(){b.trigger("destroy.ckeditor",[e])});e.on("save",function(){a(h.form).submit();return!1},null,null,20);if(e.config.autoUpdateElementJquery&&b.is("textarea")&&a(h.form).length){var c=function(){b.ckeditor(function(){e.updateElement()})};a(h.form).submit(c);a(h.form).bind("form-pre-serialize",c);b.bind("destroy.ckeditor",function(){a(h.form).unbind("submit",c);a(h.form).unbind("form-pre-serialize",
|
||||||
|
c)})}e.on("destroy",function(){b.removeData("ckeditorInstance")});b.removeData("_ckeditorInstanceLock");b.trigger("instanceReady.ckeditor",[e]);g&&g.apply(e,[h]);j.resolve()}else setTimeout(arguments.callee,100)},0)},null,null,9999)}});var f=new a.Deferred;this.promise=f.promise();a.when.apply(this,i).then(function(){f.resolve()});this.editor=this.eq(0).data("ckeditorInstance");return this}});CKEDITOR.config.jqueryOverrideVal&&(a.fn.val=CKEDITOR.tools.override(a.fn.val,function(g){return function(d){if(arguments.length){var k=
|
||||||
|
this,i=[],f=this.each(function(){var b=a(this),c=b.data("ckeditorInstance");if(b.is("textarea")&&c){var f=new a.Deferred;c.setData(d,function(){f.resolve()});i.push(f.promise());return!0}return g.call(b,d)});if(i.length){var b=new a.Deferred;a.when.apply(this,i).done(function(){b.resolveWith(k)});return b.promise()}return f}var f=a(this).eq(0),c=f.data("ckeditorInstance");return f.is("textarea")&&c?c.getData():g.call(f)}}))})(window.jQuery);
|
||||||
@ -1,117 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var config = {
|
|
||||||
|
|
||||||
applications: {
|
|
||||||
ckeditor: {
|
|
||||||
path: '.',
|
|
||||||
files: [
|
|
||||||
'ckeditor.js'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
assertion: 'yui',
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
'benderjs-yui',
|
|
||||||
'benderjs-jquery',
|
|
||||||
'benderjs-ckeditor'
|
|
||||||
],
|
|
||||||
|
|
||||||
tests: {
|
|
||||||
'Adapters': {
|
|
||||||
applications: [ 'ckeditor' ],
|
|
||||||
basePath: 'tests/',
|
|
||||||
paths: [
|
|
||||||
'adapters/',
|
|
||||||
'!/_'
|
|
||||||
],
|
|
||||||
jquery: [ '1.7', '1.7.2', '1.8.3', '1.9.1', '1.10.2', '2.0.0' ]
|
|
||||||
},
|
|
||||||
|
|
||||||
'Core': {
|
|
||||||
applications: [ 'ckeditor' ],
|
|
||||||
basePath: 'tests/',
|
|
||||||
paths: [
|
|
||||||
'core/',
|
|
||||||
'!/_'
|
|
||||||
],
|
|
||||||
regressions: {
|
|
||||||
// IE8 (#11242)
|
|
||||||
'tests/core/style/editor#test apply inline style on non-editable inline element - at non-editable inline boundary': 'env.ie && env.version == 8',
|
|
||||||
'tests/core/style/editor#test remove inline style from non-editable inline element - at non-editable inline boundary': 'env.ie && env.version == 8',
|
|
||||||
|
|
||||||
// IE8 (fails only in testing env - window.window === window gives false)
|
|
||||||
'tests/core/tools#test_clone_Window': 'env.ie && env.version == 8',
|
|
||||||
|
|
||||||
// Safari (#11111)
|
|
||||||
'tests/core/dom/range/enlarge#test_enlarge_element12': 'env.safari',
|
|
||||||
|
|
||||||
// Safari (#11980)
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace #2': 'env.safari',
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace #3': 'env.safari',
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace #9': 'env.safari',
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace, merge #2': 'env.safari',
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace, merge #3': 'env.safari',
|
|
||||||
'tests/core/editable/keystrokes/delbackspacequirks/collapsed#test backspace, merge #8': 'env.safari',
|
|
||||||
|
|
||||||
// Firefox (#12104)
|
|
||||||
'tests/core/editor/focus#test blur after setData': 'env.gecko'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'Plugins': {
|
|
||||||
applications: [ 'ckeditor' ],
|
|
||||||
basePath: 'tests/',
|
|
||||||
paths: [
|
|
||||||
'plugins/',
|
|
||||||
'!/_'
|
|
||||||
],
|
|
||||||
regressions: {
|
|
||||||
// IE10
|
|
||||||
'tests/plugins/ajax/ajax#test_loadXml_sync': 'env.ie && env.version > 9',
|
|
||||||
'tests/plugins/ajax/ajax#test_loadXml_async': 'env.ie && env.version > 9',
|
|
||||||
|
|
||||||
// IE8 (#11242)
|
|
||||||
'tests/plugins/indent/indent#test indent next to inline non-editable': 'env.ie && env.version == 8',
|
|
||||||
|
|
||||||
// IE8 (#11055)
|
|
||||||
'tests/plugins/widget/nestededitables#test pasting widget which was copied (d&d) when its nested editable was focused': 'env.ie && env.version == 8',
|
|
||||||
|
|
||||||
// Firefox (#11399)
|
|
||||||
'tests/plugins/widget/nestededitables#test selection in nested editable is preserved after opening and closing dialog - inline editor': 'env.gecko',
|
|
||||||
|
|
||||||
// Firefox (#12104)
|
|
||||||
'tests/plugins/widget/widgetselection#test focusing widget': 'env.gecko',
|
|
||||||
'tests/plugins/widget/widgetselection#test focusing by click': 'env.gecko',
|
|
||||||
'tests/plugins/widget/widgetselection#test focus editor when focusing widget by click': 'env.gecko',
|
|
||||||
'tests/plugins/widget/widgetselection#test focus editor when focusing widget by method': 'env.gecko'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'Tickets': {
|
|
||||||
applications: [ 'ckeditor' ],
|
|
||||||
basePath: 'tests/',
|
|
||||||
paths: [
|
|
||||||
'tickets/',
|
|
||||||
'!/_'
|
|
||||||
],
|
|
||||||
regressions: {
|
|
||||||
// IE8 & IE9 have problems with loading iframe.
|
|
||||||
'tests/tickets/11121/1#test HC detection in hidden iframe': 'env.ie && env.version < 10'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'Utils': {
|
|
||||||
applications: [ 'ckeditor' ],
|
|
||||||
basePath: 'tests/',
|
|
||||||
paths: [
|
|
||||||
'utils/',
|
|
||||||
'!/_'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
92
scripts/ckeditor/build-config.js
Executable file → Normal file
92
scripts/ckeditor/build-config.js
Executable file → Normal file
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
* @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -13,10 +13,10 @@
|
|||||||
* (1) http://ckeditor.com/builder
|
* (1) http://ckeditor.com/builder
|
||||||
* Visit online builder to build CKEditor from scratch.
|
* Visit online builder to build CKEditor from scratch.
|
||||||
*
|
*
|
||||||
* (2) http://ckeditor.com/builder/1113842bdc54a1d62d9d96eac156fd49
|
* (2) http://ckeditor.com/builder/0692335792da3da48a79f044e6d16a49
|
||||||
* Visit online builder to build CKEditor, starting with the same setup as before.
|
* Visit online builder to build CKEditor, starting with the same setup as before.
|
||||||
*
|
*
|
||||||
* (3) http://ckeditor.com/builder/download/1113842bdc54a1d62d9d96eac156fd49
|
* (3) http://ckeditor.com/builder/download/0692335792da3da48a79f044e6d16a49
|
||||||
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
|
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
@ -29,15 +29,21 @@ var CKBUILDER_CONFIG = {
|
|||||||
preset: 'full',
|
preset: 'full',
|
||||||
ignore: [
|
ignore: [
|
||||||
'.bender',
|
'.bender',
|
||||||
'.DS_Store',
|
|
||||||
'.gitignore',
|
|
||||||
'.gitattributes',
|
|
||||||
'.idea',
|
|
||||||
'.mailmap',
|
|
||||||
'bender.js',
|
'bender.js',
|
||||||
'bender-err.log',
|
'bender-err.log',
|
||||||
'bender-out.log',
|
'bender-out.log',
|
||||||
'dev',
|
'dev',
|
||||||
|
'.DS_Store',
|
||||||
|
'.editorconfig',
|
||||||
|
'.gitattributes',
|
||||||
|
'.gitignore',
|
||||||
|
'gruntfile.js',
|
||||||
|
'.idea',
|
||||||
|
'.jscsrc',
|
||||||
|
'.jshintignore',
|
||||||
|
'.jshintrc',
|
||||||
|
'less',
|
||||||
|
'.mailmap',
|
||||||
'node_modules',
|
'node_modules',
|
||||||
'package.json',
|
'package.json',
|
||||||
'README.md',
|
'README.md',
|
||||||
@ -69,12 +75,12 @@ var CKBUILDER_CONFIG = {
|
|||||||
'htmlwriter' : 1,
|
'htmlwriter' : 1,
|
||||||
'iframe' : 1,
|
'iframe' : 1,
|
||||||
'image' : 1,
|
'image' : 1,
|
||||||
'image2' : 1,
|
|
||||||
'imagepaste' : 1,
|
'imagepaste' : 1,
|
||||||
'indentblock' : 1,
|
'indentblock' : 1,
|
||||||
'indentlist' : 1,
|
'indentlist' : 1,
|
||||||
'justify' : 1,
|
'justify' : 1,
|
||||||
'language' : 1,
|
'language' : 1,
|
||||||
|
'lineutils' : 1,
|
||||||
'link' : 1,
|
'link' : 1,
|
||||||
'list' : 1,
|
'list' : 1,
|
||||||
'liststyle' : 1,
|
'liststyle' : 1,
|
||||||
@ -103,10 +109,76 @@ var CKBUILDER_CONFIG = {
|
|||||||
'templates' : 1,
|
'templates' : 1,
|
||||||
'toolbar' : 1,
|
'toolbar' : 1,
|
||||||
'undo' : 1,
|
'undo' : 1,
|
||||||
|
'widget' : 1,
|
||||||
'wsc' : 1,
|
'wsc' : 1,
|
||||||
'wysiwygarea' : 1
|
'wysiwygarea' : 1
|
||||||
},
|
},
|
||||||
languages : {
|
languages : {
|
||||||
'en' : 1
|
'af' : 1,
|
||||||
|
'ar' : 1,
|
||||||
|
'bg' : 1,
|
||||||
|
'bn' : 1,
|
||||||
|
'bs' : 1,
|
||||||
|
'ca' : 1,
|
||||||
|
'cs' : 1,
|
||||||
|
'cy' : 1,
|
||||||
|
'da' : 1,
|
||||||
|
'de' : 1,
|
||||||
|
'el' : 1,
|
||||||
|
'en' : 1,
|
||||||
|
'en-au' : 1,
|
||||||
|
'en-ca' : 1,
|
||||||
|
'en-gb' : 1,
|
||||||
|
'eo' : 1,
|
||||||
|
'es' : 1,
|
||||||
|
'et' : 1,
|
||||||
|
'eu' : 1,
|
||||||
|
'fa' : 1,
|
||||||
|
'fi' : 1,
|
||||||
|
'fo' : 1,
|
||||||
|
'fr' : 1,
|
||||||
|
'fr-ca' : 1,
|
||||||
|
'gl' : 1,
|
||||||
|
'gu' : 1,
|
||||||
|
'he' : 1,
|
||||||
|
'hi' : 1,
|
||||||
|
'hr' : 1,
|
||||||
|
'hu' : 1,
|
||||||
|
'id' : 1,
|
||||||
|
'is' : 1,
|
||||||
|
'it' : 1,
|
||||||
|
'ja' : 1,
|
||||||
|
'ka' : 1,
|
||||||
|
'km' : 1,
|
||||||
|
'ko' : 1,
|
||||||
|
'ku' : 1,
|
||||||
|
'lt' : 1,
|
||||||
|
'lv' : 1,
|
||||||
|
'mk' : 1,
|
||||||
|
'mn' : 1,
|
||||||
|
'ms' : 1,
|
||||||
|
'nb' : 1,
|
||||||
|
'nl' : 1,
|
||||||
|
'no' : 1,
|
||||||
|
'pl' : 1,
|
||||||
|
'pt' : 1,
|
||||||
|
'pt-br' : 1,
|
||||||
|
'ro' : 1,
|
||||||
|
'ru' : 1,
|
||||||
|
'si' : 1,
|
||||||
|
'sk' : 1,
|
||||||
|
'sl' : 1,
|
||||||
|
'sq' : 1,
|
||||||
|
'sr' : 1,
|
||||||
|
'sr-latn' : 1,
|
||||||
|
'sv' : 1,
|
||||||
|
'th' : 1,
|
||||||
|
'tr' : 1,
|
||||||
|
'tt' : 1,
|
||||||
|
'ug' : 1,
|
||||||
|
'uk' : 1,
|
||||||
|
'vi' : 1,
|
||||||
|
'zh' : 1,
|
||||||
|
'zh-cn' : 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
1182
scripts/ckeditor/ckeditor.js
vendored
Executable file → Normal file
1182
scripts/ckeditor/ckeditor.js
vendored
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ CKEDITOR.editorConfig = function( config ) {
|
|||||||
|
|
||||||
// %REMOVE_START%
|
// %REMOVE_START%
|
||||||
// The configuration options below are needed when running CKEditor from source files.
|
// The configuration options below are needed when running CKEditor from source files.
|
||||||
config.plugins = 'dialogui,dialog,about,a11yhelp,dialogadvtab,basicstyles,bidi,blockquote,clipboard,button,panelbutton,panel,floatpanel,colorbutton,colordialog,templates,menu,contextmenu,div,resize,toolbar,elementspath,enterkey,entities,popup,filebrowser,find,fakeobjects,flash,floatingspace,listblock,richcombo,font,forms,format,horizontalrule,htmlwriter,iframe,wysiwygarea,image,indent,indentblock,indentlist,smiley,justify,menubutton,language,link,list,liststyle,magicline,maximize,newpage,pagebreak,pastetext,pastefromword,preview,print,removeformat,save,selectall,showblocks,showborders,sourcearea,specialchar,scayt,stylescombo,tab,table,tabletools,undo,wsc,lineutils,widget,image2,imagepaste';
|
config.plugins = 'dialogui,dialog,about,a11yhelp,dialogadvtab,basicstyles,bidi,blockquote,clipboard,button,panelbutton,panel,floatpanel,colorbutton,colordialog,templates,menu,contextmenu,div,resize,toolbar,elementspath,enterkey,entities,popup,filebrowser,find,fakeobjects,flash,floatingspace,listblock,richcombo,font,forms,format,horizontalrule,htmlwriter,iframe,wysiwygarea,image,indent,indentblock,indentlist,smiley,justify,menubutton,language,link,list,liststyle,magicline,maximize,newpage,pagebreak,pastetext,pastefromword,preview,print,removeformat,save,selectall,showblocks,showborders,sourcearea,specialchar,scayt,stylescombo,tab,table,tabletools,undo,wsc,lineutils,widget,imagepaste';
|
||||||
config.skin = 'moono';
|
config.skin = 'moono';
|
||||||
// %REMOVE_END%
|
// %REMOVE_END%
|
||||||
|
|
||||||
|
|||||||
266
scripts/ckeditor/contents.css
Executable file → Normal file
266
scripts/ckeditor/contents.css
Executable file → Normal file
@ -1,134 +1,132 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
|
||||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
/* Font */
|
/* Font */
|
||||||
font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
|
font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
/* Text color */
|
/* Text color */
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
||||||
/* Remove the background color to make it transparent */
|
/* Remove the background color to make it transparent */
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cke_editable
|
.cke_editable
|
||||||
{
|
{
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote
|
blockquote
|
||||||
{
|
{
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-family: Georgia, Times, "Times New Roman", serif;
|
font-family: Georgia, Times, "Times New Roman", serif;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cke_contents_ltr blockquote
|
.cke_contents_ltr blockquote
|
||||||
{
|
{
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
border-left-width: 5px;
|
border-left-width: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cke_contents_rtl blockquote
|
.cke_contents_rtl blockquote
|
||||||
{
|
{
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
border-right-width: 5px;
|
border-right-width: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a
|
a
|
||||||
{
|
{
|
||||||
color: #0782C1;
|
color: #0782C1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ol,ul,dl
|
ol,ul,dl
|
||||||
{
|
{
|
||||||
/* IE7: reset rtl list margin. (#7334) */
|
/* IE7: reset rtl list margin. (#7334) */
|
||||||
*margin-right: 0px;
|
*margin-right: 0px;
|
||||||
/* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/
|
/* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/
|
||||||
padding: 0 40px;
|
padding: 0 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,h2,h3,h4,h5,h6
|
h1,h2,h3,h4,h5,h6
|
||||||
{
|
{
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr
|
hr
|
||||||
{
|
{
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.right
|
img.right
|
||||||
{
|
{
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
float: right;
|
float: right;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.left
|
img.left
|
||||||
{
|
{
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre
|
pre
|
||||||
{
|
{
|
||||||
white-space: pre-wrap; /* CSS 2.1 */
|
white-space: pre-wrap; /* CSS 2.1 */
|
||||||
word-wrap: break-word; /* IE7 */
|
word-wrap: break-word; /* IE7 */
|
||||||
-moz-tab-size: 4;
|
-moz-tab-size: 4;
|
||||||
-o-tab-size: 4;
|
tab-size: 4;
|
||||||
-webkit-tab-size: 4;
|
}
|
||||||
tab-size: 4;
|
|
||||||
}
|
.marker
|
||||||
|
{
|
||||||
.marker
|
background-color: Yellow;
|
||||||
{
|
}
|
||||||
background-color: Yellow;
|
|
||||||
}
|
span[lang]
|
||||||
|
{
|
||||||
span[lang]
|
font-style: italic;
|
||||||
{
|
}
|
||||||
font-style: italic;
|
|
||||||
}
|
figure
|
||||||
|
{
|
||||||
figure
|
text-align: center;
|
||||||
{
|
border: solid 1px #ccc;
|
||||||
text-align: center;
|
border-radius: 2px;
|
||||||
border: solid 1px #ccc;
|
background: rgba(0,0,0,0.05);
|
||||||
border-radius: 2px;
|
padding: 10px;
|
||||||
background: rgba(0,0,0,0.05);
|
margin: 10px 20px;
|
||||||
padding: 10px;
|
display: inline-block;
|
||||||
margin: 10px 20px;
|
}
|
||||||
display: inline-block;
|
|
||||||
}
|
figure > figcaption
|
||||||
|
{
|
||||||
figure > figcaption
|
text-align: center;
|
||||||
{
|
display: block; /* For IE8 */
|
||||||
text-align: center;
|
}
|
||||||
display: block; /* For IE8 */
|
|
||||||
}
|
a > img {
|
||||||
|
padding: 1px;
|
||||||
a > img {
|
margin: 1px;
|
||||||
padding: 1px;
|
border: none;
|
||||||
margin: 1px;
|
outline: 1px solid #0782C1;
|
||||||
border: none;
|
}
|
||||||
outline: 1px solid #0782C1;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,74 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview API initialization code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
// Disable HC detection in WebKit. (#5429)
|
|
||||||
if ( CKEDITOR.env.webkit )
|
|
||||||
CKEDITOR.env.hc = false;
|
|
||||||
else {
|
|
||||||
// Check whether high contrast is active by creating a colored border.
|
|
||||||
var hcDetect = CKEDITOR.dom.element.createFromHtml( '<div style="width:0;height:0;position:absolute;left:-10000px;' +
|
|
||||||
'border:1px solid;border-color:red blue"></div>', CKEDITOR.document );
|
|
||||||
|
|
||||||
hcDetect.appendTo( CKEDITOR.document.getHead() );
|
|
||||||
|
|
||||||
// Update CKEDITOR.env.
|
|
||||||
// Catch exception needed sometimes for FF. (#4230)
|
|
||||||
try {
|
|
||||||
var top = hcDetect.getComputedStyle( 'border-top-color' ),
|
|
||||||
right = hcDetect.getComputedStyle( 'border-right-color' );
|
|
||||||
|
|
||||||
// We need to check if getComputedStyle returned any value, because on FF
|
|
||||||
// it returnes empty string if CKEditor is loaded in hidden iframe. (#11121)
|
|
||||||
CKEDITOR.env.hc = !!( top && top == right );
|
|
||||||
} catch ( e ) {
|
|
||||||
CKEDITOR.env.hc = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hcDetect.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( CKEDITOR.env.hc )
|
|
||||||
CKEDITOR.env.cssClass += ' cke_hc';
|
|
||||||
|
|
||||||
// Initially hide UI spaces when relevant skins are loading, later restored by skin css.
|
|
||||||
CKEDITOR.document.appendStyleText( '.cke{visibility:hidden;}' );
|
|
||||||
|
|
||||||
// Mark the editor as fully loaded.
|
|
||||||
CKEDITOR.status = 'loaded';
|
|
||||||
CKEDITOR.fireOnce( 'loaded' );
|
|
||||||
|
|
||||||
// Process all instances created by the "basic" implementation.
|
|
||||||
var pending = CKEDITOR._.pending;
|
|
||||||
if ( pending ) {
|
|
||||||
delete CKEDITOR._.pending;
|
|
||||||
|
|
||||||
for ( var i = 0; i < pending.length; i++ ) {
|
|
||||||
CKEDITOR.editor.prototype.constructor.apply( pending[ i ][ 0 ], pending[ i ][ 1 ] );
|
|
||||||
CKEDITOR.add( pending[ i ][ 0 ] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running on a High Contrast environment.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.hc )
|
|
||||||
* alert( 'You\'re running on High Contrast mode. The editor interface will get adapted to provide you a better experience.' );
|
|
||||||
*
|
|
||||||
* @property {Boolean} hc
|
|
||||||
* @member CKEDITOR.env
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when a CKEDITOR core object is fully loaded and ready for interaction.
|
|
||||||
*
|
|
||||||
* @event loaded
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
204
scripts/ckeditor/core/ckeditor.js
vendored
204
scripts/ckeditor/core/ckeditor.js
vendored
@ -1,204 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Contains the third and last part of the {@link CKEDITOR} object
|
|
||||||
* definition.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @class CKEDITOR */
|
|
||||||
|
|
||||||
// Remove the CKEDITOR.loadFullCore reference defined on ckeditor_basic.
|
|
||||||
delete CKEDITOR.loadFullCore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores references to all editor instances created. The name of the properties
|
|
||||||
* in this object correspond to instance names, and their values contain the
|
|
||||||
* {@link CKEDITOR.editor} object representing them.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.instances.editor1.name ); // 'editor1'
|
|
||||||
*
|
|
||||||
* @property {Object}
|
|
||||||
*/
|
|
||||||
CKEDITOR.instances = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The document of the window storing the CKEDITOR object.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.document.getBody().getName() ); // 'body'
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.dom.document}
|
|
||||||
*/
|
|
||||||
CKEDITOR.document = new CKEDITOR.dom.document( document );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an editor instance to the global {@link CKEDITOR} object. This function
|
|
||||||
* is available for internal use mainly.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance to be added.
|
|
||||||
*/
|
|
||||||
CKEDITOR.add = function( editor ) {
|
|
||||||
CKEDITOR.instances[ editor.name ] = editor;
|
|
||||||
|
|
||||||
editor.on( 'focus', function() {
|
|
||||||
if ( CKEDITOR.currentInstance != editor ) {
|
|
||||||
CKEDITOR.currentInstance = editor;
|
|
||||||
CKEDITOR.fire( 'currentInstance' );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
editor.on( 'blur', function() {
|
|
||||||
if ( CKEDITOR.currentInstance == editor ) {
|
|
||||||
CKEDITOR.currentInstance = null;
|
|
||||||
CKEDITOR.fire( 'currentInstance' );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
CKEDITOR.fire( 'instance', null, editor );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an editor instance from the global {@link CKEDITOR} object. This function
|
|
||||||
* is available for internal use only. External code must use {@link CKEDITOR.editor#method-destroy}.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance to be removed.
|
|
||||||
*/
|
|
||||||
CKEDITOR.remove = function( editor ) {
|
|
||||||
delete CKEDITOR.instances[ editor.name ];
|
|
||||||
};
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var tpls = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a named {@link CKEDITOR.template} instance to be reused among all editors.
|
|
||||||
* This will return the existing one if a template with same name is already
|
|
||||||
* defined. Additionally, it fires the "template" event to allow template source customization.
|
|
||||||
*
|
|
||||||
* @param {String} name The name which identifies a UI template.
|
|
||||||
* @param {String} source The source string for constructing this template.
|
|
||||||
* @returns {CKEDITOR.template} The created template instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.addTemplate = function( name, source ) {
|
|
||||||
var tpl = tpls[ name ];
|
|
||||||
if ( tpl )
|
|
||||||
return tpl;
|
|
||||||
|
|
||||||
// Make it possible to customize the template through event.
|
|
||||||
var params = { name: name, source: source };
|
|
||||||
CKEDITOR.fire( 'template', params );
|
|
||||||
|
|
||||||
return ( tpls[ name ] = new CKEDITOR.template( params.source ) );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a defined template created with {@link CKEDITOR#addTemplate}.
|
|
||||||
*
|
|
||||||
* @param {String} name The template name.
|
|
||||||
*/
|
|
||||||
CKEDITOR.getTemplate = function( name ) {
|
|
||||||
return tpls[ name ];
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var styles = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds CSS rules to be appended to the editor document.
|
|
||||||
* This method is mostly used by plugins to add custom styles to the editor
|
|
||||||
* document. For basic content styling the `contents.css` file should be
|
|
||||||
* used instead.
|
|
||||||
*
|
|
||||||
* **Note:** This function should be called before the creation of editor instances.
|
|
||||||
*
|
|
||||||
* // Add styles for all headings inside editable contents.
|
|
||||||
* CKEDITOR.addCss( '.cke_editable h1,.cke_editable h2,.cke_editable h3 { border-bottom: 1px dotted red }' );
|
|
||||||
*
|
|
||||||
* @param {String} css The style rules to be appended.
|
|
||||||
* @see CKEDITOR.config#contentsCss
|
|
||||||
*/
|
|
||||||
CKEDITOR.addCss = function( css ) {
|
|
||||||
styles.push( css );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string will all CSS rules passed to the {@link CKEDITOR#addCss} method.
|
|
||||||
*
|
|
||||||
* @returns {String} A string containing CSS rules.
|
|
||||||
*/
|
|
||||||
CKEDITOR.getCss = function() {
|
|
||||||
return styles.join( '\n' );
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
|
|
||||||
// Perform global clean up to free as much memory as possible
|
|
||||||
// when there are no instances left
|
|
||||||
CKEDITOR.on( 'instanceDestroyed', function() {
|
|
||||||
if ( CKEDITOR.tools.isEmpty( this.instances ) )
|
|
||||||
CKEDITOR.fire( 'reset' );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Load the bootstrap script.
|
|
||||||
CKEDITOR.loader.load( '_bootstrap' ); // %REMOVE_LINE%
|
|
||||||
|
|
||||||
// Tri-state constants.
|
|
||||||
/**
|
|
||||||
* Used to indicate the ON or ACTIVE state.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=1]
|
|
||||||
*/
|
|
||||||
CKEDITOR.TRISTATE_ON = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to indicate the OFF or INACTIVE state.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=2]
|
|
||||||
*/
|
|
||||||
CKEDITOR.TRISTATE_OFF = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to indicate the DISABLED state.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=0]
|
|
||||||
*/
|
|
||||||
CKEDITOR.TRISTATE_DISABLED = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor which is currently active (has user focus).
|
|
||||||
*
|
|
||||||
* function showCurrentEditorName() {
|
|
||||||
* if ( CKEDITOR.currentInstance )
|
|
||||||
* alert( CKEDITOR.currentInstance.name );
|
|
||||||
* else
|
|
||||||
* alert( 'Please focus an editor first.' );
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.editor} currentInstance
|
|
||||||
* @see CKEDITOR#event-currentInstance
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the CKEDITOR.currentInstance object reference changes. This may
|
|
||||||
* happen when setting the focus on different editor instances in the page.
|
|
||||||
*
|
|
||||||
* var editor; // A variable to store a reference to the current editor.
|
|
||||||
* CKEDITOR.on( 'currentInstance', function() {
|
|
||||||
* editor = CKEDITOR.currentInstance;
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @event currentInstance
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the last instance has been destroyed. This event is used to perform
|
|
||||||
* global memory cleanup.
|
|
||||||
*
|
|
||||||
* @event reset
|
|
||||||
*/
|
|
||||||
@ -1,315 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Contains the first and essential part of the {@link CKEDITOR}
|
|
||||||
* object definition.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// #### Compressed Code
|
|
||||||
// Must be updated on changes in the script as well as updated in the ckeditor.js file.
|
|
||||||
|
|
||||||
// window.CKEDITOR||(window.CKEDITOR=function(){var b={timestamp:"",version:"%VERSION%",revision:"%REV%",rnd:Math.floor(900*Math.random())+100,_:{pending:[]},status:"unloaded",basePath:function(){var a=window.CKEDITOR_BASEPATH||"";if(!a)for(var b=document.getElementsByTagName("script"),c=0;c<b.length;c++){var d=b[c].src.match(/(^|.*[\\\/])ckeditor(?:_basic)?(?:_source)?.js(?:\?.*)?$/i);if(d){a=d[1];break}}-1==a.indexOf(":/")&&"//"!=a.slice(0,2)&&(a=0===a.indexOf("/")?location.href.match(/^.*?:\/\/[^\/]*/)[0]+a:location.href.match(/^[^\?]*\/(?:)/)[0]+a);if(!a)throw'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';return a}(),getUrl:function(a){-1==a.indexOf(":/")&&0!==a.indexOf("/")&&(a=this.basePath+a);this.timestamp&&"/"!=a.charAt(a.length-1)&&!/[&?]t=/.test(a)&&(a+=(0<=a.indexOf("?")?"&":"?")+"t="+this.timestamp);return a},domReady:function(){function a(){try{document.addEventListener?(document.removeEventListener("DOMContentLoaded",a,!1),b()):document.attachEvent&&"complete"===document.readyState&&(document.detachEvent("onreadystatechange",a),b())}catch(d){}}function b(){for(var a;a=c.shift();)a()}var c=[];return function(b){c.push(b);"complete"===document.readyState&&setTimeout(a,1);if(1==c.length)if(document.addEventListener)document.addEventListener("DOMContentLoaded",a,!1),window.addEventListener("load",a,!1);else if(document.attachEvent){document.attachEvent("onreadystatechange",a);window.attachEvent("onload",a);b=!1;try{b=!window.frameElement}catch(e){}if(document.documentElement.doScroll&&b){var f=function(){try{document.documentElement.doScroll("left")}catch(b){setTimeout(f,1);return}a()};f()}}}}()},e=window.CKEDITOR_GETURL;if(e){var g=b.getUrl;b.getUrl=function(a){return e.call(b,a)||g.call(b,a)}}return b}());
|
|
||||||
// The Closure Compiler online service should be used when updating this manually:
|
|
||||||
// http://closure-compiler.appspot.com/
|
|
||||||
|
|
||||||
// #### Raw code
|
|
||||||
// ATTENTION: read the above "Compressed Code" notes when changing this code.
|
|
||||||
|
|
||||||
if ( !window.CKEDITOR ) {
|
|
||||||
/**
|
|
||||||
* This is the API entry point. The entire CKEditor code runs under this object.
|
|
||||||
* @class CKEDITOR
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
window.CKEDITOR = ( function() {
|
|
||||||
var CKEDITOR = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A constant string unique for each release of CKEditor. Its value
|
|
||||||
* is used, by default, to build the URL for all resources loaded
|
|
||||||
* by the editor code, guaranteeing clean cache results when
|
|
||||||
* upgrading.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.timestamp ); // e.g. '87dm'
|
|
||||||
*/
|
|
||||||
timestamp: '', // %REMOVE_LINE%
|
|
||||||
/* // %REMOVE_LINE%
|
|
||||||
// The production implementation contains a fixed timestamp, unique
|
|
||||||
// for each release and generated by the releaser.
|
|
||||||
// (Base 36 value of each component of YYMMDDHH - 4 chars total - e.g. 87bm == 08071122)
|
|
||||||
timestamp: '%TIMESTAMP%',
|
|
||||||
*/ // %REMOVE_LINE%
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the CKEditor version number.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.version ); // e.g. 'CKEditor 3.4.1'
|
|
||||||
*/
|
|
||||||
version: '%VERSION%',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the CKEditor revision number.
|
|
||||||
* The revision number is incremented automatically, following each
|
|
||||||
* modification to the CKEditor source code.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.revision ); // e.g. '3975'
|
|
||||||
*/
|
|
||||||
revision: '%REV%',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A 3-digit random integer, valid for the entire life of the CKEDITOR object.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.rnd ); // e.g. 319
|
|
||||||
*
|
|
||||||
* @property {Number}
|
|
||||||
*/
|
|
||||||
rnd: Math.floor( Math.random() * ( 999 /*Max*/ - 100 /*Min*/ + 1 ) ) + 100 /*Min*/,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private object used to hold core stuff. It should not be used outside of
|
|
||||||
* the API code as properties defined here may change at any time
|
|
||||||
* without notice.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_: {
|
|
||||||
pending: []
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates the API loading status. The following statuses are available:
|
|
||||||
*
|
|
||||||
* * **unloaded**: the API is not yet loaded.
|
|
||||||
* * **basic_loaded**: the basic API features are available.
|
|
||||||
* * **basic_ready**: the basic API is ready to load the full core code.
|
|
||||||
* * **loaded**: the API can be fully used.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.status == 'loaded' ) {
|
|
||||||
* // The API can now be fully used.
|
|
||||||
* doSomething();
|
|
||||||
* } else {
|
|
||||||
* // Wait for the full core to be loaded and fire its loading.
|
|
||||||
* CKEDITOR.on( 'load', doSomething );
|
|
||||||
* CKEDITOR.loadFullCore && CKEDITOR.loadFullCore();
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
status: 'unloaded',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The full URL for the CKEditor installation directory.
|
|
||||||
* It is possible to manually provide the base path by setting a
|
|
||||||
* global variable named `CKEDITOR_BASEPATH`. This global variable
|
|
||||||
* must be set **before** the editor script loading.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.basePath ); // e.g. 'http://www.example.com/ckeditor/'
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
basePath: ( function() {
|
|
||||||
// ATTENTION: fixes to this code must be ported to
|
|
||||||
// var basePath in "core/loader.js".
|
|
||||||
|
|
||||||
// Find out the editor directory path, based on its <script> tag.
|
|
||||||
var path = window.CKEDITOR_BASEPATH || '';
|
|
||||||
|
|
||||||
if ( !path ) {
|
|
||||||
var scripts = document.getElementsByTagName( 'script' );
|
|
||||||
|
|
||||||
for ( var i = 0; i < scripts.length; i++ ) {
|
|
||||||
var match = scripts[ i ].src.match( /(^|.*[\\\/])ckeditor(?:_basic)?(?:_source)?.js(?:\?.*)?$/i );
|
|
||||||
|
|
||||||
if ( match ) {
|
|
||||||
path = match[ 1 ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In IE (only) the script.src string is the raw value entered in the
|
|
||||||
// HTML source. Other browsers return the full resolved URL instead.
|
|
||||||
if ( path.indexOf( ':/' ) == -1 && path.slice( 0, 2 ) != '//' ) {
|
|
||||||
// Absolute path.
|
|
||||||
if ( path.indexOf( '/' ) === 0 )
|
|
||||||
path = location.href.match( /^.*?:\/\/[^\/]*/ )[ 0 ] + path;
|
|
||||||
// Relative path.
|
|
||||||
else
|
|
||||||
path = location.href.match( /^[^\?]*\/(?:)/ )[ 0 ] + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !path )
|
|
||||||
throw 'The CKEditor installation path could not be automatically detected. Please set the global variable "CKEDITOR_BASEPATH" before creating editor instances.';
|
|
||||||
|
|
||||||
return path;
|
|
||||||
} )(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the full URL for CKEditor resources. By default, URLs
|
|
||||||
* returned by this function contain a querystring parameter ("t")
|
|
||||||
* set to the {@link CKEDITOR#timestamp} value.
|
|
||||||
*
|
|
||||||
* It is possible to provide a custom implementation of this
|
|
||||||
* function by setting a global variable named `CKEDITOR_GETURL`.
|
|
||||||
* This global variable must be set **before** the editor script
|
|
||||||
* loading. If the custom implementation returns nothing (`==null`), the
|
|
||||||
* default implementation is used.
|
|
||||||
*
|
|
||||||
* // e.g. 'http://www.example.com/ckeditor/skins/default/editor.css?t=87dm'
|
|
||||||
* alert( CKEDITOR.getUrl( 'skins/default/editor.css' ) );
|
|
||||||
*
|
|
||||||
* // e.g. 'http://www.example.com/skins/default/editor.css?t=87dm'
|
|
||||||
* alert( CKEDITOR.getUrl( '/skins/default/editor.css' ) );
|
|
||||||
*
|
|
||||||
* // e.g. 'http://www.somesite.com/skins/default/editor.css?t=87dm'
|
|
||||||
* alert( CKEDITOR.getUrl( 'http://www.somesite.com/skins/default/editor.css' ) );
|
|
||||||
*
|
|
||||||
* @param {String} resource The resource whose full URL we want to get.
|
|
||||||
* It may be a full, absolute, or relative URL.
|
|
||||||
* @returns {String} The full URL.
|
|
||||||
*/
|
|
||||||
getUrl: function( resource ) {
|
|
||||||
// If this is not a full or absolute path.
|
|
||||||
if ( resource.indexOf( ':/' ) == -1 && resource.indexOf( '/' ) !== 0 )
|
|
||||||
resource = this.basePath + resource;
|
|
||||||
|
|
||||||
// Add the timestamp, except for directories.
|
|
||||||
if ( this.timestamp && resource.charAt( resource.length - 1 ) != '/' && !( /[&?]t=/ ).test( resource ) )
|
|
||||||
resource += ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + this.timestamp;
|
|
||||||
|
|
||||||
return resource;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a function to execute when the DOM is fully loaded.
|
|
||||||
*
|
|
||||||
* If called after the DOM has been initialized, the function passed in will
|
|
||||||
* be executed immediately.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
domReady: ( function() {
|
|
||||||
// Based on the original jQuery code.
|
|
||||||
|
|
||||||
var callbacks = [];
|
|
||||||
|
|
||||||
function onReady() {
|
|
||||||
try {
|
|
||||||
// Cleanup functions for the document ready method
|
|
||||||
if ( document.addEventListener ) {
|
|
||||||
document.removeEventListener( 'DOMContentLoaded', onReady, false );
|
|
||||||
executeCallbacks();
|
|
||||||
}
|
|
||||||
// Make sure body exists, at least, in case IE gets a little overzealous.
|
|
||||||
else if ( document.attachEvent && document.readyState === 'complete' ) {
|
|
||||||
document.detachEvent( 'onreadystatechange', onReady );
|
|
||||||
executeCallbacks();
|
|
||||||
}
|
|
||||||
} catch ( er ) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeCallbacks() {
|
|
||||||
var i;
|
|
||||||
while ( ( i = callbacks.shift() ) )
|
|
||||||
i();
|
|
||||||
}
|
|
||||||
|
|
||||||
return function( fn ) {
|
|
||||||
callbacks.push( fn );
|
|
||||||
|
|
||||||
// Catch cases where this is called after the
|
|
||||||
// browser event has already occurred.
|
|
||||||
if ( document.readyState === 'complete' )
|
|
||||||
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
|
||||||
setTimeout( onReady, 1 );
|
|
||||||
|
|
||||||
// Run below once on demand only.
|
|
||||||
if ( callbacks.length != 1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// For IE>8, Firefox, Opera and Webkit.
|
|
||||||
if ( document.addEventListener ) {
|
|
||||||
// Use the handy event callback
|
|
||||||
document.addEventListener( 'DOMContentLoaded', onReady, false );
|
|
||||||
|
|
||||||
// A fallback to window.onload, that will always work
|
|
||||||
window.addEventListener( 'load', onReady, false );
|
|
||||||
|
|
||||||
}
|
|
||||||
// If old IE event model is used
|
|
||||||
else if ( document.attachEvent ) {
|
|
||||||
// ensure firing before onload,
|
|
||||||
// maybe late but safe also for iframes
|
|
||||||
document.attachEvent( 'onreadystatechange', onReady );
|
|
||||||
|
|
||||||
// A fallback to window.onload, that will always work
|
|
||||||
window.attachEvent( 'onload', onReady );
|
|
||||||
|
|
||||||
// If IE and not a frame
|
|
||||||
// continually check to see if the document is ready
|
|
||||||
// use the trick by Diego Perini
|
|
||||||
// http://javascript.nwbox.com/IEContentLoaded/
|
|
||||||
var toplevel = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
toplevel = !window.frameElement;
|
|
||||||
} catch ( e ) {}
|
|
||||||
|
|
||||||
if ( document.documentElement.doScroll && toplevel ) {
|
|
||||||
function scrollCheck() {
|
|
||||||
try {
|
|
||||||
document.documentElement.doScroll( 'left' );
|
|
||||||
} catch ( e ) {
|
|
||||||
setTimeout( scrollCheck, 1 );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onReady();
|
|
||||||
}
|
|
||||||
scrollCheck();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} )()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make it possible to override the "url" function with a custom
|
|
||||||
// implementation pointing to a global named CKEDITOR_GETURL.
|
|
||||||
var newGetUrl = window.CKEDITOR_GETURL;
|
|
||||||
if ( newGetUrl ) {
|
|
||||||
var originalGetUrl = CKEDITOR.getUrl;
|
|
||||||
CKEDITOR.getUrl = function( resource ) {
|
|
||||||
return newGetUrl.call( CKEDITOR, resource ) || originalGetUrl.call( CKEDITOR, resource );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return CKEDITOR;
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function called upon loading a custom configuration file that can
|
|
||||||
* modify the editor instance configuration ({@link CKEDITOR.editor#config}).
|
|
||||||
* It is usually defined inside the custom configuration files that can
|
|
||||||
* include developer defined settings.
|
|
||||||
*
|
|
||||||
* // This is supposed to be placed in the config.js file.
|
|
||||||
* CKEDITOR.editorConfig = function( config ) {
|
|
||||||
* // Define changes to default configuration here. For example:
|
|
||||||
* config.language = 'fr';
|
|
||||||
* config.uiColor = '#AADC6E';
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* @method editorConfig
|
|
||||||
* @param {CKEDITOR.config} config A configuration object containing the
|
|
||||||
* settings defined for a {@link CKEDITOR.editor} instance up to this
|
|
||||||
* function call. Note that not all settings may still be available. See
|
|
||||||
* [Configuration Loading Order](http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Setting_Configurations#Configuration_Loading_Order)
|
|
||||||
* for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR )
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Contains the second part of the {@link CKEDITOR} object
|
|
||||||
* definition, which defines the basic editor features to be available in
|
|
||||||
* the root ckeditor_basic.js file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( CKEDITOR.status == 'unloaded' ) {
|
|
||||||
( function() {
|
|
||||||
CKEDITOR.event.implementOn( CKEDITOR );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forces the full CKEditor core code, in the case only the basic code has been
|
|
||||||
* loaded (`ckeditor_basic.js`). This method self-destroys (becomes undefined) in
|
|
||||||
* the first call or as soon as the full code is available.
|
|
||||||
*
|
|
||||||
* // Check if the full core code has been loaded and load it.
|
|
||||||
* if ( CKEDITOR.loadFullCore )
|
|
||||||
* CKEDITOR.loadFullCore();
|
|
||||||
*
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.loadFullCore = function() {
|
|
||||||
// If the basic code is not ready, just mark it to be loaded.
|
|
||||||
if ( CKEDITOR.status != 'basic_ready' ) {
|
|
||||||
CKEDITOR.loadFullCore._load = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy this function.
|
|
||||||
delete CKEDITOR.loadFullCore;
|
|
||||||
|
|
||||||
// Append the script to the head.
|
|
||||||
var script = document.createElement( 'script' );
|
|
||||||
script.type = 'text/javascript';
|
|
||||||
script.src = CKEDITOR.basePath + 'ckeditor.js';
|
|
||||||
script.src = CKEDITOR.basePath + 'ckeditor_source.js'; // %REMOVE_LINE%
|
|
||||||
|
|
||||||
document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time to wait (in seconds) to load the full editor code after the
|
|
||||||
* page load, if the "ckeditor_basic" file is used. If set to zero, the
|
|
||||||
* editor is loaded on demand, as soon as an instance is created.
|
|
||||||
*
|
|
||||||
* This value must be set on the page before the page load completion.
|
|
||||||
*
|
|
||||||
* // Loads the full source after five seconds.
|
|
||||||
* CKEDITOR.loadFullCoreTimeout = 5;
|
|
||||||
*
|
|
||||||
* @property
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.loadFullCoreTimeout = 0;
|
|
||||||
|
|
||||||
// Documented at ckeditor.js.
|
|
||||||
CKEDITOR.add = function( editor ) {
|
|
||||||
// For now, just put the editor in the pending list. It will be
|
|
||||||
// processed as soon as the full code gets loaded.
|
|
||||||
var pending = this._.pending || ( this._.pending = [] );
|
|
||||||
pending.push( editor );
|
|
||||||
};
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var onload = function() {
|
|
||||||
var loadFullCore = CKEDITOR.loadFullCore,
|
|
||||||
loadFullCoreTimeout = CKEDITOR.loadFullCoreTimeout;
|
|
||||||
|
|
||||||
if ( !loadFullCore )
|
|
||||||
return;
|
|
||||||
|
|
||||||
CKEDITOR.status = 'basic_ready';
|
|
||||||
|
|
||||||
if ( loadFullCore && loadFullCore._load )
|
|
||||||
loadFullCore();
|
|
||||||
else if ( loadFullCoreTimeout ) {
|
|
||||||
setTimeout( function() {
|
|
||||||
if ( CKEDITOR.loadFullCore )
|
|
||||||
CKEDITOR.loadFullCore();
|
|
||||||
}, loadFullCoreTimeout * 1000 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.domReady( onload );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
CKEDITOR.status = 'basic_loaded';
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a command that can be executed on an editor instance.
|
|
||||||
*
|
|
||||||
* var command = new CKEDITOR.command( editor, {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* alert( editor.document.getBody().getHtml() );
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @mixins CKEDITOR.event
|
|
||||||
* @constructor Creates a command class instance.
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance this command will be
|
|
||||||
* related to.
|
|
||||||
* @param {CKEDITOR.commandDefinition} commandDefinition The command
|
|
||||||
* definition.
|
|
||||||
*/
|
|
||||||
CKEDITOR.command = function( editor, commandDefinition ) {
|
|
||||||
/**
|
|
||||||
* Lists UI items that are associated to this command. This list can be
|
|
||||||
* used to interact with the UI on command execution (by the execution code
|
|
||||||
* itself, for example).
|
|
||||||
*
|
|
||||||
* alert( 'Number of UI items associated to this command: ' + command.uiItems.length );
|
|
||||||
*/
|
|
||||||
this.uiItems = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the command.
|
|
||||||
*
|
|
||||||
* command.exec(); // The command gets executed.
|
|
||||||
*
|
|
||||||
* @param {Object} [data] Any data to pass to the command. Depends on the
|
|
||||||
* command implementation and requirements.
|
|
||||||
* @returns {Boolean} A boolean indicating that the command has been successfully executed.
|
|
||||||
*/
|
|
||||||
this.exec = function( data ) {
|
|
||||||
if ( this.state == CKEDITOR.TRISTATE_DISABLED || !this.checkAllowed() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( this.editorFocus ) // Give editor focus if necessary (#4355).
|
|
||||||
editor.focus();
|
|
||||||
|
|
||||||
if ( this.fire( 'exec' ) === false )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return ( commandDefinition.exec.call( this, editor, data ) !== false );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Explicitly update the status of the command, by firing the {@link CKEDITOR.command#event-refresh} event,
|
|
||||||
* as well as invoke the {@link CKEDITOR.commandDefinition#refresh} method if defined, this method
|
|
||||||
* is to allow different parts of the editor code to contribute in command status resolution.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
* @param {CKEDITOR.dom.elementPath} path
|
|
||||||
*/
|
|
||||||
this.refresh = function( editor, path ) {
|
|
||||||
// Do nothing is we're on read-only and this command doesn't support it.
|
|
||||||
// We don't need to disabled the command explicitely here, because this
|
|
||||||
// is already done by the "readOnly" event listener.
|
|
||||||
if ( !this.readOnly && editor.readOnly )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Disable commands that are not allowed in the current selection path context.
|
|
||||||
if ( this.context && !path.isContextFor( this.context ) ) {
|
|
||||||
this.disable();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable commands that are not allowed by the active filter.
|
|
||||||
if ( !this.checkAllowed( true ) ) {
|
|
||||||
this.disable();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the "enabled" state a default for commands enabled from start.
|
|
||||||
if ( !this.startDisabled )
|
|
||||||
this.enable();
|
|
||||||
|
|
||||||
// Disable commands which shouldn't be enabled in this mode.
|
|
||||||
if ( this.modes && !this.modes[ editor.mode ] )
|
|
||||||
this.disable();
|
|
||||||
|
|
||||||
if ( this.fire( 'refresh', { editor: editor, path: path } ) === false )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return ( commandDefinition.refresh && commandDefinition.refresh.apply( this, arguments ) !== false );
|
|
||||||
};
|
|
||||||
|
|
||||||
var allowed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether this command is allowed by the active allowed
|
|
||||||
* content filter ({@link CKEDITOR.editor#activeFilter}). This means
|
|
||||||
* that if command implements {@link CKEDITOR.feature} interface it will be tested
|
|
||||||
* by the {@link CKEDITOR.filter#checkFeature} method.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {Boolean} [noCache] Skip cache for example due to active filter change. Since CKEditor 4.2.
|
|
||||||
* @returns {Boolean} Whether this command is allowed.
|
|
||||||
*/
|
|
||||||
this.checkAllowed = function( noCache ) {
|
|
||||||
if ( !noCache && typeof allowed == 'boolean' )
|
|
||||||
return allowed;
|
|
||||||
|
|
||||||
return allowed = editor.activeFilter.checkFeature( this );
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( this, commandDefinition, {
|
|
||||||
/**
|
|
||||||
* The editor modes within which the command can be executed. The
|
|
||||||
* execution will have no action if the current mode is not listed
|
|
||||||
* in this property.
|
|
||||||
*
|
|
||||||
* // Enable the command in both WYSIWYG and Source modes.
|
|
||||||
* command.modes = { wysiwyg:1,source:1 };
|
|
||||||
*
|
|
||||||
* // Enable the command in Source mode only.
|
|
||||||
* command.modes = { source:1 };
|
|
||||||
*
|
|
||||||
* @see CKEDITOR.editor#mode
|
|
||||||
*/
|
|
||||||
modes: { wysiwyg: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the editor will get the focus before executing
|
|
||||||
* the command.
|
|
||||||
*
|
|
||||||
* // Do not force the editor to have focus when executing the command.
|
|
||||||
* command.editorFocus = false;
|
|
||||||
*
|
|
||||||
* @property {Boolean} [=true]
|
|
||||||
*/
|
|
||||||
editorFocus: 1,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that this command is sensible to the selection context.
|
|
||||||
* If `true`, the {@link CKEDITOR.command#method-refresh} method will be
|
|
||||||
* called for this command on the {@link CKEDITOR.editor#event-selectionChange} event.
|
|
||||||
*
|
|
||||||
* @property {Boolean} [=false]
|
|
||||||
*/
|
|
||||||
contextSensitive: !!commandDefinition.context,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates the editor state. Possible values are:
|
|
||||||
*
|
|
||||||
* * {@link CKEDITOR#TRISTATE_DISABLED}: the command is
|
|
||||||
* disabled. It's execution will have no effect. Same as {@link #disable}.
|
|
||||||
* * {@link CKEDITOR#TRISTATE_ON}: the command is enabled
|
|
||||||
* and currently active in the editor (for context sensitive commands, for example).
|
|
||||||
* * {@link CKEDITOR#TRISTATE_OFF}: the command is enabled
|
|
||||||
* and currently inactive in the editor (for context sensitive commands, for example).
|
|
||||||
*
|
|
||||||
* Do not set this property directly, using the {@link #setState} method instead.
|
|
||||||
*
|
|
||||||
* if ( command.state == CKEDITOR.TRISTATE_DISABLED )
|
|
||||||
* alert( 'This command is disabled' );
|
|
||||||
*
|
|
||||||
* @property {Number} [=CKEDITOR.TRISTATE_DISABLED]
|
|
||||||
*/
|
|
||||||
state: CKEDITOR.TRISTATE_DISABLED
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Call the CKEDITOR.event constructor to initialize this instance.
|
|
||||||
CKEDITOR.event.call( this );
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.command.prototype = {
|
|
||||||
/**
|
|
||||||
* Enables the command for execution. The command state (see
|
|
||||||
* {@link CKEDITOR.command#property-state}) available before disabling it is restored.
|
|
||||||
*
|
|
||||||
* command.enable();
|
|
||||||
* command.exec(); // Execute the command.
|
|
||||||
*/
|
|
||||||
enable: function() {
|
|
||||||
if ( this.state == CKEDITOR.TRISTATE_DISABLED && this.checkAllowed() )
|
|
||||||
this.setState( ( !this.preserveState || ( typeof this.previousState == 'undefined' ) ) ? CKEDITOR.TRISTATE_OFF : this.previousState );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables the command for execution. The command state (see
|
|
||||||
* {@link CKEDITOR.command#property-state}) will be set to {@link CKEDITOR#TRISTATE_DISABLED}.
|
|
||||||
*
|
|
||||||
* command.disable();
|
|
||||||
* command.exec(); // "false" - Nothing happens.
|
|
||||||
*/
|
|
||||||
disable: function() {
|
|
||||||
this.setState( CKEDITOR.TRISTATE_DISABLED );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the command state.
|
|
||||||
*
|
|
||||||
* command.setState( CKEDITOR.TRISTATE_ON );
|
|
||||||
* command.exec(); // Execute the command.
|
|
||||||
* command.setState( CKEDITOR.TRISTATE_DISABLED );
|
|
||||||
* command.exec(); // 'false' - Nothing happens.
|
|
||||||
* command.setState( CKEDITOR.TRISTATE_OFF );
|
|
||||||
* command.exec(); // Execute the command.
|
|
||||||
*
|
|
||||||
* @param {Number} newState The new state. See {@link #property-state}.
|
|
||||||
* @returns {Boolean} Returns `true` if the command state changed.
|
|
||||||
*/
|
|
||||||
setState: function( newState ) {
|
|
||||||
// Do nothing if there is no state change.
|
|
||||||
if ( this.state == newState )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( newState != CKEDITOR.TRISTATE_DISABLED && !this.checkAllowed() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
this.previousState = this.state;
|
|
||||||
|
|
||||||
// Set the new state.
|
|
||||||
this.state = newState;
|
|
||||||
|
|
||||||
// Fire the "state" event, so other parts of the code can react to the
|
|
||||||
// change.
|
|
||||||
this.fire( 'state' );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the on/off (active/inactive) state of the command. This is
|
|
||||||
* mainly used internally by context sensitive commands.
|
|
||||||
*
|
|
||||||
* command.toggleState();
|
|
||||||
*/
|
|
||||||
toggleState: function() {
|
|
||||||
if ( this.state == CKEDITOR.TRISTATE_OFF )
|
|
||||||
this.setState( CKEDITOR.TRISTATE_ON );
|
|
||||||
else if ( this.state == CKEDITOR.TRISTATE_ON )
|
|
||||||
this.setState( CKEDITOR.TRISTATE_OFF );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.event.implementOn( CKEDITOR.command.prototype );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates the previous command state.
|
|
||||||
*
|
|
||||||
* alert( command.previousState );
|
|
||||||
*
|
|
||||||
* @property {Number} previousState
|
|
||||||
* @see #state
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the command state changes.
|
|
||||||
*
|
|
||||||
* command.on( 'state', function() {
|
|
||||||
* // Alerts the new state.
|
|
||||||
* alert( this.state );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @event state
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event refresh
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
@ -1,139 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the "virtual" {@link CKEDITOR.commandDefinition} class,
|
|
||||||
* which contains the defintion of a command. This file is for
|
|
||||||
* documentation purposes only.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual class that illustrates the features of command objects to be
|
|
||||||
* passed to the {@link CKEDITOR.editor#addCommand} function.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.commandDefinition
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function to be fired when the commend is executed.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'sample', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* alert( 'Executing a command for the editor name "' + editor.name + '"!' );
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @method exec
|
|
||||||
* @param {CKEDITOR.editor} editor The editor within which run the command.
|
|
||||||
* @param {Object} [data] Additional data to be used to execute the command.
|
|
||||||
* @returns {Boolean} Whether the command has been successfully executed.
|
|
||||||
* Defaults to `true`, if nothing is returned.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the command need to be hooked into the redo/undo system.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'alertName', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* alert( editor.name );
|
|
||||||
* },
|
|
||||||
* canUndo: false // No support for undo/redo.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Boolean} [canUndo=true]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the command is asynchronous, which means that the
|
|
||||||
* {@link CKEDITOR.editor#event-afterCommandExec} event will be fired by the
|
|
||||||
* command itself manually, and that the return value of this command is not to
|
|
||||||
* be returned by the {@link #exec} function.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'loadOptions', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* // Asynchronous operation below.
|
|
||||||
* CKEDITOR.ajax.loadXml( 'data.xml', function() {
|
|
||||||
* editor.fire( 'afterCommandExec' );
|
|
||||||
* } );
|
|
||||||
* },
|
|
||||||
* async: true // The command need some time to complete after exec function returns.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Boolean} [async=false]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the command should give focus to the editor before execution.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'maximize', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* // ...
|
|
||||||
* },
|
|
||||||
* editorFocus: false // The command doesn't require focusing the editing document.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Boolean} [editorFocus=true]
|
|
||||||
* @see CKEDITOR.command#editorFocus
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the command state should be set to {@link CKEDITOR#TRISTATE_DISABLED} on startup.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'unlink', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* // ...
|
|
||||||
* },
|
|
||||||
* startDisabled: true // Command is unavailable until selection is inside a link.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Boolean} [startDisabled=false]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that this command is sensible to the selection context.
|
|
||||||
* If `true`, the {@link CKEDITOR.command#method-refresh} method will be
|
|
||||||
* called for this command on selection changes, with a single parameter
|
|
||||||
* representing the current elements path.
|
|
||||||
*
|
|
||||||
* @property {Boolean} [contextSensitive=true]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defined by command definition a function to determinate the command state, it will be invoked
|
|
||||||
* when editor has it's `states` or `selection` changed.
|
|
||||||
*
|
|
||||||
* **Note:** The function provided must be calling {@link CKEDITOR.command#setState} in all circumstance,
|
|
||||||
* if it is intended to update the command state.
|
|
||||||
*
|
|
||||||
* @method refresh
|
|
||||||
* @param {CKEDITOR.editor} editor
|
|
||||||
* @param {CKEDITOR.dom.elementPath} path
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the element name used to reflect the command state on selection changes.
|
|
||||||
* If the selection is in a place where the element is not allowed, the command
|
|
||||||
* will be disabled.
|
|
||||||
* Setting this property overrides {@link #contextSensitive} to `true`.
|
|
||||||
*
|
|
||||||
* @property {Boolean} [context=true]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor modes within which the command can be executed. The execution
|
|
||||||
* will have no action if the current mode is not listed in this property.
|
|
||||||
*
|
|
||||||
* editorInstance.addCommand( 'link', {
|
|
||||||
* exec: function( editor ) {
|
|
||||||
* // ...
|
|
||||||
* },
|
|
||||||
* modes: { wysiwyg:1 } // Command is available in wysiwyg mode only.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Object} [modes={ wysiwyg:1 }]
|
|
||||||
* @see CKEDITOR.command#modes
|
|
||||||
*/
|
|
||||||
@ -1,380 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.config} object that stores the
|
|
||||||
* default configuration settings.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used in conjunction with {@link CKEDITOR.config#enterMode}
|
|
||||||
* and {@link CKEDITOR.config#shiftEnterMode} configuration
|
|
||||||
* settings to make the editor produce `<p>` tags when
|
|
||||||
* using the *Enter* key.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=1]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.ENTER_P = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used in conjunction with {@link CKEDITOR.config#enterMode}
|
|
||||||
* and {@link CKEDITOR.config#shiftEnterMode} configuration
|
|
||||||
* settings to make the editor produce `<br>` tags when
|
|
||||||
* using the *Enter* key.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=2]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.ENTER_BR = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used in conjunction with {@link CKEDITOR.config#enterMode}
|
|
||||||
* and {@link CKEDITOR.config#shiftEnterMode} configuration
|
|
||||||
* settings to make the editor produce `<div>` tags when
|
|
||||||
* using the *Enter* key.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=3]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.ENTER_DIV = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores default configuration settings. Changes to this object are
|
|
||||||
* reflected in all editor instances, if not specified otherwise for a particular
|
|
||||||
* instance.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.config = {
|
|
||||||
/**
|
|
||||||
* The URL path for the custom configuration file to be loaded. If not
|
|
||||||
* overloaded with inline configuration, it defaults to the `config.js`
|
|
||||||
* file present in the root of the CKEditor installation directory.
|
|
||||||
*
|
|
||||||
* CKEditor will recursively load custom configuration files defined inside
|
|
||||||
* other custom configuration files.
|
|
||||||
*
|
|
||||||
* // Load a specific configuration file.
|
|
||||||
* CKEDITOR.replace( 'myfield', { customConfig: '/myconfig.js' } );
|
|
||||||
*
|
|
||||||
* // Do not load any custom configuration file.
|
|
||||||
* CKEDITOR.replace( 'myfield', { customConfig: '' } );
|
|
||||||
*
|
|
||||||
* @cfg {String} [="<CKEditor folder>/config.js"]
|
|
||||||
*/
|
|
||||||
customConfig: 'config.js',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the replaced element (usually a `<textarea>`)
|
|
||||||
* is to be updated automatically when posting the form containing the editor.
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
autoUpdateElement: true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user interface language localization to use. If left empty, the editor
|
|
||||||
* will automatically be localized to the user language. If the user language is not supported,
|
|
||||||
* the language specified in the {@link CKEDITOR.config#defaultLanguage}
|
|
||||||
* configuration setting is used.
|
|
||||||
*
|
|
||||||
* // Load the German interface.
|
|
||||||
* config.language = 'de';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
language: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The language to be used if the {@link CKEDITOR.config#language}
|
|
||||||
* setting is left empty and it is not possible to localize the editor to the user language.
|
|
||||||
*
|
|
||||||
* config.defaultLanguage = 'it';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
defaultLanguage: 'en',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The writing direction of the language used to create editor contents.
|
|
||||||
* Allowed values are:
|
|
||||||
*
|
|
||||||
* * `''` (empty string) - indicate content direction will be the same with either the editor
|
|
||||||
* UI direction or page element direction depending on the creators:
|
|
||||||
* * Themed UI: The same with user interface language direction;
|
|
||||||
* * Inline: The same with the editable element text direction;
|
|
||||||
* * `'ltr'` - for Left-To-Right language (like English);
|
|
||||||
* * `'rtl'` - for Right-To-Left languages (like Arabic).
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* config.contentsLangDirection = 'rtl';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
contentsLangDirection: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the behavior of the *Enter* key. It also determines other behavior
|
|
||||||
* rules of the editor, like whether the `<br>` element is to be used
|
|
||||||
* as a paragraph separator when indenting text.
|
|
||||||
* The allowed values are the following constants that cause the behavior outlined below:
|
|
||||||
*
|
|
||||||
* * {@link CKEDITOR#ENTER_P} (1) – new `<p>` paragraphs are created;
|
|
||||||
* * {@link CKEDITOR#ENTER_BR} (2) – lines are broken with `<br>` elements;
|
|
||||||
* * {@link CKEDITOR#ENTER_DIV} (3) – new `<div>` blocks are created.
|
|
||||||
*
|
|
||||||
* **Note**: It is recommended to use the {@link CKEDITOR#ENTER_P} setting because of
|
|
||||||
* its semantic value and correctness. The editor is optimized for this setting.
|
|
||||||
*
|
|
||||||
* // Not recommended.
|
|
||||||
* config.enterMode = CKEDITOR.ENTER_BR;
|
|
||||||
*
|
|
||||||
* @cfg {Number} [=CKEDITOR.ENTER_P]
|
|
||||||
*/
|
|
||||||
enterMode: CKEDITOR.ENTER_P,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force the use of {@link CKEDITOR.config#enterMode} as line break regardless
|
|
||||||
* of the context. If, for example, {@link CKEDITOR.config#enterMode} is set
|
|
||||||
* to {@link CKEDITOR#ENTER_P}, pressing the *Enter* key inside a
|
|
||||||
* `<div>` element will create a new paragraph with `<p>`
|
|
||||||
* instead of a `<div>`.
|
|
||||||
*
|
|
||||||
* // Not recommended.
|
|
||||||
* config.forceEnterMode = true;
|
|
||||||
*
|
|
||||||
* @since 3.2.1
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
forceEnterMode: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Similarly to the {@link CKEDITOR.config#enterMode} setting, it defines the behavior
|
|
||||||
* of the *Shift+Enter* key combination.
|
|
||||||
*
|
|
||||||
* The allowed values are the following constants the behavior outlined below:
|
|
||||||
*
|
|
||||||
* * {@link CKEDITOR#ENTER_P} (1) – new `<p>` paragraphs are created;
|
|
||||||
* * {@link CKEDITOR#ENTER_BR} (2) – lines are broken with `<br>` elements;
|
|
||||||
* * {@link CKEDITOR#ENTER_DIV} (3) – new `<div>` blocks are created.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* config.shiftEnterMode = CKEDITOR.ENTER_P;
|
|
||||||
*
|
|
||||||
* @cfg {Number} [=CKEDITOR.ENTER_BR]
|
|
||||||
*/
|
|
||||||
shiftEnterMode: CKEDITOR.ENTER_BR,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the `DOCTYPE` to be used when loading the editor content as HTML.
|
|
||||||
*
|
|
||||||
* // Set the DOCTYPE to the HTML 4 (Quirks) mode.
|
|
||||||
* config.docType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
docType: '<!DOCTYPE html>',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the `id` attribute to be used on the `body` element
|
|
||||||
* of the editing area. This can be useful when you intend to reuse the original CSS
|
|
||||||
* file you are using on your live website and want to assign the editor the same ID
|
|
||||||
* as the section that will include the contents. In this way ID-specific CSS rules will
|
|
||||||
* be enabled.
|
|
||||||
*
|
|
||||||
* config.bodyId = 'contents_id';
|
|
||||||
*
|
|
||||||
* @since 3.1
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
bodyId: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the `class` attribute to be used on the `body` element
|
|
||||||
* of the editing area. This can be useful when you intend to reuse the original CSS
|
|
||||||
* file you are using on your live website and want to assign the editor the same class
|
|
||||||
* as the section that will include the contents. In this way class-specific CSS rules will
|
|
||||||
* be enabled.
|
|
||||||
*
|
|
||||||
* config.bodyClass = 'contents';
|
|
||||||
*
|
|
||||||
* **Note:** Editor needs to load stylesheets containing contents styles. You can either
|
|
||||||
* copy them to the `contents.css` file that editor loads by default or set the {@link #contentsCss}
|
|
||||||
* option.
|
|
||||||
*
|
|
||||||
* **Note:** This setting applies only to the classic editor (the one that uses `iframe`).
|
|
||||||
*
|
|
||||||
* @since 3.1
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
bodyClass: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether the contents to be edited are being input as a full HTML page.
|
|
||||||
* A full page includes the `<html>`, `<head>`, and `<body>` elements.
|
|
||||||
* The final output will also reflect this setting, including the
|
|
||||||
* `<body>` contents only if this setting is disabled.
|
|
||||||
*
|
|
||||||
* config.fullPage = true;
|
|
||||||
*
|
|
||||||
* @since 3.1
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
fullPage: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The height of the editing area (that includes the editor content). This
|
|
||||||
* can be an integer, for pixel sizes, or any CSS-defined length unit.
|
|
||||||
*
|
|
||||||
* **Note:** Percent units (%) are not supported.
|
|
||||||
*
|
|
||||||
* config.height = 500; // 500 pixels.
|
|
||||||
* config.height = '25em'; // CSS length.
|
|
||||||
* config.height = '300px'; // CSS length.
|
|
||||||
*
|
|
||||||
* @cfg {Number/String}
|
|
||||||
*/
|
|
||||||
height: 200,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of plugins to be used in an editor instance. Note that
|
|
||||||
* the actual plugins that are to be loaded could still be affected by two other settings:
|
|
||||||
* {@link CKEDITOR.config#extraPlugins} and {@link CKEDITOR.config#removePlugins}.
|
|
||||||
*
|
|
||||||
* @cfg {String} [="<default list of plugins>"]
|
|
||||||
*/
|
|
||||||
plugins: '', // %REMOVE_LINE%
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of additional plugins to be loaded. This setting makes it easier
|
|
||||||
* to add new plugins without having to touch the {@link CKEDITOR.config#plugins} setting.
|
|
||||||
*
|
|
||||||
* **Note:** The most recommended way to
|
|
||||||
* [add CKEditor plugins](http://docs.ckeditor.com/#!/guide/dev_plugins) is through
|
|
||||||
* [CKEditor Builder](http://ckeditor.com/builder).
|
|
||||||
*
|
|
||||||
* config.extraPlugins = 'myplugin,anotherplugin';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
extraPlugins: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of plugins that must not be loaded. This setting makes it possible
|
|
||||||
* to avoid loading some plugins defined in the {@link CKEDITOR.config#plugins}
|
|
||||||
* setting, without having to touch it.
|
|
||||||
*
|
|
||||||
* **Note:** A plugin required by another plugin cannot be removed and will cause
|
|
||||||
* an error to be thrown. So for example if `contextmenu` is required by `tabletools`,
|
|
||||||
* it can only be removed if `tabletools` is not loaded.
|
|
||||||
*
|
|
||||||
* config.removePlugins = 'elementspath,save,font';
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
removePlugins: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of regular expressions to be executed on input HTML,
|
|
||||||
* indicating HTML source code that when matched, must **not** be available in the WYSIWYG
|
|
||||||
* mode for editing.
|
|
||||||
*
|
|
||||||
* config.protectedSource.push( /<\?[\s\S]*?\?>/g ); // PHP code
|
|
||||||
* config.protectedSource.push( /<%[\s\S]*?%>/g ); // ASP code
|
|
||||||
* config.protectedSource.push( /(<asp:[^\>]+>[\s|\S]*?<\/asp:[^\>]+>)|(<asp:[^\>]+\/>)/gi ); // ASP.Net code
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
protectedSource: [],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor `tabindex` value.
|
|
||||||
*
|
|
||||||
* config.tabIndex = 1;
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
tabIndex: 0,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor UI outer width. This can be an integer, for pixel sizes, or
|
|
||||||
* any CSS-defined unit.
|
|
||||||
*
|
|
||||||
* Unlike the {@link CKEDITOR.config#height} setting, this
|
|
||||||
* one will set the outer width of the entire editor UI, not for the
|
|
||||||
* editing area only.
|
|
||||||
*
|
|
||||||
* config.width = 850; // 850 pixels wide.
|
|
||||||
* config.width = '75%'; // CSS unit.
|
|
||||||
*
|
|
||||||
* @cfg {String/Number}
|
|
||||||
*/
|
|
||||||
width: '',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base Z-index for floating dialog windows and popups.
|
|
||||||
*
|
|
||||||
* config.baseFloatZIndex = 2000;
|
|
||||||
*
|
|
||||||
* @cfg
|
|
||||||
*/
|
|
||||||
baseFloatZIndex: 10000,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The keystrokes that are blocked by default as the browser implementation
|
|
||||||
* is buggy. These default keystrokes are handled by the editor.
|
|
||||||
*
|
|
||||||
* // Default setting.
|
|
||||||
* config.blockedKeystrokes = [
|
|
||||||
* CKEDITOR.CTRL + 66, // CTRL+B
|
|
||||||
* CKEDITOR.CTRL + 73, // CTRL+I
|
|
||||||
* CKEDITOR.CTRL + 85 // CTRL+U
|
|
||||||
* ];
|
|
||||||
*
|
|
||||||
* @cfg {Array} [blockedKeystrokes=see example]
|
|
||||||
*/
|
|
||||||
blockedKeystrokes: [
|
|
||||||
CKEDITOR.CTRL + 66, // CTRL+B
|
|
||||||
CKEDITOR.CTRL + 73, // CTRL+I
|
|
||||||
CKEDITOR.CTRL + 85 // CTRL+U
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that some of the editor features, like alignment and text
|
|
||||||
* direction, should use the "computed value" of the feature to indicate its
|
|
||||||
* on/off state instead of using the "real value".
|
|
||||||
*
|
|
||||||
* If enabled in a Left-To-Right written document, the "Left Justify"
|
|
||||||
* alignment button will be shown as active, even if the alignment style is not
|
|
||||||
* explicitly applied to the current paragraph in the editor.
|
|
||||||
*
|
|
||||||
* config.useComputedState = false;
|
|
||||||
*
|
|
||||||
* @since 3.4
|
|
||||||
* @cfg {Boolean} [useComputedState=true]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base user interface color to be used by the editor. Not all skins are
|
|
||||||
* compatible with this setting.
|
|
||||||
*
|
|
||||||
* // Using a color code.
|
|
||||||
* config.uiColor = '#AADC6E';
|
|
||||||
*
|
|
||||||
* // Using an HTML color name.
|
|
||||||
* config.uiColor = 'Gold';
|
|
||||||
*
|
|
||||||
* @cfg {String} uiColor
|
|
||||||
*/
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.config )
|
|
||||||
@ -1,156 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/** @class CKEDITOR */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns a DOM element with the `contenteditable` attribute set to `true` into a
|
|
||||||
* CKEditor instance. Check {@link CKEDITOR.dtd#$editable} for a list of
|
|
||||||
* allowed element names.
|
|
||||||
*
|
|
||||||
* **Note:** If the DOM element for which inline editing is being enabled does not have
|
|
||||||
* the `contenteditable` attribute set to `true`, the editor will start in read-only mode.
|
|
||||||
*
|
|
||||||
* <div contenteditable="true" id="content">...</div>
|
|
||||||
* ...
|
|
||||||
* CKEDITOR.inline( 'content' );
|
|
||||||
*
|
|
||||||
* It is also possible to create an inline editor from the `<textarea>` element.
|
|
||||||
* If you do so, an additional `<div>` element with editable content will be created
|
|
||||||
* directly after the `<textarea>` element and the `<textarea>` element will be hidden.
|
|
||||||
*
|
|
||||||
* @param {Object/String} element The DOM element or its ID.
|
|
||||||
* @param {Object} [instanceConfig] The specific configurations to apply to this editor instance.
|
|
||||||
* See {@link CKEDITOR.config}.
|
|
||||||
* @returns {CKEDITOR.editor} The editor instance created.
|
|
||||||
*/
|
|
||||||
CKEDITOR.inline = function( element, instanceConfig ) {
|
|
||||||
if ( !CKEDITOR.env.isCompatible )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
element = CKEDITOR.dom.element.get( element );
|
|
||||||
|
|
||||||
// Avoid multiple inline editor instances on the same element.
|
|
||||||
if ( element.getEditor() )
|
|
||||||
throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.';
|
|
||||||
|
|
||||||
var editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE ),
|
|
||||||
textarea = element.is( 'textarea' ) ? element : null;
|
|
||||||
|
|
||||||
if ( textarea ) {
|
|
||||||
editor.setData( textarea.getValue(), null, true );
|
|
||||||
|
|
||||||
//Change element from textarea to div
|
|
||||||
element = CKEDITOR.dom.element.createFromHtml(
|
|
||||||
'<div contenteditable="' + !!editor.readOnly + '" class="cke_textarea_inline">' +
|
|
||||||
textarea.getValue() +
|
|
||||||
'</div>',
|
|
||||||
CKEDITOR.document );
|
|
||||||
|
|
||||||
element.insertAfter( textarea );
|
|
||||||
textarea.hide();
|
|
||||||
|
|
||||||
// Attaching the concrete form.
|
|
||||||
if ( textarea.$.form )
|
|
||||||
editor._attachToForm();
|
|
||||||
} else {
|
|
||||||
// Initial editor data is simply loaded from the page element content to make
|
|
||||||
// data retrieval possible immediately after the editor creation.
|
|
||||||
editor.setData( element.getHtml(), null, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once the editor is loaded, start the UI.
|
|
||||||
editor.on( 'loaded', function() {
|
|
||||||
editor.fire( 'uiReady' );
|
|
||||||
|
|
||||||
// Enable editing on the element.
|
|
||||||
editor.editable( element );
|
|
||||||
|
|
||||||
// Editable itself is the outermost element.
|
|
||||||
editor.container = element;
|
|
||||||
|
|
||||||
// Load and process editor data.
|
|
||||||
editor.setData( editor.getData( 1 ) );
|
|
||||||
|
|
||||||
// Clean on startup.
|
|
||||||
editor.resetDirty();
|
|
||||||
|
|
||||||
editor.fire( 'contentDom' );
|
|
||||||
|
|
||||||
// Inline editing defaults to "wysiwyg" mode, so plugins don't
|
|
||||||
// need to make special handling for this "mode-less" environment.
|
|
||||||
editor.mode = 'wysiwyg';
|
|
||||||
editor.fire( 'mode' );
|
|
||||||
|
|
||||||
// The editor is completely loaded for interaction.
|
|
||||||
editor.status = 'ready';
|
|
||||||
editor.fireOnce( 'instanceReady' );
|
|
||||||
CKEDITOR.fire( 'instanceReady', null, editor );
|
|
||||||
|
|
||||||
// give priority to plugins that relay on editor#loaded for bootstrapping.
|
|
||||||
}, null, null, 10000 );
|
|
||||||
|
|
||||||
// Handle editor destroying.
|
|
||||||
editor.on( 'destroy', function() {
|
|
||||||
// Remove container from DOM if inline-textarea editor.
|
|
||||||
// Show <textarea> back again.
|
|
||||||
if ( textarea ) {
|
|
||||||
editor.container.clearCustomData();
|
|
||||||
editor.container.remove();
|
|
||||||
textarea.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.element.clearCustomData();
|
|
||||||
|
|
||||||
delete editor.element;
|
|
||||||
} );
|
|
||||||
|
|
||||||
return editor;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link CKEDITOR#inline} for all page elements with
|
|
||||||
* the `contenteditable` attribute set to `true`.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
CKEDITOR.inlineAll = function() {
|
|
||||||
var el, data;
|
|
||||||
|
|
||||||
for ( var name in CKEDITOR.dtd.$editable ) {
|
|
||||||
var elements = CKEDITOR.document.getElementsByTag( name );
|
|
||||||
|
|
||||||
for ( var i = 0, len = elements.count(); i < len; i++ ) {
|
|
||||||
el = elements.getItem( i );
|
|
||||||
|
|
||||||
if ( el.getAttribute( 'contenteditable' ) == 'true' ) {
|
|
||||||
// Fire the "inline" event, making it possible to customize
|
|
||||||
// the instance settings and eventually cancel the creation.
|
|
||||||
|
|
||||||
data = {
|
|
||||||
element: el,
|
|
||||||
config: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( CKEDITOR.fire( 'inline', data ) !== false )
|
|
||||||
CKEDITOR.inline( el, data.config );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.domReady( function() {
|
|
||||||
!CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
|
|
||||||
} );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables creating the inline editor automatically for elements with
|
|
||||||
* the `contenteditable` attribute set to `true`.
|
|
||||||
*
|
|
||||||
* CKEDITOR.disableAutoInline = true;
|
|
||||||
*
|
|
||||||
* @cfg {Boolean} [disableAutoInline=false]
|
|
||||||
*/
|
|
||||||
@ -1,488 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @class CKEDITOR */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class name used to identify `<textarea>` elements to be replaced
|
|
||||||
* by CKEditor instances. Set it to empty/`null` to disable this feature.
|
|
||||||
*
|
|
||||||
* CKEDITOR.replaceClass = 'rich_editor';
|
|
||||||
*
|
|
||||||
* @cfg {String} [replaceClass='ckeditor']
|
|
||||||
*/
|
|
||||||
CKEDITOR.replaceClass = 'ckeditor';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Replaces a `<textarea>` or a DOM element (`<div>`) with a CKEditor
|
|
||||||
* instance. For textareas, the initial value in the editor will be the
|
|
||||||
* textarea value. For DOM elements, their `innerHTML` will be used
|
|
||||||
* instead. We recommend using `<textarea>` and `<div>` elements only.
|
|
||||||
*
|
|
||||||
* <textarea id="myfield" name="myfield"></textarea>
|
|
||||||
* ...
|
|
||||||
* CKEDITOR.replace( 'myfield' );
|
|
||||||
*
|
|
||||||
* var textarea = document.body.appendChild( document.createElement( 'textarea' ) );
|
|
||||||
* CKEDITOR.replace( textarea );
|
|
||||||
*
|
|
||||||
* @param {Object/String} element The DOM element (textarea), its ID, or name.
|
|
||||||
* @param {Object} [config] The specific configuration to apply to this
|
|
||||||
* editor instance. Configuration set here will override the global CKEditor settings
|
|
||||||
* (see {@link CKEDITOR.config}).
|
|
||||||
* @returns {CKEDITOR.editor} The editor instance created.
|
|
||||||
*/
|
|
||||||
CKEDITOR.replace = function( element, config ) {
|
|
||||||
return createInstance( element, config, null, CKEDITOR.ELEMENT_MODE_REPLACE );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new editor instance at the end of a specific DOM element.
|
|
||||||
*
|
|
||||||
* <div id="editorSpace"></div>
|
|
||||||
* ...
|
|
||||||
* CKEDITOR.appendTo( 'editorSpace' );
|
|
||||||
*
|
|
||||||
* @param {Object/String} element The DOM element, its ID, or name.
|
|
||||||
* @param {Object} [config] The specific configuration to apply to this
|
|
||||||
* editor instance. Configuration set here will override the global CKEditor settings
|
|
||||||
* (see {@link CKEDITOR.config}).
|
|
||||||
* @param {String} [data] Since 3.3. Initial value for the instance.
|
|
||||||
* @returns {CKEDITOR.editor} The editor instance created.
|
|
||||||
*/
|
|
||||||
CKEDITOR.appendTo = function( element, config, data )
|
|
||||||
{
|
|
||||||
return createInstance( element, config, data, CKEDITOR.ELEMENT_MODE_APPENDTO );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces all `<textarea>` elements available in the document with
|
|
||||||
* editor instances.
|
|
||||||
*
|
|
||||||
* // Replace all <textarea> elements in the page.
|
|
||||||
* CKEDITOR.replaceAll();
|
|
||||||
*
|
|
||||||
* // Replace all <textarea class="myClassName"> elements in the page.
|
|
||||||
* CKEDITOR.replaceAll( 'myClassName' );
|
|
||||||
*
|
|
||||||
* // Selectively replace <textarea> elements, based on custom assertions.
|
|
||||||
* CKEDITOR.replaceAll( function( textarea, config ) {
|
|
||||||
* // An assertion function that needs to be evaluated for the <textarea>
|
|
||||||
* // to be replaced. It must explicitely return "false" to ignore a
|
|
||||||
* // specific <textarea>.
|
|
||||||
* // You can also customize the editor instance by having the function
|
|
||||||
* // modify the "config" parameter.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {String} [className] The `<textarea>` class name.
|
|
||||||
* @param {Function} [function] An assertion function that must return `true` for a `<textarea>`
|
|
||||||
* to be replaced with the editor. If the function returns `false`, the `<textarea>` element
|
|
||||||
* will not be replaced.
|
|
||||||
*/
|
|
||||||
CKEDITOR.replaceAll = function() {
|
|
||||||
var textareas = document.getElementsByTagName( 'textarea' );
|
|
||||||
|
|
||||||
for ( var i = 0; i < textareas.length; i++ ) {
|
|
||||||
var config = null,
|
|
||||||
textarea = textareas[ i ];
|
|
||||||
|
|
||||||
// The "name" and/or "id" attribute must exist.
|
|
||||||
if ( !textarea.name && !textarea.id )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( typeof arguments[ 0 ] == 'string' ) {
|
|
||||||
// The textarea class name could be passed as the function
|
|
||||||
// parameter.
|
|
||||||
|
|
||||||
var classRegex = new RegExp( '(?:^|\\s)' + arguments[ 0 ] + '(?:$|\\s)' );
|
|
||||||
|
|
||||||
if ( !classRegex.test( textarea.className ) )
|
|
||||||
continue;
|
|
||||||
} else if ( typeof arguments[ 0 ] == 'function' ) {
|
|
||||||
// An assertion function could be passed as the function parameter.
|
|
||||||
// It must explicitly return "false" to ignore a specific <textarea>.
|
|
||||||
config = {};
|
|
||||||
if ( arguments[ 0 ]( textarea, config ) === false )
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.replace( textarea, config );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @class CKEDITOR.editor */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers an editing mode. This function is to be used mainly by plugins.
|
|
||||||
*
|
|
||||||
* @param {String} mode The mode name.
|
|
||||||
* @param {Function} exec The function that performs the actual mode change.
|
|
||||||
*/
|
|
||||||
CKEDITOR.editor.prototype.addMode = function( mode, exec ) {
|
|
||||||
( this._.modes || ( this._.modes = {} ) )[ mode ] = exec;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the editing mode of this editor instance.
|
|
||||||
*
|
|
||||||
* **Note:** The mode switch could be asynchronous depending on the mode provider.
|
|
||||||
* Use the `callback` to hook subsequent code.
|
|
||||||
*
|
|
||||||
* // Switch to "source" view.
|
|
||||||
* CKEDITOR.instances.editor1.setMode( 'source' );
|
|
||||||
* // Switch to "wysiwyg" view and be notified on completion.
|
|
||||||
* CKEDITOR.instances.editor1.setMode( 'wysiwyg', function() { alert( 'wysiwyg mode loaded!' ); } );
|
|
||||||
*
|
|
||||||
* @param {String} [newMode] If not specified, the {@link CKEDITOR.config#startupMode} will be used.
|
|
||||||
* @param {Function} [callback] Optional callback function which is invoked once the mode switch has succeeded.
|
|
||||||
*/
|
|
||||||
CKEDITOR.editor.prototype.setMode = function( newMode, callback ) {
|
|
||||||
var editor = this;
|
|
||||||
|
|
||||||
var modes = this._.modes;
|
|
||||||
|
|
||||||
// Mode loading quickly fails.
|
|
||||||
if ( newMode == editor.mode || !modes || !modes[ newMode ] )
|
|
||||||
return;
|
|
||||||
|
|
||||||
editor.fire( 'beforeSetMode', newMode );
|
|
||||||
|
|
||||||
if ( editor.mode ) {
|
|
||||||
var isDirty = editor.checkDirty(),
|
|
||||||
previousModeData = editor._.previousModeData,
|
|
||||||
currentData,
|
|
||||||
unlockSnapshot = 0;
|
|
||||||
|
|
||||||
editor.fire( 'beforeModeUnload' );
|
|
||||||
|
|
||||||
// Detach the current editable. While detaching editable will set
|
|
||||||
// cached editor's data (with internal setData call). We use this
|
|
||||||
// data below to avoid two getData() calls in a row.
|
|
||||||
editor.editable( 0 );
|
|
||||||
|
|
||||||
editor._.previousMode = editor.mode;
|
|
||||||
// Get cached data, which was set while detaching editable.
|
|
||||||
editor._.previousModeData = currentData = editor.getData( 1 );
|
|
||||||
|
|
||||||
// If data has not been modified in the mode which we are currently leaving,
|
|
||||||
// avoid making snapshot right after initializing new mode.
|
|
||||||
// http://dev.ckeditor.com/ticket/5217#comment:20
|
|
||||||
// Tested by:
|
|
||||||
// 'test switch mode with unrecoreded, inner HTML specific content (boguses)'
|
|
||||||
// 'test switch mode with unrecoreded, inner HTML specific content (boguses) plus changes in source mode'
|
|
||||||
if ( editor.mode == 'source' && previousModeData == currentData ) {
|
|
||||||
// We need to make sure that unlockSnapshot will update the last snapshot
|
|
||||||
// (will not create new one) if lockSnapshot is not called on outdated snapshots stack.
|
|
||||||
// Additionally, forceUpdate prevents from making content image now, which is useless
|
|
||||||
// (because it equals editor data not inner HTML).
|
|
||||||
editor.fire( 'lockSnapshot', { forceUpdate: true } );
|
|
||||||
unlockSnapshot = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear up the mode space.
|
|
||||||
editor.ui.space( 'contents' ).setHtml( '' );
|
|
||||||
|
|
||||||
editor.mode = '';
|
|
||||||
} else
|
|
||||||
editor._.previousModeData = editor.getData( 1 );
|
|
||||||
|
|
||||||
// Fire the mode handler.
|
|
||||||
this._.modes[ newMode ]( function() {
|
|
||||||
// Set the current mode.
|
|
||||||
editor.mode = newMode;
|
|
||||||
|
|
||||||
if ( isDirty !== undefined )
|
|
||||||
!isDirty && editor.resetDirty();
|
|
||||||
|
|
||||||
if ( unlockSnapshot )
|
|
||||||
editor.fire( 'unlockSnapshot' );
|
|
||||||
// Since snapshot made on dataReady (which normally catches changes done by setData)
|
|
||||||
// won't work because editor.mode was not set yet (it's set in this function), we need
|
|
||||||
// to make special snapshot for changes done in source mode here.
|
|
||||||
else if ( newMode == 'wysiwyg' )
|
|
||||||
editor.fire( 'saveSnapshot' );
|
|
||||||
|
|
||||||
// Delay to avoid race conditions (setMode inside setMode).
|
|
||||||
setTimeout( function() {
|
|
||||||
editor.fire( 'mode' );
|
|
||||||
callback && callback.call( editor );
|
|
||||||
}, 0 );
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resizes the editor interface.
|
|
||||||
*
|
|
||||||
* editor.resize( 900, 300 );
|
|
||||||
*
|
|
||||||
* editor.resize( '100%', 450, true );
|
|
||||||
*
|
|
||||||
* @param {Number/String} width The new width. It can be an integer denoting a value
|
|
||||||
* in pixels or a CSS size value with unit.
|
|
||||||
* @param {Number/String} height The new height. It can be an integer denoting a value
|
|
||||||
* in pixels or a CSS size value with unit.
|
|
||||||
* @param {Boolean} [isContentHeight] Indicates that the provided height is to
|
|
||||||
* be applied to the editor content area, and not to the entire editor
|
|
||||||
* interface. Defaults to `false`.
|
|
||||||
* @param {Boolean} [resizeInner] Indicates that it is the inner interface
|
|
||||||
* element that must be resized, not the outer element. The default theme
|
|
||||||
* defines the editor interface inside a pair of `<span>` elements
|
|
||||||
* (`<span><span>...</span></span>`). By default the first,
|
|
||||||
* outer `<span>` element receives the sizes. If this parameter is set to
|
|
||||||
* `true`, the second, inner `<span>` is resized instead.
|
|
||||||
*/
|
|
||||||
CKEDITOR.editor.prototype.resize = function( width, height, isContentHeight, resizeInner ) {
|
|
||||||
var container = this.container,
|
|
||||||
contents = this.ui.space( 'contents' ),
|
|
||||||
contentsFrame = CKEDITOR.env.webkit && this.document && this.document.getWindow().$.frameElement,
|
|
||||||
outer = resizeInner ? container.getChild( 1 ) : container;
|
|
||||||
|
|
||||||
// Set as border box width. (#5353)
|
|
||||||
outer.setSize( 'width', width, true );
|
|
||||||
|
|
||||||
// WebKit needs to refresh the iframe size to avoid rendering issues. (1/2) (#8348)
|
|
||||||
contentsFrame && ( contentsFrame.style.width = '1%' );
|
|
||||||
|
|
||||||
// Get the height delta between the outer table and the content area.
|
|
||||||
// If we're setting the content area's height, then we don't need the delta.
|
|
||||||
var delta = isContentHeight ? 0 : ( outer.$.offsetHeight || 0 ) - ( contents.$.clientHeight || 0 );
|
|
||||||
contents.setStyle( 'height', Math.max( height - delta, 0 ) + 'px' );
|
|
||||||
|
|
||||||
// WebKit needs to refresh the iframe size to avoid rendering issues. (2/2) (#8348)
|
|
||||||
contentsFrame && ( contentsFrame.style.width = '100%' );
|
|
||||||
|
|
||||||
// Emit a resize event.
|
|
||||||
this.fire( 'resize' );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the element that can be used to check the editor size. This method
|
|
||||||
* is mainly used by the `resize` plugin, which adds a UI handle that can be used
|
|
||||||
* to resize the editor.
|
|
||||||
*
|
|
||||||
* @param {Boolean} forContents Whether to return the "contents" part of the theme instead of the container.
|
|
||||||
* @returns {CKEDITOR.dom.element} The resizable element.
|
|
||||||
*/
|
|
||||||
CKEDITOR.editor.prototype.getResizable = function( forContents ) {
|
|
||||||
return forContents ? this.ui.space( 'contents' ) : this.container;
|
|
||||||
};
|
|
||||||
|
|
||||||
function createInstance( element, config, data, mode ) {
|
|
||||||
if ( !CKEDITOR.env.isCompatible )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
element = CKEDITOR.dom.element.get( element );
|
|
||||||
|
|
||||||
// Avoid multiple inline editor instances on the same element.
|
|
||||||
if ( element.getEditor() )
|
|
||||||
throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.';
|
|
||||||
|
|
||||||
// Create the editor instance.
|
|
||||||
var editor = new CKEDITOR.editor( config, element, mode );
|
|
||||||
|
|
||||||
if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
|
|
||||||
// Do not replace the textarea right now, just hide it. The effective
|
|
||||||
// replacement will be done later in the editor creation lifecycle.
|
|
||||||
element.setStyle( 'visibility', 'hidden' );
|
|
||||||
|
|
||||||
// #8031 Remember if textarea was required and remove the attribute.
|
|
||||||
editor._.required = element.hasAttribute( 'required' );
|
|
||||||
element.removeAttribute( 'required' );
|
|
||||||
}
|
|
||||||
|
|
||||||
data && editor.setData( data, null, true );
|
|
||||||
|
|
||||||
// Once the editor is loaded, start the UI.
|
|
||||||
editor.on( 'loaded', function() {
|
|
||||||
loadTheme( editor );
|
|
||||||
|
|
||||||
if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE && editor.config.autoUpdateElement && element.$.form )
|
|
||||||
editor._attachToForm();
|
|
||||||
|
|
||||||
editor.setMode( editor.config.startupMode, function() {
|
|
||||||
// Clean on startup.
|
|
||||||
editor.resetDirty();
|
|
||||||
|
|
||||||
// Editor is completely loaded for interaction.
|
|
||||||
editor.status = 'ready';
|
|
||||||
editor.fireOnce( 'instanceReady' );
|
|
||||||
CKEDITOR.fire( 'instanceReady', null, editor );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
editor.on( 'destroy', destroy );
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroy() {
|
|
||||||
var editor = this,
|
|
||||||
container = editor.container,
|
|
||||||
element = editor.element;
|
|
||||||
|
|
||||||
if ( container ) {
|
|
||||||
container.clearCustomData();
|
|
||||||
container.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( element ) {
|
|
||||||
element.clearCustomData();
|
|
||||||
if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
|
|
||||||
element.show();
|
|
||||||
if ( editor._.required )
|
|
||||||
element.setAttribute( 'required', 'required' );
|
|
||||||
}
|
|
||||||
delete editor.element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var themedTpl;
|
|
||||||
|
|
||||||
function loadTheme( editor ) {
|
|
||||||
var name = editor.name,
|
|
||||||
element = editor.element,
|
|
||||||
elementMode = editor.elementMode;
|
|
||||||
|
|
||||||
// Get the HTML for the predefined spaces.
|
|
||||||
var topHtml = editor.fire( 'uiSpace', { space: 'top', html: '' } ).html;
|
|
||||||
var bottomHtml = editor.fire( 'uiSpace', { space: 'bottom', html: '' } ).html;
|
|
||||||
|
|
||||||
if ( !themedTpl ) {
|
|
||||||
themedTpl = CKEDITOR.addTemplate( 'maincontainer', '<{outerEl}' +
|
|
||||||
' id="cke_{name}"' +
|
|
||||||
' class="{id} cke cke_reset cke_chrome cke_editor_{name} cke_{langDir} ' + CKEDITOR.env.cssClass + '" ' +
|
|
||||||
' dir="{langDir}"' +
|
|
||||||
' lang="{langCode}"' +
|
|
||||||
' role="application"' +
|
|
||||||
' aria-labelledby="cke_{name}_arialbl">' +
|
|
||||||
'<span id="cke_{name}_arialbl" class="cke_voice_label">{voiceLabel}</span>' +
|
|
||||||
'<{outerEl} class="cke_inner cke_reset" role="presentation">' +
|
|
||||||
'{topHtml}' +
|
|
||||||
'<{outerEl} id="{contentId}" class="cke_contents cke_reset" role="presentation"></{outerEl}>' +
|
|
||||||
'{bottomHtml}' +
|
|
||||||
'</{outerEl}>' +
|
|
||||||
'</{outerEl}>' );
|
|
||||||
}
|
|
||||||
|
|
||||||
var container = CKEDITOR.dom.element.createFromHtml( themedTpl.output( {
|
|
||||||
id: editor.id,
|
|
||||||
name: name,
|
|
||||||
langDir: editor.lang.dir,
|
|
||||||
langCode: editor.langCode,
|
|
||||||
voiceLabel: [ editor.lang.editor, editor.name ].join( ', ' ),
|
|
||||||
topHtml: topHtml ? '<span id="' + editor.ui.spaceId( 'top' ) + '" class="cke_top cke_reset_all" role="presentation" style="height:auto">' + topHtml + '</span>' : '',
|
|
||||||
contentId: editor.ui.spaceId( 'contents' ),
|
|
||||||
bottomHtml: bottomHtml ? '<span id="' + editor.ui.spaceId( 'bottom' ) + '" class="cke_bottom cke_reset_all" role="presentation">' + bottomHtml + '</span>' : '',
|
|
||||||
outerEl: CKEDITOR.env.ie ? 'span' : 'div' // #9571
|
|
||||||
} ) );
|
|
||||||
|
|
||||||
if ( elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ) {
|
|
||||||
element.hide();
|
|
||||||
container.insertAfter( element );
|
|
||||||
} else
|
|
||||||
element.append( container );
|
|
||||||
|
|
||||||
editor.container = container;
|
|
||||||
|
|
||||||
// Make top and bottom spaces unelectable, but not content space,
|
|
||||||
// otherwise the editable area would be affected.
|
|
||||||
topHtml && editor.ui.space( 'top' ).unselectable();
|
|
||||||
bottomHtml && editor.ui.space( 'bottom' ).unselectable();
|
|
||||||
|
|
||||||
var width = editor.config.width, height = editor.config.height;
|
|
||||||
if ( width )
|
|
||||||
container.setStyle( 'width', CKEDITOR.tools.cssLength( width ) );
|
|
||||||
|
|
||||||
// The editor height is applied to the contents space.
|
|
||||||
if ( height )
|
|
||||||
editor.ui.space( 'contents' ).setStyle( 'height', CKEDITOR.tools.cssLength( height ) );
|
|
||||||
|
|
||||||
// Disable browser context menu for editor's chrome.
|
|
||||||
container.disableContextMenu();
|
|
||||||
|
|
||||||
// Redirect the focus into editor for webkit. (#5713)
|
|
||||||
CKEDITOR.env.webkit && container.on( 'focus', function() {
|
|
||||||
editor.focus();
|
|
||||||
} );
|
|
||||||
|
|
||||||
editor.fireOnce( 'uiReady' );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace all textareas with the default class name.
|
|
||||||
CKEDITOR.domReady( function() {
|
|
||||||
CKEDITOR.replaceClass && CKEDITOR.replaceAll( CKEDITOR.replaceClass );
|
|
||||||
} );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current editing mode. An editing mode basically provides
|
|
||||||
* different ways of editing or viewing the contents.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.instances.editor1.mode ); // (e.g.) 'wysiwyg'
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {String} mode
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mode to load at the editor startup. It depends on the plugins
|
|
||||||
* loaded. By default, the `wysiwyg` and `source` modes are available.
|
|
||||||
*
|
|
||||||
* config.startupMode = 'source';
|
|
||||||
*
|
|
||||||
* @cfg {String} [startupMode='wysiwyg']
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
CKEDITOR.config.startupMode = 'wysiwyg';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired after the editor instance is resized through
|
|
||||||
* the {@link CKEDITOR.editor#method-resize CKEDITOR.resize} method.
|
|
||||||
*
|
|
||||||
* @event resize
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired before changing the editing mode. See also
|
|
||||||
* {@link #beforeSetMode} and {@link #event-mode}.
|
|
||||||
*
|
|
||||||
* @event beforeModeUnload
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired before the editor mode is set. See also
|
|
||||||
* {@link #event-mode} and {@link #beforeModeUnload}.
|
|
||||||
*
|
|
||||||
* @since 3.5.3
|
|
||||||
* @event beforeSetMode
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
* @param {String} data The name of the mode which is about to be set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired after setting the editing mode. See also {@link #beforeSetMode} and {@link #beforeModeUnload}
|
|
||||||
*
|
|
||||||
* @event mode
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the editor (replacing a `<textarea>` which has a `required` attribute) is empty during form submission.
|
|
||||||
*
|
|
||||||
* This event replaces native required fields validation that the browsers cannot
|
|
||||||
* perform when CKEditor replaces `<textarea>` elements.
|
|
||||||
*
|
|
||||||
* You can cancel this event to prevent the page from submitting data.
|
|
||||||
*
|
|
||||||
* editor.on( 'required', function( evt ) {
|
|
||||||
* alert( 'Article content is required.' );
|
|
||||||
* evt.cancel();
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @event required
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
*/
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the "virtual" {@link CKEDITOR.dataProcessor} class, which
|
|
||||||
* defines the basic structure of data processor objects to be
|
|
||||||
* set to {@link CKEDITOR.editor.dataProcessor}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If defined, points to the data processor which is responsible to translate
|
|
||||||
* and transform the editor data on input and output.
|
|
||||||
* Generaly it will point to an instance of {@link CKEDITOR.htmlDataProcessor},
|
|
||||||
* which handles HTML data. The editor may also handle other data formats by
|
|
||||||
* using different data processors provided by specific plugins.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.dataProcessor} dataProcessor
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a data processor, which is responsible to translate and
|
|
||||||
* transform the editor data on input and output.
|
|
||||||
*
|
|
||||||
* This class is here for documentation purposes only and is not really part of
|
|
||||||
* the API. It serves as the base ("interface") for data processors implementation.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.dataProcessor
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms input data into HTML to be loaded in the editor.
|
|
||||||
* While the editor is able to handle non HTML data (like BBCode), at runtime
|
|
||||||
* it can handle HTML data only. The role of the data processor is transforming
|
|
||||||
* the input data into HTML through this function.
|
|
||||||
*
|
|
||||||
* // Tranforming BBCode data, having a custom BBCode data processor.
|
|
||||||
* var data = 'This is [b]an example[/b].';
|
|
||||||
* var html = editor.dataProcessor.toHtml( data ); // '<p>This is <b>an example</b>.</p>'
|
|
||||||
*
|
|
||||||
* @method toHtml
|
|
||||||
* @param {String} data The input data to be transformed.
|
|
||||||
* @param {String} [fixForBody] The tag name to be used if the data must be
|
|
||||||
* fixed because it is supposed to be loaded direcly into the `<body>`
|
|
||||||
* tag. This is generally not used by non-HTML data processors.
|
|
||||||
* @todo fixForBody type - compare to htmlDataProcessor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms HTML into data to be outputted by the editor, in the format
|
|
||||||
* expected by the data processor.
|
|
||||||
*
|
|
||||||
* While the editor is able to handle non HTML data (like BBCode), at runtime
|
|
||||||
* it can handle HTML data only. The role of the data processor is transforming
|
|
||||||
* the HTML data containined by the editor into a specific data format through
|
|
||||||
* this function.
|
|
||||||
*
|
|
||||||
* // Tranforming into BBCode data, having a custom BBCode data processor.
|
|
||||||
* var html = '<p>This is <b>an example</b>.</p>';
|
|
||||||
* var data = editor.dataProcessor.toDataFormat( html ); // 'This is [b]an example[/b].'
|
|
||||||
*
|
|
||||||
* @method toDataFormat
|
|
||||||
* @param {String} html The HTML to be transformed.
|
|
||||||
* @param {String} fixForBody The tag name to be used if the output data is
|
|
||||||
* coming from `<body>` and may be eventually fixed for it. This is
|
|
||||||
* generally not used by non-HTML data processors.
|
|
||||||
*/
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom} object, which contains DOM
|
|
||||||
* manipulation objects and function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
CKEDITOR.dom = {};
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.dom )
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents
|
|
||||||
* a DOM comment node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DOM comment node.
|
|
||||||
*
|
|
||||||
* var nativeNode = document.createComment( 'Example' );
|
|
||||||
* var comment = new CKEDITOR.dom.comment( nativeNode );
|
|
||||||
*
|
|
||||||
* var comment = new CKEDITOR.dom.comment( 'Example' );
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.dom.node
|
|
||||||
* @constructor Creates a comment class instance.
|
|
||||||
* @param {Object/String} comment A native DOM comment node or a string containing
|
|
||||||
* the text to use to create a new comment node.
|
|
||||||
* @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
|
|
||||||
* the node in case of new node creation. Defaults to the current document.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.comment = function( comment, ownerDocument ) {
|
|
||||||
if ( typeof comment == 'string' )
|
|
||||||
comment = ( ownerDocument ? ownerDocument.$ : document ).createComment( comment );
|
|
||||||
|
|
||||||
CKEDITOR.dom.domObject.call( this, comment );
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.comment.prototype = new CKEDITOR.dom.node();
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.comment.prototype, {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_COMMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_COMMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the outer HTML of this comment.
|
|
||||||
*
|
|
||||||
* @returns {String} The HTML `<!-- comment value -->`.
|
|
||||||
*/
|
|
||||||
getOuterHtml: function() {
|
|
||||||
return '<!--' + this.$.nodeValue + '-->';
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,316 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
|
|
||||||
* represents a DOM document.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DOM document.
|
|
||||||
*
|
|
||||||
* var document = new CKEDITOR.dom.document( document );
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.dom.domObject
|
|
||||||
* @constructor Creates a document class instance.
|
|
||||||
* @param {Object} domDocument A native DOM document.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.document = function( domDocument ) {
|
|
||||||
CKEDITOR.dom.domObject.call( this, domDocument );
|
|
||||||
};
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.dom.document )
|
|
||||||
|
|
||||||
CKEDITOR.dom.document.prototype = new CKEDITOR.dom.domObject();
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.document.prototype, {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_DOCUMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_DOCUMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends a CSS file to the document.
|
|
||||||
*
|
|
||||||
* CKEDITOR.document.appendStyleSheet( '/mystyles.css' );
|
|
||||||
*
|
|
||||||
* @param {String} cssFileUrl The CSS file URL.
|
|
||||||
*/
|
|
||||||
appendStyleSheet: function( cssFileUrl ) {
|
|
||||||
if ( this.$.createStyleSheet )
|
|
||||||
this.$.createStyleSheet( cssFileUrl );
|
|
||||||
else {
|
|
||||||
var link = new CKEDITOR.dom.element( 'link' );
|
|
||||||
link.setAttributes( {
|
|
||||||
rel: 'stylesheet',
|
|
||||||
type: 'text/css',
|
|
||||||
href: cssFileUrl
|
|
||||||
} );
|
|
||||||
|
|
||||||
this.getHead().append( link );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a CSS style sheet and inserts it into the document.
|
|
||||||
*
|
|
||||||
* @param cssStyleText {String} CSS style text.
|
|
||||||
* @returns {Object} The created DOM native style sheet object.
|
|
||||||
*/
|
|
||||||
appendStyleText: function( cssStyleText ) {
|
|
||||||
if ( this.$.createStyleSheet ) {
|
|
||||||
var styleSheet = this.$.createStyleSheet( "" );
|
|
||||||
styleSheet.cssText = cssStyleText;
|
|
||||||
} else {
|
|
||||||
var style = new CKEDITOR.dom.element( 'style', this );
|
|
||||||
style.append( new CKEDITOR.dom.text( cssStyleText, this ) );
|
|
||||||
this.getHead().append( style );
|
|
||||||
}
|
|
||||||
|
|
||||||
return styleSheet || style.$.sheet;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates {@link CKEDITOR.dom.element} instance in this document.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element}
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
createElement: function( name, attribsAndStyles ) {
|
|
||||||
var element = new CKEDITOR.dom.element( name, this );
|
|
||||||
|
|
||||||
if ( attribsAndStyles ) {
|
|
||||||
if ( attribsAndStyles.attributes )
|
|
||||||
element.setAttributes( attribsAndStyles.attributes );
|
|
||||||
|
|
||||||
if ( attribsAndStyles.styles )
|
|
||||||
element.setStyles( attribsAndStyles.styles );
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates {@link CKEDITOR.dom.text} instance in this document.
|
|
||||||
*
|
|
||||||
* @param {String} text Value of the text node.
|
|
||||||
* @returns {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
createText: function( text ) {
|
|
||||||
return new CKEDITOR.dom.text( text, this );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the selection focus to this document's window.
|
|
||||||
*/
|
|
||||||
focus: function() {
|
|
||||||
this.getWindow().focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the element that is currently designated as the active element in the document.
|
|
||||||
*
|
|
||||||
* **Note:** Only one element can be active at a time in a document.
|
|
||||||
* An active element does not necessarily have focus,
|
|
||||||
* but an element with focus is always the active element in a document.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
getActive: function() {
|
|
||||||
return new CKEDITOR.dom.element( this.$.activeElement );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an element based on its id.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getById( 'myElement' );
|
|
||||||
* alert( element.getId() ); // 'myElement'
|
|
||||||
*
|
|
||||||
* @param {String} elementId The element id.
|
|
||||||
* @returns {CKEDITOR.dom.element} The element instance, or null if not found.
|
|
||||||
*/
|
|
||||||
getById: function( elementId ) {
|
|
||||||
var $ = this.$.getElementById( elementId );
|
|
||||||
return $ ? new CKEDITOR.dom.element( $ ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a node based on its address. See {@link CKEDITOR.dom.node#getAddress}.
|
|
||||||
*
|
|
||||||
* @param {Array} address
|
|
||||||
* @param {Boolean} [normalized=false]
|
|
||||||
*/
|
|
||||||
getByAddress: function( address, normalized ) {
|
|
||||||
var $ = this.$.documentElement;
|
|
||||||
|
|
||||||
for ( var i = 0; $ && i < address.length; i++ ) {
|
|
||||||
var target = address[ i ];
|
|
||||||
|
|
||||||
if ( !normalized ) {
|
|
||||||
$ = $.childNodes[ target ];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentIndex = -1;
|
|
||||||
|
|
||||||
for ( var j = 0; j < $.childNodes.length; j++ ) {
|
|
||||||
var candidate = $.childNodes[ j ];
|
|
||||||
|
|
||||||
if ( normalized === true && candidate.nodeType == 3 && candidate.previousSibling && candidate.previousSibling.nodeType == 3 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
currentIndex++;
|
|
||||||
|
|
||||||
if ( currentIndex == target ) {
|
|
||||||
$ = candidate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ ? new CKEDITOR.dom.node( $ ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets elements list based on given tag name.
|
|
||||||
*
|
|
||||||
* @param {String} tagName The element tag name.
|
|
||||||
* @returns {CKEDITOR.dom.nodeList} The nodes list.
|
|
||||||
*/
|
|
||||||
getElementsByTag: function( tagName, namespace ) {
|
|
||||||
if ( !( CKEDITOR.env.ie && !( document.documentMode > 8 ) ) && namespace )
|
|
||||||
tagName = namespace + ':' + tagName;
|
|
||||||
return new CKEDITOR.dom.nodeList( this.$.getElementsByTagName( tagName ) );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the `<head>` element for this document.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getHead();
|
|
||||||
* alert( element.getName() ); // 'head'
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element} The `<head>` element.
|
|
||||||
*/
|
|
||||||
getHead: function() {
|
|
||||||
var head = this.$.getElementsByTagName( 'head' )[ 0 ];
|
|
||||||
if ( !head )
|
|
||||||
head = this.getDocumentElement().append( new CKEDITOR.dom.element( 'head' ), true );
|
|
||||||
else
|
|
||||||
head = new CKEDITOR.dom.element( head );
|
|
||||||
|
|
||||||
return head;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the `<body>` element for this document.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getBody();
|
|
||||||
* alert( element.getName() ); // 'body'
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element} The `<body>` element.
|
|
||||||
*/
|
|
||||||
getBody: function() {
|
|
||||||
return new CKEDITOR.dom.element( this.$.body );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the DOM document element for this document.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element} The DOM document element.
|
|
||||||
*/
|
|
||||||
getDocumentElement: function() {
|
|
||||||
return new CKEDITOR.dom.element( this.$.documentElement );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the window object that holds this document.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.window} The window object.
|
|
||||||
*/
|
|
||||||
getWindow: function() {
|
|
||||||
return new CKEDITOR.dom.window( this.$.parentWindow || this.$.defaultView );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the document contents through document.write. Note that the
|
|
||||||
* previous document contents will be lost (cleaned).
|
|
||||||
*
|
|
||||||
* document.write(
|
|
||||||
* '<html>' +
|
|
||||||
* '<head><title>Sample Doc</title></head>' +
|
|
||||||
* '<body>Document contents created by code</body>' +
|
|
||||||
* '</html>'
|
|
||||||
* );
|
|
||||||
*
|
|
||||||
* @since 3.5
|
|
||||||
* @param {String} html The HTML defining the document contents.
|
|
||||||
*/
|
|
||||||
write: function( html ) {
|
|
||||||
// Don't leave any history log in IE. (#5657)
|
|
||||||
this.$.open( 'text/html', 'replace' );
|
|
||||||
|
|
||||||
// Support for custom document.domain in IE.
|
|
||||||
//
|
|
||||||
// The script must be appended because if placed before the
|
|
||||||
// doctype, IE will go into quirks mode and mess with
|
|
||||||
// the editable, e.g. by changing its default height.
|
|
||||||
if ( CKEDITOR.env.ie )
|
|
||||||
html = html.replace( /(?:^\s*<!DOCTYPE[^>]*?>)|^/i, '$&\n<script data-cke-temp="1">(' + CKEDITOR.tools.fixDomain + ')();</script>' );
|
|
||||||
|
|
||||||
this.$.write( html );
|
|
||||||
this.$.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for `querySelectorAll`. Returns a list of elements within this document that match
|
|
||||||
* specified `selector`.
|
|
||||||
*
|
|
||||||
* **Note:** returned list is not a live collection (like a result of native `querySelectorAll`).
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String} selector
|
|
||||||
* @returns {CKEDITOR.dom.nodeList}
|
|
||||||
*/
|
|
||||||
find: function( selector ) {
|
|
||||||
return new CKEDITOR.dom.nodeList( this.$.querySelectorAll( selector ) );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for `querySelector`. Returns first element within this document that matches
|
|
||||||
* specified `selector`.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String} selector
|
|
||||||
* @returns {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
findOne: function( selector ) {
|
|
||||||
var el = this.$.querySelector( selector );
|
|
||||||
|
|
||||||
return el ? new CKEDITOR.dom.element( el ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IE8 only method. It returns document fragment which has all HTML5 elements enabled.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @private
|
|
||||||
* @returns DocumentFragment
|
|
||||||
*/
|
|
||||||
_getHtml5ShivFrag: function() {
|
|
||||||
var $frag = this.getCustomData( 'html5ShivFrag' );
|
|
||||||
|
|
||||||
if ( !$frag ) {
|
|
||||||
$frag = this.$.createDocumentFragment();
|
|
||||||
CKEDITOR.tools.enableHtml5Elements( $frag, true );
|
|
||||||
this.setCustomData( 'html5ShivFrag', $frag );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $frag;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DocumentFragment is a "lightweight" or "minimal" Document object. It is
|
|
||||||
* commonly used to extract a portion of a document's tree or to create a new
|
|
||||||
* fragment of a document. Various operations may take DocumentFragment objects
|
|
||||||
* as arguments and results in all the child nodes of the DocumentFragment being
|
|
||||||
* moved to the child list of this node.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a document fragment class instance.
|
|
||||||
* @param {Object} nodeOrDoc
|
|
||||||
* @todo example and param doc
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.documentFragment = function( nodeOrDoc ) {
|
|
||||||
nodeOrDoc = nodeOrDoc || CKEDITOR.document;
|
|
||||||
|
|
||||||
if ( nodeOrDoc.type == CKEDITOR.NODE_DOCUMENT )
|
|
||||||
this.$ = nodeOrDoc.$.createDocumentFragment();
|
|
||||||
else
|
|
||||||
this.$ = nodeOrDoc;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype, CKEDITOR.dom.element.prototype, {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts document fragment's contents after specified node.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.node} node
|
|
||||||
*/
|
|
||||||
insertAfterNode: function( node ) {
|
|
||||||
node = node.$;
|
|
||||||
node.parentNode.insertBefore( this.$, node.nextSibling );
|
|
||||||
}
|
|
||||||
}, true, { 'append': 1, 'appendBogus': 1, 'getFirst': 1, 'getLast': 1, 'getParent': 1, 'getNext': 1, 'getPrevious': 1, 'appendTo': 1, 'moveChildren': 1, 'insertBefore': 1, 'insertAfterNode': 1, 'replace': 1, 'trim': 1, 'type': 1, 'ltrim': 1, 'rtrim': 1, 'getDocument': 1, 'getChildCount': 1, 'getChild': 1, 'getChildren': 1 } );
|
|
||||||
@ -1,266 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.editor} class, which is the base
|
|
||||||
* for other classes representing DOM objects.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DOM object. This class is not intended to be used directly. It
|
|
||||||
* serves as the base class for other classes representing specific DOM
|
|
||||||
* objects.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @mixins CKEDITOR.event
|
|
||||||
* @constructor Creates a domObject class instance.
|
|
||||||
* @param {Object} nativeDomObject A native DOM object.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.domObject = function( nativeDomObject ) {
|
|
||||||
if ( nativeDomObject ) {
|
|
||||||
/**
|
|
||||||
* The native DOM object represented by this class instance.
|
|
||||||
*
|
|
||||||
* var element = new CKEDITOR.dom.element( 'span' );
|
|
||||||
* alert( element.$.nodeType ); // '1'
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Object}
|
|
||||||
*/
|
|
||||||
this.$ = nativeDomObject;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.domObject.prototype = ( function() {
|
|
||||||
// Do not define other local variables here. We want to keep the native
|
|
||||||
// listener closures as clean as possible.
|
|
||||||
|
|
||||||
var getNativeListener = function( domObject, eventName ) {
|
|
||||||
return function( domEvent ) {
|
|
||||||
// In FF, when reloading the page with the editor focused, it may
|
|
||||||
// throw an error because the CKEDITOR global is not anymore
|
|
||||||
// available. So, we check it here first. (#2923)
|
|
||||||
if ( typeof CKEDITOR != 'undefined' )
|
|
||||||
domObject.fire( eventName, new CKEDITOR.dom.event( domEvent ) );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the private `_` object which is bound to the native
|
|
||||||
* DOM object using {@link #getCustomData}.
|
|
||||||
*
|
|
||||||
* var elementA = new CKEDITOR.dom.element( nativeElement );
|
|
||||||
* elementA.getPrivate().value = 1;
|
|
||||||
* ...
|
|
||||||
* var elementB = new CKEDITOR.dom.element( nativeElement );
|
|
||||||
* elementB.getPrivate().value; // 1
|
|
||||||
*
|
|
||||||
* @returns {Object} The private object.
|
|
||||||
*/
|
|
||||||
getPrivate: function() {
|
|
||||||
var priv;
|
|
||||||
|
|
||||||
// Get the main private object from the custom data. Create it if not defined.
|
|
||||||
if ( !( priv = this.getCustomData( '_' ) ) )
|
|
||||||
this.setCustomData( '_', ( priv = {} ) );
|
|
||||||
|
|
||||||
return priv;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Docs inherited from event.
|
|
||||||
on: function( eventName ) {
|
|
||||||
// We customize the "on" function here. The basic idea is that we'll have
|
|
||||||
// only one listener for a native event, which will then call all listeners
|
|
||||||
// set to the event.
|
|
||||||
|
|
||||||
// Get the listeners holder object.
|
|
||||||
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
|
|
||||||
|
|
||||||
if ( !nativeListeners ) {
|
|
||||||
nativeListeners = {};
|
|
||||||
this.setCustomData( '_cke_nativeListeners', nativeListeners );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have a listener for that event.
|
|
||||||
if ( !nativeListeners[ eventName ] ) {
|
|
||||||
var listener = nativeListeners[ eventName ] = getNativeListener( this, eventName );
|
|
||||||
|
|
||||||
if ( this.$.addEventListener )
|
|
||||||
this.$.addEventListener( eventName, listener, !!CKEDITOR.event.useCapture );
|
|
||||||
else if ( this.$.attachEvent )
|
|
||||||
this.$.attachEvent( 'on' + eventName, listener );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the original implementation.
|
|
||||||
return CKEDITOR.event.prototype.on.apply( this, arguments );
|
|
||||||
},
|
|
||||||
|
|
||||||
// Docs inherited from event.
|
|
||||||
removeListener: function( eventName ) {
|
|
||||||
// Call the original implementation.
|
|
||||||
CKEDITOR.event.prototype.removeListener.apply( this, arguments );
|
|
||||||
|
|
||||||
// If we don't have listeners for this event, clean the DOM up.
|
|
||||||
if ( !this.hasListeners( eventName ) ) {
|
|
||||||
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
|
|
||||||
var listener = nativeListeners && nativeListeners[ eventName ];
|
|
||||||
if ( listener ) {
|
|
||||||
if ( this.$.removeEventListener )
|
|
||||||
this.$.removeEventListener( eventName, listener, false );
|
|
||||||
else if ( this.$.detachEvent )
|
|
||||||
this.$.detachEvent( 'on' + eventName, listener );
|
|
||||||
|
|
||||||
delete nativeListeners[ eventName ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes any listener set on this object.
|
|
||||||
*
|
|
||||||
* To avoid memory leaks we must assure that there are no
|
|
||||||
* references left after the object is no longer needed.
|
|
||||||
*/
|
|
||||||
removeAllListeners: function() {
|
|
||||||
var nativeListeners = this.getCustomData( '_cke_nativeListeners' );
|
|
||||||
for ( var eventName in nativeListeners ) {
|
|
||||||
var listener = nativeListeners[ eventName ];
|
|
||||||
if ( this.$.detachEvent )
|
|
||||||
this.$.detachEvent( 'on' + eventName, listener );
|
|
||||||
else if ( this.$.removeEventListener )
|
|
||||||
this.$.removeEventListener( eventName, listener, false );
|
|
||||||
|
|
||||||
delete nativeListeners[ eventName ];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove events from events object so fire() method will not call
|
|
||||||
// listeners (#11400).
|
|
||||||
CKEDITOR.event.prototype.removeAllListeners.call( this );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
|
|
||||||
( function( domObjectProto ) {
|
|
||||||
var customData = {};
|
|
||||||
|
|
||||||
CKEDITOR.on( 'reset', function() {
|
|
||||||
customData = {};
|
|
||||||
} );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the specified object is equal to the current object.
|
|
||||||
*
|
|
||||||
* var doc = new CKEDITOR.dom.document( document );
|
|
||||||
* alert( doc.equals( CKEDITOR.document ) ); // true
|
|
||||||
* alert( doc == CKEDITOR.document ); // false
|
|
||||||
*
|
|
||||||
* @param {Object} object The object to compare with the current object.
|
|
||||||
* @returns {Boolean} `true` if the object is equal.
|
|
||||||
*/
|
|
||||||
domObjectProto.equals = function( object ) {
|
|
||||||
// Try/Catch to avoid IE permission error when object is from different document.
|
|
||||||
try {
|
|
||||||
return ( object && object.$ === this.$ );
|
|
||||||
} catch ( er ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a data slot value for this object. These values are shared by all
|
|
||||||
* instances pointing to that same DOM object.
|
|
||||||
*
|
|
||||||
* **Note:** The created data slot is only guarantied to be available on this unique dom node,
|
|
||||||
* thus any wish to continue access it from other element clones (either created by
|
|
||||||
* clone node or from `innerHtml`) will fail, for such usage, please use
|
|
||||||
* {@link CKEDITOR.dom.element#setAttribute} instead.
|
|
||||||
*
|
|
||||||
* **Note**: This method does not work on text nodes prior to Internet Explorer 9.
|
|
||||||
*
|
|
||||||
* var element = new CKEDITOR.dom.element( 'span' );
|
|
||||||
* element.setCustomData( 'hasCustomData', true );
|
|
||||||
*
|
|
||||||
* @param {String} key A key used to identify the data slot.
|
|
||||||
* @param {Object} value The value to set to the data slot.
|
|
||||||
* @returns {CKEDITOR.dom.domObject} This DOM object instance.
|
|
||||||
* @chainable
|
|
||||||
*/
|
|
||||||
domObjectProto.setCustomData = function( key, value ) {
|
|
||||||
var expandoNumber = this.getUniqueId(),
|
|
||||||
dataSlot = customData[ expandoNumber ] || ( customData[ expandoNumber ] = {} );
|
|
||||||
|
|
||||||
dataSlot[ key ] = value;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value set to a data slot in this object.
|
|
||||||
*
|
|
||||||
* var element = new CKEDITOR.dom.element( 'span' );
|
|
||||||
* alert( element.getCustomData( 'hasCustomData' ) ); // e.g. 'true'
|
|
||||||
* alert( element.getCustomData( 'nonExistingKey' ) ); // null
|
|
||||||
*
|
|
||||||
* @param {String} key The key used to identify the data slot.
|
|
||||||
* @returns {Object} This value set to the data slot.
|
|
||||||
*/
|
|
||||||
domObjectProto.getCustomData = function( key ) {
|
|
||||||
var expandoNumber = this.$[ 'data-cke-expando' ],
|
|
||||||
dataSlot = expandoNumber && customData[ expandoNumber ];
|
|
||||||
|
|
||||||
return ( dataSlot && key in dataSlot ) ? dataSlot[ key ] : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the value in data slot under given `key`.
|
|
||||||
*
|
|
||||||
* @param {String} key
|
|
||||||
* @returns {Object} Removed value or `null` if not found.
|
|
||||||
*/
|
|
||||||
domObjectProto.removeCustomData = function( key ) {
|
|
||||||
var expandoNumber = this.$[ 'data-cke-expando' ],
|
|
||||||
dataSlot = expandoNumber && customData[ expandoNumber ],
|
|
||||||
retval, hadKey;
|
|
||||||
|
|
||||||
if ( dataSlot ) {
|
|
||||||
retval = dataSlot[ key ];
|
|
||||||
hadKey = key in dataSlot;
|
|
||||||
delete dataSlot[ key ];
|
|
||||||
}
|
|
||||||
|
|
||||||
return hadKey ? retval : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes any data stored on this object.
|
|
||||||
* To avoid memory leaks we must assure that there are no
|
|
||||||
* references left after the object is no longer needed.
|
|
||||||
*/
|
|
||||||
domObjectProto.clearCustomData = function() {
|
|
||||||
// Clear all event listeners
|
|
||||||
this.removeAllListeners();
|
|
||||||
|
|
||||||
var expandoNumber = this.$[ 'data-cke-expando' ];
|
|
||||||
expandoNumber && delete customData[ expandoNumber ];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an ID that can be used to identify this DOM object in
|
|
||||||
* the running session.
|
|
||||||
*
|
|
||||||
* **Note**: This method does not work on text nodes prior to Internet Explorer 9.
|
|
||||||
*
|
|
||||||
* @returns {Number} A unique ID.
|
|
||||||
*/
|
|
||||||
domObjectProto.getUniqueId = function() {
|
|
||||||
return this.$[ 'data-cke-expando' ] || ( this.$[ 'data-cke-expando' ] = CKEDITOR.tools.getNextNumber() );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implement CKEDITOR.event.
|
|
||||||
CKEDITOR.event.implementOn( domObjectProto );
|
|
||||||
|
|
||||||
} )( CKEDITOR.dom.domObject.prototype );
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,251 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
|
|
||||||
var pathBlockLimitElements = {},
|
|
||||||
pathBlockElements = {},
|
|
||||||
tag;
|
|
||||||
|
|
||||||
// Elements that are considered the "Block limit" in an element path.
|
|
||||||
for ( tag in CKEDITOR.dtd.$blockLimit ) {
|
|
||||||
// Exclude from list roots.
|
|
||||||
if ( !( tag in CKEDITOR.dtd.$list ) )
|
|
||||||
pathBlockLimitElements[ tag ] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Elements that are considered the "End level Block" in an element path.
|
|
||||||
for ( tag in CKEDITOR.dtd.$block ) {
|
|
||||||
// Exclude block limits, and empty block element, e.g. hr.
|
|
||||||
if ( !( tag in CKEDITOR.dtd.$blockLimit || tag in CKEDITOR.dtd.$empty ) )
|
|
||||||
pathBlockElements[ tag ] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if an element contains any block element.
|
|
||||||
function checkHasBlock( element ) {
|
|
||||||
var childNodes = element.getChildren();
|
|
||||||
|
|
||||||
for ( var i = 0, count = childNodes.count(); i < count; i++ ) {
|
|
||||||
var child = childNodes.getItem( i );
|
|
||||||
|
|
||||||
if ( child.type == CKEDITOR.NODE_ELEMENT && CKEDITOR.dtd.$block[ child.getName() ] )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the list of nodes walked from the start node up to the editable element of the editor.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates an element path class instance.
|
|
||||||
* @param {CKEDITOR.dom.element} startNode From which the path should start.
|
|
||||||
* @param {CKEDITOR.dom.element} root To which element the path should stop, defaults to the `body` element.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.elementPath = function( startNode, root ) {
|
|
||||||
var block = null,
|
|
||||||
blockLimit = null,
|
|
||||||
elements = [],
|
|
||||||
e = startNode,
|
|
||||||
elementName;
|
|
||||||
|
|
||||||
// Backward compact.
|
|
||||||
root = root || startNode.getDocument().getBody();
|
|
||||||
|
|
||||||
do {
|
|
||||||
if ( e.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
elements.push( e );
|
|
||||||
|
|
||||||
if ( !this.lastElement ) {
|
|
||||||
this.lastElement = e;
|
|
||||||
|
|
||||||
// If an object or non-editable element is fully selected at the end of the element path,
|
|
||||||
// it must not become the block limit.
|
|
||||||
if ( e.is( CKEDITOR.dtd.$object ) || e.getAttribute( 'contenteditable' ) == 'false' )
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( e.equals( root ) )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ( !blockLimit ) {
|
|
||||||
elementName = e.getName();
|
|
||||||
|
|
||||||
// First editable element becomes a block limit, because it cannot be split.
|
|
||||||
if ( e.getAttribute( 'contenteditable' ) == 'true' )
|
|
||||||
blockLimit = e;
|
|
||||||
// "Else" because element cannot be both - block and block levelimit.
|
|
||||||
else if ( !block && pathBlockElements[ elementName ] )
|
|
||||||
block = e;
|
|
||||||
|
|
||||||
if ( pathBlockLimitElements[ elementName ] ) {
|
|
||||||
// End level DIV is considered as the block, if no block is available. (#525)
|
|
||||||
// But it must NOT be the root element (checked above).
|
|
||||||
if ( !block && elementName == 'div' && !checkHasBlock( e ) )
|
|
||||||
block = e;
|
|
||||||
else
|
|
||||||
blockLimit = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ( ( e = e.getParent() ) );
|
|
||||||
|
|
||||||
// Block limit defaults to root.
|
|
||||||
if ( !blockLimit )
|
|
||||||
blockLimit = root;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* First non-empty block element which:
|
|
||||||
*
|
|
||||||
* * is not a {@link CKEDITOR.dtd#$blockLimit},
|
|
||||||
* * or is a `div` which does not contain block elements and is not a `root`.
|
|
||||||
*
|
|
||||||
* This means a first, splittable block in elements path.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
this.block = block;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See the {@link CKEDITOR.dtd#$blockLimit} description.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
this.blockLimit = blockLimit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root of the elements path - `root` argument passed to class constructor or a `body` element.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.dom.element}
|
|
||||||
*/
|
|
||||||
this.root = root;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array of elements (from `startNode` to `root`) in the path.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.dom.element[]}
|
|
||||||
*/
|
|
||||||
this.elements = elements;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last element of the elements path - `startNode` or its parent.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.dom.element} lastElement
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
} )();
|
|
||||||
|
|
||||||
CKEDITOR.dom.elementPath.prototype = {
|
|
||||||
/**
|
|
||||||
* Compares this element path with another one.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.elementPath} otherPath The elementPath object to be
|
|
||||||
* compared with this one.
|
|
||||||
* @returns {Boolean} `true` if the paths are equal, containing the same
|
|
||||||
* number of elements and the same elements in the same order.
|
|
||||||
*/
|
|
||||||
compare: function( otherPath ) {
|
|
||||||
var thisElements = this.elements;
|
|
||||||
var otherElements = otherPath && otherPath.elements;
|
|
||||||
|
|
||||||
if ( !otherElements || thisElements.length != otherElements.length )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for ( var i = 0; i < thisElements.length; i++ ) {
|
|
||||||
if ( !thisElements[ i ].equals( otherElements[ i ] ) )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search the path elements that meets the specified criteria.
|
|
||||||
*
|
|
||||||
* @param {String/Array/Function/Object/CKEDITOR.dom.element} query The criteria that can be
|
|
||||||
* either a tag name, list (array and object) of tag names, element or an node evaluator function.
|
|
||||||
* @param {Boolean} [excludeRoot] Not taking path root element into consideration.
|
|
||||||
* @param {Boolean} [fromTop] Search start from the topmost element instead of bottom.
|
|
||||||
* @returns {CKEDITOR.dom.element} The first matched dom element or `null`.
|
|
||||||
*/
|
|
||||||
contains: function( query, excludeRoot, fromTop ) {
|
|
||||||
var evaluator;
|
|
||||||
if ( typeof query == 'string' )
|
|
||||||
evaluator = function( node ) {
|
|
||||||
return node.getName() == query;
|
|
||||||
};
|
|
||||||
if ( query instanceof CKEDITOR.dom.element )
|
|
||||||
evaluator = function( node ) {
|
|
||||||
return node.equals( query );
|
|
||||||
};
|
|
||||||
else if ( CKEDITOR.tools.isArray( query ) )
|
|
||||||
evaluator = function( node ) {
|
|
||||||
return CKEDITOR.tools.indexOf( query, node.getName() ) > -1;
|
|
||||||
};
|
|
||||||
else if ( typeof query == 'function' )
|
|
||||||
evaluator = query;
|
|
||||||
else if ( typeof query == 'object' )
|
|
||||||
evaluator = function( node ) {
|
|
||||||
return node.getName() in query;
|
|
||||||
};
|
|
||||||
|
|
||||||
var elements = this.elements,
|
|
||||||
length = elements.length;
|
|
||||||
excludeRoot && length--;
|
|
||||||
|
|
||||||
if ( fromTop ) {
|
|
||||||
elements = Array.prototype.slice.call( elements, 0 );
|
|
||||||
elements.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var i = 0; i < length; i++ ) {
|
|
||||||
if ( evaluator( elements[ i ] ) )
|
|
||||||
return elements[ i ];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the elements path is the proper context for the specified
|
|
||||||
* tag name in the DTD.
|
|
||||||
*
|
|
||||||
* @param {String} tag The tag name.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
isContextFor: function( tag ) {
|
|
||||||
var holder;
|
|
||||||
|
|
||||||
// Check for block context.
|
|
||||||
if ( tag in CKEDITOR.dtd.$block ) {
|
|
||||||
// Indeterminate elements which are not subjected to be splitted or surrounded must be checked first.
|
|
||||||
var inter = this.contains( CKEDITOR.dtd.$intermediate );
|
|
||||||
holder = inter || ( this.root.equals( this.block ) && this.block ) || this.blockLimit;
|
|
||||||
return !!holder.getDtd()[ tag ];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the text direction for this elements path.
|
|
||||||
*
|
|
||||||
* @returns {'ltr'/'rtl'}
|
|
||||||
*/
|
|
||||||
direction: function() {
|
|
||||||
var directionNode = this.block || this.blockLimit || this.root;
|
|
||||||
return directionNode.getDirection( 1 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,208 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.event} class, which
|
|
||||||
* represents the a native DOM event object.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a native DOM event object.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates an event class instance.
|
|
||||||
* @param {Object} domEvent A native DOM event object.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.event = function( domEvent ) {
|
|
||||||
/**
|
|
||||||
* The native DOM event object represented by this class instance.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.$ = domEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.event.prototype = {
|
|
||||||
/**
|
|
||||||
* Gets the key code associated to the event.
|
|
||||||
*
|
|
||||||
* alert( event.getKey() ); // '65' is 'a' has been pressed
|
|
||||||
*
|
|
||||||
* @returns {Number} The key code.
|
|
||||||
*/
|
|
||||||
getKey: function() {
|
|
||||||
return this.$.keyCode || this.$.which;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a number represeting the combination of the keys pressed during the
|
|
||||||
* event. It is the sum with the current key code and the {@link CKEDITOR#CTRL},
|
|
||||||
* {@link CKEDITOR#SHIFT} and {@link CKEDITOR#ALT} constants.
|
|
||||||
*
|
|
||||||
* alert( event.getKeystroke() == 65 ); // 'a' key
|
|
||||||
* alert( event.getKeystroke() == CKEDITOR.CTRL + 65 ); // CTRL + 'a' key
|
|
||||||
* alert( event.getKeystroke() == CKEDITOR.CTRL + CKEDITOR.SHIFT + 65 ); // CTRL + SHIFT + 'a' key
|
|
||||||
*
|
|
||||||
* @returns {Number} The number representing the keys combination.
|
|
||||||
*/
|
|
||||||
getKeystroke: function() {
|
|
||||||
var keystroke = this.getKey();
|
|
||||||
|
|
||||||
if ( this.$.ctrlKey || this.$.metaKey )
|
|
||||||
keystroke += CKEDITOR.CTRL;
|
|
||||||
|
|
||||||
if ( this.$.shiftKey )
|
|
||||||
keystroke += CKEDITOR.SHIFT;
|
|
||||||
|
|
||||||
if ( this.$.altKey )
|
|
||||||
keystroke += CKEDITOR.ALT;
|
|
||||||
|
|
||||||
return keystroke;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevents the original behavior of the event to happen. It can optionally
|
|
||||||
* stop propagating the event in the event chain.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getById( 'myElement' );
|
|
||||||
* element.on( 'click', function( ev ) {
|
|
||||||
* // The DOM event object is passed by the 'data' property.
|
|
||||||
* var domEvent = ev.data;
|
|
||||||
* // Prevent the click to chave any effect in the element.
|
|
||||||
* domEvent.preventDefault();
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {Boolean} [stopPropagation=false] Stop propagating this event in the
|
|
||||||
* event chain.
|
|
||||||
*/
|
|
||||||
preventDefault: function( stopPropagation ) {
|
|
||||||
var $ = this.$;
|
|
||||||
if ( $.preventDefault )
|
|
||||||
$.preventDefault();
|
|
||||||
else
|
|
||||||
$.returnValue = false;
|
|
||||||
|
|
||||||
if ( stopPropagation )
|
|
||||||
this.stopPropagation();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops this event propagation in the event chain.
|
|
||||||
*/
|
|
||||||
stopPropagation: function() {
|
|
||||||
var $ = this.$;
|
|
||||||
if ( $.stopPropagation )
|
|
||||||
$.stopPropagation();
|
|
||||||
else
|
|
||||||
$.cancelBubble = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the DOM node where the event was targeted to.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getById( 'myElement' );
|
|
||||||
* element.on( 'click', function( ev ) {
|
|
||||||
* // The DOM event object is passed by the 'data' property.
|
|
||||||
* var domEvent = ev.data;
|
|
||||||
* // Add a CSS class to the event target.
|
|
||||||
* domEvent.getTarget().addClass( 'clicked' );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node} The target DOM node.
|
|
||||||
*/
|
|
||||||
getTarget: function() {
|
|
||||||
var rawNode = this.$.target || this.$.srcElement;
|
|
||||||
return rawNode ? new CKEDITOR.dom.node( rawNode ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an integer value that indicates the current processing phase of an event.
|
|
||||||
* For browsers that doesn't support event phase, {@link CKEDITOR#EVENT_PHASE_AT_TARGET} is always returned.
|
|
||||||
*
|
|
||||||
* @returns {Number} One of {@link CKEDITOR#EVENT_PHASE_CAPTURING},
|
|
||||||
* {@link CKEDITOR#EVENT_PHASE_AT_TARGET}, or {@link CKEDITOR#EVENT_PHASE_BUBBLING}.
|
|
||||||
*/
|
|
||||||
getPhase: function() {
|
|
||||||
return this.$.eventPhase || 2;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the coordinates of the mouse pointer relative to the top-left
|
|
||||||
* corner of the document, in mouse related event.
|
|
||||||
*
|
|
||||||
* element.on( 'mousemouse', function( ev ) {
|
|
||||||
* var pageOffset = ev.data.getPageOffset();
|
|
||||||
* alert( pageOffset.x ); // page offset X
|
|
||||||
* alert( pageOffset.y ); // page offset Y
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @returns {Object} The object contains the position.
|
|
||||||
* @returns {Number} return.x
|
|
||||||
* @returns {Number} return.y
|
|
||||||
*/
|
|
||||||
getPageOffset : function() {
|
|
||||||
var doc = this.getTarget().getDocument().$;
|
|
||||||
var pageX = this.$.pageX || this.$.clientX + ( doc.documentElement.scrollLeft || doc.body.scrollLeft );
|
|
||||||
var pageY = this.$.pageY || this.$.clientY + ( doc.documentElement.scrollTop || doc.body.scrollTop );
|
|
||||||
return { x : pageX, y : pageY };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// For the followind constants, we need to go over the Unicode boundaries
|
|
||||||
// (0x10FFFF) to avoid collision.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CTRL key (0x110000).
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=0x110000]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.CTRL = 0x110000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHIFT key (0x220000).
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=0x220000]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.SHIFT = 0x220000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ALT key (0x440000).
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=0x440000]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.ALT = 0x440000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capturing phase.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=1]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.EVENT_PHASE_CAPTURING = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event at target.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=2]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.EVENT_PHASE_AT_TARGET = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bubbling phase.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=3]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.EVENT_PHASE_BUBBLING = 3;
|
|
||||||
@ -1,500 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
* File overview: DOM iterator, which iterates over list items, lines and paragraphs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Represents iterator class. It can be used to iterate
|
|
||||||
* over all elements (or even text nodes in case of {@link #enlargeBr} set to `false`)
|
|
||||||
* which establish "paragraph-like" spaces within passed range.
|
|
||||||
*
|
|
||||||
* // <h1>[foo</h1><p>bar]</p>
|
|
||||||
* var iterator = range.createIterator();
|
|
||||||
* iterator.getNextParagraph(); // h1 element
|
|
||||||
* iterator.getNextParagraph(); // p element
|
|
||||||
*
|
|
||||||
* // <ul><li>[foo</li><li>bar]</li>
|
|
||||||
* // With enforceRealBlocks set to false iterator will return two list item elements.
|
|
||||||
* // With enforceRealBlocks set to true iterator will return two paragraphs and the DOM will be changed to:
|
|
||||||
* // <ul><li><p>foo</p></li><li><p>bar</p></li>
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.dom.iterator
|
|
||||||
* @constructor Creates an iterator class instance.
|
|
||||||
* @param {CKEDITOR.dom.range} range
|
|
||||||
*/
|
|
||||||
function iterator( range ) {
|
|
||||||
if ( arguments.length < 1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.range = range;
|
|
||||||
this.forceBrBreak = 0;
|
|
||||||
|
|
||||||
// (#3730).
|
|
||||||
/**
|
|
||||||
* Whether include `<br>`s into the enlarged range. Should be
|
|
||||||
* set to `false` when using iterator in {@link CKEDITOR#ENTER_BR} mode.
|
|
||||||
*
|
|
||||||
* @property {Boolean} [enlargeBr=true]
|
|
||||||
*/
|
|
||||||
this.enlargeBr = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether iterator should create transformable block
|
|
||||||
* if the current one contains text and it cannot be transformed.
|
|
||||||
* For example new blocks will be established in elements like
|
|
||||||
* `<li>` or `<td>`.
|
|
||||||
*
|
|
||||||
* @property {Boolean} [enforceRealBlocks=false]
|
|
||||||
*/
|
|
||||||
this.enforceRealBlocks = 0;
|
|
||||||
|
|
||||||
this._ || ( this._ = {} );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default iterator's filter. It is set only for nested iterators.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.filter} filter
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterator's active filter. It is set by the {@link #getNextParagraph} method
|
|
||||||
* when it enters nested editable.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @readonly
|
|
||||||
* @property {CKEDITOR.filter} activeFilter
|
|
||||||
*/
|
|
||||||
|
|
||||||
var beginWhitespaceRegex = /^[\r\n\t ]+$/,
|
|
||||||
// Ignore bookmark nodes.(#3783)
|
|
||||||
bookmarkGuard = CKEDITOR.dom.walker.bookmark( false, true ),
|
|
||||||
whitespacesGuard = CKEDITOR.dom.walker.whitespaces( true ),
|
|
||||||
skipGuard = function( node ) {
|
|
||||||
return bookmarkGuard( node ) && whitespacesGuard( node );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get a reference for the next element, bookmark nodes are skipped.
|
|
||||||
function getNextSourceNode( node, startFromSibling, lastNode ) {
|
|
||||||
var next = node.getNextSourceNode( startFromSibling, null, lastNode );
|
|
||||||
while ( !bookmarkGuard( next ) )
|
|
||||||
next = next.getNextSourceNode( startFromSibling, null, lastNode );
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator.prototype = {
|
|
||||||
/**
|
|
||||||
* Returns next paragraph-like element or `null` if reached the end of range.
|
|
||||||
*
|
|
||||||
* @param {String} [blockTag='p'] Name of a block element which will be established by
|
|
||||||
* iterator in block-less elements (see {@link #enforceRealBlocks}).
|
|
||||||
*/
|
|
||||||
getNextParagraph: function( blockTag ) {
|
|
||||||
// The block element to be returned.
|
|
||||||
var block;
|
|
||||||
|
|
||||||
// The range object used to identify the paragraph contents.
|
|
||||||
var range;
|
|
||||||
|
|
||||||
// Indicats that the current element in the loop is the last one.
|
|
||||||
var isLast;
|
|
||||||
|
|
||||||
// Instructs to cleanup remaining BRs.
|
|
||||||
var removePreviousBr, removeLastBr;
|
|
||||||
|
|
||||||
blockTag = blockTag || 'p';
|
|
||||||
|
|
||||||
// We're iterating over nested editable.
|
|
||||||
if ( this._.nestedEditable ) {
|
|
||||||
// Get next block from nested iterator and returns it if was found.
|
|
||||||
block = this._.nestedEditable.iterator.getNextParagraph( blockTag );
|
|
||||||
if ( block ) {
|
|
||||||
// Inherit activeFilter from the nested iterator.
|
|
||||||
this.activeFilter = this._.nestedEditable.iterator.activeFilter;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No block in nested iterator means that we reached the end of the nested editable.
|
|
||||||
// Reset the active filter to the default filter (or undefined if this iterator didn't have it).
|
|
||||||
this.activeFilter = this.filter;
|
|
||||||
|
|
||||||
// Try to find next nested editable or get back to parent (this) iterator.
|
|
||||||
if ( startNestedEditableIterator( this, blockTag, this._.nestedEditable.container, this._.nestedEditable.remaining ) ) {
|
|
||||||
// Inherit activeFilter from the nested iterator.
|
|
||||||
this.activeFilter = this._.nestedEditable.iterator.activeFilter;
|
|
||||||
return this._.nestedEditable.iterator.getNextParagraph( blockTag );
|
|
||||||
} else
|
|
||||||
this._.nestedEditable = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block-less range should be checked first.
|
|
||||||
if ( !this.range.root.getDtd()[ blockTag ] )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// This is the first iteration. Let's initialize it.
|
|
||||||
if ( !this._.started )
|
|
||||||
range = startIterator.call( this );
|
|
||||||
|
|
||||||
var currentNode = this._.nextNode,
|
|
||||||
lastNode = this._.lastNode;
|
|
||||||
|
|
||||||
this._.nextNode = null;
|
|
||||||
while ( currentNode ) {
|
|
||||||
// closeRange indicates that a paragraph boundary has been found,
|
|
||||||
// so the range can be closed.
|
|
||||||
var closeRange = 0,
|
|
||||||
parentPre = currentNode.hasAscendant( 'pre' );
|
|
||||||
|
|
||||||
// includeNode indicates that the current node is good to be part
|
|
||||||
// of the range. By default, any non-element node is ok for it.
|
|
||||||
var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
|
|
||||||
continueFromSibling = 0;
|
|
||||||
|
|
||||||
// If it is an element node, let's check if it can be part of the range.
|
|
||||||
if ( !includeNode ) {
|
|
||||||
var nodeName = currentNode.getName();
|
|
||||||
|
|
||||||
// Non-editable block was found - return it and move to processing
|
|
||||||
// its nested editables if they exist.
|
|
||||||
if ( CKEDITOR.dtd.$block[ nodeName ] && currentNode.getAttribute( 'contenteditable' ) == 'false' ) {
|
|
||||||
block = currentNode;
|
|
||||||
|
|
||||||
// Setup iterator for first of nested editables.
|
|
||||||
// If there's no editable, then algorithm will move to next element after current block.
|
|
||||||
startNestedEditableIterator( this, blockTag, block );
|
|
||||||
|
|
||||||
// Gets us straight to the end of getParagraph() because block variable is set.
|
|
||||||
break;
|
|
||||||
} else if ( currentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
|
|
||||||
// <br> boundaries must be part of the range. It will
|
|
||||||
// happen only if ForceBrBreak.
|
|
||||||
if ( nodeName == 'br' )
|
|
||||||
includeNode = 1;
|
|
||||||
else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' ) {
|
|
||||||
// If we have found an empty block, and haven't started
|
|
||||||
// the range yet, it means we must return this block.
|
|
||||||
block = currentNode;
|
|
||||||
isLast = currentNode.equals( lastNode );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The range must finish right before the boundary,
|
|
||||||
// including possibly skipped empty spaces. (#1603)
|
|
||||||
if ( range ) {
|
|
||||||
range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
|
|
||||||
|
|
||||||
// The found boundary must be set as the next one at this
|
|
||||||
// point. (#1717)
|
|
||||||
if ( nodeName != 'br' )
|
|
||||||
this._.nextNode = currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
closeRange = 1;
|
|
||||||
} else {
|
|
||||||
// If we have child nodes, let's check them.
|
|
||||||
if ( currentNode.getFirst() ) {
|
|
||||||
// If we don't have a range yet, let's start it.
|
|
||||||
if ( !range ) {
|
|
||||||
range = this.range.clone();
|
|
||||||
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = currentNode.getFirst();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
includeNode = 1;
|
|
||||||
}
|
|
||||||
} else if ( currentNode.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
// Ignore normal whitespaces (i.e. not including or
|
|
||||||
// other unicode whitespaces) before/after a block node.
|
|
||||||
if ( beginWhitespaceRegex.test( currentNode.getText() ) )
|
|
||||||
includeNode = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The current node is good to be part of the range and we are
|
|
||||||
// starting a new range, initialize it first.
|
|
||||||
if ( includeNode && !range ) {
|
|
||||||
range = this.range.clone();
|
|
||||||
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
|
|
||||||
}
|
|
||||||
|
|
||||||
// The last node has been found.
|
|
||||||
isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
|
|
||||||
|
|
||||||
// If we are in an element boundary, let's check if it is time
|
|
||||||
// to close the range, otherwise we include the parent within it.
|
|
||||||
if ( range && !closeRange ) {
|
|
||||||
while ( !currentNode.getNext( skipGuard ) && !isLast ) {
|
|
||||||
var parentNode = currentNode.getParent();
|
|
||||||
|
|
||||||
if ( parentNode.isBlockBoundary( this.forceBrBreak && !parentPre && { br: 1 } ) ) {
|
|
||||||
closeRange = 1;
|
|
||||||
includeNode = 0;
|
|
||||||
isLast = isLast || ( parentNode.equals( lastNode ) );
|
|
||||||
// Make sure range includes bookmarks at the end of the block. (#7359)
|
|
||||||
range.setEndAt( parentNode, CKEDITOR.POSITION_BEFORE_END );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = parentNode;
|
|
||||||
includeNode = 1;
|
|
||||||
isLast = ( currentNode.equals( lastNode ) );
|
|
||||||
continueFromSibling = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now finally include the node.
|
|
||||||
if ( includeNode )
|
|
||||||
range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
|
|
||||||
|
|
||||||
currentNode = getNextSourceNode( currentNode, continueFromSibling, lastNode );
|
|
||||||
isLast = !currentNode;
|
|
||||||
|
|
||||||
// We have found a block boundary. Let's close the range and move out of the
|
|
||||||
// loop.
|
|
||||||
if ( isLast || ( closeRange && range ) )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, based on the processed range, look for (or create) the block to be returned.
|
|
||||||
if ( !block ) {
|
|
||||||
// If no range has been found, this is the end.
|
|
||||||
if ( !range ) {
|
|
||||||
this._.docEndMarker && this._.docEndMarker.remove();
|
|
||||||
this._.nextNode = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var startPath = new CKEDITOR.dom.elementPath( range.startContainer, range.root );
|
|
||||||
var startBlockLimit = startPath.blockLimit,
|
|
||||||
checkLimits = { div: 1, th: 1, td: 1 };
|
|
||||||
block = startPath.block;
|
|
||||||
|
|
||||||
if ( !block && startBlockLimit && !this.enforceRealBlocks && checkLimits[ startBlockLimit.getName() ] && range.checkStartOfBlock() && range.checkEndOfBlock() && !startBlockLimit.equals( range.root ) )
|
|
||||||
block = startBlockLimit;
|
|
||||||
else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) ) {
|
|
||||||
// Create the fixed block.
|
|
||||||
block = this.range.document.createElement( blockTag );
|
|
||||||
|
|
||||||
// Move the contents of the temporary range to the fixed block.
|
|
||||||
range.extractContents().appendTo( block );
|
|
||||||
block.trim();
|
|
||||||
|
|
||||||
// Insert the fixed block into the DOM.
|
|
||||||
range.insertNode( block );
|
|
||||||
|
|
||||||
removePreviousBr = removeLastBr = true;
|
|
||||||
} else if ( block.getName() != 'li' ) {
|
|
||||||
// If the range doesn't includes the entire contents of the
|
|
||||||
// block, we must split it, isolating the range in a dedicated
|
|
||||||
// block.
|
|
||||||
if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() ) {
|
|
||||||
// The resulting block will be a clone of the current one.
|
|
||||||
block = block.clone( false );
|
|
||||||
|
|
||||||
// Extract the range contents, moving it to the new block.
|
|
||||||
range.extractContents().appendTo( block );
|
|
||||||
block.trim();
|
|
||||||
|
|
||||||
// Split the block. At this point, the range will be in the
|
|
||||||
// right position for our intents.
|
|
||||||
var splitInfo = range.splitBlock();
|
|
||||||
|
|
||||||
removePreviousBr = !splitInfo.wasStartOfBlock;
|
|
||||||
removeLastBr = !splitInfo.wasEndOfBlock;
|
|
||||||
|
|
||||||
// Insert the new block into the DOM.
|
|
||||||
range.insertNode( block );
|
|
||||||
}
|
|
||||||
} else if ( !isLast ) {
|
|
||||||
// LIs are returned as is, with all their children (due to the
|
|
||||||
// nested lists). But, the next node is the node right after
|
|
||||||
// the current range, which could be an <li> child (nested
|
|
||||||
// lists) or the next sibling <li>.
|
|
||||||
|
|
||||||
this._.nextNode = ( block.equals( lastNode ) ? null : getNextSourceNode( range.getBoundaryNodes().endNode, 1, lastNode ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( removePreviousBr ) {
|
|
||||||
var previousSibling = block.getPrevious();
|
|
||||||
if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
if ( previousSibling.getName() == 'br' )
|
|
||||||
previousSibling.remove();
|
|
||||||
else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
|
|
||||||
previousSibling.getLast().remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( removeLastBr ) {
|
|
||||||
var lastChild = block.getLast();
|
|
||||||
if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' ) {
|
|
||||||
// Remove br filler on browser which do not need it.
|
|
||||||
if ( !CKEDITOR.env.needsBrFiller || lastChild.getPrevious( bookmarkGuard ) || lastChild.getNext( bookmarkGuard ) )
|
|
||||||
lastChild.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a reference for the next element. This is important because the
|
|
||||||
// above block can be removed or changed, so we can rely on it for the
|
|
||||||
// next interation.
|
|
||||||
if ( !this._.nextNode )
|
|
||||||
this._.nextNode = ( isLast || block.equals( lastNode ) || !lastNode ) ? null : getNextSourceNode( block, 1, lastNode );
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// @context CKEDITOR.dom.iterator
|
|
||||||
// @returns Collapsed range which will be reused when during furter processing.
|
|
||||||
function startIterator() {
|
|
||||||
var range = this.range.clone(),
|
|
||||||
// Indicate at least one of the range boundaries is inside a preformat block.
|
|
||||||
touchPre;
|
|
||||||
|
|
||||||
// Shrink the range to exclude harmful "noises" (#4087, #4450, #5435).
|
|
||||||
range.shrink( CKEDITOR.SHRINK_ELEMENT, true );
|
|
||||||
|
|
||||||
touchPre = range.endContainer.hasAscendant( 'pre', true ) || range.startContainer.hasAscendant( 'pre', true );
|
|
||||||
|
|
||||||
range.enlarge( this.forceBrBreak && !touchPre || !this.enlargeBr ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
|
|
||||||
|
|
||||||
if ( !range.collapsed ) {
|
|
||||||
var walker = new CKEDITOR.dom.walker( range.clone() ),
|
|
||||||
ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
|
|
||||||
// Avoid anchor inside bookmark inner text.
|
|
||||||
walker.evaluator = ignoreBookmarkTextEvaluator;
|
|
||||||
this._.nextNode = walker.next();
|
|
||||||
// TODO: It's better to have walker.reset() used here.
|
|
||||||
walker = new CKEDITOR.dom.walker( range.clone() );
|
|
||||||
walker.evaluator = ignoreBookmarkTextEvaluator;
|
|
||||||
var lastNode = walker.previous();
|
|
||||||
this._.lastNode = lastNode.getNextSourceNode( true );
|
|
||||||
|
|
||||||
// We may have an empty text node at the end of block due to [3770].
|
|
||||||
// If that node is the lastNode, it would cause our logic to leak to the
|
|
||||||
// next block.(#3887)
|
|
||||||
if ( this._.lastNode && this._.lastNode.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( this._.lastNode.getText() ) && this._.lastNode.getParent().isBlockBoundary() ) {
|
|
||||||
var testRange = this.range.clone();
|
|
||||||
testRange.moveToPosition( this._.lastNode, CKEDITOR.POSITION_AFTER_END );
|
|
||||||
if ( testRange.checkEndOfBlock() ) {
|
|
||||||
var path = new CKEDITOR.dom.elementPath( testRange.endContainer, testRange.root ),
|
|
||||||
lastBlock = path.block || path.blockLimit;
|
|
||||||
this._.lastNode = lastBlock.getNextSourceNode( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The end of document or range.root was reached, so we need a marker node inside.
|
|
||||||
if ( !this._.lastNode || !range.root.contains( this._.lastNode ) ) {
|
|
||||||
this._.lastNode = this._.docEndMarker = range.document.createText( '' );
|
|
||||||
this._.lastNode.insertAfter( lastNode );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's reuse this variable.
|
|
||||||
range = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._.started = 1;
|
|
||||||
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does a nested editables lookup inside editablesContainer.
|
|
||||||
// If remainingEditables is set will lookup inside this array.
|
|
||||||
// @param {CKEDITOR.dom.element} editablesContainer
|
|
||||||
// @param {CKEDITOR.dom.element[]} [remainingEditables]
|
|
||||||
function getNestedEditableIn( editablesContainer, remainingEditables ) {
|
|
||||||
if ( remainingEditables == undefined )
|
|
||||||
remainingEditables = findNestedEditables( editablesContainer );
|
|
||||||
|
|
||||||
var editable;
|
|
||||||
|
|
||||||
while ( ( editable = remainingEditables.shift() ) ) {
|
|
||||||
if ( isIterableEditable( editable ) )
|
|
||||||
return { element: editable, remaining: remainingEditables };
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checkes whether we can iterate over this editable.
|
|
||||||
function isIterableEditable( editable ) {
|
|
||||||
// Reject blockless editables.
|
|
||||||
return editable.getDtd().p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finds nested editables within container. Does not return
|
|
||||||
// editables nested in another editable (twice).
|
|
||||||
function findNestedEditables( container ) {
|
|
||||||
var editables = [];
|
|
||||||
|
|
||||||
container.forEach( function( element ) {
|
|
||||||
if ( element.getAttribute( 'contenteditable' ) == 'true' ) {
|
|
||||||
editables.push( element );
|
|
||||||
return false; // Skip children.
|
|
||||||
}
|
|
||||||
}, CKEDITOR.NODE_ELEMENT, true );
|
|
||||||
|
|
||||||
return editables;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Looks for a first nested editable after previousEditable (if passed) and creates
|
|
||||||
// nested iterator for it.
|
|
||||||
function startNestedEditableIterator( parentIterator, blockTag, editablesContainer, remainingEditables ) {
|
|
||||||
var editable = getNestedEditableIn( editablesContainer, remainingEditables );
|
|
||||||
|
|
||||||
if ( !editable )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
var filter = CKEDITOR.filter.instances[ editable.element.data( 'cke-filter' ) ];
|
|
||||||
|
|
||||||
// If current editable has a filter and this filter does not allow for block tag,
|
|
||||||
// search for next nested editable in remaining ones.
|
|
||||||
if ( filter && !filter.check( blockTag ) )
|
|
||||||
return startNestedEditableIterator( parentIterator, blockTag, editablesContainer, editable.remaining );
|
|
||||||
|
|
||||||
var range = new CKEDITOR.dom.range( editable.element );
|
|
||||||
range.selectNodeContents( editable.element );
|
|
||||||
|
|
||||||
var iterator = range.createIterator();
|
|
||||||
// This setting actually does not change anything in this case,
|
|
||||||
// because entire range contents is selected, so there're no <br>s to be included.
|
|
||||||
// But it seems right to copy it too.
|
|
||||||
iterator.enlargeBr = parentIterator.enlargeBr;
|
|
||||||
// Inherit configuration from parent iterator.
|
|
||||||
iterator.enforceRealBlocks = parentIterator.enforceRealBlocks;
|
|
||||||
// Set the activeFilter (which can be overriden when this iteator will start nested iterator)
|
|
||||||
// and the default filter, which will make it possible to reset to
|
|
||||||
// current iterator's activeFilter after leaving nested editable.
|
|
||||||
iterator.activeFilter = iterator.filter = filter;
|
|
||||||
|
|
||||||
parentIterator._.nestedEditable = {
|
|
||||||
element: editable.element,
|
|
||||||
container: editablesContainer,
|
|
||||||
remaining: editable.remaining,
|
|
||||||
iterator: iterator
|
|
||||||
};
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates {CKEDITOR.dom.iterator} instance for this range.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.dom.range
|
|
||||||
* @returns {CKEDITOR.dom.iterator}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.range.prototype.createIterator = function() {
|
|
||||||
return new iterator( this );
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
@ -1,748 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.node} class which is the base
|
|
||||||
* class for classes that represent DOM nodes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for classes representing DOM nodes. This constructor may return
|
|
||||||
* an instance of a class that inherits from this class, like
|
|
||||||
* {@link CKEDITOR.dom.element} or {@link CKEDITOR.dom.text}.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.dom.domObject
|
|
||||||
* @constructor Creates a node class instance.
|
|
||||||
* @param {Object} domNode A native DOM node.
|
|
||||||
* @see CKEDITOR.dom.element
|
|
||||||
* @see CKEDITOR.dom.text
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.node = function( domNode ) {
|
|
||||||
if ( domNode ) {
|
|
||||||
var type = domNode.nodeType == CKEDITOR.NODE_DOCUMENT ? 'document' : domNode.nodeType == CKEDITOR.NODE_ELEMENT ? 'element' : domNode.nodeType == CKEDITOR.NODE_TEXT ? 'text' : domNode.nodeType == CKEDITOR.NODE_COMMENT ? 'comment' : domNode.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ? 'documentFragment' : 'domObject'; // Call the base constructor otherwise.
|
|
||||||
|
|
||||||
return new CKEDITOR.dom[ type ]( domNode );
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.node.prototype = new CKEDITOR.dom.domObject();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Element node type.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=1]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.NODE_ELEMENT = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Document node type.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=9]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.NODE_DOCUMENT = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text node type.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=3]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.NODE_TEXT = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comment node type.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=8]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.NODE_COMMENT = 8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Document fragment node type.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=11]
|
|
||||||
* @member CKEDITOR
|
|
||||||
*/
|
|
||||||
CKEDITOR.NODE_DOCUMENT_FRAGMENT = 11;
|
|
||||||
|
|
||||||
CKEDITOR.POSITION_IDENTICAL = 0;
|
|
||||||
CKEDITOR.POSITION_DISCONNECTED = 1;
|
|
||||||
CKEDITOR.POSITION_FOLLOWING = 2;
|
|
||||||
CKEDITOR.POSITION_PRECEDING = 4;
|
|
||||||
CKEDITOR.POSITION_IS_CONTAINED = 8;
|
|
||||||
CKEDITOR.POSITION_CONTAINS = 16;
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.node.prototype, {
|
|
||||||
/**
|
|
||||||
* Makes this node a child of another element.
|
|
||||||
*
|
|
||||||
* var p = new CKEDITOR.dom.element( 'p' );
|
|
||||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
|
||||||
* strong.appendTo( p );
|
|
||||||
*
|
|
||||||
* // Result: '<p><strong></strong></p>'.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.element} element The target element to which this node will be appended.
|
|
||||||
* @returns {CKEDITOR.dom.element} The target element.
|
|
||||||
*/
|
|
||||||
appendTo: function( element, toStart ) {
|
|
||||||
element.append( this, toStart );
|
|
||||||
return element;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clone this node.
|
|
||||||
*
|
|
||||||
* **Note**: Values set by {#setCustomData} won't be available in the clone.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [includeChildren=false] If `true` then all node's
|
|
||||||
* children will be cloned recursively.
|
|
||||||
* @param {Boolean} [cloneId=false] Whether ID attributes should be cloned too.
|
|
||||||
* @returns {CKEDITOR.dom.node} Clone of this node.
|
|
||||||
*/
|
|
||||||
clone: function( includeChildren, cloneId ) {
|
|
||||||
var $clone = this.$.cloneNode( includeChildren );
|
|
||||||
|
|
||||||
var removeIds = function( node ) {
|
|
||||||
// Reset data-cke-expando only when has been cloned (IE and only for some types of objects).
|
|
||||||
if ( node[ 'data-cke-expando' ] )
|
|
||||||
node[ 'data-cke-expando' ] = false;
|
|
||||||
|
|
||||||
if ( node.nodeType != CKEDITOR.NODE_ELEMENT )
|
|
||||||
return;
|
|
||||||
if ( !cloneId )
|
|
||||||
node.removeAttribute( 'id', false );
|
|
||||||
|
|
||||||
if ( includeChildren ) {
|
|
||||||
var childs = node.childNodes;
|
|
||||||
for ( var i = 0; i < childs.length; i++ )
|
|
||||||
removeIds( childs[ i ] );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The "id" attribute should never be cloned to avoid duplication.
|
|
||||||
removeIds( $clone );
|
|
||||||
|
|
||||||
return new CKEDITOR.dom.node( $clone );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if node is preceded by any sibling.
|
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
hasPrevious: function() {
|
|
||||||
return !!this.$.previousSibling;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if node is succeeded by any sibling.
|
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
hasNext: function() {
|
|
||||||
return !!this.$.nextSibling;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts this element after a node.
|
|
||||||
*
|
|
||||||
* var em = new CKEDITOR.dom.element( 'em' );
|
|
||||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
|
||||||
* strong.insertAfter( em );
|
|
||||||
*
|
|
||||||
* // Result: '<em></em><strong></strong>'
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.node} node The node that will precede this element.
|
|
||||||
* @returns {CKEDITOR.dom.node} The node preceding this one after insertion.
|
|
||||||
*/
|
|
||||||
insertAfter: function( node ) {
|
|
||||||
node.$.parentNode.insertBefore( this.$, node.$.nextSibling );
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts this element before a node.
|
|
||||||
*
|
|
||||||
* var em = new CKEDITOR.dom.element( 'em' );
|
|
||||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
|
||||||
* strong.insertBefore( em );
|
|
||||||
*
|
|
||||||
* // result: '<strong></strong><em></em>'
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.node} node The node that will succeed this element.
|
|
||||||
* @returns {CKEDITOR.dom.node} The node being inserted.
|
|
||||||
*/
|
|
||||||
insertBefore: function( node ) {
|
|
||||||
node.$.parentNode.insertBefore( this.$, node.$ );
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts node before this node.
|
|
||||||
*
|
|
||||||
* var em = new CKEDITOR.dom.element( 'em' );
|
|
||||||
* var strong = new CKEDITOR.dom.element( 'strong' );
|
|
||||||
* strong.insertBeforeMe( em );
|
|
||||||
*
|
|
||||||
* // result: '<em></em><strong></strong>'
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.node} node The node that will preceed this element.
|
|
||||||
* @returns {CKEDITOR.dom.node} The node being inserted.
|
|
||||||
*/
|
|
||||||
insertBeforeMe: function( node ) {
|
|
||||||
this.$.parentNode.insertBefore( node.$, this.$ );
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a uniquely identifiable tree address for this node.
|
|
||||||
* The tree address returned is an array of integers, with each integer
|
|
||||||
* indicating a child index of a DOM node, starting from
|
|
||||||
* `document.documentElement`.
|
|
||||||
*
|
|
||||||
* For example, assuming `<body>` is the second child
|
|
||||||
* of `<html>` (`<head>` being the first),
|
|
||||||
* and we would like to address the third child under the
|
|
||||||
* fourth child of `<body>`, the tree address returned would be:
|
|
||||||
* `[1, 3, 2]`.
|
|
||||||
*
|
|
||||||
* The tree address cannot be used for finding back the DOM tree node once
|
|
||||||
* the DOM tree structure has been modified.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [normalized=false] See {@link #getIndex}.
|
|
||||||
* @returns {Array} The address.
|
|
||||||
*/
|
|
||||||
getAddress: function( normalized ) {
|
|
||||||
var address = [];
|
|
||||||
var $documentElement = this.getDocument().$.documentElement;
|
|
||||||
var node = this.$;
|
|
||||||
|
|
||||||
while ( node && node != $documentElement ) {
|
|
||||||
var parentNode = node.parentNode;
|
|
||||||
|
|
||||||
if ( parentNode ) {
|
|
||||||
// Get the node index. For performance, call getIndex
|
|
||||||
// directly, instead of creating a new node object.
|
|
||||||
address.unshift( this.getIndex.call( { $: node }, normalized ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
node = parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return address;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the document containing this element.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getById( 'example' );
|
|
||||||
* alert( element.getDocument().equals( CKEDITOR.document ) ); // true
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.document} The document.
|
|
||||||
*/
|
|
||||||
getDocument: function() {
|
|
||||||
return new CKEDITOR.dom.document( this.$.ownerDocument || this.$.parentNode.ownerDocument );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get index of a node in an array of its parent.childNodes.
|
|
||||||
*
|
|
||||||
* Let's assume having childNodes array:
|
|
||||||
*
|
|
||||||
* [ emptyText, element1, text, text, element2 ]
|
|
||||||
* element1.getIndex(); // 1
|
|
||||||
* element1.getIndex( true ); // 0
|
|
||||||
* element2.getIndex(); // 4
|
|
||||||
* element2.getIndex( true ); // 2
|
|
||||||
*
|
|
||||||
* @param {Boolean} normalized When `true` empty text nodes and one followed
|
|
||||||
* by another one text node are not counted in.
|
|
||||||
* @returns {Number} Index of a node.
|
|
||||||
*/
|
|
||||||
getIndex: function( normalized ) {
|
|
||||||
// Attention: getAddress depends on this.$
|
|
||||||
// getIndex is called on a plain object: { $ : node }
|
|
||||||
|
|
||||||
var current = this.$,
|
|
||||||
index = -1,
|
|
||||||
isNormalizing;
|
|
||||||
|
|
||||||
if ( !this.$.parentNode )
|
|
||||||
return index;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Bypass blank node and adjacent text nodes.
|
|
||||||
if ( normalized && current != this.$ && current.nodeType == CKEDITOR.NODE_TEXT && ( isNormalizing || !current.nodeValue ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
index++;
|
|
||||||
isNormalizing = current.nodeType == CKEDITOR.NODE_TEXT;
|
|
||||||
}
|
|
||||||
while ( ( current = current.previousSibling ) )
|
|
||||||
|
|
||||||
return index;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
getNextSourceNode: function( startFromSibling, nodeType, guard ) {
|
|
||||||
// If "guard" is a node, transform it in a function.
|
|
||||||
if ( guard && !guard.call ) {
|
|
||||||
var guardNode = guard;
|
|
||||||
guard = function( node ) {
|
|
||||||
return !node.equals( guardNode );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var node = ( !startFromSibling && this.getFirst && this.getFirst() ),
|
|
||||||
parent;
|
|
||||||
|
|
||||||
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
|
|
||||||
// send the 'moving out' signal even we don't actually dive into.
|
|
||||||
if ( !node ) {
|
|
||||||
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
|
|
||||||
return null;
|
|
||||||
node = this.getNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( !node && ( parent = ( parent || this ).getParent() ) ) {
|
|
||||||
// The guard check sends the "true" paramenter to indicate that
|
|
||||||
// we are moving "out" of the element.
|
|
||||||
if ( guard && guard( parent, true ) === false )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
node = parent.getNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !node )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( guard && guard( node ) === false )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( nodeType && nodeType != node.type )
|
|
||||||
return node.getNextSourceNode( false, nodeType, guard );
|
|
||||||
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
getPreviousSourceNode: function( startFromSibling, nodeType, guard ) {
|
|
||||||
if ( guard && !guard.call ) {
|
|
||||||
var guardNode = guard;
|
|
||||||
guard = function( node ) {
|
|
||||||
return !node.equals( guardNode );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var node = ( !startFromSibling && this.getLast && this.getLast() ),
|
|
||||||
parent;
|
|
||||||
|
|
||||||
// Guarding when we're skipping the current element( no children or 'startFromSibling' ).
|
|
||||||
// send the 'moving out' signal even we don't actually dive into.
|
|
||||||
if ( !node ) {
|
|
||||||
if ( this.type == CKEDITOR.NODE_ELEMENT && guard && guard( this, true ) === false )
|
|
||||||
return null;
|
|
||||||
node = this.getPrevious();
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( !node && ( parent = ( parent || this ).getParent() ) ) {
|
|
||||||
// The guard check sends the "true" paramenter to indicate that
|
|
||||||
// we are moving "out" of the element.
|
|
||||||
if ( guard && guard( parent, true ) === false )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
node = parent.getPrevious();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !node )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( guard && guard( node ) === false )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( nodeType && node.type != nodeType )
|
|
||||||
return node.getPreviousSourceNode( false, nodeType, guard );
|
|
||||||
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the node that preceed this element in its parent's child list.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.dom.element.createFromHtml( '<div><i>prev</i><b>Example</b></div>' );
|
|
||||||
* var first = element.getLast().getPrev();
|
|
||||||
* alert( first.getName() ); // 'i'
|
|
||||||
*
|
|
||||||
* @param {Function} [evaluator] Filtering the result node.
|
|
||||||
* @returns {CKEDITOR.dom.node} The previous node or null if not available.
|
|
||||||
*/
|
|
||||||
getPrevious: function( evaluator ) {
|
|
||||||
var previous = this.$,
|
|
||||||
retval;
|
|
||||||
do {
|
|
||||||
previous = previous.previousSibling;
|
|
||||||
|
|
||||||
// Avoid returning the doc type node.
|
|
||||||
// http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-412266927
|
|
||||||
retval = previous && previous.nodeType != 10 && new CKEDITOR.dom.node( previous );
|
|
||||||
}
|
|
||||||
while ( retval && evaluator && !evaluator( retval ) )
|
|
||||||
return retval;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the node that follows this element in its parent's child list.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.dom.element.createFromHtml( '<div><b>Example</b><i>next</i></div>' );
|
|
||||||
* var last = element.getFirst().getNext();
|
|
||||||
* alert( last.getName() ); // 'i'
|
|
||||||
*
|
|
||||||
* @param {Function} [evaluator] Filtering the result node.
|
|
||||||
* @returns {CKEDITOR.dom.node} The next node or null if not available.
|
|
||||||
*/
|
|
||||||
getNext: function( evaluator ) {
|
|
||||||
var next = this.$,
|
|
||||||
retval;
|
|
||||||
do {
|
|
||||||
next = next.nextSibling;
|
|
||||||
retval = next && new CKEDITOR.dom.node( next );
|
|
||||||
}
|
|
||||||
while ( retval && evaluator && !evaluator( retval ) )
|
|
||||||
return retval;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the parent element for this node.
|
|
||||||
*
|
|
||||||
* var node = editor.document.getBody().getFirst();
|
|
||||||
* var parent = node.getParent();
|
|
||||||
* alert( parent.getName() ); // 'body'
|
|
||||||
*
|
|
||||||
* @param {Boolean} [allowFragmentParent=false] Consider also parent node that is of
|
|
||||||
* fragment type {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
|
|
||||||
* @returns {CKEDITOR.dom.element} The parent element.
|
|
||||||
*/
|
|
||||||
getParent: function( allowFragmentParent ) {
|
|
||||||
var parent = this.$.parentNode;
|
|
||||||
return ( parent && ( parent.nodeType == CKEDITOR.NODE_ELEMENT || allowFragmentParent && parent.nodeType == CKEDITOR.NODE_DOCUMENT_FRAGMENT ) ) ? new CKEDITOR.dom.node( parent ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns array containing node parents and node itself. By default nodes are in _descending_ order.
|
|
||||||
*
|
|
||||||
* // Assuming that body has paragraph as first child.
|
|
||||||
* var node = editor.document.getBody().getFirst();
|
|
||||||
* var parents = node.getParents();
|
|
||||||
* alert( parents[ 0 ].getName() + ',' + parents[ 2 ].getName() ); // 'html,p'
|
|
||||||
*
|
|
||||||
* @param {Boolean} [closerFirst=false] Determines order of returned nodes.
|
|
||||||
* @returns {Array} Returns array of {@link CKEDITOR.dom.node}.
|
|
||||||
*/
|
|
||||||
getParents: function( closerFirst ) {
|
|
||||||
var node = this;
|
|
||||||
var parents = [];
|
|
||||||
|
|
||||||
do {
|
|
||||||
parents[ closerFirst ? 'push' : 'unshift' ]( node );
|
|
||||||
}
|
|
||||||
while ( ( node = node.getParent() ) )
|
|
||||||
|
|
||||||
return parents;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
getCommonAncestor: function( node ) {
|
|
||||||
if ( node.equals( this ) )
|
|
||||||
return this;
|
|
||||||
|
|
||||||
if ( node.contains && node.contains( this ) )
|
|
||||||
return node;
|
|
||||||
|
|
||||||
var start = this.contains ? this : this.getParent();
|
|
||||||
|
|
||||||
do {
|
|
||||||
if ( start.contains( node ) ) return start;
|
|
||||||
}
|
|
||||||
while ( ( start = start.getParent() ) );
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
getPosition: function( otherNode ) {
|
|
||||||
var $ = this.$;
|
|
||||||
var $other = otherNode.$;
|
|
||||||
|
|
||||||
if ( $.compareDocumentPosition )
|
|
||||||
return $.compareDocumentPosition( $other );
|
|
||||||
|
|
||||||
// IE and Safari have no support for compareDocumentPosition.
|
|
||||||
|
|
||||||
if ( $ == $other )
|
|
||||||
return CKEDITOR.POSITION_IDENTICAL;
|
|
||||||
|
|
||||||
// Only element nodes support contains and sourceIndex.
|
|
||||||
if ( this.type == CKEDITOR.NODE_ELEMENT && otherNode.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
if ( $.contains ) {
|
|
||||||
if ( $.contains( $other ) )
|
|
||||||
return CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING;
|
|
||||||
|
|
||||||
if ( $other.contains( $ ) )
|
|
||||||
return CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( 'sourceIndex' in $ )
|
|
||||||
return ( $.sourceIndex < 0 || $other.sourceIndex < 0 ) ? CKEDITOR.POSITION_DISCONNECTED : ( $.sourceIndex < $other.sourceIndex ) ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// For nodes that don't support compareDocumentPosition, contains
|
|
||||||
// or sourceIndex, their "address" is compared.
|
|
||||||
|
|
||||||
var addressOfThis = this.getAddress(),
|
|
||||||
addressOfOther = otherNode.getAddress(),
|
|
||||||
minLevel = Math.min( addressOfThis.length, addressOfOther.length );
|
|
||||||
|
|
||||||
// Determinate preceed/follow relationship.
|
|
||||||
for ( var i = 0; i <= minLevel - 1; i++ ) {
|
|
||||||
if ( addressOfThis[ i ] != addressOfOther[ i ] ) {
|
|
||||||
if ( i < minLevel )
|
|
||||||
return addressOfThis[ i ] < addressOfOther[ i ] ? CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_FOLLOWING;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determinate contains/contained relationship.
|
|
||||||
return ( addressOfThis.length < addressOfOther.length ) ? CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING : CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the closest ancestor node of this node, specified by its name.
|
|
||||||
*
|
|
||||||
* // Suppose we have the following HTML structure:
|
|
||||||
* // <div id="outer"><div id="inner"><p><b>Some text</b></p></div></div>
|
|
||||||
* // If node == <b>
|
|
||||||
* ascendant = node.getAscendant( 'div' ); // ascendant == <div id="inner">
|
|
||||||
* ascendant = node.getAscendant( 'b' ); // ascendant == null
|
|
||||||
* ascendant = node.getAscendant( 'b', true ); // ascendant == <b>
|
|
||||||
* ascendant = node.getAscendant( { div:1,p:1 } ); // Searches for the first 'div' or 'p': ascendant == <div id="inner">
|
|
||||||
*
|
|
||||||
* @since 3.6.1
|
|
||||||
* @param {String} reference The name of the ancestor node to search or
|
|
||||||
* an object with the node names to search for.
|
|
||||||
* @param {Boolean} [includeSelf] Whether to include the current
|
|
||||||
* node in the search.
|
|
||||||
* @returns {CKEDITOR.dom.node} The located ancestor node or null if not found.
|
|
||||||
*/
|
|
||||||
getAscendant: function( reference, includeSelf ) {
|
|
||||||
var $ = this.$,
|
|
||||||
name;
|
|
||||||
|
|
||||||
if ( !includeSelf )
|
|
||||||
$ = $.parentNode;
|
|
||||||
|
|
||||||
while ( $ ) {
|
|
||||||
if ( $.nodeName && ( name = $.nodeName.toLowerCase(), ( typeof reference == 'string' ? name == reference : name in reference ) ) )
|
|
||||||
return new CKEDITOR.dom.node( $ );
|
|
||||||
|
|
||||||
try {
|
|
||||||
$ = $.parentNode;
|
|
||||||
} catch ( e ) {
|
|
||||||
$ = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
hasAscendant: function( name, includeSelf ) {
|
|
||||||
var $ = this.$;
|
|
||||||
|
|
||||||
if ( !includeSelf )
|
|
||||||
$ = $.parentNode;
|
|
||||||
|
|
||||||
while ( $ ) {
|
|
||||||
if ( $.nodeName && $.nodeName.toLowerCase() == name )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
$ = $.parentNode;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
move: function( target, toStart ) {
|
|
||||||
target.append( this.remove(), toStart );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes this node from the document DOM.
|
|
||||||
*
|
|
||||||
* var element = CKEDITOR.document.getById( 'MyElement' );
|
|
||||||
* element.remove();
|
|
||||||
*
|
|
||||||
* @param {Boolean} [preserveChildren=false] Indicates that the children
|
|
||||||
* elements must remain in the document, removing only the outer tags.
|
|
||||||
*/
|
|
||||||
remove: function( preserveChildren ) {
|
|
||||||
var $ = this.$;
|
|
||||||
var parent = $.parentNode;
|
|
||||||
|
|
||||||
if ( parent ) {
|
|
||||||
if ( preserveChildren ) {
|
|
||||||
// Move all children before the node.
|
|
||||||
for ( var child;
|
|
||||||
( child = $.firstChild ); ) {
|
|
||||||
parent.insertBefore( $.removeChild( child ), $ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.removeChild( $ );
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
replace: function( nodeToReplace ) {
|
|
||||||
this.insertBefore( nodeToReplace );
|
|
||||||
nodeToReplace.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
trim: function() {
|
|
||||||
this.ltrim();
|
|
||||||
this.rtrim();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
ltrim: function() {
|
|
||||||
var child;
|
|
||||||
while ( this.getFirst && ( child = this.getFirst() ) ) {
|
|
||||||
if ( child.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
var trimmed = CKEDITOR.tools.ltrim( child.getText() ),
|
|
||||||
originalLength = child.getLength();
|
|
||||||
|
|
||||||
if ( !trimmed ) {
|
|
||||||
child.remove();
|
|
||||||
continue;
|
|
||||||
} else if ( trimmed.length < originalLength ) {
|
|
||||||
child.split( originalLength - trimmed.length );
|
|
||||||
|
|
||||||
// IE BUG: child.remove() may raise JavaScript errors here. (#81)
|
|
||||||
this.$.removeChild( this.$.firstChild );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
rtrim: function() {
|
|
||||||
var child;
|
|
||||||
while ( this.getLast && ( child = this.getLast() ) ) {
|
|
||||||
if ( child.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
var trimmed = CKEDITOR.tools.rtrim( child.getText() ),
|
|
||||||
originalLength = child.getLength();
|
|
||||||
|
|
||||||
if ( !trimmed ) {
|
|
||||||
child.remove();
|
|
||||||
continue;
|
|
||||||
} else if ( trimmed.length < originalLength ) {
|
|
||||||
child.split( trimmed.length );
|
|
||||||
|
|
||||||
// IE BUG: child.getNext().remove() may raise JavaScript errors here.
|
|
||||||
// (#81)
|
|
||||||
this.$.lastChild.parentNode.removeChild( this.$.lastChild );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( CKEDITOR.env.needsBrFiller ) {
|
|
||||||
child = this.$.lastChild;
|
|
||||||
|
|
||||||
if ( child && child.type == 1 && child.nodeName.toLowerCase() == 'br' ) {
|
|
||||||
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
|
|
||||||
child.parentNode.removeChild( child );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this node is read-only (should not be changed).
|
|
||||||
*
|
|
||||||
* **Note:** When `attributeCheck` is not used, this method only work for elements
|
|
||||||
* that are already presented in the document, otherwise the result
|
|
||||||
* is not guaranteed, it's mainly for performance consideration.
|
|
||||||
*
|
|
||||||
* // For the following HTML:
|
|
||||||
* // <div contenteditable="false">Some <b>text</b></div>
|
|
||||||
*
|
|
||||||
* // If "ele" is the above <div>
|
|
||||||
* element.isReadOnly(); // true
|
|
||||||
*
|
|
||||||
* @since 3.5
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
isReadOnly: function() {
|
|
||||||
var element = this;
|
|
||||||
if ( this.type != CKEDITOR.NODE_ELEMENT )
|
|
||||||
element = this.getParent();
|
|
||||||
|
|
||||||
if ( element && typeof element.$.isContentEditable != 'undefined' )
|
|
||||||
return !( element.$.isContentEditable || element.data( 'cke-editable' ) );
|
|
||||||
else {
|
|
||||||
// Degrade for old browsers which don't support "isContentEditable", e.g. FF3
|
|
||||||
|
|
||||||
while ( element ) {
|
|
||||||
if ( element.data( 'cke-editable' ) )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ( element.getAttribute( 'contentEditable' ) == 'false' )
|
|
||||||
return true;
|
|
||||||
else if ( element.getAttribute( 'contentEditable' ) == 'true' )
|
|
||||||
break;
|
|
||||||
|
|
||||||
element = element.getParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reached the root of DOM tree, no editable found.
|
|
||||||
return !element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a list of {@link CKEDITOR.dom.node} objects.
|
|
||||||
* It's a wrapper for native nodes list.
|
|
||||||
*
|
|
||||||
* var nodeList = CKEDITOR.document.getBody().getChildren();
|
|
||||||
* alert( nodeList.count() ); // number [0;N]
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a document class instance.
|
|
||||||
* @param {Object} nativeList
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.nodeList = function( nativeList ) {
|
|
||||||
this.$ = nativeList;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.nodeList.prototype = {
|
|
||||||
/**
|
|
||||||
* Get count of nodes in this list.
|
|
||||||
*
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
count: function() {
|
|
||||||
return this.$.length;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get node from the list.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node}
|
|
||||||
*/
|
|
||||||
getItem: function( index ) {
|
|
||||||
if ( index < 0 || index >= this.$.length )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var $node = this.$[ index ];
|
|
||||||
return $node ? new CKEDITOR.dom.node( $node ) : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,201 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Represents a list os CKEDITOR.dom.range objects, which can be easily
|
|
||||||
* iterated sequentially.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends Array
|
|
||||||
* @constructor Creates a rangeList class instance.
|
|
||||||
* @param {CKEDITOR.dom.range/CKEDITOR.dom.range[]} [ranges] The ranges contained on this list.
|
|
||||||
* Note that, if an array of ranges is specified, the range sequence
|
|
||||||
* should match its DOM order. This class will not help to sort them.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.rangeList = function( ranges ) {
|
|
||||||
if ( ranges instanceof CKEDITOR.dom.rangeList )
|
|
||||||
return ranges;
|
|
||||||
|
|
||||||
if ( !ranges )
|
|
||||||
ranges = [];
|
|
||||||
else if ( ranges instanceof CKEDITOR.dom.range )
|
|
||||||
ranges = [ ranges ];
|
|
||||||
|
|
||||||
return CKEDITOR.tools.extend( ranges, mixins );
|
|
||||||
};
|
|
||||||
|
|
||||||
var mixins = {
|
|
||||||
/**
|
|
||||||
* Creates an instance of the rangeList iterator, it should be used
|
|
||||||
* only when the ranges processing could be DOM intrusive, which
|
|
||||||
* means it may pollute and break other ranges in this list.
|
|
||||||
* Otherwise, it's enough to just iterate over this array in a for loop.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.rangeListIterator}
|
|
||||||
*/
|
|
||||||
createIterator: function() {
|
|
||||||
var rangeList = this,
|
|
||||||
bookmark = CKEDITOR.dom.walker.bookmark(),
|
|
||||||
guard = function( node ) {
|
|
||||||
return !( node.is && node.is( 'tr' ) );
|
|
||||||
},
|
|
||||||
bookmarks = [],
|
|
||||||
current;
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Retrieves the next range in the list.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.dom.rangeListIterator
|
|
||||||
* @param {Boolean} [mergeConsequent=false] Whether join two adjacent
|
|
||||||
* ranges into single, e.g. consequent table cells.
|
|
||||||
*/
|
|
||||||
getNextRange: function( mergeConsequent ) {
|
|
||||||
current = current == undefined ? 0 : current + 1;
|
|
||||||
|
|
||||||
var range = rangeList[ current ];
|
|
||||||
|
|
||||||
// Multiple ranges might be mangled by each other.
|
|
||||||
if ( range && rangeList.length > 1 ) {
|
|
||||||
// Bookmarking all other ranges on the first iteration,
|
|
||||||
// the range correctness after it doesn't matter since we'll
|
|
||||||
// restore them before the next iteration.
|
|
||||||
if ( !current ) {
|
|
||||||
// Make sure bookmark correctness by reverse processing.
|
|
||||||
for ( var i = rangeList.length - 1; i >= 0; i-- )
|
|
||||||
bookmarks.unshift( rangeList[ i ].createBookmark( true ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mergeConsequent ) {
|
|
||||||
// Figure out how many ranges should be merged.
|
|
||||||
var mergeCount = 0;
|
|
||||||
while ( rangeList[ current + mergeCount + 1 ] ) {
|
|
||||||
var doc = range.document,
|
|
||||||
found = 0,
|
|
||||||
left = doc.getById( bookmarks[ mergeCount ].endNode ),
|
|
||||||
right = doc.getById( bookmarks[ mergeCount + 1 ].startNode ),
|
|
||||||
next;
|
|
||||||
|
|
||||||
// Check subsequent range.
|
|
||||||
while ( 1 ) {
|
|
||||||
next = left.getNextSourceNode( false );
|
|
||||||
if ( !right.equals( next ) ) {
|
|
||||||
// This could be yet another bookmark or
|
|
||||||
// walking across block boundaries.
|
|
||||||
if ( bookmark( next ) || ( next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() ) ) {
|
|
||||||
left = next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
found = 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !found )
|
|
||||||
break;
|
|
||||||
|
|
||||||
mergeCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
range.moveToBookmark( bookmarks.shift() );
|
|
||||||
|
|
||||||
// Merge ranges finally after moving to bookmarks.
|
|
||||||
while ( mergeCount-- ) {
|
|
||||||
next = rangeList[ ++current ];
|
|
||||||
next.moveToBookmark( bookmarks.shift() );
|
|
||||||
range.setEnd( next.endContainer, next.endOffset );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark}.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [serializable=false] See {@link CKEDITOR.dom.range#createBookmark}.
|
|
||||||
* @returns {Array} Array of bookmarks.
|
|
||||||
*/
|
|
||||||
createBookmarks: function( serializable ) {
|
|
||||||
var retval = [],
|
|
||||||
bookmark;
|
|
||||||
for ( var i = 0; i < this.length; i++ ) {
|
|
||||||
retval.push( bookmark = this[ i ].createBookmark( serializable, true ) );
|
|
||||||
|
|
||||||
// Updating the container & offset values for ranges
|
|
||||||
// that have been touched.
|
|
||||||
for ( var j = i + 1; j < this.length; j++ ) {
|
|
||||||
this[ j ] = updateDirtyRange( bookmark, this[ j ] );
|
|
||||||
this[ j ] = updateDirtyRange( bookmark, this[ j ], true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create "unobtrusive" bookmarks for all ranges. See {@link CKEDITOR.dom.range#createBookmark2}.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [normalized=false] See {@link CKEDITOR.dom.range#createBookmark2}.
|
|
||||||
* @returns {Array} Array of bookmarks.
|
|
||||||
*/
|
|
||||||
createBookmarks2: function( normalized ) {
|
|
||||||
var bookmarks = [];
|
|
||||||
|
|
||||||
for ( var i = 0; i < this.length; i++ )
|
|
||||||
bookmarks.push( this[ i ].createBookmark2( normalized ) );
|
|
||||||
|
|
||||||
return bookmarks;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move each range in the list to the position specified by a list of bookmarks.
|
|
||||||
*
|
|
||||||
* @param {Array} bookmarks The list of bookmarks, each one matching a range in the list.
|
|
||||||
*/
|
|
||||||
moveToBookmarks: function( bookmarks ) {
|
|
||||||
for ( var i = 0; i < this.length; i++ )
|
|
||||||
this[ i ].moveToBookmark( bookmarks[ i ] );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the specified range which has been mangled by previous insertion of
|
|
||||||
// range bookmark nodes.(#3256)
|
|
||||||
function updateDirtyRange( bookmark, dirtyRange, checkEnd ) {
|
|
||||||
var serializable = bookmark.serializable,
|
|
||||||
container = dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ],
|
|
||||||
offset = checkEnd ? 'endOffset' : 'startOffset';
|
|
||||||
|
|
||||||
var bookmarkStart = serializable ? dirtyRange.document.getById( bookmark.startNode ) : bookmark.startNode;
|
|
||||||
|
|
||||||
var bookmarkEnd = serializable ? dirtyRange.document.getById( bookmark.endNode ) : bookmark.endNode;
|
|
||||||
|
|
||||||
if ( container.equals( bookmarkStart.getPrevious() ) ) {
|
|
||||||
dirtyRange.startOffset = dirtyRange.startOffset - container.getLength() - bookmarkEnd.getPrevious().getLength();
|
|
||||||
container = bookmarkEnd.getNext();
|
|
||||||
} else if ( container.equals( bookmarkEnd.getPrevious() ) ) {
|
|
||||||
dirtyRange.startOffset = dirtyRange.startOffset - container.getLength();
|
|
||||||
container = bookmarkEnd.getNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
container.equals( bookmarkStart.getParent() ) && dirtyRange[ offset ]++;
|
|
||||||
container.equals( bookmarkEnd.getParent() ) && dirtyRange[ offset ]++;
|
|
||||||
|
|
||||||
// Update and return this range.
|
|
||||||
dirtyRange[ checkEnd ? 'endContainer' : 'startContainer' ] = container;
|
|
||||||
return dirtyRange;
|
|
||||||
}
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* (Virtual Class) Do not call this constructor. This class is not really part
|
|
||||||
* of the API. It just describes the return type of {@link CKEDITOR.dom.rangeList#createIterator}.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.dom.rangeListIterator
|
|
||||||
*/
|
|
||||||
@ -1,139 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.text} class, which represents
|
|
||||||
* a DOM text node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DOM text node.
|
|
||||||
*
|
|
||||||
* var nativeNode = document.createTextNode( 'Example' );
|
|
||||||
* var text = CKEDITOR.dom.text( nativeNode );
|
|
||||||
*
|
|
||||||
* var text = CKEDITOR.dom.text( 'Example' );
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.dom.node
|
|
||||||
* @constructor Creates a text class instance.
|
|
||||||
* @param {Object/String} text A native DOM text node or a string containing
|
|
||||||
* the text to use to create a new text node.
|
|
||||||
* @param {CKEDITOR.dom.document} [ownerDocument] The document that will contain
|
|
||||||
* the node in case of new node creation. Defaults to the current document.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.text = function( text, ownerDocument ) {
|
|
||||||
if ( typeof text == 'string' )
|
|
||||||
text = ( ownerDocument ? ownerDocument.$ : document ).createTextNode( text );
|
|
||||||
|
|
||||||
// Theoretically, we should call the base constructor here
|
|
||||||
// (not CKEDITOR.dom.node though). But, IE doesn't support expando
|
|
||||||
// properties on text node, so the features provided by domObject will not
|
|
||||||
// work for text nodes (which is not a big issue for us).
|
|
||||||
//
|
|
||||||
// CKEDITOR.dom.domObject.call( this, element );
|
|
||||||
|
|
||||||
this.$ = text;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.text.prototype = new CKEDITOR.dom.node();
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.text.prototype, {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_TEXT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_TEXT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets length of node's value.
|
|
||||||
*
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
getLength: function() {
|
|
||||||
return this.$.nodeValue.length;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets node's value.
|
|
||||||
*
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
getText: function() {
|
|
||||||
return this.$.nodeValue;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets node's value.
|
|
||||||
*
|
|
||||||
* @param {String} text
|
|
||||||
*/
|
|
||||||
setText: function( text ) {
|
|
||||||
this.$.nodeValue = text;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Breaks this text node into two nodes at the specified offset,
|
|
||||||
* keeping both in the tree as siblings. This node then only contains
|
|
||||||
* all the content up to the offset point. A new text node, which is
|
|
||||||
* inserted as the next sibling of this node, contains all the content
|
|
||||||
* at and after the offset point. When the offset is equal to the
|
|
||||||
* length of this node, the new node has no data.
|
|
||||||
*
|
|
||||||
* @param {Number} The position at which to split, starting from zero.
|
|
||||||
* @returns {CKEDITOR.dom.text} The new text node.
|
|
||||||
*/
|
|
||||||
split: function( offset ) {
|
|
||||||
|
|
||||||
// Saved the children count and text length beforehand.
|
|
||||||
var parent = this.$.parentNode,
|
|
||||||
count = parent.childNodes.length,
|
|
||||||
length = this.getLength();
|
|
||||||
|
|
||||||
var doc = this.getDocument();
|
|
||||||
var retval = new CKEDITOR.dom.text( this.$.splitText( offset ), doc );
|
|
||||||
|
|
||||||
if ( parent.childNodes.length == count )
|
|
||||||
{
|
|
||||||
// If the offset is after the last char, IE creates the text node
|
|
||||||
// on split, but don't include it into the DOM. So, we have to do
|
|
||||||
// that manually here.
|
|
||||||
if ( offset >= length )
|
|
||||||
{
|
|
||||||
retval = doc.createText( '' );
|
|
||||||
retval.insertAfter( this );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// IE BUG: IE8+ does not update the childNodes array in DOM after splitText(),
|
|
||||||
// we need to make some DOM changes to make it update. (#3436)
|
|
||||||
var workaround = doc.createText( '' );
|
|
||||||
workaround.insertAfter( retval );
|
|
||||||
workaround.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts characters from indexA up to but not including `indexB`.
|
|
||||||
*
|
|
||||||
* @param {Number} indexA An integer between `0` and one less than the
|
|
||||||
* length of the text.
|
|
||||||
* @param {Number} [indexB] An integer between `0` and the length of the
|
|
||||||
* string. If omitted, extracts characters to the end of the text.
|
|
||||||
*/
|
|
||||||
substring: function( indexA, indexB ) {
|
|
||||||
// We need the following check due to a Firefox bug
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=458886
|
|
||||||
if ( typeof indexB != 'number' )
|
|
||||||
return this.$.nodeValue.substr( indexA );
|
|
||||||
else
|
|
||||||
return this.$.nodeValue.substring( indexA, indexB );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,620 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
// This function is to be called under a "walker" instance scope.
|
|
||||||
function iterate( rtl, breakOnFalse ) {
|
|
||||||
var range = this.range;
|
|
||||||
|
|
||||||
// Return null if we have reached the end.
|
|
||||||
if ( this._.end )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// This is the first call. Initialize it.
|
|
||||||
if ( !this._.start ) {
|
|
||||||
this._.start = 1;
|
|
||||||
|
|
||||||
// A collapsed range must return null at first call.
|
|
||||||
if ( range.collapsed ) {
|
|
||||||
this.end();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move outside of text node edges.
|
|
||||||
range.optimize();
|
|
||||||
}
|
|
||||||
|
|
||||||
var node,
|
|
||||||
startCt = range.startContainer,
|
|
||||||
endCt = range.endContainer,
|
|
||||||
startOffset = range.startOffset,
|
|
||||||
endOffset = range.endOffset,
|
|
||||||
guard,
|
|
||||||
userGuard = this.guard,
|
|
||||||
type = this.type,
|
|
||||||
getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
|
|
||||||
|
|
||||||
// Create the LTR guard function, if necessary.
|
|
||||||
if ( !rtl && !this._.guardLTR ) {
|
|
||||||
// The node that stops walker from moving up.
|
|
||||||
var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt : endCt.getParent();
|
|
||||||
|
|
||||||
// The node that stops the walker from going to next.
|
|
||||||
var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt.getChild( endOffset ) : endCt.getNext();
|
|
||||||
|
|
||||||
this._.guardLTR = function( node, movingOut ) {
|
|
||||||
return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the RTL guard function, if necessary.
|
|
||||||
if ( rtl && !this._.guardRTL ) {
|
|
||||||
// The node that stops walker from moving up.
|
|
||||||
var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startCt : startCt.getParent();
|
|
||||||
|
|
||||||
// The node that stops the walker from going to next.
|
|
||||||
var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startOffset ? startCt.getChild( startOffset - 1 ) : null : startCt.getPrevious();
|
|
||||||
|
|
||||||
this._.guardRTL = function( node, movingOut ) {
|
|
||||||
return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define which guard function to use.
|
|
||||||
var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
|
|
||||||
|
|
||||||
// Make the user defined guard function participate in the process,
|
|
||||||
// otherwise simply use the boundary guard.
|
|
||||||
if ( userGuard ) {
|
|
||||||
guard = function( node, movingOut ) {
|
|
||||||
if ( stopGuard( node, movingOut ) === false )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return userGuard( node, movingOut );
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
guard = stopGuard;
|
|
||||||
|
|
||||||
if ( this.current )
|
|
||||||
node = this.current[ getSourceNodeFn ]( false, type, guard );
|
|
||||||
else {
|
|
||||||
// Get the first node to be returned.
|
|
||||||
if ( rtl ) {
|
|
||||||
node = endCt;
|
|
||||||
|
|
||||||
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
if ( endOffset > 0 )
|
|
||||||
node = node.getChild( endOffset - 1 );
|
|
||||||
else
|
|
||||||
node = ( guard( node, true ) === false ) ? null : node.getPreviousSourceNode( true, type, guard );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
node = startCt;
|
|
||||||
|
|
||||||
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
if ( !( node = node.getChild( startOffset ) ) )
|
|
||||||
node = ( guard( startCt, true ) === false ) ? null : startCt.getNextSourceNode( true, type, guard );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( node && guard( node ) === false )
|
|
||||||
node = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( node && !this._.end ) {
|
|
||||||
this.current = node;
|
|
||||||
|
|
||||||
if ( !this.evaluator || this.evaluator( node ) !== false ) {
|
|
||||||
if ( !breakOnFalse )
|
|
||||||
return node;
|
|
||||||
} else if ( breakOnFalse && this.evaluator )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
node = node[ getSourceNodeFn ]( false, type, guard );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.end();
|
|
||||||
return this.current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function iterateToLast( rtl ) {
|
|
||||||
var node,
|
|
||||||
last = null;
|
|
||||||
|
|
||||||
while ( ( node = iterate.call( this, rtl ) ) )
|
|
||||||
last = node;
|
|
||||||
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to "walk" the DOM inside a range boundaries. If the
|
|
||||||
* range starts or ends in the middle of the text node this node will
|
|
||||||
* be included as a whole. Outside changes to the range may break the walker.
|
|
||||||
*
|
|
||||||
* The walker may return nodes that are not totaly included into the
|
|
||||||
* range boundaires. Let's take the following range representation,
|
|
||||||
* where the square brackets indicate the boundaries:
|
|
||||||
*
|
|
||||||
* [<p>Some <b>sample] text</b>
|
|
||||||
*
|
|
||||||
* While walking forward into the above range, the following nodes are
|
|
||||||
* returned: `<p>`, `"Some "`, `<b>` and `"sample"`. Going
|
|
||||||
* backwards instead we have: `"sample"` and `"Some "`. So note that the
|
|
||||||
* walker always returns nodes when "entering" them, but not when
|
|
||||||
* "leaving" them. The guard function is instead called both when
|
|
||||||
* entering and leaving nodes.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker = CKEDITOR.tools.createClass( {
|
|
||||||
/**
|
|
||||||
* Creates a walker class instance.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @param {CKEDITOR.dom.range} range The range within which walk.
|
|
||||||
*/
|
|
||||||
$: function( range ) {
|
|
||||||
this.range = range;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function executed for every matched node, to check whether
|
|
||||||
* it's to be considered into the walk or not. If not provided, all
|
|
||||||
* matched nodes are considered good.
|
|
||||||
*
|
|
||||||
* If the function returns `false` the node is ignored.
|
|
||||||
*
|
|
||||||
* @property {Function} evaluator
|
|
||||||
*/
|
|
||||||
// this.evaluator = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function executed for every node the walk pass by to check
|
|
||||||
* whether the walk is to be finished. It's called when both
|
|
||||||
* entering and exiting nodes, as well as for the matched nodes.
|
|
||||||
*
|
|
||||||
* If this function returns `false`, the walking ends and no more
|
|
||||||
* nodes are evaluated.
|
|
||||||
|
|
||||||
* @property {Function} guard
|
|
||||||
*/
|
|
||||||
// this.guard = null;
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this._ = {};
|
|
||||||
},
|
|
||||||
|
|
||||||
// statics :
|
|
||||||
// {
|
|
||||||
// /* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
|
|
||||||
// * @param {CKEDITOR.dom.node} startNode The node from wich the walk
|
|
||||||
// * will start.
|
|
||||||
// * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
|
|
||||||
// * in the walk. No more nodes are retrieved after touching or
|
|
||||||
// * passing it. If not provided, the walker stops at the
|
|
||||||
// * <body> closing boundary.
|
|
||||||
// * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
|
|
||||||
// * provided nodes.
|
|
||||||
// */
|
|
||||||
// createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
|
|
||||||
// {
|
|
||||||
// var range = new CKEDITOR.dom.range();
|
|
||||||
// if ( startNode )
|
|
||||||
// range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
|
|
||||||
// else
|
|
||||||
// range.setStartAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_AFTER_START ) ;
|
|
||||||
//
|
|
||||||
// if ( endNode )
|
|
||||||
// range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
|
|
||||||
// else
|
|
||||||
// range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
|
|
||||||
//
|
|
||||||
// return new CKEDITOR.dom.walker( range );
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
proto: {
|
|
||||||
/**
|
|
||||||
* Stops walking. No more nodes are retrieved if this function gets called.
|
|
||||||
*/
|
|
||||||
end: function() {
|
|
||||||
this._.end = 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the next node (at right).
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node} The next node or null if no more
|
|
||||||
* nodes are available.
|
|
||||||
*/
|
|
||||||
next: function() {
|
|
||||||
return iterate.call( this );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the previous node (at left).
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node} The previous node or null if no more
|
|
||||||
* nodes are available.
|
|
||||||
*/
|
|
||||||
previous: function() {
|
|
||||||
return iterate.call( this, 1 );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check all nodes at right, executing the evaluation function.
|
|
||||||
*
|
|
||||||
* @returns {Boolean} `false` if the evaluator function returned
|
|
||||||
* `false` for any of the matched nodes. Otherwise `true`.
|
|
||||||
*/
|
|
||||||
checkForward: function() {
|
|
||||||
return iterate.call( this, 0, 1 ) !== false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check all nodes at left, executing the evaluation function.
|
|
||||||
*
|
|
||||||
* @returns {Boolean} `false` if the evaluator function returned
|
|
||||||
* `false` for any of the matched nodes. Otherwise `true`.
|
|
||||||
*/
|
|
||||||
checkBackward: function() {
|
|
||||||
return iterate.call( this, 1, 1 ) !== false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a full walk forward (to the right), until no more nodes
|
|
||||||
* are available, returning the last valid node.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node} The last node at the right or null
|
|
||||||
* if no valid nodes are available.
|
|
||||||
*/
|
|
||||||
lastForward: function() {
|
|
||||||
return iterateToLast.call( this );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a full walk backwards (to the left), until no more nodes
|
|
||||||
* are available, returning the last valid node.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.node} The last node at the left or null
|
|
||||||
* if no valid nodes are available.
|
|
||||||
*/
|
|
||||||
lastBackward: function() {
|
|
||||||
return iterateToLast.call( this, 1 );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets walker.
|
|
||||||
*/
|
|
||||||
reset: function() {
|
|
||||||
delete this.current;
|
|
||||||
this._ = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Anything whose display computed style is block, list-item, table,
|
|
||||||
// table-row-group, table-header-group, table-footer-group, table-row,
|
|
||||||
// table-column-group, table-column, table-cell, table-caption, or whose node
|
|
||||||
// name is hr, br (when enterMode is br only) is a block boundary.
|
|
||||||
var blockBoundaryDisplayMatch = { block: 1, 'list-item': 1, table: 1, 'table-row-group': 1,
|
|
||||||
'table-header-group': 1, 'table-footer-group': 1, 'table-row': 1, 'table-column-group': 1,
|
|
||||||
'table-column': 1, 'table-cell': 1, 'table-caption': 1 },
|
|
||||||
outOfFlowPositions = { absolute: 1, fixed: 1 };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether element is displayed as a block.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.dom.element
|
|
||||||
* @param [customNodeNames] Custom list of nodes which will extend
|
|
||||||
* default {@link CKEDITOR.dtd#$block} list.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.element.prototype.isBlockBoundary = function( customNodeNames ) {
|
|
||||||
// Whether element is in normal page flow. Floated or positioned elements are out of page flow.
|
|
||||||
// Don't consider floated or positioned formatting as block boundary, fall back to dtd check in that case. (#6297)
|
|
||||||
var inPageFlow = this.getComputedStyle( 'float' ) == 'none' && !( this.getComputedStyle( 'position' ) in outOfFlowPositions );
|
|
||||||
|
|
||||||
if ( inPageFlow && blockBoundaryDisplayMatch[ this.getComputedStyle( 'display' ) ] )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Either in $block or in customNodeNames if defined.
|
|
||||||
return !!( this.is( CKEDITOR.dtd.$block ) || customNodeNames && this.is( customNodeNames ) );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether the node is a block boundary.
|
|
||||||
* See {@link CKEDITOR.dom.element#isBlockBoundary}.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param customNodeNames
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.blockBoundary = function( customNodeNames ) {
|
|
||||||
return function( node, type ) {
|
|
||||||
return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary( customNodeNames ) );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @static
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.listItemBoundary = function() {
|
|
||||||
return this.blockBoundary( { br: 1 } );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether the node is a bookmark node OR bookmark node
|
|
||||||
* inner contents.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [contentOnly=false] Whether only test against the text content of
|
|
||||||
* bookmark node instead of the element itself (default).
|
|
||||||
* @param {Boolean} [isReject=false] Whether should return `false` for the bookmark
|
|
||||||
* node instead of `true` (default).
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.bookmark = function( contentOnly, isReject ) {
|
|
||||||
function isBookmarkNode( node ) {
|
|
||||||
return ( node && node.getName && node.getName() == 'span' && node.data( 'cke-bookmark' ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return function( node ) {
|
|
||||||
var isBookmark, parent;
|
|
||||||
// Is bookmark inner text node?
|
|
||||||
isBookmark = ( node && node.type != CKEDITOR.NODE_ELEMENT && ( parent = node.getParent() ) && isBookmarkNode( parent ) );
|
|
||||||
// Is bookmark node?
|
|
||||||
isBookmark = contentOnly ? isBookmark : isBookmark || isBookmarkNode( node );
|
|
||||||
return !!( isReject ^ isBookmark );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether the node is a text node containing only whitespaces characters.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false]
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.whitespaces = function( isReject ) {
|
|
||||||
return function( node ) {
|
|
||||||
var isWhitespace;
|
|
||||||
if ( node && node.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
// whitespace, as well as the text cursor filler node we used in Webkit. (#9384)
|
|
||||||
isWhitespace = !CKEDITOR.tools.trim( node.getText() ) ||
|
|
||||||
CKEDITOR.env.webkit && node.getText() == '\u200b';
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!( isReject ^ isWhitespace );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether the node is invisible in wysiwyg mode.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false]
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.invisible = function( isReject ) {
|
|
||||||
var whitespace = CKEDITOR.dom.walker.whitespaces();
|
|
||||||
return function( node ) {
|
|
||||||
var invisible;
|
|
||||||
|
|
||||||
if ( whitespace( node ) )
|
|
||||||
invisible = 1;
|
|
||||||
else {
|
|
||||||
// Visibility should be checked on element.
|
|
||||||
if ( node.type == CKEDITOR.NODE_TEXT )
|
|
||||||
node = node.getParent();
|
|
||||||
|
|
||||||
// Nodes that take no spaces in wysiwyg:
|
|
||||||
// 1. White-spaces but not including NBSP;
|
|
||||||
// 2. Empty inline elements, e.g. <b></b> we're checking here
|
|
||||||
// 'offsetHeight' instead of 'offsetWidth' for properly excluding
|
|
||||||
// all sorts of empty paragraph, e.g. <br />.
|
|
||||||
invisible = !node.$.offsetHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!( isReject ^ invisible );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether node's type is equal to passed one.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Number} type
|
|
||||||
* @param {Boolean} [isReject=false]
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.nodeType = function( type, isReject ) {
|
|
||||||
return function( node ) {
|
|
||||||
return !!( isReject ^ ( node.type == type ) );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether node is a bogus (filler) node from
|
|
||||||
* contenteditable element's point of view.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false]
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.bogus = function( isReject ) {
|
|
||||||
function nonEmpty( node ) {
|
|
||||||
return !isWhitespaces( node ) && !isBookmark( node );
|
|
||||||
}
|
|
||||||
|
|
||||||
return function( node ) {
|
|
||||||
var isBogus = CKEDITOR.env.needsBrFiller ? node.is && node.is( 'br' ) : node.getText && tailNbspRegex.test( node.getText() );
|
|
||||||
|
|
||||||
if ( isBogus ) {
|
|
||||||
var parent = node.getParent(),
|
|
||||||
next = node.getNext( nonEmpty );
|
|
||||||
|
|
||||||
isBogus = parent.isBlockBoundary() && ( !next || next.type == CKEDITOR.NODE_ELEMENT && next.isBlockBoundary() );
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!( isReject ^ isBogus );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether node is a temporary element
|
|
||||||
* (element with `data-cke-temp` attribute) or its child.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false] Whether should return `false` for the
|
|
||||||
* temporary element instead of `true` (default).
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.temp = function( isReject ) {
|
|
||||||
return function( node ) {
|
|
||||||
if ( node.type != CKEDITOR.NODE_ELEMENT )
|
|
||||||
node = node.getParent();
|
|
||||||
|
|
||||||
var isTemp = node && node.hasAttribute( 'data-cke-temp' );
|
|
||||||
|
|
||||||
return !!( isReject ^ isTemp );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/,
|
|
||||||
isWhitespaces = CKEDITOR.dom.walker.whitespaces(),
|
|
||||||
isBookmark = CKEDITOR.dom.walker.bookmark(),
|
|
||||||
isTemp = CKEDITOR.dom.walker.temp(),
|
|
||||||
toSkip = function( node ) {
|
|
||||||
return isBookmark( node ) ||
|
|
||||||
isWhitespaces( node ) ||
|
|
||||||
node.type == CKEDITOR.NODE_ELEMENT && node.is( CKEDITOR.dtd.$inline ) && !node.is( CKEDITOR.dtd.$empty );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether node should be ignored in terms of "editability".
|
|
||||||
*
|
|
||||||
* This includes:
|
|
||||||
*
|
|
||||||
* * whitespaces (see {@link CKEDITOR.dom.walker#whitespaces}),
|
|
||||||
* * bookmarks (see {@link CKEDITOR.dom.walker#bookmark}),
|
|
||||||
* * temporary elements (see {@link CKEDITOR.dom.walker#temp}).
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false] Whether should return `false` for the
|
|
||||||
* ignored element instead of `true` (default).
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.ignored = function( isReject ) {
|
|
||||||
return function( node ) {
|
|
||||||
var isIgnored = isWhitespaces( node ) || isBookmark( node ) || isTemp( node );
|
|
||||||
|
|
||||||
return !!( isReject ^ isIgnored );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var isIgnored = CKEDITOR.dom.walker.ignored();
|
|
||||||
|
|
||||||
function isEmpty( node ) {
|
|
||||||
var i = 0,
|
|
||||||
l = node.getChildCount();
|
|
||||||
|
|
||||||
for ( ; i < l; ++i ) {
|
|
||||||
if ( !isIgnored( node.getChild( i ) ) )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterTextContainers( dtd ) {
|
|
||||||
var hash = {},
|
|
||||||
name;
|
|
||||||
|
|
||||||
for ( name in dtd ) {
|
|
||||||
if ( CKEDITOR.dtd[ name ][ '#' ] )
|
|
||||||
hash[ name ] = 1;
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block elements which can contain text nodes (without ul, ol, dl, etc.).
|
|
||||||
var dtdTextBlock = filterTextContainers( CKEDITOR.dtd.$block );
|
|
||||||
|
|
||||||
function isEditable( node ) {
|
|
||||||
// Skip temporary elements, bookmarks and whitespaces.
|
|
||||||
if ( isIgnored( node ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( node.type == CKEDITOR.NODE_TEXT )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( node.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
// All inline and non-editable elements are valid editable places.
|
|
||||||
// Note: the <hr> is currently the only element in CKEDITOR.dtd.$empty and CKEDITOR.dtd.$block,
|
|
||||||
// but generally speaking we need an intersection of these two sets.
|
|
||||||
// Note: non-editable block has to be treated differently (should be selected entirely).
|
|
||||||
if ( node.is( CKEDITOR.dtd.$inline ) || node.is( 'hr' ) || node.getAttribute( 'contenteditable' ) == 'false' )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Empty blocks are editable on IE.
|
|
||||||
if ( !CKEDITOR.env.needsBrFiller && node.is( dtdTextBlock ) && isEmpty( node ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip all other nodes.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function which checks whether node can be a container or a sibling
|
|
||||||
* of selection end.
|
|
||||||
*
|
|
||||||
* This includes:
|
|
||||||
*
|
|
||||||
* * text nodes (but not whitespaces),
|
|
||||||
* * inline elements,
|
|
||||||
* * intersection of {@link CKEDITOR.dtd#$empty} and {@link CKEDITOR.dtd#$block} (currenly
|
|
||||||
* it's only `<hr>`),
|
|
||||||
* * non-editable blocks (special case - such blocks cannot be containers nor
|
|
||||||
* siblings, they need to be selected entirely),
|
|
||||||
* * empty blocks which can contain text (IE only).
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @static
|
|
||||||
* @param {Boolean} [isReject=false] Whether should return `false` for the
|
|
||||||
* ignored element instead of `true` (default).
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.walker.editable = function( isReject ) {
|
|
||||||
return function( node ) {
|
|
||||||
return !!( isReject ^ isEditable( node ) );
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if there's a filler node at the end of an element, and returns it.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.dom.element
|
|
||||||
* @returns {CKEDITOR.dom.node/Boolean} Bogus node or `false`.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.element.prototype.getBogus = function() {
|
|
||||||
// Bogus are not always at the end, e.g. <p><a>text<br /></a></p> (#7070).
|
|
||||||
var tail = this;
|
|
||||||
do {
|
|
||||||
tail = tail.getPreviousSourceNode();
|
|
||||||
}
|
|
||||||
while ( toSkip( tail ) )
|
|
||||||
|
|
||||||
if ( tail && ( CKEDITOR.env.needsBrFiller ? tail.is && tail.is( 'br' ) : tail.getText && tailNbspRegex.test( tail.getText() ) ) )
|
|
||||||
return tail;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
} )();
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dom.document} class, which
|
|
||||||
* represents a DOM document.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DOM window.
|
|
||||||
*
|
|
||||||
* var document = new CKEDITOR.dom.window( window );
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.dom.domObject
|
|
||||||
* @constructor Creates a window class instance.
|
|
||||||
* @param {Object} domWindow A native DOM window.
|
|
||||||
*/
|
|
||||||
CKEDITOR.dom.window = function( domWindow ) {
|
|
||||||
CKEDITOR.dom.domObject.call( this, domWindow );
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.dom.window.prototype = new CKEDITOR.dom.domObject();
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.dom.window.prototype, {
|
|
||||||
/**
|
|
||||||
* Moves the selection focus to this window.
|
|
||||||
*
|
|
||||||
* var win = new CKEDITOR.dom.window( window );
|
|
||||||
* win.focus();
|
|
||||||
*/
|
|
||||||
focus: function() {
|
|
||||||
this.$.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the width and height of this window's viewable area.
|
|
||||||
*
|
|
||||||
* var win = new CKEDITOR.dom.window( window );
|
|
||||||
* var size = win.getViewPaneSize();
|
|
||||||
* alert( size.width );
|
|
||||||
* alert( size.height );
|
|
||||||
*
|
|
||||||
* @returns {Object} An object with the `width` and `height`
|
|
||||||
* properties containing the size.
|
|
||||||
*/
|
|
||||||
getViewPaneSize: function() {
|
|
||||||
var doc = this.$.document,
|
|
||||||
stdMode = doc.compatMode == 'CSS1Compat';
|
|
||||||
return {
|
|
||||||
width: ( stdMode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
|
|
||||||
height: ( stdMode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current position of the window's scroll.
|
|
||||||
*
|
|
||||||
* var win = new CKEDITOR.dom.window( window );
|
|
||||||
* var pos = win.getScrollPosition();
|
|
||||||
* alert( pos.x );
|
|
||||||
* alert( pos.y );
|
|
||||||
*
|
|
||||||
* @returns {Object} An object with the `x` and `y` properties
|
|
||||||
* containing the scroll position.
|
|
||||||
*/
|
|
||||||
getScrollPosition: function() {
|
|
||||||
var $ = this.$;
|
|
||||||
|
|
||||||
if ( 'pageXOffset' in $ ) {
|
|
||||||
return {
|
|
||||||
x: $.pageXOffset || 0,
|
|
||||||
y: $.pageYOffset || 0
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var doc = $.document;
|
|
||||||
return {
|
|
||||||
x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
|
|
||||||
y: doc.documentElement.scrollTop || doc.body.scrollTop || 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the frame element containing this window context.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.dom.element} The frame element or `null` if not in a frame context.
|
|
||||||
*/
|
|
||||||
getFrame: function() {
|
|
||||||
var iframe = this.$.frameElement;
|
|
||||||
return iframe ? new CKEDITOR.dom.element.get( iframe ) : null;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,328 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.dtd} object, which holds the DTD
|
|
||||||
* mapping for XHTML 1.0 Transitional. This file was automatically
|
|
||||||
* generated from the file: xhtml1-transitional.dtd.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds and object representation of the HTML DTD to be used by the
|
|
||||||
* editor in its internal operations.
|
|
||||||
*
|
|
||||||
* Each element in the DTD is represented by a property in this object. Each
|
|
||||||
* property contains the list of elements that can be contained by the element.
|
|
||||||
* Text is represented by the `#` property.
|
|
||||||
*
|
|
||||||
* Several special grouping properties are also available. Their names start
|
|
||||||
* with the `$` character.
|
|
||||||
*
|
|
||||||
* // Check if <div> can be contained in a <p> element.
|
|
||||||
* alert( !!CKEDITOR.dtd[ 'p' ][ 'div' ] ); // false
|
|
||||||
*
|
|
||||||
* // Check if <p> can be contained in a <div> element.
|
|
||||||
* alert( !!CKEDITOR.dtd[ 'div' ][ 'p' ] ); // true
|
|
||||||
*
|
|
||||||
* // Check if <p> is a block element.
|
|
||||||
* alert( !!CKEDITOR.dtd.$block[ 'p' ] ); // true
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.dtd
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.dtd = ( function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var X = CKEDITOR.tools.extend,
|
|
||||||
// Subtraction rest of sets, from the first set.
|
|
||||||
Y = function( source, removed ) {
|
|
||||||
var substracted = CKEDITOR.tools.clone( source );
|
|
||||||
for ( var i = 1; i < arguments.length; i++ ) {
|
|
||||||
removed = arguments[ i ];
|
|
||||||
for ( var name in removed )
|
|
||||||
delete substracted[ name ];
|
|
||||||
}
|
|
||||||
return substracted;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Phrasing elements.
|
|
||||||
// P = { a: 1, em: 1, strong: 1, small: 1, abbr: 1, dfn: 1, i: 1, b: 1, s: 1,
|
|
||||||
// u: 1, code: 1, 'var': 1, samp: 1, kbd: 1, sup: 1, sub: 1, q: 1, cite: 1,
|
|
||||||
// span: 1, bdo: 1, bdi: 1, br: 1, wbr: 1, ins: 1, del: 1, img: 1, embed: 1,
|
|
||||||
// object: 1, iframe: 1, map: 1, area: 1, script: 1, noscript: 1, ruby: 1,
|
|
||||||
// video: 1, audio: 1, input: 1, textarea: 1, select: 1, button: 1, label: 1,
|
|
||||||
// output: 1, keygen: 1, progress: 1, command: 1, canvas: 1, time: 1,
|
|
||||||
// meter: 1, detalist: 1 },
|
|
||||||
|
|
||||||
// Flow elements.
|
|
||||||
// F = { a: 1, p: 1, hr: 1, pre: 1, ul: 1, ol: 1, dl: 1, div: 1, h1: 1, h2: 1,
|
|
||||||
// h3: 1, h4: 1, h5: 1, h6: 1, hgroup: 1, address: 1, blockquote: 1, ins: 1,
|
|
||||||
// del: 1, object: 1, map: 1, noscript: 1, section: 1, nav: 1, article: 1,
|
|
||||||
// aside: 1, header: 1, footer: 1, video: 1, audio: 1, figure: 1, table: 1,
|
|
||||||
// form: 1, fieldset: 1, menu: 1, canvas: 1, details:1 },
|
|
||||||
|
|
||||||
// Text can be everywhere.
|
|
||||||
// X( P, T );
|
|
||||||
// Flow elements set consists of phrasing elements set.
|
|
||||||
// X( F, P );
|
|
||||||
|
|
||||||
var P = {}, F = {},
|
|
||||||
// Intersection of flow elements set and phrasing elements set.
|
|
||||||
PF = { a: 1, abbr: 1, area: 1, audio: 1, b: 1, bdi: 1, bdo: 1, br: 1, button: 1, canvas: 1, cite: 1,
|
|
||||||
code: 1, command: 1, datalist: 1, del: 1, dfn: 1, em: 1, embed: 1, i: 1, iframe: 1, img: 1,
|
|
||||||
input: 1, ins: 1, kbd: 1, keygen: 1, label: 1, map: 1, mark: 1, meter: 1, noscript: 1, object: 1,
|
|
||||||
output: 1, progress: 1, q: 1, ruby: 1, s: 1, samp: 1, script: 1, select: 1, small: 1, span: 1,
|
|
||||||
strong: 1, sub: 1, sup: 1, textarea: 1, time: 1, u: 1, 'var': 1, video: 1, wbr: 1 },
|
|
||||||
// F - PF (Flow Only).
|
|
||||||
FO = { address: 1, article: 1, aside: 1, blockquote: 1, details: 1, div: 1, dl: 1, fieldset: 1,
|
|
||||||
figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
|
|
||||||
hr: 1, menu: 1, nav: 1, ol: 1, p: 1, pre: 1, section: 1, table: 1, ul: 1 },
|
|
||||||
// Metadata elements.
|
|
||||||
M = { command: 1, link: 1, meta: 1, noscript: 1, script: 1, style: 1 },
|
|
||||||
// Empty.
|
|
||||||
E = {},
|
|
||||||
// Text.
|
|
||||||
T = { '#': 1 },
|
|
||||||
|
|
||||||
// Deprecated phrasing elements.
|
|
||||||
DP = { acronym: 1, applet: 1, basefont: 1, big: 1, font: 1, isindex: 1, strike: 1, style: 1, tt: 1 }, // TODO remove "style".
|
|
||||||
// Deprecated flow only elements.
|
|
||||||
DFO = { center: 1, dir: 1, noframes: 1 };
|
|
||||||
|
|
||||||
// Phrasing elements := PF + T + DP
|
|
||||||
X( P, PF, T, DP );
|
|
||||||
// Flow elements := FO + P + DFO
|
|
||||||
X( F, FO, P, DFO );
|
|
||||||
|
|
||||||
var dtd = {
|
|
||||||
a: Y( P, { a: 1, button: 1 } ), // Treat as normal inline element (not a transparent one).
|
|
||||||
abbr: P,
|
|
||||||
address: F,
|
|
||||||
area: E,
|
|
||||||
article: X( { style: 1 }, F ),
|
|
||||||
aside: X( { style: 1 }, F ),
|
|
||||||
audio: X( { source: 1, track: 1 }, F ),
|
|
||||||
b: P,
|
|
||||||
base: E,
|
|
||||||
bdi: P,
|
|
||||||
bdo: P,
|
|
||||||
blockquote: F,
|
|
||||||
body: F,
|
|
||||||
br: E,
|
|
||||||
button: Y( P, { a: 1, button: 1 } ),
|
|
||||||
canvas: P, // Treat as normal inline element (not a transparent one).
|
|
||||||
caption: F,
|
|
||||||
cite: P,
|
|
||||||
code: P,
|
|
||||||
col: E,
|
|
||||||
colgroup: { col: 1 },
|
|
||||||
command: E,
|
|
||||||
datalist: X( { option: 1 }, P ),
|
|
||||||
dd: F,
|
|
||||||
del: P, // Treat as normal inline element (not a transparent one).
|
|
||||||
details: X( { summary: 1 }, F ),
|
|
||||||
dfn: P,
|
|
||||||
div: X( { style: 1 }, F ),
|
|
||||||
dl: { dt: 1, dd: 1 },
|
|
||||||
dt: F,
|
|
||||||
em: P,
|
|
||||||
embed: E,
|
|
||||||
fieldset: X( { legend: 1 }, F ),
|
|
||||||
figcaption: F,
|
|
||||||
figure: X( { figcaption: 1 }, F ),
|
|
||||||
footer: F,
|
|
||||||
form: F,
|
|
||||||
h1: P,
|
|
||||||
h2: P,
|
|
||||||
h3: P,
|
|
||||||
h4: P,
|
|
||||||
h5: P,
|
|
||||||
h6: P,
|
|
||||||
head: X( { title: 1, base: 1 }, M ),
|
|
||||||
header: F,
|
|
||||||
hgroup: { h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 },
|
|
||||||
hr: E,
|
|
||||||
html: X( { head: 1, body: 1 }, F, M ), // Head and body are optional...
|
|
||||||
i: P,
|
|
||||||
iframe: T,
|
|
||||||
img: E,
|
|
||||||
input: E,
|
|
||||||
ins: P, // Treat as normal inline element (not a transparent one).
|
|
||||||
kbd: P,
|
|
||||||
keygen: E,
|
|
||||||
label: P,
|
|
||||||
legend: P,
|
|
||||||
li: F,
|
|
||||||
link: E,
|
|
||||||
map: F,
|
|
||||||
mark: P, // Treat as normal inline element (not a transparent one).
|
|
||||||
menu: X( { li: 1 }, F ),
|
|
||||||
meta: E,
|
|
||||||
meter: Y( P, { meter: 1 } ),
|
|
||||||
nav: F,
|
|
||||||
noscript: X( { link: 1, meta: 1, style: 1 }, P ), // Treat as normal inline element (not a transparent one).
|
|
||||||
object: X( { param: 1 }, P ), // Treat as normal inline element (not a transparent one).
|
|
||||||
ol: { li: 1 },
|
|
||||||
optgroup: { option: 1 },
|
|
||||||
option: T,
|
|
||||||
output: P,
|
|
||||||
p: P,
|
|
||||||
param: E,
|
|
||||||
pre: P,
|
|
||||||
progress: Y( P, { progress: 1 } ),
|
|
||||||
q: P,
|
|
||||||
rp: P,
|
|
||||||
rt: P,
|
|
||||||
ruby: X( { rp: 1, rt: 1 }, P ),
|
|
||||||
s: P,
|
|
||||||
samp: P,
|
|
||||||
script: T,
|
|
||||||
section: X( { style: 1 }, F ),
|
|
||||||
select: { optgroup: 1, option: 1 },
|
|
||||||
small: P,
|
|
||||||
source: E,
|
|
||||||
span: P,
|
|
||||||
strong: P,
|
|
||||||
style: T,
|
|
||||||
sub: P,
|
|
||||||
summary: P,
|
|
||||||
sup: P,
|
|
||||||
table: { caption: 1, colgroup: 1, thead: 1, tfoot: 1, tbody: 1, tr: 1 },
|
|
||||||
tbody: { tr: 1 },
|
|
||||||
td: F,
|
|
||||||
textarea: T,
|
|
||||||
tfoot: { tr: 1 },
|
|
||||||
th: F,
|
|
||||||
thead: { tr: 1 },
|
|
||||||
time: Y( P, { time: 1 } ),
|
|
||||||
title: T,
|
|
||||||
tr: { th: 1, td: 1 },
|
|
||||||
track: E,
|
|
||||||
u: P,
|
|
||||||
ul: { li: 1 },
|
|
||||||
'var': P,
|
|
||||||
video: X( { source: 1, track: 1 }, F ),
|
|
||||||
wbr: E,
|
|
||||||
|
|
||||||
// Deprecated tags.
|
|
||||||
acronym: P,
|
|
||||||
applet: X( { param: 1 }, F ),
|
|
||||||
basefont: E,
|
|
||||||
big: P,
|
|
||||||
center: F,
|
|
||||||
dialog: E,
|
|
||||||
dir: { li: 1 },
|
|
||||||
font: P,
|
|
||||||
isindex: E,
|
|
||||||
noframes: F,
|
|
||||||
strike: P,
|
|
||||||
tt: P
|
|
||||||
};
|
|
||||||
|
|
||||||
X( dtd, {
|
|
||||||
/**
|
|
||||||
* List of block elements, like `<p>` or `<div>`.
|
|
||||||
*/
|
|
||||||
$block: X( { audio: 1, dd: 1, dt: 1, figcaption: 1, li: 1, video: 1 }, FO, DFO ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that contain other blocks, in which block-level operations should be limited,
|
|
||||||
* this property is not intended to be checked directly, use {@link CKEDITOR.dom.elementPath#blockLimit} instead.
|
|
||||||
*
|
|
||||||
* Some examples of editor behaviors that are impacted by block limits:
|
|
||||||
*
|
|
||||||
* * Enter key never split a block-limit element;
|
|
||||||
* * Style application is constraint by the block limit of the current selection.
|
|
||||||
* * Pasted html will be inserted into the block limit of the current selection.
|
|
||||||
*
|
|
||||||
* **Note:** As an exception `<li>` is not considered as a block limit, as it's generally used as a text block.
|
|
||||||
*/
|
|
||||||
$blockLimit: { article: 1, aside: 1, audio: 1, body: 1, caption: 1, details: 1, dir: 1, div: 1, dl: 1,
|
|
||||||
fieldset: 1, figcaption: 1, figure: 1, footer: 1, form: 1, header: 1, hgroup: 1, menu: 1, nav: 1,
|
|
||||||
ol: 1, section: 1, table: 1, td: 1, th: 1, tr: 1, ul: 1, video: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that contain character data.
|
|
||||||
*/
|
|
||||||
$cdata: { script: 1, style: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that are accepted as inline editing hosts.
|
|
||||||
*/
|
|
||||||
$editable: { address: 1, article: 1, aside: 1, blockquote: 1, body: 1, details: 1, div: 1, fieldset: 1,
|
|
||||||
figcaption: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hgroup: 1,
|
|
||||||
nav: 1, p: 1, pre: 1, section: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of empty (self-closing) elements, like `<br>` or `<img>`.
|
|
||||||
*/
|
|
||||||
$empty: { area: 1, base: 1, basefont: 1, br: 1, col: 1, command: 1, dialog: 1, embed: 1, hr: 1, img: 1,
|
|
||||||
input: 1, isindex: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, track: 1, wbr: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of inline (`<span>` like) elements.
|
|
||||||
*/
|
|
||||||
$inline: P,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of list root elements.
|
|
||||||
*/
|
|
||||||
$list: { dl: 1, ol: 1, ul: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of list item elements, like `<li>` or `<dd>`.
|
|
||||||
*/
|
|
||||||
$listItem: { dd: 1, dt: 1, li: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements which may live outside body.
|
|
||||||
*/
|
|
||||||
$nonBodyContent: X( { body: 1, head: 1, html: 1 }, dtd.head ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Elements that accept text nodes, but are not possible to edit into the browser.
|
|
||||||
*/
|
|
||||||
$nonEditable: { applet: 1, audio: 1, button: 1, embed: 1, iframe: 1, map: 1, object: 1, option: 1,
|
|
||||||
param: 1, script: 1, textarea: 1, video: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Elements that are considered objects, therefore selected as a whole in the editor.
|
|
||||||
*/
|
|
||||||
$object: { applet: 1, audio: 1, button: 1, hr: 1, iframe: 1, img: 1, input: 1, object: 1, select: 1,
|
|
||||||
table: 1, textarea: 1, video: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that can be ignored if empty, like `<b>` or `<span>`.
|
|
||||||
*/
|
|
||||||
$removeEmpty: { abbr: 1, acronym: 1, b: 1, bdi: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1,
|
|
||||||
em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, mark: 1, meter: 1, output: 1, q: 1, ruby: 1, s: 1,
|
|
||||||
samp: 1, small: 1, span: 1, strike: 1, strong: 1, sub: 1, sup: 1, time: 1, tt: 1, u: 1, 'var': 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that have tabindex set to zero by default.
|
|
||||||
*/
|
|
||||||
$tabIndex: { a: 1, area: 1, button: 1, input: 1, object: 1, select: 1, textarea: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements used inside the `<table>` element, like `<tbody>` or `<td>`.
|
|
||||||
*/
|
|
||||||
$tableContent: { caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of "transparent" elements. See [W3C's definition of "transparent" element](http://dev.w3.org/html5/markup/terminology.html#transparent).
|
|
||||||
*/
|
|
||||||
$transparent: { a: 1, audio: 1, canvas: 1, del: 1, ins: 1, map: 1, noscript: 1, object: 1, video: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of elements that are not to exist standalone that must live under it's parent element.
|
|
||||||
*/
|
|
||||||
$intermediate: { caption: 1, colgroup: 1, dd: 1, dt: 1, figcaption: 1, legend: 1, li: 1, optgroup: 1,
|
|
||||||
option: 1, rp: 1, rt: 1, summary: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1 }
|
|
||||||
} );
|
|
||||||
|
|
||||||
return dtd;
|
|
||||||
} )();
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.dtd )
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( !CKEDITOR.editor ) {
|
|
||||||
// Documented at editor.js.
|
|
||||||
CKEDITOR.editor = function() {
|
|
||||||
// Push this editor to the pending list. It'll be processed later once
|
|
||||||
// the full editor code is loaded.
|
|
||||||
CKEDITOR._.pending.push( [ this, arguments ] );
|
|
||||||
|
|
||||||
// Call the CKEDITOR.event constructor to initialize this instance.
|
|
||||||
CKEDITOR.event.call( this );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Both fire and fireOnce will always pass this editor instance as the
|
|
||||||
// "editor" param in CKEDITOR.event.fire. So, we override it to do that
|
|
||||||
// automaticaly.
|
|
||||||
CKEDITOR.editor.prototype.fire = function( eventName, data ) {
|
|
||||||
if ( eventName in { instanceReady: 1, loaded: 1 } )
|
|
||||||
this[ eventName ] = true;
|
|
||||||
|
|
||||||
return CKEDITOR.event.prototype.fire.call( this, eventName, data, this );
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.editor.prototype.fireOnce = function( eventName, data ) {
|
|
||||||
if ( eventName in { instanceReady: 1, loaded: 1 } )
|
|
||||||
this[ eventName ] = true;
|
|
||||||
|
|
||||||
return CKEDITOR.event.prototype.fireOnce.call( this, eventName, data, this );
|
|
||||||
};
|
|
||||||
|
|
||||||
// "Inherit" (copy actually) from CKEDITOR.event.
|
|
||||||
CKEDITOR.event.implementOn( CKEDITOR.editor.prototype );
|
|
||||||
}
|
|
||||||
@ -1,333 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.env} object which contains
|
|
||||||
* environment and browser information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( !CKEDITOR.env ) {
|
|
||||||
/**
|
|
||||||
* Environment and browser information.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.env
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.env = ( function() {
|
|
||||||
var agent = navigator.userAgent.toLowerCase();
|
|
||||||
|
|
||||||
var env = {
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Internet Explorer.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.ie )
|
|
||||||
* alert( 'I\'m running in IE!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
ie: ( agent.indexOf( 'trident/' ) > -1 ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a WebKit-based browser, like Safari.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.webkit )
|
|
||||||
* alert( 'I\'m running in a WebKit browser!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
webkit: ( agent.indexOf( ' applewebkit/' ) > -1 ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Adobe AIR.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.air )
|
|
||||||
* alert( 'I\'m on AIR!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
air: ( agent.indexOf( ' adobeair/' ) > -1 ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running on Macintosh.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.mac )
|
|
||||||
* alert( 'I love apples!'' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
mac: ( agent.indexOf( 'macintosh' ) > -1 ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a Quirks Mode environment.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.quirks )
|
|
||||||
* alert( 'Nooooo!' );
|
|
||||||
*
|
|
||||||
* Internet Explorer 10 introduced the _New Quirks Mode_, which is similar to the _Quirks Mode_
|
|
||||||
* implemented in other modern browsers and defined in the HTML5 specification. It can be handled
|
|
||||||
* as the Standards mode, so the value of this property will be set to `false`.
|
|
||||||
*
|
|
||||||
* The _Internet Explorer 5 Quirks_ mode which is still available in Internet Explorer 10+
|
|
||||||
* sets this value to `true` and {@link #version} to `7`.
|
|
||||||
*
|
|
||||||
* Read more: [IEBlog](http://blogs.msdn.com/b/ie/archive/2011/12/14/interoperable-html5-quirks-mode-in-ie10.aspx)
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
quirks: ( document.compatMode == 'BackCompat' && ( !document.documentMode || document.documentMode < 10 ) ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a mobile environemnt.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.mobile )
|
|
||||||
* alert( 'I\'m running with CKEditor today!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
mobile: ( agent.indexOf( 'mobile' ) > -1 ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running on Apple iPhone/iPad/iPod devices.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.iOS )
|
|
||||||
* alert( 'I like little apples!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
iOS: /(ipad|iphone|ipod)/.test( agent ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the browser has a custom domain enabled. This has
|
|
||||||
* been set with `document.domain`.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.isCustomDomain() )
|
|
||||||
* alert( 'I\'m in a custom domain!' );
|
|
||||||
*
|
|
||||||
* @returns {Boolean} `true` if a custom domain is enabled.
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
isCustomDomain: function() {
|
|
||||||
if ( !this.ie )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var domain = document.domain,
|
|
||||||
hostname = window.location.hostname;
|
|
||||||
|
|
||||||
return domain != hostname && domain != ( '[' + hostname + ']' ); // IPv6 IP support (#5434)
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the page is running under an encrypted connection.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.secure )
|
|
||||||
* alert( 'I\'m on SSL!' );
|
|
||||||
*
|
|
||||||
* @returns {Boolean} `true` if the page has an encrypted connection.
|
|
||||||
*/
|
|
||||||
secure: location.protocol == 'https:'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a Gecko-based browser, like
|
|
||||||
* Firefox.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.gecko )
|
|
||||||
* alert( 'I\'m riding a gecko!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
env.gecko = ( navigator.product == 'Gecko' && !env.webkit && !env.ie );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Chrome.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.chrome )
|
|
||||||
* alert( 'I\'m running in Chrome!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean} chrome
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Safari (including the mobile version).
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.safari )
|
|
||||||
* alert( 'I\'m on Safari!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean} safari
|
|
||||||
*/
|
|
||||||
if ( env.webkit ) {
|
|
||||||
if ( agent.indexOf( 'chrome' ) > -1 )
|
|
||||||
env.chrome = true;
|
|
||||||
else
|
|
||||||
env.safari = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var version = 0;
|
|
||||||
|
|
||||||
// Internet Explorer 6.0+
|
|
||||||
if ( env.ie ) {
|
|
||||||
// We use env.version for feature detection, so set it properly.
|
|
||||||
if ( env.quirks || !document.documentMode )
|
|
||||||
version = parseFloat( agent.match( /msie (\d+)/ )[ 1 ] );
|
|
||||||
else
|
|
||||||
version = document.documentMode;
|
|
||||||
|
|
||||||
// Deprecated features available just for backwards compatibility.
|
|
||||||
env.ie9Compat = version == 9;
|
|
||||||
env.ie8Compat = version == 8;
|
|
||||||
env.ie7Compat = version == 7;
|
|
||||||
env.ie6Compat = version < 7 || env.quirks;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in an IE6-like environment, which
|
|
||||||
* includes IE6 itself as well as IE7, IE8 and IE9 in Quirks Mode.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @property {Boolean} ie6Compat
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in an IE7-like environment, which
|
|
||||||
* includes IE7 itself and IE8's IE7 Document Mode.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @property {Boolean} ie7Compat
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Internet Explorer 8 on
|
|
||||||
* Standards Mode.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @property {Boolean} ie8Compat
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in Internet Explorer 9 on
|
|
||||||
* Standards Mode.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @property {Boolean} ie9Compat
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gecko.
|
|
||||||
if ( env.gecko ) {
|
|
||||||
var geckoRelease = agent.match( /rv:([\d\.]+)/ );
|
|
||||||
if ( geckoRelease ) {
|
|
||||||
geckoRelease = geckoRelease[ 1 ].split( '.' );
|
|
||||||
version = geckoRelease[ 0 ] * 10000 + ( geckoRelease[ 1 ] || 0 ) * 100 + ( geckoRelease[ 2 ] || 0 ) * 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adobe AIR 1.0+
|
|
||||||
// Checked before Safari because AIR have the WebKit rich text editor
|
|
||||||
// features from Safari 3.0.4, but the version reported is 420.
|
|
||||||
if ( env.air )
|
|
||||||
version = parseFloat( agent.match( / adobeair\/(\d+)/ )[ 1 ] );
|
|
||||||
|
|
||||||
// WebKit 522+ (Safari 3+)
|
|
||||||
if ( env.webkit )
|
|
||||||
version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[ 1 ] );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the browser version.
|
|
||||||
*
|
|
||||||
* For Gecko-based browsers (like Firefox) it contains the revision
|
|
||||||
* number with first three parts concatenated with a padding zero
|
|
||||||
* (e.g. for revision 1.9.0.2 we have 10900).
|
|
||||||
*
|
|
||||||
* For WebKit-based browsers (like Safari and Chrome) it contains the
|
|
||||||
* WebKit build version (e.g. 522).
|
|
||||||
*
|
|
||||||
* For IE browsers, it matches the "Document Mode".
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.ie && CKEDITOR.env.version <= 6 )
|
|
||||||
* alert( 'Ouch!' );
|
|
||||||
*
|
|
||||||
* @property {Number}
|
|
||||||
*/
|
|
||||||
env.version = version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a compatible browser.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.isCompatible )
|
|
||||||
* alert( 'Your browser is pretty cool!' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
env.isCompatible =
|
|
||||||
// White list of mobile devices that supports.
|
|
||||||
env.iOS && version >= 534 ||
|
|
||||||
!env.mobile && (
|
|
||||||
( env.ie && version > 6 ) ||
|
|
||||||
( env.gecko && version >= 10801 ) ||
|
|
||||||
( env.opera && version >= 9.5 ) ||
|
|
||||||
( env.air && version >= 1 ) ||
|
|
||||||
( env.webkit && version >= 522 ) ||
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in the HiDPI environment.
|
|
||||||
*
|
|
||||||
* if ( CKEDITOR.env.hidpi )
|
|
||||||
* alert( 'You are using a screen with high pixel density.' );
|
|
||||||
*
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
env.hidpi = window.devicePixelRatio >= 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a browser which uses a bogus
|
|
||||||
* `<br>` filler in order to correctly display caret in empty blocks.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
env.needsBrFiller = env.gecko || env.webkit || ( env.ie && version > 10 );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that CKEditor is running in a browser which needs a
|
|
||||||
* non-breaking space filler in order to correctly display caret in empty blocks.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @property {Boolean}
|
|
||||||
*/
|
|
||||||
env.needsNbspFiller = env.ie && version < 11;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A CSS class that denotes the browser where CKEditor runs and is appended
|
|
||||||
* to the HTML element that contains the editor. It makes it easier to apply
|
|
||||||
* browser-specific styles to editor instances.
|
|
||||||
*
|
|
||||||
* myDiv.className = CKEDITOR.env.cssClass;
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
env.cssClass = 'cke_browser_' + ( env.ie ? 'ie' : env.gecko ? 'gecko' : env.webkit ? 'webkit' : 'unknown' );
|
|
||||||
|
|
||||||
if ( env.quirks )
|
|
||||||
env.cssClass += ' cke_browser_quirks';
|
|
||||||
|
|
||||||
if ( env.ie )
|
|
||||||
env.cssClass += ' cke_browser_ie' + ( env.quirks ? '6 cke_browser_iequirks' : env.version );
|
|
||||||
|
|
||||||
if ( env.air )
|
|
||||||
env.cssClass += ' cke_browser_air';
|
|
||||||
|
|
||||||
if ( env.iOS )
|
|
||||||
env.cssClass += ' cke_browser_ios';
|
|
||||||
|
|
||||||
if ( env.hidpi )
|
|
||||||
env.cssClass += ' cke_hidpi';
|
|
||||||
|
|
||||||
return env;
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.env )
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.env.ie )
|
|
||||||
@ -1,387 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.event} class, which serves as the
|
|
||||||
* base for classes and objects that require event handling features.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( !CKEDITOR.event ) {
|
|
||||||
/**
|
|
||||||
* Creates an event class instance. This constructor is rearely used, being
|
|
||||||
* the {@link #implementOn} function used in class prototypes directly
|
|
||||||
* instead.
|
|
||||||
*
|
|
||||||
* This is a base class for classes and objects that require event
|
|
||||||
* handling features.
|
|
||||||
*
|
|
||||||
* Do not confuse this class with {@link CKEDITOR.dom.event} which is
|
|
||||||
* instead used for DOM events. The CKEDITOR.event class implements the
|
|
||||||
* internal event system used by the CKEditor to fire API related events.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates an event class instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.event = function() {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the {@link CKEDITOR.event} features in an object.
|
|
||||||
*
|
|
||||||
* var myObject = { message: 'Example' };
|
|
||||||
* CKEDITOR.event.implementOn( myObject );
|
|
||||||
*
|
|
||||||
* myObject.on( 'testEvent', function() {
|
|
||||||
* alert( this.message );
|
|
||||||
* } );
|
|
||||||
* myObject.fire( 'testEvent' ); // 'Example'
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {Object} targetObject The object into which implement the features.
|
|
||||||
*/
|
|
||||||
CKEDITOR.event.implementOn = function( targetObject ) {
|
|
||||||
var eventProto = CKEDITOR.event.prototype;
|
|
||||||
|
|
||||||
for ( var prop in eventProto ) {
|
|
||||||
if ( targetObject[ prop ] == undefined )
|
|
||||||
targetObject[ prop ] = eventProto[ prop ];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.event.prototype = ( function() {
|
|
||||||
// Returns the private events object for a given object.
|
|
||||||
var getPrivate = function( obj ) {
|
|
||||||
var _ = ( obj.getPrivate && obj.getPrivate() ) || obj._ || ( obj._ = {} );
|
|
||||||
return _.events || ( _.events = {} );
|
|
||||||
};
|
|
||||||
|
|
||||||
var eventEntry = function( eventName ) {
|
|
||||||
this.name = eventName;
|
|
||||||
this.listeners = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
eventEntry.prototype = {
|
|
||||||
// Get the listener index for a specified function.
|
|
||||||
// Returns -1 if not found.
|
|
||||||
getListenerIndex: function( listenerFunction ) {
|
|
||||||
for ( var i = 0, listeners = this.listeners; i < listeners.length; i++ ) {
|
|
||||||
if ( listeners[ i ].fn == listenerFunction )
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Retrieve the event entry on the event host (create it if needed).
|
|
||||||
function getEntry( name ) {
|
|
||||||
// Get the event entry (create it if needed).
|
|
||||||
var events = getPrivate( this );
|
|
||||||
return events[ name ] || ( events[ name ] = new eventEntry( name ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Predefine some intrinsic properties on a specific event name.
|
|
||||||
*
|
|
||||||
* @param {String} name The event name
|
|
||||||
* @param meta
|
|
||||||
* @param [meta.errorProof=false] Whether the event firing should catch error thrown from a per listener call.
|
|
||||||
*/
|
|
||||||
define: function( name, meta ) {
|
|
||||||
var entry = getEntry.call( this, name );
|
|
||||||
CKEDITOR.tools.extend( entry, meta, true );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a listener to a specific event in the current object.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function() {
|
|
||||||
* alert( this == someObject ); // true
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function() {
|
|
||||||
* alert( this == anotherObject ); // true
|
|
||||||
* }, anotherObject );
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.listenerData ); // 'Example'
|
|
||||||
* }, null, 'Example' );
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function() { ... } ); // 2nd called
|
|
||||||
* someObject.on( 'someEvent', function() { ... }, null, null, 100 ); // 3rd called
|
|
||||||
* someObject.on( 'someEvent', function() { ... }, null, null, 1 ); // 1st called
|
|
||||||
*
|
|
||||||
* @param {String} eventName The event name to which listen.
|
|
||||||
* @param {Function} listenerFunction The function listening to the
|
|
||||||
* event. A single {@link CKEDITOR.eventInfo} object instanced
|
|
||||||
* is passed to this function containing all the event data.
|
|
||||||
* @param {Object} [scopeObj] The object used to scope the listener
|
|
||||||
* call (the `this` object). If omitted, the current object is used.
|
|
||||||
* @param {Object} [listenerData] Data to be sent as the
|
|
||||||
* {@link CKEDITOR.eventInfo#listenerData} when calling the
|
|
||||||
* listener.
|
|
||||||
* @param {Number} [priority=10] The listener priority. Lower priority
|
|
||||||
* listeners are called first. Listeners with the same priority
|
|
||||||
* value are called in registration order.
|
|
||||||
* @returns {Object} An object containing the `removeListener`
|
|
||||||
* function, which can be used to remove the listener at any time.
|
|
||||||
*/
|
|
||||||
on: function( eventName, listenerFunction, scopeObj, listenerData, priority ) {
|
|
||||||
// Create the function to be fired for this listener.
|
|
||||||
function listenerFirer( editor, publisherData, stopFn, cancelFn ) {
|
|
||||||
var ev = {
|
|
||||||
name: eventName,
|
|
||||||
sender: this,
|
|
||||||
editor: editor,
|
|
||||||
data: publisherData,
|
|
||||||
listenerData: listenerData,
|
|
||||||
stop: stopFn,
|
|
||||||
cancel: cancelFn,
|
|
||||||
removeListener: removeListener
|
|
||||||
};
|
|
||||||
|
|
||||||
var ret = listenerFunction.call( scopeObj, ev );
|
|
||||||
|
|
||||||
return ret === false ? false : ev.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeListener() {
|
|
||||||
me.removeListener( eventName, listenerFunction );
|
|
||||||
}
|
|
||||||
|
|
||||||
var event = getEntry.call( this, eventName );
|
|
||||||
|
|
||||||
if ( event.getListenerIndex( listenerFunction ) < 0 ) {
|
|
||||||
// Get the listeners.
|
|
||||||
var listeners = event.listeners;
|
|
||||||
|
|
||||||
// Fill the scope.
|
|
||||||
if ( !scopeObj )
|
|
||||||
scopeObj = this;
|
|
||||||
|
|
||||||
// Default the priority, if needed.
|
|
||||||
if ( isNaN( priority ) )
|
|
||||||
priority = 10;
|
|
||||||
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
listenerFirer.fn = listenerFunction;
|
|
||||||
listenerFirer.priority = priority;
|
|
||||||
|
|
||||||
// Search for the right position for this new listener, based on its
|
|
||||||
// priority.
|
|
||||||
for ( var i = listeners.length - 1; i >= 0; i-- ) {
|
|
||||||
// Find the item which should be before the new one.
|
|
||||||
if ( listeners[ i ].priority <= priority ) {
|
|
||||||
// Insert the listener in the array.
|
|
||||||
listeners.splice( i + 1, 0, listenerFirer );
|
|
||||||
return { removeListener: removeListener };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no position has been found (or zero length), put it in
|
|
||||||
// the front of list.
|
|
||||||
listeners.unshift( listenerFirer );
|
|
||||||
}
|
|
||||||
|
|
||||||
return { removeListener: removeListener };
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Similiar with {@link #on} but the listener will be called only once upon the next event firing.
|
|
||||||
*
|
|
||||||
* @see CKEDITOR.event#on
|
|
||||||
*/
|
|
||||||
once: function() {
|
|
||||||
var fn = arguments[ 1 ];
|
|
||||||
|
|
||||||
arguments[ 1 ] = function( evt ) {
|
|
||||||
evt.removeListener();
|
|
||||||
return fn.apply( this, arguments );
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.on.apply( this, arguments );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @static
|
|
||||||
* @property {Boolean} useCapture
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register event handler under the capturing stage on supported target.
|
|
||||||
*/
|
|
||||||
capture: function() {
|
|
||||||
CKEDITOR.event.useCapture = 1;
|
|
||||||
var retval = this.on.apply( this, arguments );
|
|
||||||
CKEDITOR.event.useCapture = 0;
|
|
||||||
return retval;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fires an specific event in the object. All registered listeners are
|
|
||||||
* called at this point.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function() { ... } );
|
|
||||||
* someObject.on( 'someEvent', function() { ... } );
|
|
||||||
* someObject.fire( 'someEvent' ); // Both listeners are called.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.data ); // 'Example'
|
|
||||||
* } );
|
|
||||||
* someObject.fire( 'someEvent', 'Example' );
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @param {String} eventName The event name to fire.
|
|
||||||
* @param {Object} [data] Data to be sent as the
|
|
||||||
* {@link CKEDITOR.eventInfo#data} when calling the listeners.
|
|
||||||
* @param {CKEDITOR.editor} [editor] The editor instance to send as the
|
|
||||||
* {@link CKEDITOR.eventInfo#editor} when calling the listener.
|
|
||||||
* @returns {Boolean/Object} A boolean indicating that the event is to be
|
|
||||||
* canceled, or data returned by one of the listeners.
|
|
||||||
*/
|
|
||||||
fire: ( function() {
|
|
||||||
// Create the function that marks the event as stopped.
|
|
||||||
var stopped = 0;
|
|
||||||
var stopEvent = function() {
|
|
||||||
stopped = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the function that marks the event as canceled.
|
|
||||||
var canceled = 0;
|
|
||||||
var cancelEvent = function() {
|
|
||||||
canceled = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
return function( eventName, data, editor ) {
|
|
||||||
// Get the event entry.
|
|
||||||
var event = getPrivate( this )[ eventName ];
|
|
||||||
|
|
||||||
// Save the previous stopped and cancelled states. We may
|
|
||||||
// be nesting fire() calls.
|
|
||||||
var previousStopped = stopped,
|
|
||||||
previousCancelled = canceled;
|
|
||||||
|
|
||||||
// Reset the stopped and canceled flags.
|
|
||||||
stopped = canceled = 0;
|
|
||||||
|
|
||||||
if ( event ) {
|
|
||||||
var listeners = event.listeners;
|
|
||||||
|
|
||||||
if ( listeners.length ) {
|
|
||||||
// As some listeners may remove themselves from the
|
|
||||||
// event, the original array length is dinamic. So,
|
|
||||||
// let's make a copy of all listeners, so we are
|
|
||||||
// sure we'll call all of them.
|
|
||||||
listeners = listeners.slice( 0 );
|
|
||||||
|
|
||||||
var retData;
|
|
||||||
// Loop through all listeners.
|
|
||||||
for ( var i = 0; i < listeners.length; i++ ) {
|
|
||||||
// Call the listener, passing the event data.
|
|
||||||
if ( event.errorProof ) {
|
|
||||||
try {
|
|
||||||
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
|
|
||||||
} catch ( er ) {}
|
|
||||||
} else
|
|
||||||
retData = listeners[ i ].call( this, editor, data, stopEvent, cancelEvent );
|
|
||||||
|
|
||||||
if ( retData === false )
|
|
||||||
canceled = 1;
|
|
||||||
else if ( typeof retData != 'undefined' )
|
|
||||||
data = retData;
|
|
||||||
|
|
||||||
// No further calls is stopped or canceled.
|
|
||||||
if ( stopped || canceled )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret = canceled ? false : ( typeof data == 'undefined' ? true : data );
|
|
||||||
|
|
||||||
// Restore the previous stopped and canceled states.
|
|
||||||
stopped = previousStopped;
|
|
||||||
canceled = previousCancelled;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
} )(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fires an specific event in the object, releasing all listeners
|
|
||||||
* registered to that event. The same listeners are not called again on
|
|
||||||
* successive calls of it or of {@link #fire}.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function() { ... } );
|
|
||||||
* someObject.fire( 'someEvent' ); // Above listener called.
|
|
||||||
* someObject.fireOnce( 'someEvent' ); // Above listener called.
|
|
||||||
* someObject.fire( 'someEvent' ); // No listeners called.
|
|
||||||
*
|
|
||||||
* @param {String} eventName The event name to fire.
|
|
||||||
* @param {Object} [data] Data to be sent as the
|
|
||||||
* {@link CKEDITOR.eventInfo#data} when calling the listeners.
|
|
||||||
* @param {CKEDITOR.editor} [editor] The editor instance to send as the
|
|
||||||
* {@link CKEDITOR.eventInfo#editor} when calling the listener.
|
|
||||||
* @returns {Boolean/Object} A booloan indicating that the event is to be
|
|
||||||
* canceled, or data returned by one of the listeners.
|
|
||||||
*/
|
|
||||||
fireOnce: function( eventName, data, editor ) {
|
|
||||||
var ret = this.fire( eventName, data, editor );
|
|
||||||
delete getPrivate( this )[ eventName ];
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters a listener function from being called at the specified
|
|
||||||
* event. No errors are thrown if the listener has not been registered previously.
|
|
||||||
*
|
|
||||||
* var myListener = function() { ... };
|
|
||||||
* someObject.on( 'someEvent', myListener );
|
|
||||||
* someObject.fire( 'someEvent' ); // myListener called.
|
|
||||||
* someObject.removeListener( 'someEvent', myListener );
|
|
||||||
* someObject.fire( 'someEvent' ); // myListener not called.
|
|
||||||
*
|
|
||||||
* @param {String} eventName The event name.
|
|
||||||
* @param {Function} listenerFunction The listener function to unregister.
|
|
||||||
*/
|
|
||||||
removeListener: function( eventName, listenerFunction ) {
|
|
||||||
// Get the event entry.
|
|
||||||
var event = getPrivate( this )[ eventName ];
|
|
||||||
|
|
||||||
if ( event ) {
|
|
||||||
var index = event.getListenerIndex( listenerFunction );
|
|
||||||
if ( index >= 0 )
|
|
||||||
event.listeners.splice( index, 1 );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all existing listeners on this object, for cleanup purpose.
|
|
||||||
*/
|
|
||||||
removeAllListeners: function() {
|
|
||||||
var events = getPrivate( this );
|
|
||||||
for ( var i in events )
|
|
||||||
delete events[ i ];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if there is any listener registered to a given event.
|
|
||||||
*
|
|
||||||
* var myListener = function() { ... };
|
|
||||||
* someObject.on( 'someEvent', myListener );
|
|
||||||
* alert( someObject.hasListeners( 'someEvent' ) ); // true
|
|
||||||
* alert( someObject.hasListeners( 'noEvent' ) ); // false
|
|
||||||
*
|
|
||||||
* @param {String} eventName The event name.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
hasListeners: function( eventName ) {
|
|
||||||
var event = getPrivate( this )[ eventName ];
|
|
||||||
return ( event && event.listeners.length > 0 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
@ -1,115 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the "virtual" {@link CKEDITOR.eventInfo} class, which
|
|
||||||
* contains the defintions of the event object passed to event listeners.
|
|
||||||
* This file is for documentation purposes only.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual class that illustrates the features of the event object to be
|
|
||||||
* passed to event listeners by a {@link CKEDITOR.event} based object.
|
|
||||||
*
|
|
||||||
* This class is not really part of the API.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.eventInfo
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The event name.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.name ); // 'someEvent'
|
|
||||||
* } );
|
|
||||||
* someObject.fire( 'someEvent' );
|
|
||||||
*
|
|
||||||
* @property {String} name
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The object that publishes (sends) the event.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.sender == someObject ); // true
|
|
||||||
* } );
|
|
||||||
* someObject.fire( 'someEvent' );
|
|
||||||
*
|
|
||||||
* @property sender
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor instance that holds the sender. May be the same as sender. May be
|
|
||||||
* null if the sender is not part of an editor instance, like a component
|
|
||||||
* running in standalone mode.
|
|
||||||
*
|
|
||||||
* myButton.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.editor == myEditor ); // true
|
|
||||||
* } );
|
|
||||||
* myButton.fire( 'someEvent', null, myEditor );
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.editor} editor
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Any kind of additional data. Its format and usage is event dependent.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.data ); // 'Example'
|
|
||||||
* } );
|
|
||||||
* someObject.fire( 'someEvent', 'Example' );
|
|
||||||
*
|
|
||||||
* @property data
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Any extra data appended during the listener registration.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* alert( event.listenerData ); // 'Example'
|
|
||||||
* }, null, 'Example' );
|
|
||||||
*
|
|
||||||
* @property listenerData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that no further listeners are to be called.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* event.stop();
|
|
||||||
* } );
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* // This one will not be called.
|
|
||||||
* } );
|
|
||||||
* alert( someObject.fire( 'someEvent' ) ); // false
|
|
||||||
*
|
|
||||||
* @method stop
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the event is to be cancelled (if cancelable).
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* event.cancel();
|
|
||||||
* } );
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* // This one will not be called.
|
|
||||||
* } );
|
|
||||||
* alert( someObject.fire( 'someEvent' ) ); // true
|
|
||||||
*
|
|
||||||
* @method cancel
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the current listener.
|
|
||||||
*
|
|
||||||
* someObject.on( 'someEvent', function( event ) {
|
|
||||||
* event.removeListener();
|
|
||||||
* // Now this function won't be called again by 'someEvent'.
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @method removeListener
|
|
||||||
*/
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,271 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.focusManager} class, which is used
|
|
||||||
* to handle the focus on editor instances..
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Manages the focus activity in an editor instance. This class is to be
|
|
||||||
* used mainly by UI elements coders when adding interface elements that need
|
|
||||||
* to set the focus state of the editor.
|
|
||||||
*
|
|
||||||
* var focusManager = new CKEDITOR.focusManager( editor );
|
|
||||||
* focusManager.focus();
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a focusManager class instance.
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.focusManager = function( editor ) {
|
|
||||||
if ( editor.focusManager )
|
|
||||||
return editor.focusManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that the editor instance has focus.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.instances.editor1.focusManager.hasFocus ); // e.g. true
|
|
||||||
*/
|
|
||||||
this.hasFocus = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate the currently focused DOM element that makes the editor activated.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.dom.domObject}
|
|
||||||
*/
|
|
||||||
this.currentActive = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object used to hold private stuff.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._ = {
|
|
||||||
editor: editor
|
|
||||||
};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
var SLOT_NAME = 'focusmanager',
|
|
||||||
SLOT_NAME_LISTENERS = 'focusmanager_handlers';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object used to hold private stuff.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.focusManager._ = {
|
|
||||||
/**
|
|
||||||
* The delay (in milliseconds) to deactivate the editor when UI dom element has lost focus.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @property {Number} [blurDelay=200]
|
|
||||||
* @member CKEDITOR.focusManager._
|
|
||||||
*/
|
|
||||||
blurDelay: 200
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.focusManager.prototype = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate this editor instance is activated (due to DOM focus change),
|
|
||||||
* the `activated` state is a symbolic indicator of an active user
|
|
||||||
* interaction session.
|
|
||||||
*
|
|
||||||
* **Note:** This method will not introduce UI focus
|
|
||||||
* impact on DOM, it's here to record editor UI focus state internally.
|
|
||||||
* If you want to make the cursor blink inside of the editable, use
|
|
||||||
* {@link CKEDITOR.editor#method-focus} instead.
|
|
||||||
*
|
|
||||||
* var editor = CKEDITOR.instances.editor1;
|
|
||||||
* editor.focusManage.focus( editor.editable() );
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.element} [currentActive] The new value of {@link #currentActive} property.
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
focus: function( currentActive ) {
|
|
||||||
if ( this._.timer )
|
|
||||||
clearTimeout( this._.timer );
|
|
||||||
|
|
||||||
if ( currentActive )
|
|
||||||
this.currentActive = currentActive;
|
|
||||||
|
|
||||||
if ( !( this.hasFocus || this._.locked ) ) {
|
|
||||||
// If another editor has the current focus, we first "blur" it. In
|
|
||||||
// this way the events happen in a more logical sequence, like:
|
|
||||||
// "focus 1" > "blur 1" > "focus 2"
|
|
||||||
// ... instead of:
|
|
||||||
// "focus 1" > "focus 2" > "blur 1"
|
|
||||||
var current = CKEDITOR.currentInstance;
|
|
||||||
current && current.focusManager.blur( 1 );
|
|
||||||
|
|
||||||
this.hasFocus = true;
|
|
||||||
|
|
||||||
var ct = this._.editor.container;
|
|
||||||
ct && ct.addClass( 'cke_focus' );
|
|
||||||
this._.editor.fire( 'focus' );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent from changing the focus manager state until next {@link #unlock} is called.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
lock: function() {
|
|
||||||
this._.locked = 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore the automatic focus management, if {@link #lock} is called.
|
|
||||||
*
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
unlock: function() {
|
|
||||||
delete this._.locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to indicate that the editor instance has been deactivated by the specified
|
|
||||||
* element which has just lost focus.
|
|
||||||
*
|
|
||||||
* **Note:** that this functions acts asynchronously with a delay of 100ms to
|
|
||||||
* avoid temporary deactivation. Use instead the `noDelay` parameter
|
|
||||||
* to deactivate immediately.
|
|
||||||
*
|
|
||||||
* var editor = CKEDITOR.instances.editor1;
|
|
||||||
* editor.focusManager.blur();
|
|
||||||
*
|
|
||||||
* @param {Boolean} [noDelay=false] Deactivate immediately the editor instance synchronously.
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
blur: function( noDelay ) {
|
|
||||||
if ( this._.locked )
|
|
||||||
return;
|
|
||||||
|
|
||||||
function doBlur() {
|
|
||||||
if ( this.hasFocus ) {
|
|
||||||
this.hasFocus = false;
|
|
||||||
|
|
||||||
var ct = this._.editor.container;
|
|
||||||
ct && ct.removeClass( 'cke_focus' );
|
|
||||||
this._.editor.fire( 'blur' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this._.timer )
|
|
||||||
clearTimeout( this._.timer );
|
|
||||||
|
|
||||||
var delay = CKEDITOR.focusManager._.blurDelay;
|
|
||||||
if ( noDelay || !delay )
|
|
||||||
doBlur.call( this );
|
|
||||||
else {
|
|
||||||
this._.timer = CKEDITOR.tools.setTimeout( function() {
|
|
||||||
delete this._.timer;
|
|
||||||
doBlur.call( this );
|
|
||||||
}, delay, this );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an UI DOM element to the focus manager, which will make the focus manager "hasFocus"
|
|
||||||
* once input focus is relieved on the element, it's to be used by plugins to expand the jurisdiction of the editor focus.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.element} element The container (top most) element of one UI part.
|
|
||||||
* @param {Boolean} isCapture If specified {@link CKEDITOR.event#useCapture} will be used when listening to the focus event.
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
add: function( element, isCapture ) {
|
|
||||||
var fm = element.getCustomData( SLOT_NAME );
|
|
||||||
if ( !fm || fm != this ) {
|
|
||||||
// If this element is already taken by another instance, dismiss it first.
|
|
||||||
fm && fm.remove( element );
|
|
||||||
|
|
||||||
var focusEvent = 'focus',
|
|
||||||
blurEvent = 'blur';
|
|
||||||
|
|
||||||
// Bypass the element's internal DOM focus change.
|
|
||||||
if ( isCapture ) {
|
|
||||||
|
|
||||||
// Use "focusin/focusout" events instead of capture phase in IEs,
|
|
||||||
// which fires synchronously.
|
|
||||||
if ( CKEDITOR.env.ie ) {
|
|
||||||
focusEvent = 'focusin';
|
|
||||||
blurEvent = 'focusout';
|
|
||||||
} else
|
|
||||||
CKEDITOR.event.useCapture = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var listeners = {
|
|
||||||
blur: function() {
|
|
||||||
if ( element.equals( this.currentActive ) )
|
|
||||||
this.blur();
|
|
||||||
},
|
|
||||||
focus: function() {
|
|
||||||
this.focus( element );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
element.on( focusEvent, listeners.focus, this );
|
|
||||||
element.on( blurEvent, listeners.blur, this );
|
|
||||||
|
|
||||||
if ( isCapture )
|
|
||||||
CKEDITOR.event.useCapture = 0;
|
|
||||||
|
|
||||||
element.setCustomData( SLOT_NAME, this );
|
|
||||||
element.setCustomData( SLOT_NAME_LISTENERS, listeners );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dismiss an element from the the focus manager delegations added by {@link #add}.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.element} element The element to be removed from the focusmanager.
|
|
||||||
* @member CKEDITOR.focusManager
|
|
||||||
*/
|
|
||||||
remove: function( element ) {
|
|
||||||
element.removeCustomData( SLOT_NAME );
|
|
||||||
var listeners = element.removeCustomData( SLOT_NAME_LISTENERS );
|
|
||||||
element.removeListener( 'blur', listeners.blur );
|
|
||||||
element.removeListener( 'focus', listeners.focus );
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the editor instance receives the input focus.
|
|
||||||
*
|
|
||||||
* editor.on( 'focus', function( e ) {
|
|
||||||
* alert( 'The editor named ' + e.editor.name + ' is now focused' );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @event focus
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when the editor instance loses the input focus.
|
|
||||||
*
|
|
||||||
* **Note:** This event will **NOT** be triggered when focus is moved internally, e.g. from
|
|
||||||
* the editable to other part of the editor UI like dialog.
|
|
||||||
* If you're interested on only the editable focus state listen to the {@link CKEDITOR.editable#event-focus}
|
|
||||||
* and {@link CKEDITOR.editable#blur} events instead.
|
|
||||||
*
|
|
||||||
* editor.on( 'blur', function( e ) {
|
|
||||||
* alert( 'The editor named ' + e.editor.name + ' lost the focus' );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @event blur
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
*/
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,207 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an "event like" system to parse strings of HTML data.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onTagOpen = function( tagName, attributes, selfClosing ) {
|
|
||||||
* alert( tagName );
|
|
||||||
* };
|
|
||||||
* parser.parse( '<p>Some <b>text</b>.</p>' ); // Alerts 'p', 'b'.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a htmlParser class instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser = function() {
|
|
||||||
this._ = {
|
|
||||||
htmlPartsRegex: new RegExp( '<(?:(?:\\/([^>]+)>)|(?:!--([\\S|\\s]*?)-->)|(?:([^\\s>]+)\\s*((?:(?:"[^"]*")|(?:\'[^\']*\')|[^"\'>])*)\\/?>))', 'g' )
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var attribsRegex = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,
|
|
||||||
emptyAttribs = { checked: 1, compact: 1, declare: 1, defer: 1, disabled: 1, ismap: 1, multiple: 1, nohref: 1, noresize: 1, noshade: 1, nowrap: 1, readonly: 1, selected: 1 };
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.prototype = {
|
|
||||||
/**
|
|
||||||
* Function to be fired when a tag opener is found. This function
|
|
||||||
* should be overriden when using this class.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onTagOpen = function( tagName, attributes, selfClosing ) {
|
|
||||||
* alert( tagName ); // e.g. 'b'
|
|
||||||
* } );
|
|
||||||
* parser.parse( '<!-- Example --><b>Hello</b>' );
|
|
||||||
*
|
|
||||||
* @param {String} tagName The tag name. The name is guarantted to be lowercased.
|
|
||||||
* @param {Object} attributes An object containing all tag attributes. Each
|
|
||||||
* property in this object represent and attribute name and its value is the attribute value.
|
|
||||||
* @param {Boolean} selfClosing `true` if the tag closes itself, false if the tag doesn't.
|
|
||||||
*/
|
|
||||||
onTagOpen: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be fired when a tag closer is found. This function
|
|
||||||
* should be overriden when using this class.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onTagClose = function( tagName ) {
|
|
||||||
* alert( tagName ); // 'b'
|
|
||||||
* } );
|
|
||||||
* parser.parse( '<!-- Example --><b>Hello</b>' );
|
|
||||||
*
|
|
||||||
* @param {String} tagName The tag name. The name is guarantted to be lowercased.
|
|
||||||
*/
|
|
||||||
onTagClose: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be fired when text is found. This function
|
|
||||||
* should be overriden when using this class.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onText = function( text ) {
|
|
||||||
* alert( text ); // 'Hello'
|
|
||||||
* } );
|
|
||||||
* parser.parse( '<!-- Example --><b>Hello</b>' );
|
|
||||||
*
|
|
||||||
* @param {String} text The text found.
|
|
||||||
*/
|
|
||||||
onText: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be fired when CDATA section is found. This function
|
|
||||||
* should be overriden when using this class.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onCDATA = function( cdata ) {
|
|
||||||
* alert( cdata ); // 'var hello;'
|
|
||||||
* } );
|
|
||||||
* parser.parse( '<script>var hello;</script>' );
|
|
||||||
*
|
|
||||||
* @param {String} cdata The CDATA been found.
|
|
||||||
*/
|
|
||||||
onCDATA: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be fired when a commend is found. This function
|
|
||||||
* should be overriden when using this class.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* parser.onComment = function( comment ) {
|
|
||||||
* alert( comment ); // ' Example '
|
|
||||||
* } );
|
|
||||||
* parser.parse( '<!-- Example --><b>Hello</b>' );
|
|
||||||
*
|
|
||||||
* @param {String} comment The comment text.
|
|
||||||
*/
|
|
||||||
onComment: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses text, looking for HTML tokens, like tag openers or closers,
|
|
||||||
* or comments. This function fires the onTagOpen, onTagClose, onText
|
|
||||||
* and onComment function during its execution.
|
|
||||||
*
|
|
||||||
* var parser = new CKEDITOR.htmlParser();
|
|
||||||
* // The onTagOpen, onTagClose, onText and onComment should be overriden
|
|
||||||
* // at this point.
|
|
||||||
* parser.parse( '<!-- Example --><b>Hello</b>' );
|
|
||||||
*
|
|
||||||
* @param {String} html The HTML to be parsed.
|
|
||||||
*/
|
|
||||||
parse: function( html ) {
|
|
||||||
var parts, tagName,
|
|
||||||
nextIndex = 0,
|
|
||||||
cdata; // The collected data inside a CDATA section.
|
|
||||||
|
|
||||||
while ( ( parts = this._.htmlPartsRegex.exec( html ) ) ) {
|
|
||||||
var tagIndex = parts.index;
|
|
||||||
if ( tagIndex > nextIndex ) {
|
|
||||||
var text = html.substring( nextIndex, tagIndex );
|
|
||||||
|
|
||||||
if ( cdata )
|
|
||||||
cdata.push( text );
|
|
||||||
else
|
|
||||||
this.onText( text );
|
|
||||||
}
|
|
||||||
|
|
||||||
nextIndex = this._.htmlPartsRegex.lastIndex;
|
|
||||||
|
|
||||||
/*
|
|
||||||
"parts" is an array with the following items:
|
|
||||||
0 : The entire match for opening/closing tags and comments.
|
|
||||||
1 : Group filled with the tag name for closing tags.
|
|
||||||
2 : Group filled with the comment text.
|
|
||||||
3 : Group filled with the tag name for opening tags.
|
|
||||||
4 : Group filled with the attributes part of opening tags.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Closing tag
|
|
||||||
if ( ( tagName = parts[ 1 ] ) ) {
|
|
||||||
tagName = tagName.toLowerCase();
|
|
||||||
|
|
||||||
if ( cdata && CKEDITOR.dtd.$cdata[ tagName ] ) {
|
|
||||||
// Send the CDATA data.
|
|
||||||
this.onCDATA( cdata.join( '' ) );
|
|
||||||
cdata = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !cdata ) {
|
|
||||||
this.onTagClose( tagName );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If CDATA is enabled, just save the raw match.
|
|
||||||
if ( cdata ) {
|
|
||||||
cdata.push( parts[ 0 ] );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opening tag
|
|
||||||
if ( ( tagName = parts[ 3 ] ) ) {
|
|
||||||
tagName = tagName.toLowerCase();
|
|
||||||
|
|
||||||
// There are some tag names that can break things, so let's
|
|
||||||
// simply ignore them when parsing. (#5224)
|
|
||||||
if ( /="/.test( tagName ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var attribs = {},
|
|
||||||
attribMatch,
|
|
||||||
attribsPart = parts[ 4 ],
|
|
||||||
selfClosing = !!( attribsPart && attribsPart.charAt( attribsPart.length - 1 ) == '/' );
|
|
||||||
|
|
||||||
if ( attribsPart ) {
|
|
||||||
while ( ( attribMatch = attribsRegex.exec( attribsPart ) ) ) {
|
|
||||||
var attName = attribMatch[ 1 ].toLowerCase(),
|
|
||||||
attValue = attribMatch[ 2 ] || attribMatch[ 3 ] || attribMatch[ 4 ] || '';
|
|
||||||
|
|
||||||
if ( !attValue && emptyAttribs[ attName ] )
|
|
||||||
attribs[ attName ] = attName;
|
|
||||||
else
|
|
||||||
attribs[ attName ] = CKEDITOR.tools.htmlDecodeAttr( attValue );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onTagOpen( tagName, attribs, selfClosing );
|
|
||||||
|
|
||||||
// Open CDATA mode when finding the appropriate tags.
|
|
||||||
if ( !cdata && CKEDITOR.dtd.$cdata[ tagName ] )
|
|
||||||
cdata = [];
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment
|
|
||||||
if ( ( tagName = parts[ 2 ] ) )
|
|
||||||
this.onComment( tagName );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( html.length > nextIndex )
|
|
||||||
this.onText( html.substring( nextIndex, html.length ) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass( {
|
|
||||||
/**
|
|
||||||
* Creates a basicWriter class instance.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
$: function() {
|
|
||||||
this._ = {
|
|
||||||
output: []
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
proto: {
|
|
||||||
/**
|
|
||||||
* Writes the tag opening part for a opener tag.
|
|
||||||
*
|
|
||||||
* // Writes '<p'.
|
|
||||||
* writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
|
|
||||||
*
|
|
||||||
* @param {String} tagName The element name for this tag.
|
|
||||||
* @param {Object} attributes The attributes defined for this tag. The
|
|
||||||
* attributes could be used to inspect the tag.
|
|
||||||
*/
|
|
||||||
openTag: function( tagName, attributes ) {
|
|
||||||
this._.output.push( '<', tagName );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the tag closing part for a opener tag.
|
|
||||||
*
|
|
||||||
* // Writes '>'.
|
|
||||||
* writer.openTagClose( 'p', false );
|
|
||||||
*
|
|
||||||
* // Writes ' />'.
|
|
||||||
* writer.openTagClose( 'br', true );
|
|
||||||
*
|
|
||||||
* @param {String} tagName The element name for this tag.
|
|
||||||
* @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
|
|
||||||
* like `<br>` or `<img>`.
|
|
||||||
*/
|
|
||||||
openTagClose: function( tagName, isSelfClose ) {
|
|
||||||
if ( isSelfClose )
|
|
||||||
this._.output.push( ' />' );
|
|
||||||
else
|
|
||||||
this._.output.push( '>' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an attribute. This function should be called after opening the
|
|
||||||
* tag with {@link #openTagClose}.
|
|
||||||
*
|
|
||||||
* // Writes ' class="MyClass"'.
|
|
||||||
* writer.attribute( 'class', 'MyClass' );
|
|
||||||
*
|
|
||||||
* @param {String} attName The attribute name.
|
|
||||||
* @param {String} attValue The attribute value.
|
|
||||||
*/
|
|
||||||
attribute: function( attName, attValue ) {
|
|
||||||
// Browsers don't always escape special character in attribute values. (#4683, #4719).
|
|
||||||
if ( typeof attValue == 'string' )
|
|
||||||
attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );
|
|
||||||
|
|
||||||
this._.output.push( ' ', attName, '="', attValue, '"' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a closer tag.
|
|
||||||
*
|
|
||||||
* // Writes '</p>'.
|
|
||||||
* writer.closeTag( 'p' );
|
|
||||||
*
|
|
||||||
* @param {String} tagName The element name for this tag.
|
|
||||||
*/
|
|
||||||
closeTag: function( tagName ) {
|
|
||||||
this._.output.push( '</', tagName, '>' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes text.
|
|
||||||
*
|
|
||||||
* // Writes 'Hello Word'.
|
|
||||||
* writer.text( 'Hello Word' );
|
|
||||||
*
|
|
||||||
* @param {String} text The text value.
|
|
||||||
*/
|
|
||||||
text: function( text ) {
|
|
||||||
this._.output.push( text );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a comment.
|
|
||||||
*
|
|
||||||
* // Writes '<!-- My comment -->'.
|
|
||||||
* writer.comment( ' My comment ' );
|
|
||||||
*
|
|
||||||
* @param {String} comment The comment text.
|
|
||||||
*/
|
|
||||||
comment: function( comment ) {
|
|
||||||
this._.output.push( '<!--', comment, '-->' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes any kind of data to the ouput.
|
|
||||||
*
|
|
||||||
* writer.write( 'This is an <b>example</b>.' );
|
|
||||||
*
|
|
||||||
* @param {String} data
|
|
||||||
*/
|
|
||||||
write: function( data ) {
|
|
||||||
this._.output.push( data );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Empties the current output buffer.
|
|
||||||
*
|
|
||||||
* writer.reset();
|
|
||||||
*/
|
|
||||||
reset: function() {
|
|
||||||
this._.output = [];
|
|
||||||
this._.indent = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Empties the current output buffer.
|
|
||||||
*
|
|
||||||
* var html = writer.getHtml();
|
|
||||||
*
|
|
||||||
* @param {Boolean} reset Indicates that the {@link #reset} method is to
|
|
||||||
* be automatically called after retrieving the HTML.
|
|
||||||
* @returns {String} The HTML written to the writer so far.
|
|
||||||
*/
|
|
||||||
getHtml: function( reset ) {
|
|
||||||
var html = this._.output.join( '' );
|
|
||||||
|
|
||||||
if ( reset )
|
|
||||||
this.reset();
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A lightweight representation of HTML CDATA.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.htmlParser.node
|
|
||||||
* @constructor Creates a cdata class instance.
|
|
||||||
* @param {String} value The CDATA section value.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.cdata = function( value ) {
|
|
||||||
/**
|
|
||||||
* The CDATA value.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.value = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.cdata.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
|
|
||||||
/**
|
|
||||||
* CDATA has the same type as {@link CKEDITOR.htmlParser.text} This is
|
|
||||||
* a constant value set to {@link CKEDITOR#NODE_TEXT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_TEXT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_TEXT,
|
|
||||||
|
|
||||||
filter: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the CDATA with no special manipulations.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
|
|
||||||
*/
|
|
||||||
writeHtml: function( writer ) {
|
|
||||||
writer.write( this.value );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
} )();
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A lightweight representation of an HTML comment.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.htmlParser.node
|
|
||||||
* @constructor Creates a comment class instance.
|
|
||||||
* @param {String} value The comment text value.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.comment = function( value ) {
|
|
||||||
/**
|
|
||||||
* The comment text.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.value = value;
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this._ = {
|
|
||||||
isBlockLike: false
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.comment.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_COMMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_COMMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_COMMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter this comment with given filter.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
* @returns {Boolean} Method returns `false` when this comment has
|
|
||||||
* been removed or replaced with other node. This is an information for
|
|
||||||
* {@link CKEDITOR.htmlParser.element#filterChildren} that it has
|
|
||||||
* to repeat filter on current position in parent's children array.
|
|
||||||
*/
|
|
||||||
filter: function( filter, context ) {
|
|
||||||
var comment = this.value;
|
|
||||||
|
|
||||||
if ( !( comment = filter.onComment( context, comment, this ) ) ) {
|
|
||||||
this.remove();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof comment != 'string' ) {
|
|
||||||
this.replaceWith( comment );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = comment;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the HTML representation of this comment to a CKEDITOR.htmlWriter.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
|
|
||||||
* **Note:** it's unsafe to filter offline (not appended) node.
|
|
||||||
*/
|
|
||||||
writeHtml: function( writer, filter ) {
|
|
||||||
if ( filter )
|
|
||||||
this.filter( filter );
|
|
||||||
|
|
||||||
writer.comment( this.value );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
@ -1,534 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A lightweight representation of an HTML element.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.htmlParser.node
|
|
||||||
* @constructor Creates an element class instance.
|
|
||||||
* @param {String} name The element name.
|
|
||||||
* @param {Object} attributes An object storing all attributes defined for
|
|
||||||
* this element.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.element = function( name, attributes ) {
|
|
||||||
/**
|
|
||||||
* The element name.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.name = name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the attributes defined for this element.
|
|
||||||
*
|
|
||||||
* @property {Object}
|
|
||||||
*/
|
|
||||||
this.attributes = attributes || {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The nodes that are direct children of this element.
|
|
||||||
*/
|
|
||||||
this.children = [];
|
|
||||||
|
|
||||||
// Reveal the real semantic of our internal custom tag name (#6639),
|
|
||||||
// when resolving whether it's block like.
|
|
||||||
var realName = name || '',
|
|
||||||
prefixed = realName.match( /^cke:(.*)/ );
|
|
||||||
prefixed && ( realName = prefixed[ 1 ] );
|
|
||||||
|
|
||||||
var isBlockLike = !!( CKEDITOR.dtd.$nonBodyContent[ realName ] || CKEDITOR.dtd.$block[ realName ] || CKEDITOR.dtd.$listItem[ realName ] || CKEDITOR.dtd.$tableContent[ realName ] || CKEDITOR.dtd.$nonEditable[ realName ] || realName == 'br' );
|
|
||||||
|
|
||||||
this.isEmpty = !!CKEDITOR.dtd.$empty[ name ];
|
|
||||||
this.isUnknown = !CKEDITOR.dtd[ name ];
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this._ = {
|
|
||||||
isBlockLike: isBlockLike,
|
|
||||||
hasInlineStarted: this.isEmpty || !isBlockLike
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object presentation of CSS style declaration text.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a `cssStyle` class instance.
|
|
||||||
* @param {CKEDITOR.htmlParser.element/String} elementOrStyleText
|
|
||||||
* An HTML parser element or the inline style text.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.cssStyle = function() {
|
|
||||||
var styleText,
|
|
||||||
arg = arguments[ 0 ],
|
|
||||||
rules = {};
|
|
||||||
|
|
||||||
styleText = arg instanceof CKEDITOR.htmlParser.element ? arg.attributes.style : arg;
|
|
||||||
|
|
||||||
// html-encoded quote might be introduced by 'font-family'
|
|
||||||
// from MS-Word which confused the following regexp. e.g.
|
|
||||||
//'font-family: "Lucida, Console"'
|
|
||||||
// TODO reuse CSS methods from tools.
|
|
||||||
( styleText || '' ).replace( /"/g, '"' ).replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) {
|
|
||||||
name == 'font-family' && ( value = value.replace( /["']/g, '' ) );
|
|
||||||
rules[ name.toLowerCase() ] = value;
|
|
||||||
} );
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
rules: rules,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies the styles to the specified element or object.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.element/CKEDITOR.dom.element/Object} obj
|
|
||||||
*/
|
|
||||||
populate: function( obj ) {
|
|
||||||
var style = this.toString();
|
|
||||||
if ( style )
|
|
||||||
obj instanceof CKEDITOR.dom.element ? obj.setAttribute( 'style', style ) : obj instanceof CKEDITOR.htmlParser.element ? obj.attributes.style = style : obj.style = style;
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes CSS style declaration to a string.
|
|
||||||
*
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
toString: function() {
|
|
||||||
var output = [];
|
|
||||||
for ( var i in rules )
|
|
||||||
rules[ i ] && output.push( i, ':', rules[ i ], ';' );
|
|
||||||
return output.join( '' );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @class CKEDITOR.htmlParser.element */
|
|
||||||
( function() {
|
|
||||||
// Used to sort attribute entries in an array, where the first element of
|
|
||||||
// each object is the attribute name.
|
|
||||||
var sortAttribs = function( a, b ) {
|
|
||||||
a = a[ 0 ];
|
|
||||||
b = b[ 0 ];
|
|
||||||
return a < b ? -1 : a > b ? 1 : 0;
|
|
||||||
},
|
|
||||||
fragProto = CKEDITOR.htmlParser.fragment.prototype;
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.element.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_ELEMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_ELEMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_ELEMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a node to the element children list.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node to be added.
|
|
||||||
* @param {Number} [index] From where the insertion happens.
|
|
||||||
*/
|
|
||||||
add: fragProto.add,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clones this element.
|
|
||||||
*
|
|
||||||
* @returns {CKEDITOR.htmlParser.element} The element clone.
|
|
||||||
*/
|
|
||||||
clone: function() {
|
|
||||||
return new CKEDITOR.htmlParser.element( this.name, this.attributes );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters this element and its children with the given filter.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
* @returns {Boolean} The method returns `false` when this element has
|
|
||||||
* been removed or replaced with another. This information means that
|
|
||||||
* {@link #filterChildren} has to repeat the filter on the current
|
|
||||||
* position in parent's children array.
|
|
||||||
*/
|
|
||||||
filter: function( filter, context ) {
|
|
||||||
var element = this,
|
|
||||||
originalName, name;
|
|
||||||
|
|
||||||
context = element.getFilterContext( context );
|
|
||||||
|
|
||||||
// Do not process elements with data-cke-processor attribute set to off.
|
|
||||||
if ( context.off )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Filtering if it's the root node.
|
|
||||||
if ( !element.parent )
|
|
||||||
filter.onRoot( context, element );
|
|
||||||
|
|
||||||
while ( true ) {
|
|
||||||
originalName = element.name;
|
|
||||||
|
|
||||||
if ( !( name = filter.onElementName( context, originalName ) ) ) {
|
|
||||||
this.remove();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
element.name = name;
|
|
||||||
|
|
||||||
if ( !( element = filter.onElement( context, element ) ) ) {
|
|
||||||
this.remove();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// New element has been returned - replace current one
|
|
||||||
// and process it (stop processing this and return false, what
|
|
||||||
// means that element has been removed).
|
|
||||||
if ( element !== this ) {
|
|
||||||
this.replaceWith( element );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If name has been changed - continue loop, so in next iteration
|
|
||||||
// filters for new name will be applied to this element.
|
|
||||||
// If name hasn't been changed - stop.
|
|
||||||
if ( element.name == originalName )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// If element has been replaced with something of a
|
|
||||||
// different type, then make the replacement filter itself.
|
|
||||||
if ( element.type != CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
this.replaceWith( element );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This indicate that the element has been dropped by
|
|
||||||
// filter but not the children.
|
|
||||||
if ( !element.name ) {
|
|
||||||
this.replaceWithChildren();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributes = element.attributes,
|
|
||||||
a, value, newAttrName;
|
|
||||||
|
|
||||||
for ( a in attributes ) {
|
|
||||||
newAttrName = a;
|
|
||||||
value = attributes[ a ];
|
|
||||||
|
|
||||||
// Loop until name isn't modified.
|
|
||||||
// A little bit senseless, but IE would do that anyway
|
|
||||||
// because it iterates with for-in loop even over properties
|
|
||||||
// created during its run.
|
|
||||||
while ( true ) {
|
|
||||||
if ( !( newAttrName = filter.onAttributeName( context, a ) ) ) {
|
|
||||||
delete attributes[ a ];
|
|
||||||
break;
|
|
||||||
} else if ( newAttrName != a ) {
|
|
||||||
delete attributes[ a ];
|
|
||||||
a = newAttrName;
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( newAttrName ) {
|
|
||||||
if ( ( value = filter.onAttribute( context, element, newAttrName, value ) ) === false )
|
|
||||||
delete attributes[ newAttrName ];
|
|
||||||
else
|
|
||||||
attributes[ newAttrName ] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !element.isEmpty )
|
|
||||||
this.filterChildren( filter, false, context );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters this element's children with the given filter.
|
|
||||||
*
|
|
||||||
* Element's children may only be filtered once by one
|
|
||||||
* instance of the filter.
|
|
||||||
*
|
|
||||||
* @method filterChildren
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
*/
|
|
||||||
filterChildren: fragProto.filterChildren,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the element HTML to the CKEDITOR.htmlWriter.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
|
|
||||||
* **Note:** It is unsafe to filter an offline (not appended) node.
|
|
||||||
*/
|
|
||||||
writeHtml: function( writer, filter ) {
|
|
||||||
if ( filter )
|
|
||||||
this.filter( filter );
|
|
||||||
|
|
||||||
var name = this.name,
|
|
||||||
attribsArray = [],
|
|
||||||
attributes = this.attributes,
|
|
||||||
attrName,
|
|
||||||
attr, i, l;
|
|
||||||
|
|
||||||
// Open element tag.
|
|
||||||
writer.openTag( name, attributes );
|
|
||||||
|
|
||||||
// Copy all attributes to an array.
|
|
||||||
for ( attrName in attributes )
|
|
||||||
attribsArray.push( [ attrName, attributes[ attrName ] ] );
|
|
||||||
|
|
||||||
// Sort the attributes by name.
|
|
||||||
if ( writer.sortAttributes )
|
|
||||||
attribsArray.sort( sortAttribs );
|
|
||||||
|
|
||||||
// Send the attributes.
|
|
||||||
for ( i = 0, l = attribsArray.length; i < l; i++ ) {
|
|
||||||
attr = attribsArray[ i ];
|
|
||||||
writer.attribute( attr[ 0 ], attr[ 1 ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the tag.
|
|
||||||
writer.openTagClose( name, this.isEmpty );
|
|
||||||
|
|
||||||
this.writeChildrenHtml( writer );
|
|
||||||
|
|
||||||
// Close the element.
|
|
||||||
if ( !this.isEmpty )
|
|
||||||
writer.closeTag( name );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends children of this element to the writer.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which HTML will be written.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter]
|
|
||||||
*/
|
|
||||||
writeChildrenHtml: fragProto.writeChildrenHtml,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces this element with its children.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
replaceWithChildren: function() {
|
|
||||||
var children = this.children;
|
|
||||||
|
|
||||||
for ( var i = children.length; i; )
|
|
||||||
children[ --i ].insertAfter( this );
|
|
||||||
|
|
||||||
this.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a callback on each node (of the given type) in this element.
|
|
||||||
*
|
|
||||||
* // Create a <p> element with foo<b>bar</b>bom as its content.
|
|
||||||
* var elP = CKEDITOR.htmlParser.fragment.fromHtml( 'foo<b>bar</b>bom', 'p' );
|
|
||||||
* elP.forEach( function( node ) {
|
|
||||||
* console.log( node );
|
|
||||||
* } );
|
|
||||||
* // Will log:
|
|
||||||
* // 1. document fragment,
|
|
||||||
* // 2. <p> element,
|
|
||||||
* // 3. "foo" text node,
|
|
||||||
* // 4. <b> element,
|
|
||||||
* // 5. "bar" text node,
|
|
||||||
* // 6. "bom" text node.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {Function} callback Function to be executed on every node.
|
|
||||||
* **Since 4.3**: If `callback` returned `false`, the descendants of the current node will be ignored.
|
|
||||||
* @param {CKEDITOR.htmlParser.node} callback.node Node passed as an argument.
|
|
||||||
* @param {Number} [type] Whether the specified `callback` will be executed only on nodes of this type.
|
|
||||||
* @param {Boolean} [skipRoot] Do not execute `callback` on this element.
|
|
||||||
*/
|
|
||||||
forEach: fragProto.forEach,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this element's first child. If `condition` is given, this method returns
|
|
||||||
* the first child which satisfies that condition.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String/Object/Function} condition Name of a child, a hash of names, or a validator function.
|
|
||||||
* @returns {CKEDITOR.htmlParser.node}
|
|
||||||
*/
|
|
||||||
getFirst: function( condition ) {
|
|
||||||
if ( !condition )
|
|
||||||
return this.children.length ? this.children[ 0 ] : null;
|
|
||||||
|
|
||||||
if ( typeof condition != 'function' )
|
|
||||||
condition = nameCondition( condition );
|
|
||||||
|
|
||||||
for ( var i = 0, l = this.children.length; i < l; ++i ) {
|
|
||||||
if ( condition( this.children[ i ] ) )
|
|
||||||
return this.children[ i ];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this element's inner HTML.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
getHtml: function() {
|
|
||||||
var writer = new CKEDITOR.htmlParser.basicWriter();
|
|
||||||
this.writeChildrenHtml( writer );
|
|
||||||
return writer.getHtml();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this element's inner HTML.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String} html
|
|
||||||
*/
|
|
||||||
setHtml: function( html ) {
|
|
||||||
var children = this.children = CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
|
|
||||||
|
|
||||||
for ( var i = 0, l = children.length; i < l; ++i )
|
|
||||||
children[ i ].parent = this;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this element's outer HTML.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
getOuterHtml: function() {
|
|
||||||
var writer = new CKEDITOR.htmlParser.basicWriter();
|
|
||||||
this.writeHtml( writer );
|
|
||||||
return writer.getHtml();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits this element at the given index.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {Number} index Index at which the element will be split — `0` means the beginning,
|
|
||||||
* `1` after first child node, etc.
|
|
||||||
* @returns {CKEDITOR.htmlParser.element} The new element following this one.
|
|
||||||
*/
|
|
||||||
split: function( index ) {
|
|
||||||
var cloneChildren = this.children.splice( index, this.children.length - index ),
|
|
||||||
clone = this.clone();
|
|
||||||
|
|
||||||
for ( var i = 0; i < cloneChildren.length; ++i )
|
|
||||||
cloneChildren[ i ].parent = clone;
|
|
||||||
|
|
||||||
clone.children = cloneChildren;
|
|
||||||
|
|
||||||
if ( cloneChildren[ 0 ] )
|
|
||||||
cloneChildren[ 0 ].previous = null;
|
|
||||||
|
|
||||||
if ( index > 0 )
|
|
||||||
this.children[ index - 1 ].next = null;
|
|
||||||
|
|
||||||
this.parent.add( clone, this.getIndex() + 1 );
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a class name to the list of classes.
|
|
||||||
*
|
|
||||||
* @since 4.4
|
|
||||||
* @param {String} className The class name to be added.
|
|
||||||
*/
|
|
||||||
addClass: function( className ) {
|
|
||||||
if ( this.hasClass( className ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var c = this.attributes[ 'class' ] || '';
|
|
||||||
|
|
||||||
this.attributes[ 'class' ] = c + ( c ? ' ' : '' ) + className;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a class name from the list of classes.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String} className The class name to be removed.
|
|
||||||
*/
|
|
||||||
removeClass: function( className ) {
|
|
||||||
var classes = this.attributes[ 'class' ],
|
|
||||||
index;
|
|
||||||
|
|
||||||
if ( !classes )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// We can safely assume that className won't break regexp.
|
|
||||||
// http://stackoverflow.com/questions/448981/what-characters-are-valid-in-css-class-names
|
|
||||||
classes = CKEDITOR.tools.trim( classes.replace( new RegExp( '(?:\\s+|^)' + className + '(?:\\s+|$)' ), ' ' ) );
|
|
||||||
|
|
||||||
if ( classes )
|
|
||||||
this.attributes[ 'class' ] = classes;
|
|
||||||
else
|
|
||||||
delete this.attributes[ 'class' ];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checkes whether this element has a class name.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String} className The class name to be checked.
|
|
||||||
* @returns {Boolean} Whether this element has a `className`.
|
|
||||||
*/
|
|
||||||
hasClass: function( className ) {
|
|
||||||
var classes = this.attributes[ 'class' ];
|
|
||||||
|
|
||||||
if ( !classes )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return ( new RegExp( '(?:^|\\s)' + className + '(?=\\s|$)' ) ).test( classes );
|
|
||||||
},
|
|
||||||
|
|
||||||
getFilterContext: function( ctx ) {
|
|
||||||
var changes = [];
|
|
||||||
|
|
||||||
if ( !ctx ) {
|
|
||||||
ctx = {
|
|
||||||
off: false,
|
|
||||||
nonEditable: false,
|
|
||||||
nestedEditable: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !ctx.off && this.attributes[ 'data-cke-processor' ] == 'off' )
|
|
||||||
changes.push( 'off', true );
|
|
||||||
|
|
||||||
if ( !ctx.nonEditable && this.attributes.contenteditable == 'false' )
|
|
||||||
changes.push( 'nonEditable', true );
|
|
||||||
// A context to be given nestedEditable must be nonEditable first (by inheritance) (#11372, #11698).
|
|
||||||
// Special case: #11504 - filter starts on <body contenteditable=true>,
|
|
||||||
// so ctx.nonEditable has not been yet set to true.
|
|
||||||
else if ( ctx.nonEditable && !ctx.nestedEditable && this.attributes.contenteditable == 'true' )
|
|
||||||
changes.push( 'nestedEditable', true );
|
|
||||||
|
|
||||||
if ( changes.length ) {
|
|
||||||
ctx = CKEDITOR.tools.copy( ctx );
|
|
||||||
for ( var i = 0; i < changes.length; i += 2 )
|
|
||||||
ctx[ changes[ i ] ] = changes[ i + 1 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
}, true );
|
|
||||||
|
|
||||||
function nameCondition( condition ) {
|
|
||||||
return function( el ) {
|
|
||||||
return el.type == CKEDITOR.NODE_ELEMENT &&
|
|
||||||
( typeof condition == 'string' ? el.name == condition : el.name in condition );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} )();
|
|
||||||
@ -1,407 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Filter is a configurable tool for transforming and filtering {@link CKEDITOR.htmlParser.node nodes}.
|
|
||||||
* It is mainly used during data processing phase which is done not on real DOM nodes,
|
|
||||||
* but on their simplified form represented by {@link CKEDITOR.htmlParser.node} class and its subclasses.
|
|
||||||
*
|
|
||||||
* var filter = new CKEDITOR.htmlParser.filter( {
|
|
||||||
* text: function( value ) {
|
|
||||||
* return '@' + value + '@';
|
|
||||||
* },
|
|
||||||
* elements: {
|
|
||||||
* p: function( element ) {
|
|
||||||
* element.attributes.foo = '1';
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>Foo<b>bar!</b></p>' ),
|
|
||||||
* writer = new CKEDITOR.htmlParser.basicWriter();
|
|
||||||
* filter.applyTo( fragment );
|
|
||||||
* fragment.writeHtml( writer );
|
|
||||||
* writer.getHtml(); // '<p foo="1">@Foo@<b>@bar!@</b></p>'
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass( {
|
|
||||||
/**
|
|
||||||
* @constructor Creates a filter class instance.
|
|
||||||
* @param {CKEDITOR.htmlParser.filterRulesDefinition} [rules]
|
|
||||||
*/
|
|
||||||
$: function( rules ) {
|
|
||||||
/**
|
|
||||||
* ID of filter instance, which is used to mark elements
|
|
||||||
* to which this filter has been already applied.
|
|
||||||
*
|
|
||||||
* @property {Number} id
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.id = CKEDITOR.tools.getNextNumber();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rules for element names.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.htmlParser.filterRulesGroup}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.elementNameRules = new filterRulesGroup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rules for attribute names.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.htmlParser.filterRulesGroup}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.attributeNameRules = new filterRulesGroup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of elementName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for elements}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.elementsRules = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of attributeName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for attributes}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.attributesRules = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rules for text nodes.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.htmlParser.filterRulesGroup}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.textRules = new filterRulesGroup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rules for comment nodes.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.htmlParser.filterRulesGroup}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.commentRules = new filterRulesGroup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rules for a root node.
|
|
||||||
*
|
|
||||||
* @property {CKEDITOR.htmlParser.filterRulesGroup}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.rootRules = new filterRulesGroup();
|
|
||||||
|
|
||||||
if ( rules )
|
|
||||||
this.addRules( rules, 10 );
|
|
||||||
},
|
|
||||||
|
|
||||||
proto: {
|
|
||||||
/**
|
|
||||||
* Add rules to this filter.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.filterRulesDefinition} rules Object containing filter rules.
|
|
||||||
* @param {Object/Number} [options] Object containing rules' options or a priority
|
|
||||||
* (for a backward compatibility with CKEditor versions up to 4.2.x).
|
|
||||||
* @param {Number} [options.priority=10] The priority of a rule.
|
|
||||||
* @param {Boolean} [options.applyToAll=false] Whether to apply rule to non-editable
|
|
||||||
* elements and their descendants too.
|
|
||||||
*/
|
|
||||||
addRules: function( rules, options ) {
|
|
||||||
var priority;
|
|
||||||
|
|
||||||
// Backward compatibility.
|
|
||||||
if ( typeof options == 'number' )
|
|
||||||
priority = options;
|
|
||||||
// New version - try reading from options.
|
|
||||||
else if ( options && ( 'priority' in options ) )
|
|
||||||
priority = options.priority;
|
|
||||||
|
|
||||||
// Defaults.
|
|
||||||
if ( typeof priority != 'number' )
|
|
||||||
priority = 10;
|
|
||||||
if ( typeof options != 'object' )
|
|
||||||
options = {};
|
|
||||||
|
|
||||||
// Add the elementNames.
|
|
||||||
if ( rules.elementNames )
|
|
||||||
this.elementNameRules.addMany( rules.elementNames, priority, options );
|
|
||||||
|
|
||||||
// Add the attributeNames.
|
|
||||||
if ( rules.attributeNames )
|
|
||||||
this.attributeNameRules.addMany( rules.attributeNames, priority, options );
|
|
||||||
|
|
||||||
// Add the elements.
|
|
||||||
if ( rules.elements )
|
|
||||||
addNamedRules( this.elementsRules, rules.elements, priority, options );
|
|
||||||
|
|
||||||
// Add the attributes.
|
|
||||||
if ( rules.attributes )
|
|
||||||
addNamedRules( this.attributesRules, rules.attributes, priority, options );
|
|
||||||
|
|
||||||
// Add the text.
|
|
||||||
if ( rules.text )
|
|
||||||
this.textRules.add( rules.text, priority, options );
|
|
||||||
|
|
||||||
// Add the comment.
|
|
||||||
if ( rules.comment )
|
|
||||||
this.commentRules.add( rules.comment, priority, options );
|
|
||||||
|
|
||||||
// Add root node rules.
|
|
||||||
if ( rules.root )
|
|
||||||
this.rootRules.add( rules.root, priority, options );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply this filter to given node.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node to be filtered.
|
|
||||||
*/
|
|
||||||
applyTo: function( node ) {
|
|
||||||
node.filter( this );
|
|
||||||
},
|
|
||||||
|
|
||||||
onElementName: function( context, name ) {
|
|
||||||
return this.elementNameRules.execOnName( context, name );
|
|
||||||
},
|
|
||||||
|
|
||||||
onAttributeName: function( context, name ) {
|
|
||||||
return this.attributeNameRules.execOnName( context, name );
|
|
||||||
},
|
|
||||||
|
|
||||||
onText: function( context, text, node ) {
|
|
||||||
return this.textRules.exec( context, text, node );
|
|
||||||
},
|
|
||||||
|
|
||||||
onComment: function( context, commentText, comment ) {
|
|
||||||
return this.commentRules.exec( context, commentText, comment );
|
|
||||||
},
|
|
||||||
|
|
||||||
onRoot: function( context, element ) {
|
|
||||||
return this.rootRules.exec( context, element );
|
|
||||||
},
|
|
||||||
|
|
||||||
onElement: function( context, element ) {
|
|
||||||
// We must apply filters set to the specific element name as
|
|
||||||
// well as those set to the generic ^/$ name. So, add both to an
|
|
||||||
// array and process them in a small loop.
|
|
||||||
var rulesGroups = [ this.elementsRules[ '^' ], this.elementsRules[ element.name ], this.elementsRules.$ ],
|
|
||||||
rulesGroup, ret;
|
|
||||||
|
|
||||||
for ( var i = 0; i < 3; i++ ) {
|
|
||||||
rulesGroup = rulesGroups[ i ];
|
|
||||||
if ( rulesGroup ) {
|
|
||||||
ret = rulesGroup.exec( context, element, this );
|
|
||||||
|
|
||||||
if ( ret === false )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( ret && ret != element )
|
|
||||||
return this.onNode( context, ret );
|
|
||||||
|
|
||||||
// The non-root element has been dismissed by one of the filters.
|
|
||||||
if ( element.parent && !element.name )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
|
||||||
},
|
|
||||||
|
|
||||||
onNode: function( context, node ) {
|
|
||||||
var type = node.type;
|
|
||||||
|
|
||||||
return type == CKEDITOR.NODE_ELEMENT ? this.onElement( context, node ) :
|
|
||||||
type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( context, node.value ) ) :
|
|
||||||
type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( context, node.value ) ) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
onAttribute: function( context, element, name, value ) {
|
|
||||||
var rulesGroup = this.attributesRules[ name ];
|
|
||||||
|
|
||||||
if ( rulesGroup )
|
|
||||||
return rulesGroup.exec( context, value, element, this );
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class grouping filter rules for one subject (like element or attribute names).
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.htmlParser.filterRulesGroup
|
|
||||||
*/
|
|
||||||
function filterRulesGroup() {
|
|
||||||
/**
|
|
||||||
* Array of objects containing rule, priority and options.
|
|
||||||
*
|
|
||||||
* @property {Object[]}
|
|
||||||
* @readonly
|
|
||||||
*/
|
|
||||||
this.rules = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.filterRulesGroup = filterRulesGroup;
|
|
||||||
|
|
||||||
filterRulesGroup.prototype = {
|
|
||||||
/**
|
|
||||||
* Adds specified rule to this group.
|
|
||||||
*
|
|
||||||
* @param {Function/Array} rule Function for function based rule or [ pattern, replacement ] array for
|
|
||||||
* rule applicable to names.
|
|
||||||
* @param {Number} priority
|
|
||||||
* @param options
|
|
||||||
*/
|
|
||||||
add: function( rule, priority, options ) {
|
|
||||||
this.rules.splice( this.findIndex( priority ), 0, {
|
|
||||||
value: rule,
|
|
||||||
priority: priority,
|
|
||||||
options: options
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds specified rules to this group.
|
|
||||||
*
|
|
||||||
* @param {Array} rules Array of rules - see {@link #add}.
|
|
||||||
* @param {Number} priority
|
|
||||||
* @param options
|
|
||||||
*/
|
|
||||||
addMany: function( rules, priority, options ) {
|
|
||||||
var args = [ this.findIndex( priority ), 0 ];
|
|
||||||
|
|
||||||
for ( var i = 0, len = rules.length; i < len; i++ ) {
|
|
||||||
args.push( {
|
|
||||||
value: rules[ i ],
|
|
||||||
priority: priority,
|
|
||||||
options: options
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rules.splice.apply( this.rules, args );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds an index at which rule with given priority should be inserted.
|
|
||||||
*
|
|
||||||
* @param {Number} priority
|
|
||||||
* @returns {Number} Index.
|
|
||||||
*/
|
|
||||||
findIndex: function( priority ) {
|
|
||||||
var rules = this.rules,
|
|
||||||
len = rules.length,
|
|
||||||
i = len - 1;
|
|
||||||
|
|
||||||
// Search from the end, because usually rules will be added with default priority, so
|
|
||||||
// we will be able to stop loop quickly.
|
|
||||||
while ( i >= 0 && priority < rules[ i ].priority )
|
|
||||||
i--;
|
|
||||||
|
|
||||||
return i + 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes this rules group on given value. Applicable only if function based rules were added.
|
|
||||||
*
|
|
||||||
* All arguments passed to this function will be forwarded to rules' functions.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} currentValue The value to be filtered.
|
|
||||||
* @returns {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} Filtered value.
|
|
||||||
*/
|
|
||||||
exec: function( context, currentValue ) {
|
|
||||||
var isNode = currentValue instanceof CKEDITOR.htmlParser.node || currentValue instanceof CKEDITOR.htmlParser.fragment,
|
|
||||||
// Splice '1' to remove context, which we don't want to pass to filter rules.
|
|
||||||
args = Array.prototype.slice.call( arguments, 1 ),
|
|
||||||
rules = this.rules,
|
|
||||||
len = rules.length,
|
|
||||||
orgType, orgName, ret, i, rule;
|
|
||||||
|
|
||||||
for ( i = 0; i < len; i++ ) {
|
|
||||||
// Backup the node info before filtering.
|
|
||||||
if ( isNode ) {
|
|
||||||
orgType = currentValue.type;
|
|
||||||
orgName = currentValue.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
rule = rules[ i ];
|
|
||||||
if ( isRuleApplicable( context, rule ) ) {
|
|
||||||
ret = rule.value.apply( null, args );
|
|
||||||
|
|
||||||
if ( ret === false )
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
// We're filtering node (element/fragment).
|
|
||||||
// No further filtering if it's not anymore fitable for the subsequent filters.
|
|
||||||
if ( isNode && ret && ( ret.name != orgName || ret.type != orgType ) )
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
// Update currentValue and corresponding argument in args array.
|
|
||||||
// Updated values will be used in next for-loop step.
|
|
||||||
if ( ret != undefined )
|
|
||||||
args[ 0 ] = currentValue = ret;
|
|
||||||
|
|
||||||
// ret == undefined will continue loop as nothing has happened.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentValue;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes this rules group on name. Applicable only if filter rules for names were added.
|
|
||||||
*
|
|
||||||
* @param {String} currentName The name to be filtered.
|
|
||||||
* @returns {String} Filtered name.
|
|
||||||
*/
|
|
||||||
execOnName: function( context, currentName ) {
|
|
||||||
var i = 0,
|
|
||||||
rules = this.rules,
|
|
||||||
len = rules.length,
|
|
||||||
rule;
|
|
||||||
|
|
||||||
for ( ; currentName && i < len; i++ ) {
|
|
||||||
rule = rules[ i ];
|
|
||||||
if ( isRuleApplicable( context, rule ) )
|
|
||||||
currentName = currentName.replace( rule.value[ 0 ], rule.value[ 1 ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentName;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function addNamedRules( rulesGroups, newRules, priority, options ) {
|
|
||||||
var ruleName, rulesGroup;
|
|
||||||
|
|
||||||
for ( ruleName in newRules ) {
|
|
||||||
rulesGroup = rulesGroups[ ruleName ];
|
|
||||||
|
|
||||||
if ( !rulesGroup )
|
|
||||||
rulesGroup = rulesGroups[ ruleName ] = new filterRulesGroup();
|
|
||||||
|
|
||||||
rulesGroup.add( newRules[ ruleName ], priority, options );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRuleApplicable( context, rule ) {
|
|
||||||
if ( context.nonEditable && !rule.options.applyToAll )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( context.nestedEditable && rule.options.excludeNestedEditable )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class CKEDITOR.htmlParser.filterRulesDefinition
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
@ -1,643 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A lightweight representation of an HTML DOM structure.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a fragment class instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.fragment = function() {
|
|
||||||
/**
|
|
||||||
* The nodes contained in the root of this fragment.
|
|
||||||
*
|
|
||||||
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
|
|
||||||
* alert( fragment.children.length ); // 2
|
|
||||||
*/
|
|
||||||
this.children = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the fragment parent. Should always be null.
|
|
||||||
*
|
|
||||||
* @property {Object} [=null]
|
|
||||||
*/
|
|
||||||
this.parent = null;
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this._ = {
|
|
||||||
isBlockLike: true,
|
|
||||||
hasInlineStarted: false
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
// Block-level elements whose internal structure should be respected during
|
|
||||||
// parser fixing.
|
|
||||||
var nonBreakingBlocks = CKEDITOR.tools.extend( { table: 1, ul: 1, ol: 1, dl: 1 }, CKEDITOR.dtd.table, CKEDITOR.dtd.ul, CKEDITOR.dtd.ol, CKEDITOR.dtd.dl );
|
|
||||||
|
|
||||||
var listBlocks = { ol: 1, ul: 1 };
|
|
||||||
|
|
||||||
// Dtd of the fragment element, basically it accept anything except for intermediate structure, e.g. orphan <li>.
|
|
||||||
var rootDtd = CKEDITOR.tools.extend( {}, { html: 1 }, CKEDITOR.dtd.html, CKEDITOR.dtd.body, CKEDITOR.dtd.head, { style: 1, script: 1 } );
|
|
||||||
|
|
||||||
// Which element to create when encountered not allowed content.
|
|
||||||
var structureFixes = {
|
|
||||||
ul: 'li',
|
|
||||||
ol: 'li',
|
|
||||||
dl: 'dd',
|
|
||||||
table: 'tbody',
|
|
||||||
tbody: 'tr',
|
|
||||||
thead: 'tr',
|
|
||||||
tfoot: 'tr',
|
|
||||||
tr: 'td'
|
|
||||||
};
|
|
||||||
|
|
||||||
function isRemoveEmpty( node ) {
|
|
||||||
// Keep marked element event if it is empty.
|
|
||||||
if ( node.attributes[ 'data-cke-survive' ] )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Empty link is to be removed when empty but not anchor. (#7894)
|
|
||||||
return node.name == 'a' && node.attributes.href || CKEDITOR.dtd.$removeEmpty[ node.name ];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
|
|
||||||
*
|
|
||||||
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
|
|
||||||
* alert( fragment.children[ 0 ].name ); // 'b'
|
|
||||||
* alert( fragment.children[ 1 ].value ); // ' Text'
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param {String} fragmentHtml The HTML to be parsed, filling the fragment.
|
|
||||||
* @param {CKEDITOR.htmlParser.element/String} [parent] Optional contextual
|
|
||||||
* element which makes the content been parsed as the content of this element and fix
|
|
||||||
* to match it.
|
|
||||||
* If not provided, then {@link CKEDITOR.htmlParser.fragment} will be used
|
|
||||||
* as the parent and it will be returned.
|
|
||||||
* @param {String/Boolean} [fixingBlock] When `parent` is a block limit element,
|
|
||||||
* and the param is a string value other than `false`, it is to
|
|
||||||
* avoid having block-less content as the direct children of parent by wrapping
|
|
||||||
* the content with a block element of the specified tag, e.g.
|
|
||||||
* when `fixingBlock` specified as `p`, the content `<body><i>foo</i></body>`
|
|
||||||
* will be fixed into `<body><p><i>foo</i></p></body>`.
|
|
||||||
* @returns {CKEDITOR.htmlParser.fragment/CKEDITOR.htmlParser.element} The created fragment or passed `parent`.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.fragment.fromHtml = function( fragmentHtml, parent, fixingBlock ) {
|
|
||||||
var parser = new CKEDITOR.htmlParser();
|
|
||||||
|
|
||||||
var root = parent instanceof CKEDITOR.htmlParser.element ? parent : typeof parent == 'string' ? new CKEDITOR.htmlParser.element( parent ) : new CKEDITOR.htmlParser.fragment();
|
|
||||||
|
|
||||||
var pendingInline = [],
|
|
||||||
pendingBRs = [],
|
|
||||||
currentNode = root,
|
|
||||||
// Indicate we're inside a <textarea> element, spaces should be touched differently.
|
|
||||||
inTextarea = root.name == 'textarea',
|
|
||||||
// Indicate we're inside a <pre> element, spaces should be touched differently.
|
|
||||||
inPre = root.name == 'pre';
|
|
||||||
|
|
||||||
function checkPending( newTagName ) {
|
|
||||||
var pendingBRsSent;
|
|
||||||
|
|
||||||
if ( pendingInline.length > 0 ) {
|
|
||||||
for ( var i = 0; i < pendingInline.length; i++ ) {
|
|
||||||
var pendingElement = pendingInline[ i ],
|
|
||||||
pendingName = pendingElement.name,
|
|
||||||
pendingDtd = CKEDITOR.dtd[ pendingName ],
|
|
||||||
currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ];
|
|
||||||
|
|
||||||
if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) ) {
|
|
||||||
if ( !pendingBRsSent ) {
|
|
||||||
sendPendingBRs();
|
|
||||||
pendingBRsSent = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a clone for the pending element.
|
|
||||||
pendingElement = pendingElement.clone();
|
|
||||||
|
|
||||||
// Add it to the current node and make it the current,
|
|
||||||
// so the new element will be added inside of it.
|
|
||||||
pendingElement.parent = currentNode;
|
|
||||||
currentNode = pendingElement;
|
|
||||||
|
|
||||||
// Remove the pending element (back the index by one
|
|
||||||
// to properly process the next entry).
|
|
||||||
pendingInline.splice( i, 1 );
|
|
||||||
i--;
|
|
||||||
} else {
|
|
||||||
// Some element of the same type cannot be nested, flat them,
|
|
||||||
// e.g. <a href="#">foo<a href="#">bar</a></a>. (#7894)
|
|
||||||
if ( pendingName == currentNode.name )
|
|
||||||
addElement( currentNode, currentNode.parent, 1 ), i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendPendingBRs() {
|
|
||||||
while ( pendingBRs.length )
|
|
||||||
addElement( pendingBRs.shift(), currentNode );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rtrim empty spaces on block end boundary. (#3585)
|
|
||||||
function removeTailWhitespace( element ) {
|
|
||||||
if ( element._.isBlockLike && element.name != 'pre' && element.name != 'textarea' ) {
|
|
||||||
|
|
||||||
var length = element.children.length,
|
|
||||||
lastChild = element.children[ length - 1 ],
|
|
||||||
text;
|
|
||||||
if ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
if ( !( text = CKEDITOR.tools.rtrim( lastChild.value ) ) )
|
|
||||||
element.children.length = length - 1;
|
|
||||||
else
|
|
||||||
lastChild.value = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Beside of simply append specified element to target, this function also takes
|
|
||||||
// care of other dirty lifts like forcing block in body, trimming spaces at
|
|
||||||
// the block boundaries etc.
|
|
||||||
//
|
|
||||||
// @param {Element} element The element to be added as the last child of {@link target}.
|
|
||||||
// @param {Element} target The parent element to relieve the new node.
|
|
||||||
// @param {Boolean} [moveCurrent=false] Don't change the "currentNode" global unless
|
|
||||||
// there's a return point node specified on the element, otherwise move current onto {@link target} node.
|
|
||||||
//
|
|
||||||
function addElement( element, target, moveCurrent ) {
|
|
||||||
target = target || currentNode || root;
|
|
||||||
|
|
||||||
// Current element might be mangled by fix body below,
|
|
||||||
// save it for restore later.
|
|
||||||
var savedCurrent = currentNode;
|
|
||||||
|
|
||||||
// Ignore any element that has already been added.
|
|
||||||
if ( element.previous === undefined ) {
|
|
||||||
if ( checkAutoParagraphing( target, element ) ) {
|
|
||||||
// Create a <p> in the fragment.
|
|
||||||
currentNode = target;
|
|
||||||
parser.onTagOpen( fixingBlock, {} );
|
|
||||||
|
|
||||||
// The new target now is the <p>.
|
|
||||||
element.returnPoint = target = currentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTailWhitespace( element );
|
|
||||||
|
|
||||||
// Avoid adding empty inline.
|
|
||||||
if ( !( isRemoveEmpty( element ) && !element.children.length ) )
|
|
||||||
target.add( element );
|
|
||||||
|
|
||||||
if ( element.name == 'pre' )
|
|
||||||
inPre = false;
|
|
||||||
|
|
||||||
if ( element.name == 'textarea' )
|
|
||||||
inTextarea = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( element.returnPoint ) {
|
|
||||||
currentNode = element.returnPoint;
|
|
||||||
delete element.returnPoint;
|
|
||||||
} else
|
|
||||||
currentNode = moveCurrent ? target : savedCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto paragraphing should happen when inline content enters the root element.
|
|
||||||
function checkAutoParagraphing( parent, node ) {
|
|
||||||
|
|
||||||
// Check for parent that can contain block.
|
|
||||||
if ( ( parent == root || parent.name == 'body' ) && fixingBlock &&
|
|
||||||
( !parent.name || CKEDITOR.dtd[ parent.name ][ fixingBlock ] ) )
|
|
||||||
{
|
|
||||||
var name, realName;
|
|
||||||
if ( node.attributes && ( realName = node.attributes[ 'data-cke-real-element-type' ] ) )
|
|
||||||
name = realName;
|
|
||||||
else
|
|
||||||
name = node.name;
|
|
||||||
|
|
||||||
// Text node, inline elements are subjected, except for <script>/<style>.
|
|
||||||
return name && name in CKEDITOR.dtd.$inline &&
|
|
||||||
!( name in CKEDITOR.dtd.head ) &&
|
|
||||||
!node.isOrphan ||
|
|
||||||
node.type == CKEDITOR.NODE_TEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Judge whether two element tag names are likely the siblings from the same
|
|
||||||
// structural element.
|
|
||||||
function possiblySibling( tag1, tag2 ) {
|
|
||||||
|
|
||||||
if ( tag1 in CKEDITOR.dtd.$listItem || tag1 in CKEDITOR.dtd.$tableContent )
|
|
||||||
return tag1 == tag2 || tag1 == 'dt' && tag2 == 'dd' || tag1 == 'dd' && tag2 == 'dt';
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.onTagOpen = function( tagName, attributes, selfClosing, optionalClose ) {
|
|
||||||
var element = new CKEDITOR.htmlParser.element( tagName, attributes );
|
|
||||||
|
|
||||||
// "isEmpty" will be always "false" for unknown elements, so we
|
|
||||||
// must force it if the parser has identified it as a selfClosing tag.
|
|
||||||
if ( element.isUnknown && selfClosing )
|
|
||||||
element.isEmpty = true;
|
|
||||||
|
|
||||||
// Check for optional closed elements, including browser quirks and manually opened blocks.
|
|
||||||
element.isOptionalClose = optionalClose;
|
|
||||||
|
|
||||||
// This is a tag to be removed if empty, so do not add it immediately.
|
|
||||||
if ( isRemoveEmpty( element ) ) {
|
|
||||||
pendingInline.push( element );
|
|
||||||
return;
|
|
||||||
} else if ( tagName == 'pre' )
|
|
||||||
inPre = true;
|
|
||||||
else if ( tagName == 'br' && inPre ) {
|
|
||||||
currentNode.add( new CKEDITOR.htmlParser.text( '\n' ) );
|
|
||||||
return;
|
|
||||||
} else if ( tagName == 'textarea' )
|
|
||||||
inTextarea = true;
|
|
||||||
|
|
||||||
if ( tagName == 'br' ) {
|
|
||||||
pendingBRs.push( element );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( 1 ) {
|
|
||||||
var currentName = currentNode.name;
|
|
||||||
|
|
||||||
var currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
|
|
||||||
|
|
||||||
// If the element cannot be child of the current element.
|
|
||||||
if ( !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] ) {
|
|
||||||
// Current node doesn't have a close tag, time for a close
|
|
||||||
// as this element isn't fit in. (#7497)
|
|
||||||
if ( currentNode.isOptionalClose )
|
|
||||||
parser.onTagClose( currentName );
|
|
||||||
// Fixing malformed nested lists by moving it into a previous list item. (#3828)
|
|
||||||
else if ( tagName in listBlocks && currentName in listBlocks ) {
|
|
||||||
var children = currentNode.children,
|
|
||||||
lastChild = children[ children.length - 1 ];
|
|
||||||
|
|
||||||
// Establish the list item if it's not existed.
|
|
||||||
if ( !( lastChild && lastChild.name == 'li' ) )
|
|
||||||
addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
|
|
||||||
|
|
||||||
!element.returnPoint && ( element.returnPoint = currentNode );
|
|
||||||
currentNode = lastChild;
|
|
||||||
}
|
|
||||||
// Establish new list root for orphan list items, but NOT to create
|
|
||||||
// new list for the following ones, fix them instead. (#6975)
|
|
||||||
// <dl><dt>foo<dd>bar</dl>
|
|
||||||
// <ul><li>foo<li>bar</ul>
|
|
||||||
else if ( tagName in CKEDITOR.dtd.$listItem &&
|
|
||||||
!possiblySibling( tagName, currentName ) ) {
|
|
||||||
parser.onTagOpen( tagName == 'li' ? 'ul' : 'dl', {}, 0, 1 );
|
|
||||||
}
|
|
||||||
// We're inside a structural block like table and list, AND the incoming element
|
|
||||||
// is not of the same type (e.g. <td>td1<td>td2</td>), we simply add this new one before it,
|
|
||||||
// and most importantly, return back to here once this element is added,
|
|
||||||
// e.g. <table><tr><td>td1</td><p>p1</p><td>td2</td></tr></table>
|
|
||||||
else if ( currentName in nonBreakingBlocks &&
|
|
||||||
!possiblySibling( tagName, currentName ) ) {
|
|
||||||
!element.returnPoint && ( element.returnPoint = currentNode );
|
|
||||||
currentNode = currentNode.parent;
|
|
||||||
} else {
|
|
||||||
// The current element is an inline element, which
|
|
||||||
// need to be continued even after the close, so put
|
|
||||||
// it in the pending list.
|
|
||||||
if ( currentName in CKEDITOR.dtd.$inline )
|
|
||||||
pendingInline.unshift( currentNode );
|
|
||||||
|
|
||||||
// The most common case where we just need to close the
|
|
||||||
// current one and append the new one to the parent.
|
|
||||||
if ( currentNode.parent )
|
|
||||||
addElement( currentNode, currentNode.parent, 1 );
|
|
||||||
// We've tried our best to fix the embarrassment here, while
|
|
||||||
// this element still doesn't find it's parent, mark it as
|
|
||||||
// orphan and show our tolerance to it.
|
|
||||||
else {
|
|
||||||
element.isOrphan = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkPending( tagName );
|
|
||||||
sendPendingBRs();
|
|
||||||
|
|
||||||
element.parent = currentNode;
|
|
||||||
|
|
||||||
if ( element.isEmpty )
|
|
||||||
addElement( element );
|
|
||||||
else
|
|
||||||
currentNode = element;
|
|
||||||
};
|
|
||||||
|
|
||||||
parser.onTagClose = function( tagName ) {
|
|
||||||
// Check if there is any pending tag to be closed.
|
|
||||||
for ( var i = pendingInline.length - 1; i >= 0; i-- ) {
|
|
||||||
// If found, just remove it from the list.
|
|
||||||
if ( tagName == pendingInline[ i ].name ) {
|
|
||||||
pendingInline.splice( i, 1 );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pendingAdd = [],
|
|
||||||
newPendingInline = [],
|
|
||||||
candidate = currentNode;
|
|
||||||
|
|
||||||
while ( candidate != root && candidate.name != tagName ) {
|
|
||||||
// If this is an inline element, add it to the pending list, if we're
|
|
||||||
// really closing one of the parents element later, they will continue
|
|
||||||
// after it.
|
|
||||||
if ( !candidate._.isBlockLike )
|
|
||||||
newPendingInline.unshift( candidate );
|
|
||||||
|
|
||||||
// This node should be added to it's parent at this point. But,
|
|
||||||
// it should happen only if the closing tag is really closing
|
|
||||||
// one of the nodes. So, for now, we just cache it.
|
|
||||||
pendingAdd.push( candidate );
|
|
||||||
|
|
||||||
// Make sure return point is properly restored.
|
|
||||||
candidate = candidate.returnPoint || candidate.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( candidate != root ) {
|
|
||||||
// Add all elements that have been found in the above loop.
|
|
||||||
for ( i = 0; i < pendingAdd.length; i++ ) {
|
|
||||||
var node = pendingAdd[ i ];
|
|
||||||
addElement( node, node.parent );
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = candidate;
|
|
||||||
|
|
||||||
if ( candidate._.isBlockLike )
|
|
||||||
sendPendingBRs();
|
|
||||||
|
|
||||||
addElement( candidate, candidate.parent );
|
|
||||||
|
|
||||||
// The parent should start receiving new nodes now, except if
|
|
||||||
// addElement changed the currentNode.
|
|
||||||
if ( candidate == currentNode )
|
|
||||||
currentNode = currentNode.parent;
|
|
||||||
|
|
||||||
pendingInline = pendingInline.concat( newPendingInline );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tagName == 'body' )
|
|
||||||
fixingBlock = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
parser.onText = function( text ) {
|
|
||||||
// Trim empty spaces at beginning of text contents except <pre> and <textarea>.
|
|
||||||
if ( ( !currentNode._.hasInlineStarted || pendingBRs.length ) && !inPre && !inTextarea ) {
|
|
||||||
text = CKEDITOR.tools.ltrim( text );
|
|
||||||
|
|
||||||
if ( text.length === 0 )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentName = currentNode.name,
|
|
||||||
currentDtd = currentName ? ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) ) : rootDtd;
|
|
||||||
|
|
||||||
// Fix orphan text in list/table. (#8540) (#8870)
|
|
||||||
if ( !inTextarea && !currentDtd[ '#' ] && currentName in nonBreakingBlocks ) {
|
|
||||||
parser.onTagOpen( structureFixes[ currentName ] || '' );
|
|
||||||
parser.onText( text );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendPendingBRs();
|
|
||||||
checkPending();
|
|
||||||
|
|
||||||
// Shrinking consequential spaces into one single for all elements
|
|
||||||
// text contents.
|
|
||||||
if ( !inPre && !inTextarea )
|
|
||||||
text = text.replace( /[\t\r\n ]{2,}|[\t\r\n]/g, ' ' );
|
|
||||||
|
|
||||||
text = new CKEDITOR.htmlParser.text( text );
|
|
||||||
|
|
||||||
|
|
||||||
if ( checkAutoParagraphing( currentNode, text ) )
|
|
||||||
this.onTagOpen( fixingBlock, {}, 0, 1 );
|
|
||||||
|
|
||||||
currentNode.add( text );
|
|
||||||
};
|
|
||||||
|
|
||||||
parser.onCDATA = function( cdata ) {
|
|
||||||
currentNode.add( new CKEDITOR.htmlParser.cdata( cdata ) );
|
|
||||||
};
|
|
||||||
|
|
||||||
parser.onComment = function( comment ) {
|
|
||||||
sendPendingBRs();
|
|
||||||
checkPending();
|
|
||||||
currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse it.
|
|
||||||
parser.parse( fragmentHtml );
|
|
||||||
|
|
||||||
sendPendingBRs();
|
|
||||||
|
|
||||||
// Close all pending nodes, make sure return point is properly restored.
|
|
||||||
while ( currentNode != root )
|
|
||||||
addElement( currentNode, currentNode.parent, 1 );
|
|
||||||
|
|
||||||
removeTailWhitespace( root );
|
|
||||||
|
|
||||||
return root;
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.fragment.prototype = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_DOCUMENT_FRAGMENT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_DOCUMENT_FRAGMENT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_DOCUMENT_FRAGMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a node to this fragment.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node to be added.
|
|
||||||
* @param {Number} [index] From where the insertion happens.
|
|
||||||
*/
|
|
||||||
add: function( node, index ) {
|
|
||||||
isNaN( index ) && ( index = this.children.length );
|
|
||||||
|
|
||||||
var previous = index > 0 ? this.children[ index - 1 ] : null;
|
|
||||||
if ( previous ) {
|
|
||||||
// If the block to be appended is following text, trim spaces at
|
|
||||||
// the right of it.
|
|
||||||
if ( node._.isBlockLike && previous.type == CKEDITOR.NODE_TEXT ) {
|
|
||||||
previous.value = CKEDITOR.tools.rtrim( previous.value );
|
|
||||||
|
|
||||||
// If we have completely cleared the previous node.
|
|
||||||
if ( previous.value.length === 0 ) {
|
|
||||||
// Remove it from the list and add the node again.
|
|
||||||
this.children.pop();
|
|
||||||
this.add( node );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
previous.next = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node.previous = previous;
|
|
||||||
node.parent = this;
|
|
||||||
|
|
||||||
this.children.splice( index, 0, node );
|
|
||||||
|
|
||||||
if ( !this._.hasInlineStarted )
|
|
||||||
this._.hasInlineStarted = node.type == CKEDITOR.NODE_TEXT || ( node.type == CKEDITOR.NODE_ELEMENT && !node._.isBlockLike );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter this fragment's content with given filter.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
*/
|
|
||||||
filter: function( filter, context ) {
|
|
||||||
context = this.getFilterContext( context );
|
|
||||||
|
|
||||||
// Apply the root filter.
|
|
||||||
filter.onRoot( context, this );
|
|
||||||
|
|
||||||
this.filterChildren( filter, false, context );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter this fragment's children with given filter.
|
|
||||||
*
|
|
||||||
* Element's children may only be filtered once by one
|
|
||||||
* instance of filter.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
* @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
|
|
||||||
*/
|
|
||||||
filterChildren: function( filter, filterRoot, context ) {
|
|
||||||
// If this element's children were already filtered
|
|
||||||
// by current filter, don't filter them 2nd time.
|
|
||||||
// This situation may occur when filtering bottom-up
|
|
||||||
// (filterChildren() called manually in element's filter),
|
|
||||||
// or in unpredictable edge cases when filter
|
|
||||||
// is manipulating DOM structure.
|
|
||||||
if ( this.childrenFilteredBy == filter.id )
|
|
||||||
return;
|
|
||||||
|
|
||||||
context = this.getFilterContext( context );
|
|
||||||
|
|
||||||
// Filtering root if enforced.
|
|
||||||
if ( filterRoot && !this.parent )
|
|
||||||
filter.onRoot( context, this );
|
|
||||||
|
|
||||||
this.childrenFilteredBy = filter.id;
|
|
||||||
|
|
||||||
// Don't cache anything, children array may be modified by filter rule.
|
|
||||||
for ( var i = 0; i < this.children.length; i++ ) {
|
|
||||||
// Stay in place if filter returned false, what means
|
|
||||||
// that node has been removed.
|
|
||||||
if ( this.children[ i ].filter( filter, context ) === false )
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the fragment HTML to a {@link CKEDITOR.htmlParser.basicWriter}.
|
|
||||||
*
|
|
||||||
* var writer = new CKEDITOR.htmlWriter();
|
|
||||||
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<P><B>Example' );
|
|
||||||
* fragment.writeHtml( writer );
|
|
||||||
* alert( writer.getHtml() ); // '<p><b>Example</b></p>'
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
|
|
||||||
*/
|
|
||||||
writeHtml: function( writer, filter ) {
|
|
||||||
if ( filter )
|
|
||||||
this.filter( filter );
|
|
||||||
|
|
||||||
this.writeChildrenHtml( writer );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write and filtering the child nodes of this fragment.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to use when writing the HTML.
|
|
||||||
* @param {Boolean} [filterRoot] Whether to apply the "root" filter rule specified in the `filter`.
|
|
||||||
*/
|
|
||||||
writeChildrenHtml: function( writer, filter, filterRoot ) {
|
|
||||||
var context = this.getFilterContext();
|
|
||||||
|
|
||||||
// Filtering root if enforced.
|
|
||||||
if ( filterRoot && !this.parent && filter )
|
|
||||||
filter.onRoot( context, this );
|
|
||||||
|
|
||||||
if ( filter )
|
|
||||||
this.filterChildren( filter, false, context );
|
|
||||||
|
|
||||||
for ( var i = 0, children = this.children, l = children.length; i < l; i++ )
|
|
||||||
children[ i ].writeHtml( writer );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute callback on each node (of given type) in this document fragment.
|
|
||||||
*
|
|
||||||
* var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>foo<b>bar</b>bom</p>' );
|
|
||||||
* fragment.forEach( function( node ) {
|
|
||||||
* console.log( node );
|
|
||||||
* } );
|
|
||||||
* // Will log:
|
|
||||||
* // 1. document fragment,
|
|
||||||
* // 2. <p> element,
|
|
||||||
* // 3. "foo" text node,
|
|
||||||
* // 4. <b> element,
|
|
||||||
* // 5. "bar" text node,
|
|
||||||
* // 6. "bom" text node.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {Function} callback Function to be executed on every node.
|
|
||||||
* **Since 4.3** if `callback` returned `false` descendants of current node will be ignored.
|
|
||||||
* @param {CKEDITOR.htmlParser.node} callback.node Node passed as argument.
|
|
||||||
* @param {Number} [type] If specified `callback` will be executed only on nodes of this type.
|
|
||||||
* @param {Boolean} [skipRoot] Don't execute `callback` on this fragment.
|
|
||||||
*/
|
|
||||||
forEach: function( callback, type, skipRoot ) {
|
|
||||||
if ( !skipRoot && ( !type || this.type == type ) )
|
|
||||||
var ret = callback( this );
|
|
||||||
|
|
||||||
// Do not filter children if callback returned false.
|
|
||||||
if ( ret === false )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var children = this.children,
|
|
||||||
node,
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// We do not cache the size, because the list of nodes may be changed by the callback.
|
|
||||||
for ( ; i < children.length; i++ ) {
|
|
||||||
node = children[ i ];
|
|
||||||
if ( node.type == CKEDITOR.NODE_ELEMENT )
|
|
||||||
node.forEach( callback, type );
|
|
||||||
else if ( !type || node.type == type )
|
|
||||||
callback( node );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getFilterContext: function( context ) {
|
|
||||||
return context || {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
@ -1,150 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* A lightweight representation of HTML node.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a node class instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.node = function() {};
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.node.prototype = {
|
|
||||||
/**
|
|
||||||
* Remove this node from a tree.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
*/
|
|
||||||
remove: function() {
|
|
||||||
var children = this.parent.children,
|
|
||||||
index = CKEDITOR.tools.indexOf( children, this ),
|
|
||||||
previous = this.previous,
|
|
||||||
next = this.next;
|
|
||||||
|
|
||||||
previous && ( previous.next = next );
|
|
||||||
next && ( next.previous = previous );
|
|
||||||
children.splice( index, 1 );
|
|
||||||
this.parent = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace this node with given one.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node that will replace this one.
|
|
||||||
*/
|
|
||||||
replaceWith: function( node ) {
|
|
||||||
var children = this.parent.children,
|
|
||||||
index = CKEDITOR.tools.indexOf( children, this ),
|
|
||||||
previous = node.previous = this.previous,
|
|
||||||
next = node.next = this.next;
|
|
||||||
|
|
||||||
previous && ( previous.next = node );
|
|
||||||
next && ( next.previous = node );
|
|
||||||
|
|
||||||
children[ index ] = node;
|
|
||||||
|
|
||||||
node.parent = this.parent;
|
|
||||||
this.parent = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert this node after given one.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node that will precede this element.
|
|
||||||
*/
|
|
||||||
insertAfter: function( node ) {
|
|
||||||
var children = node.parent.children,
|
|
||||||
index = CKEDITOR.tools.indexOf( children, node ),
|
|
||||||
next = node.next;
|
|
||||||
|
|
||||||
children.splice( index + 1, 0, this );
|
|
||||||
|
|
||||||
this.next = node.next;
|
|
||||||
this.previous = node;
|
|
||||||
node.next = this;
|
|
||||||
next && ( next.previous = this );
|
|
||||||
|
|
||||||
this.parent = node.parent;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert this node before given one.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.node} node The node that will follow this element.
|
|
||||||
*/
|
|
||||||
insertBefore: function( node ) {
|
|
||||||
var children = node.parent.children,
|
|
||||||
index = CKEDITOR.tools.indexOf( children, node );
|
|
||||||
|
|
||||||
children.splice( index, 0, this );
|
|
||||||
|
|
||||||
this.next = node;
|
|
||||||
this.previous = node.previous;
|
|
||||||
node.previous && ( node.previous.next = this );
|
|
||||||
node.previous = this;
|
|
||||||
|
|
||||||
this.parent = node.parent;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the closest ancestor element of this element which satisfies given condition
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {String/Object/Function} condition Name of an ancestor, hash of names or validator function.
|
|
||||||
* @returns {CKEDITOR.htmlParser.element} The closest ancestor which satisfies given condition or `null`.
|
|
||||||
*/
|
|
||||||
getAscendant: function( condition ) {
|
|
||||||
var checkFn =
|
|
||||||
typeof condition == 'function' ? condition :
|
|
||||||
typeof condition == 'string' ? function( el ) { return el.name == condition; } :
|
|
||||||
function( el ) { return el.name in condition; };
|
|
||||||
|
|
||||||
var parent = this.parent;
|
|
||||||
|
|
||||||
// Parent has to be an element - don't check doc fragment.
|
|
||||||
while ( parent && parent.type == CKEDITOR.NODE_ELEMENT ) {
|
|
||||||
if ( checkFn( parent ) )
|
|
||||||
return parent;
|
|
||||||
parent = parent.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps this element with given `wrapper`.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @param {CKEDITOR.htmlParser.element} wrapper The element which will be this element's new parent.
|
|
||||||
* @returns {CKEDITOR.htmlParser.element} Wrapper.
|
|
||||||
*/
|
|
||||||
wrapWith: function( wrapper ) {
|
|
||||||
this.replaceWith( wrapper );
|
|
||||||
wrapper.add( this );
|
|
||||||
return wrapper;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets this node's index in its parent's children array.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
getIndex: function() {
|
|
||||||
return CKEDITOR.tools.indexOf( this.parent.children, this );
|
|
||||||
},
|
|
||||||
|
|
||||||
getFilterContext: function( context ) {
|
|
||||||
return context || {};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* A lightweight representation of HTML text.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.htmlParser.node
|
|
||||||
* @constructor Creates a text class instance.
|
|
||||||
* @param {String} value The text node value.
|
|
||||||
*/
|
|
||||||
CKEDITOR.htmlParser.text = function( value ) {
|
|
||||||
/**
|
|
||||||
* The text value.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.value = value;
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
this._ = {
|
|
||||||
isBlockLike: false
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.htmlParser.text.prototype = CKEDITOR.tools.extend( new CKEDITOR.htmlParser.node(), {
|
|
||||||
/**
|
|
||||||
* The node type. This is a constant value set to {@link CKEDITOR#NODE_TEXT}.
|
|
||||||
*
|
|
||||||
* @readonly
|
|
||||||
* @property {Number} [=CKEDITOR.NODE_TEXT]
|
|
||||||
*/
|
|
||||||
type: CKEDITOR.NODE_TEXT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter this text node with given filter.
|
|
||||||
*
|
|
||||||
* @since 4.1
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} filter
|
|
||||||
* @returns {Boolean} Method returns `false` when this text node has
|
|
||||||
* been removed. This is an information for {@link CKEDITOR.htmlParser.element#filterChildren}
|
|
||||||
* that it has to repeat filter on current position in parent's children array.
|
|
||||||
*/
|
|
||||||
filter: function( filter, context ) {
|
|
||||||
if ( !( this.value = filter.onText( context, this.value, this ) ) ) {
|
|
||||||
this.remove();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the HTML representation of this text to a {CKEDITOR.htmlParser.basicWriter}.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.htmlParser.basicWriter} writer The writer to which write the HTML.
|
|
||||||
* @param {CKEDITOR.htmlParser.filter} [filter] The filter to be applied to this node.
|
|
||||||
* **Note:** it's unsafe to filter offline (not appended) node.
|
|
||||||
*/
|
|
||||||
writeHtml: function( writer, filter ) {
|
|
||||||
if ( filter )
|
|
||||||
this.filter( filter );
|
|
||||||
|
|
||||||
writer.text( this.value );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
} )();
|
|
||||||
@ -1,169 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controls keystrokes typing in an editor instance.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a keystrokeHandler class instance.
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.keystrokeHandler = function( editor ) {
|
|
||||||
if ( editor.keystrokeHandler )
|
|
||||||
return editor.keystrokeHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of keystrokes associated with commands. Each entry points to the
|
|
||||||
* command to be executed.
|
|
||||||
*
|
|
||||||
* Since CKEditor 4 there is no need to modify this property directly during the runtime.
|
|
||||||
* Use {@link CKEDITOR.editor#setKeystroke} instead.
|
|
||||||
*/
|
|
||||||
this.keystrokes = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of keystrokes that should be blocked if not defined in
|
|
||||||
* {@link #keystrokes}. In this way it is possible to block the default
|
|
||||||
* browser behavior for those keystrokes.
|
|
||||||
*/
|
|
||||||
this.blockedKeystrokes = {};
|
|
||||||
|
|
||||||
this._ = {
|
|
||||||
editor: editor
|
|
||||||
};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var cancel;
|
|
||||||
|
|
||||||
var onKeyDown = function( event ) {
|
|
||||||
// The DOM event object is passed by the "data" property.
|
|
||||||
event = event.data;
|
|
||||||
|
|
||||||
var keyCombination = event.getKeystroke();
|
|
||||||
var command = this.keystrokes[ keyCombination ];
|
|
||||||
var editor = this._.editor;
|
|
||||||
|
|
||||||
cancel = ( editor.fire( 'key', { keyCode: keyCombination, domEvent: event } ) === false );
|
|
||||||
|
|
||||||
if ( !cancel ) {
|
|
||||||
if ( command ) {
|
|
||||||
var data = { from: 'keystrokeHandler' };
|
|
||||||
cancel = ( editor.execCommand( command, data ) !== false );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !cancel )
|
|
||||||
cancel = !!this.blockedKeystrokes[ keyCombination ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( cancel )
|
|
||||||
event.preventDefault( true );
|
|
||||||
|
|
||||||
return !cancel;
|
|
||||||
};
|
|
||||||
|
|
||||||
var onKeyPress = function( event ) {
|
|
||||||
if ( cancel ) {
|
|
||||||
cancel = false;
|
|
||||||
event.data.preventDefault( true );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.keystrokeHandler.prototype = {
|
|
||||||
/**
|
|
||||||
* Attaches this keystroke handle to a DOM object. Keystrokes typed
|
|
||||||
* over this object will be handled by this keystrokeHandler.
|
|
||||||
*
|
|
||||||
* @param {CKEDITOR.dom.domObject} domObject The DOM object to attach to.
|
|
||||||
*/
|
|
||||||
attach: function( domObject ) {
|
|
||||||
// For most browsers, it is enough to listen to the keydown event
|
|
||||||
// only.
|
|
||||||
domObject.on( 'keydown', onKeyDown, this );
|
|
||||||
|
|
||||||
// Some browsers instead, don't cancel key events in the keydown, but in the
|
|
||||||
// keypress. So we must do a longer trip in those cases.
|
|
||||||
if ( CKEDITOR.env.gecko && CKEDITOR.env.mac )
|
|
||||||
domObject.on( 'keypress', onKeyPress, this );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list associating keystrokes with editor commands. Each element in the list
|
|
||||||
* is an array where the first item is the keystroke, and the second is the
|
|
||||||
* name of the command to be executed.
|
|
||||||
*
|
|
||||||
* This setting should be used to define (as well as to overwrite or remove) keystrokes
|
|
||||||
* set by plugins (like `link` and `basicstyles`). If you want to set a keystroke
|
|
||||||
* for your plugin or during the runtime, use {@link CKEDITOR.editor#setKeystroke} instead.
|
|
||||||
*
|
|
||||||
* Since default keystrokes are set by the {@link CKEDITOR.editor#setKeystroke}
|
|
||||||
* method, by default `config.keystrokes` is an empty array.
|
|
||||||
*
|
|
||||||
* See {@link CKEDITOR.editor#setKeystroke} documentation for more details
|
|
||||||
* regarding the start up order.
|
|
||||||
*
|
|
||||||
* // Change default Ctrl+L keystroke for 'link' command to Ctrl+Shift+L.
|
|
||||||
* config.keystrokes = [
|
|
||||||
* ...
|
|
||||||
* [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 76, 'link' ], // Ctrl+Shift+L
|
|
||||||
* ...
|
|
||||||
* ];
|
|
||||||
*
|
|
||||||
* To reset a particular keystroke, the following approach can be used:
|
|
||||||
*
|
|
||||||
* // Disable default Ctrl+L keystroke which executes the 'link' command by default.
|
|
||||||
* config.keystrokes = [
|
|
||||||
* ...
|
|
||||||
* [ CKEDITOR.CTRL + 76, null ], // Ctrl+L
|
|
||||||
* ...
|
|
||||||
* ];
|
|
||||||
*
|
|
||||||
* In order to reset all default keystrokes, a {@link CKEDITOR#instanceReady} callback should be
|
|
||||||
* used. This is since editor defaults are merged rather than overwritten by
|
|
||||||
* user keystrokes.
|
|
||||||
*
|
|
||||||
* **Note**: This can be potentially harmful for the editor. Avoid this unless you are
|
|
||||||
* aware of the consequences.
|
|
||||||
*
|
|
||||||
* // Reset all default keystrokes.
|
|
||||||
* config.on.instanceReady = function() {
|
|
||||||
* this.keystrokeHandler.keystrokes = [];
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* @cfg {Array} [keystrokes=[]]
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fired when any keyboard key (or a combination thereof) is pressed in the editing area.
|
|
||||||
*
|
|
||||||
* editor.on( 'key', function( evt ) {
|
|
||||||
* if ( evt.data.keyCode == CKEDITOR.CTRL + 90 ) {
|
|
||||||
* // Do something...
|
|
||||||
*
|
|
||||||
* // Cancel the event, so other listeners will not be executed and
|
|
||||||
* // the keydown's default behavior will be prevented.
|
|
||||||
* evt.cancel();
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* Usually you will want to use the {@link CKEDITOR.editor#setKeystroke} method or
|
|
||||||
* the {@link CKEDITOR.config#keystrokes} option to attach a keystroke to some {@link CKEDITOR.command command}.
|
|
||||||
* Key event listeners are usuful when some action should be executed conditionally, based
|
|
||||||
* for example on precise selection location.
|
|
||||||
*
|
|
||||||
* @event key
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
* @param data
|
|
||||||
* @param {Number} data.keyCode A number representing the key code (or a combination thereof).
|
|
||||||
* It is the sum of the current key code and the {@link CKEDITOR#CTRL}, {@link CKEDITOR#SHIFT}
|
|
||||||
* and {@link CKEDITOR#ALT} constants, if those are pressed.
|
|
||||||
* @param {CKEDITOR.dom.event} data.domEvent A `keydown` DOM event instance. Available since CKEditor 4.4.1.
|
|
||||||
* @param {CKEDITOR.editor} editor This editor instance.
|
|
||||||
*/
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
/**
|
|
||||||
* Stores language-related functions.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.lang = {
|
|
||||||
/**
|
|
||||||
* The list of languages available in the editor core.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.lang.languages.en ); // 1
|
|
||||||
*/
|
|
||||||
languages: { af: 1, ar: 1, bg: 1, bn: 1, bs: 1, ca: 1, cs: 1, cy: 1, da: 1, de: 1, el: 1,
|
|
||||||
'en-au': 1, 'en-ca': 1, 'en-gb': 1, en: 1, eo: 1, es: 1, et: 1, eu: 1, fa: 1, fi: 1, fo: 1,
|
|
||||||
'fr-ca': 1, fr: 1, gl: 1, gu: 1, he: 1, hi: 1, hr: 1, hu: 1, id: 1, is: 1, it: 1, ja: 1, ka: 1,
|
|
||||||
km: 1, ko: 1, ku: 1, lt: 1, lv: 1, mk: 1, mn: 1, ms: 1, nb: 1, nl: 1, no: 1, pl: 1, 'pt-br': 1,
|
|
||||||
pt: 1, ro: 1, ru: 1, si: 1, sk: 1, sl: 1, sq: 1, 'sr-latn': 1, sr: 1, sv: 1, th: 1, tr: 1, tt: 1, ug: 1,
|
|
||||||
uk: 1, vi: 1, 'zh-cn': 1, zh: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of languages that are written Right-To-Left (RTL) and are supported by the editor.
|
|
||||||
*/
|
|
||||||
rtl: { ar: 1, fa: 1, he: 1, ku: 1, ug: 1 },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specific language file, or auto detects it. A callback is
|
|
||||||
* then called when the file gets loaded.
|
|
||||||
*
|
|
||||||
* @param {String} languageCode The code of the language file to be
|
|
||||||
* loaded. If null or empty, autodetection will be performed. The
|
|
||||||
* same happens if the language is not supported.
|
|
||||||
* @param {String} defaultLanguage The language to be used if
|
|
||||||
* `languageCode` is not supported or if the autodetection fails.
|
|
||||||
* @param {Function} callback A function to be called once the
|
|
||||||
* language file is loaded. Two parameters are passed to this
|
|
||||||
* function: the language code and the loaded language entries.
|
|
||||||
*/
|
|
||||||
load: function( languageCode, defaultLanguage, callback ) {
|
|
||||||
// If no languageCode - fallback to browser or default.
|
|
||||||
// If languageCode - fallback to no-localized version or default.
|
|
||||||
if ( !languageCode || !CKEDITOR.lang.languages[ languageCode ] )
|
|
||||||
languageCode = this.detect( defaultLanguage, languageCode );
|
|
||||||
|
|
||||||
var that = this,
|
|
||||||
loadedCallback = function() {
|
|
||||||
that[ languageCode ].dir = that.rtl[ languageCode ] ? 'rtl' : 'ltr';
|
|
||||||
callback( languageCode, that[ languageCode ] );
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( !this[ languageCode ] )
|
|
||||||
CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( 'lang/' + languageCode + '.js' ), loadedCallback, this );
|
|
||||||
else
|
|
||||||
loadedCallback();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the language that best fits the user language. For example,
|
|
||||||
* suppose that the user language is "pt-br". If this language is
|
|
||||||
* supported by the editor, it is returned. Otherwise, if only "pt" is
|
|
||||||
* supported, it is returned instead. If none of the previous are
|
|
||||||
* supported, a default language is then returned.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.lang.detect( 'en' ) ); // e.g., in a German browser: 'de'
|
|
||||||
*
|
|
||||||
* @param {String} defaultLanguage The default language to be returned
|
|
||||||
* if the user language is not supported.
|
|
||||||
* @param {String} [probeLanguage] A language code to try to use,
|
|
||||||
* instead of the browser-based autodetection.
|
|
||||||
* @returns {String} The detected language code.
|
|
||||||
*/
|
|
||||||
detect: function( defaultLanguage, probeLanguage ) {
|
|
||||||
var languages = this.languages;
|
|
||||||
probeLanguage = probeLanguage || navigator.userLanguage || navigator.language || defaultLanguage;
|
|
||||||
|
|
||||||
var parts = probeLanguage.toLowerCase().match( /([a-z]+)(?:-([a-z]+))?/ ),
|
|
||||||
lang = parts[ 1 ],
|
|
||||||
locale = parts[ 2 ];
|
|
||||||
|
|
||||||
if ( languages[ lang + '-' + locale ] )
|
|
||||||
lang = lang + '-' + locale;
|
|
||||||
else if ( !languages[ lang ] )
|
|
||||||
lang = null;
|
|
||||||
|
|
||||||
CKEDITOR.lang.detect = lang ?
|
|
||||||
function() {
|
|
||||||
return lang;
|
|
||||||
} : function( defaultLanguage ) {
|
|
||||||
return defaultLanguage;
|
|
||||||
};
|
|
||||||
|
|
||||||
return lang || defaultLanguage;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} )();
|
|
||||||
@ -1,247 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.loader} objects, which is used to
|
|
||||||
* load core scripts and their dependencies from _source.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( typeof CKEDITOR == 'undefined' )
|
|
||||||
CKEDITOR = {};
|
|
||||||
|
|
||||||
if ( !CKEDITOR.loader ) {
|
|
||||||
/**
|
|
||||||
* Load core scripts and their dependencies from _source.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.loader = ( function() {
|
|
||||||
// Table of script names and their dependencies.
|
|
||||||
var scripts = {
|
|
||||||
'_bootstrap': [ 'config', 'creators/inline', 'creators/themedui', 'editable', 'ckeditor', 'plugins', 'scriptloader', 'style', 'tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'dom/comment', 'dom/elementpath', 'dom/text', 'dom/rangelist', 'skin' ],
|
|
||||||
'ckeditor': [ 'ckeditor_basic', 'dom', 'dtd', 'dom/document', 'dom/element', 'dom/iterator', 'editor', 'event', 'htmldataprocessor', 'htmlparser', 'htmlparser/element', 'htmlparser/fragment', 'htmlparser/filter', 'htmlparser/basicwriter', 'template', 'tools' ],
|
|
||||||
'ckeditor_base': [],
|
|
||||||
'ckeditor_basic': [ 'editor_basic', 'env', 'event' ],
|
|
||||||
'command': [],
|
|
||||||
'config': [ 'ckeditor_base' ],
|
|
||||||
'dom': [],
|
|
||||||
'dom/comment': [ 'dom/node' ],
|
|
||||||
'dom/document': [ 'dom/node', 'dom/window' ],
|
|
||||||
'dom/documentfragment': [ 'dom/element' ],
|
|
||||||
'dom/element': [ 'dom', 'dom/document', 'dom/domobject', 'dom/node', 'dom/nodelist', 'tools' ],
|
|
||||||
'dom/elementpath': [ 'dom/element' ],
|
|
||||||
'dom/event': [],
|
|
||||||
'dom/iterator': [ 'dom/range' ],
|
|
||||||
'dom/node': [ 'dom/domobject', 'tools' ],
|
|
||||||
'dom/nodelist': [ 'dom/node' ],
|
|
||||||
'dom/domobject': [ 'dom/event' ],
|
|
||||||
'dom/range': [ 'dom/document', 'dom/documentfragment', 'dom/element', 'dom/walker' ],
|
|
||||||
'dom/rangelist': [ 'dom/range' ],
|
|
||||||
'dom/text': [ 'dom/node', 'dom/domobject' ],
|
|
||||||
'dom/walker': [ 'dom/node' ],
|
|
||||||
'dom/window': [ 'dom/domobject' ],
|
|
||||||
'dtd': [ 'tools' ],
|
|
||||||
'editable': [ 'editor', 'tools' ],
|
|
||||||
'editor': [ 'command', 'config', 'editor_basic', 'filter', 'focusmanager', 'keystrokehandler', 'lang', 'plugins', 'tools', 'ui' ],
|
|
||||||
'editor_basic': [ 'event' ],
|
|
||||||
'env': [],
|
|
||||||
'event': [],
|
|
||||||
'filter': [ 'dtd', 'tools' ],
|
|
||||||
'focusmanager': [],
|
|
||||||
'htmldataprocessor': [ 'htmlparser', 'htmlparser/basicwriter', 'htmlparser/fragment', 'htmlparser/filter' ],
|
|
||||||
'htmlparser': [],
|
|
||||||
'htmlparser/comment': [ 'htmlparser', 'htmlparser/node' ],
|
|
||||||
'htmlparser/element': [ 'htmlparser', 'htmlparser/fragment', 'htmlparser/node' ],
|
|
||||||
'htmlparser/fragment': [ 'htmlparser', 'htmlparser/comment', 'htmlparser/text', 'htmlparser/cdata' ],
|
|
||||||
'htmlparser/text': [ 'htmlparser', 'htmlparser/node' ],
|
|
||||||
'htmlparser/cdata': [ 'htmlparser', 'htmlparser/node' ],
|
|
||||||
'htmlparser/filter': [ 'htmlparser' ],
|
|
||||||
'htmlparser/basicwriter': [ 'htmlparser' ],
|
|
||||||
'htmlparser/node': [ 'htmlparser' ],
|
|
||||||
'keystrokehandler': [ 'event' ],
|
|
||||||
'lang': [],
|
|
||||||
'plugins': [ 'resourcemanager' ],
|
|
||||||
'resourcemanager': [ 'scriptloader', 'tools' ],
|
|
||||||
'scriptloader': [ 'dom/element', 'env' ],
|
|
||||||
'selection': [ 'dom/range', 'dom/walker' ],
|
|
||||||
'skin': [],
|
|
||||||
'style': [ 'selection' ],
|
|
||||||
'template': [],
|
|
||||||
'tools': [ 'env' ],
|
|
||||||
'ui': [],
|
|
||||||
'creators/themedui': [],
|
|
||||||
'creators/inline': []
|
|
||||||
};
|
|
||||||
|
|
||||||
var basePath = ( function() {
|
|
||||||
// This is a copy of CKEDITOR.basePath, but requires the script having
|
|
||||||
// "_source/loader.js".
|
|
||||||
if ( CKEDITOR && CKEDITOR.basePath )
|
|
||||||
return CKEDITOR.basePath;
|
|
||||||
|
|
||||||
// Find out the editor directory path, based on its <script> tag.
|
|
||||||
var path = '';
|
|
||||||
var scripts = document.getElementsByTagName( 'script' );
|
|
||||||
|
|
||||||
for ( var i = 0; i < scripts.length; i++ ) {
|
|
||||||
var match = scripts[ i ].src.match( /(^|.*?[\\\/])(?:_source\/)?core\/loader.js(?:\?.*)?$/i );
|
|
||||||
|
|
||||||
if ( match ) {
|
|
||||||
path = match[ 1 ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In IE (only) the script.src string is the raw valued entered in the
|
|
||||||
// HTML. Other browsers return the full resolved URL instead.
|
|
||||||
if ( path.indexOf( '://' ) == -1 ) {
|
|
||||||
// Absolute path.
|
|
||||||
if ( path.indexOf( '/' ) === 0 )
|
|
||||||
path = location.href.match( /^.*?:\/\/[^\/]*/ )[ 0 ] + path;
|
|
||||||
// Relative path.
|
|
||||||
else
|
|
||||||
path = location.href.match( /^[^\?]*\// )[ 0 ] + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
} )();
|
|
||||||
|
|
||||||
var timestamp = ( CKEDITOR && CKEDITOR.timestamp ) || ( new Date() ).valueOf(); // %REMOVE_LINE%
|
|
||||||
/* // %REMOVE_LINE%
|
|
||||||
* The production implementation contains a fixed timestamp // %REMOVE_LINE%
|
|
||||||
* generated by the releaser // %REMOVE_LINE%
|
|
||||||
var timestamp = '%TIMESTAMP%';
|
|
||||||
*/ // %REMOVE_LINE%
|
|
||||||
|
|
||||||
var getUrl = function( resource ) {
|
|
||||||
if ( CKEDITOR && CKEDITOR.getUrl )
|
|
||||||
return CKEDITOR.getUrl( resource );
|
|
||||||
|
|
||||||
return basePath + resource + ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + timestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
var pendingLoad = [];
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* The list of loaded scripts in their loading order.
|
|
||||||
*
|
|
||||||
* // Alert the loaded script names.
|
|
||||||
* alert( CKEDITOR.loader.loadedScripts );
|
|
||||||
*/
|
|
||||||
loadedScripts: [],
|
|
||||||
/**
|
|
||||||
* Table of script names and their dependencies.
|
|
||||||
*
|
|
||||||
* @property {Array}
|
|
||||||
*/
|
|
||||||
scripts: scripts,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
loadPending: function() {
|
|
||||||
var scriptName = pendingLoad.shift();
|
|
||||||
|
|
||||||
if ( !scriptName )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
|
|
||||||
|
|
||||||
var script = document.createElement( 'script' );
|
|
||||||
script.type = 'text/javascript';
|
|
||||||
script.src = scriptSrc;
|
|
||||||
|
|
||||||
function onScriptLoaded() {
|
|
||||||
// Append this script to the list of loaded scripts.
|
|
||||||
CKEDITOR.loader.loadedScripts.push( scriptName );
|
|
||||||
|
|
||||||
// Load the next.
|
|
||||||
CKEDITOR.loader.loadPending();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must guarantee the execution order of the scripts, so we
|
|
||||||
// need to load them one by one. (#4145)
|
|
||||||
// The following if/else block has been taken from the scriptloader core code.
|
|
||||||
if ( typeof( script.onreadystatechange ) !== "undefined" ) {
|
|
||||||
/** @ignore */
|
|
||||||
script.onreadystatechange = function() {
|
|
||||||
if ( script.readyState == 'loaded' || script.readyState == 'complete' ) {
|
|
||||||
script.onreadystatechange = null;
|
|
||||||
onScriptLoaded();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
/** @ignore */
|
|
||||||
script.onload = function() {
|
|
||||||
// Some browsers, such as Safari, may call the onLoad function
|
|
||||||
// immediately. Which will break the loading sequence. (#3661)
|
|
||||||
setTimeout( function() {
|
|
||||||
onScriptLoaded( scriptName );
|
|
||||||
}, 0 );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.appendChild( script );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specific script, including its dependencies. This is not a
|
|
||||||
* synchronous loading, which means that the code to be loaded will
|
|
||||||
* not necessarily be available after this call.
|
|
||||||
*
|
|
||||||
* CKEDITOR.loader.load( 'dom/element' );
|
|
||||||
*
|
|
||||||
* @param {String} scriptName
|
|
||||||
* @param {Boolean} [defer=false]
|
|
||||||
* @todo params
|
|
||||||
*/
|
|
||||||
load: function( scriptName, defer ) {
|
|
||||||
// Check if the script has already been loaded.
|
|
||||||
if ( ( 's:' + scriptName ) in this.loadedScripts )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the script dependencies list.
|
|
||||||
var dependencies = scripts[ scriptName ];
|
|
||||||
if ( !dependencies )
|
|
||||||
throw 'The script name"' + scriptName + '" is not defined.';
|
|
||||||
|
|
||||||
// Mark the script as loaded, even before really loading it, to
|
|
||||||
// avoid cross references recursion.
|
|
||||||
// Prepend script name with 's:' to avoid conflict with Array's methods.
|
|
||||||
this.loadedScripts[ 's:' + scriptName ] = true;
|
|
||||||
|
|
||||||
// Load all dependencies first.
|
|
||||||
for ( var i = 0; i < dependencies.length; i++ )
|
|
||||||
this.load( dependencies[ i ], true );
|
|
||||||
|
|
||||||
var scriptSrc = getUrl( 'core/' + scriptName + '.js' );
|
|
||||||
|
|
||||||
// Append the <script> element to the DOM.
|
|
||||||
// If the page is fully loaded, we can't use document.write
|
|
||||||
// but if the script is run while the body is loading then it's safe to use it
|
|
||||||
// Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement
|
|
||||||
if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) {
|
|
||||||
pendingLoad.push( scriptName );
|
|
||||||
|
|
||||||
if ( !defer )
|
|
||||||
this.loadPending();
|
|
||||||
} else {
|
|
||||||
// Append this script to the list of loaded scripts.
|
|
||||||
this.loadedScripts.push( scriptName );
|
|
||||||
|
|
||||||
document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any script has been defined for autoload.
|
|
||||||
if ( CKEDITOR._autoLoad ) {
|
|
||||||
CKEDITOR.loader.load( CKEDITOR._autoLoad );
|
|
||||||
delete CKEDITOR._autoLoad;
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the "virtual" {@link CKEDITOR.pluginDefinition} class which
|
|
||||||
* contains the defintion of a plugin. This file is for documentation
|
|
||||||
* purposes only.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual class which just illustrates the features of plugin objects to be
|
|
||||||
* passed to the {@link CKEDITOR.plugins#add} method.
|
|
||||||
*
|
|
||||||
* This class is not really part of the API, so its constructor should not be called.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.pluginDefinition
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of plugins that are required by this plugin. Note that this property
|
|
||||||
* does not determine the loading order of the plugins.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.add( 'sample', {
|
|
||||||
* requires: [ 'button', 'selection' ]
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Array} requires
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of language files available for this plugin. These files are stored inside
|
|
||||||
* the `lang` directory inside the plugin directory, follow the name
|
|
||||||
* pattern of `langCode.js`, and contain the language definition created with
|
|
||||||
* {@link CKEDITOR.plugins#setLang}.
|
|
||||||
*
|
|
||||||
* When the plugin is being loaded, the editor checks this list to see if
|
|
||||||
* a language file of the current editor language ({@link CKEDITOR.editor#langCode})
|
|
||||||
* is available, and if so, loads it. Otherwise, the file represented by the first item
|
|
||||||
* in the list is loaded.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.add( 'sample', {
|
|
||||||
* lang: [ 'en', 'fr' ]
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @property {Array} lang
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function called on initialization of every editor instance created in the
|
|
||||||
* page before the {@link #init} call task. The `beforeInit` function will be called for
|
|
||||||
* all plugins, after that the `init` function is called for all of them. This
|
|
||||||
* feature makes it possible to initialize things that could be used in the
|
|
||||||
* `init` function of other plugins.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.add( 'sample', {
|
|
||||||
* beforeInit: function( editor ) {
|
|
||||||
* alert( 'Editor "' + editor.name + '" is to be initialized!' );
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @method beforeInit
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance being initialized.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function called on initialization of every editor instance created in the page.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.add( 'sample', {
|
|
||||||
* init: function( editor ) {
|
|
||||||
* alert( 'Editor "' + editor.name + '" is being initialized!' );
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @method init
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance being initialized.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Announces the plugin as HiDPI-ready (optimized for high pixel density screens, e.g. *Retina*)
|
|
||||||
* by providing high-resolution icons and images. HiDPI icons must be twice as big
|
|
||||||
* (defaults are `16px x 16px`) and stored under `plugin_name/icons/hidpi/` directory.
|
|
||||||
*
|
|
||||||
* The common place for additional HiDPI images used by the plugin (**but not icons**)
|
|
||||||
* is `plugin_name/images/hidpi/` directory.
|
|
||||||
*
|
|
||||||
* This property is optional and only makes sense if `32px x 32px` icons
|
|
||||||
* and high-resolution images actually exist. If this flag is set `true`, the editor
|
|
||||||
* will automatically detect the HiDPI environment and attempt to load the
|
|
||||||
* high-resolution resources.
|
|
||||||
*
|
|
||||||
* @since 4.2
|
|
||||||
* @property {Boolean} hidpi
|
|
||||||
*/
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.plugins} object, which is used to
|
|
||||||
* manage plugins registration and loading.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages plugins registration and loading.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @extends CKEDITOR.resourceManager
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.plugins = new CKEDITOR.resourceManager( 'plugins/', 'plugin' );
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.plugins )
|
|
||||||
|
|
||||||
CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function( originalLoad ) {
|
|
||||||
var initialized = {};
|
|
||||||
|
|
||||||
return function( name, callback, scope ) {
|
|
||||||
var allPlugins = {};
|
|
||||||
|
|
||||||
var loadPlugins = function( names ) {
|
|
||||||
originalLoad.call( this, names, function( plugins ) {
|
|
||||||
CKEDITOR.tools.extend( allPlugins, plugins );
|
|
||||||
|
|
||||||
var requiredPlugins = [];
|
|
||||||
for ( var pluginName in plugins ) {
|
|
||||||
var plugin = plugins[ pluginName ],
|
|
||||||
requires = plugin && plugin.requires;
|
|
||||||
|
|
||||||
if ( !initialized[ pluginName ] ) {
|
|
||||||
// Register all icons eventually defined by this plugin.
|
|
||||||
if ( plugin.icons ) {
|
|
||||||
var icons = plugin.icons.split( ',' );
|
|
||||||
for ( var ic = icons.length; ic--; ) {
|
|
||||||
CKEDITOR.skin.addIcon( icons[ ic ],
|
|
||||||
plugin.path +
|
|
||||||
'icons/' +
|
|
||||||
( CKEDITOR.env.hidpi && plugin.hidpi ? 'hidpi/' : '' ) +
|
|
||||||
icons[ ic ] +
|
|
||||||
'.png' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initialized[ pluginName ] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( requires ) {
|
|
||||||
// Trasnform it into an array, if it's not one.
|
|
||||||
if ( requires.split )
|
|
||||||
requires = requires.split( ',' );
|
|
||||||
|
|
||||||
for ( var i = 0; i < requires.length; i++ ) {
|
|
||||||
if ( !allPlugins[ requires[ i ] ] )
|
|
||||||
requiredPlugins.push( requires[ i ] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( requiredPlugins.length )
|
|
||||||
loadPlugins.call( this, requiredPlugins );
|
|
||||||
else {
|
|
||||||
// Call the "onLoad" function for all plugins.
|
|
||||||
for ( pluginName in allPlugins ) {
|
|
||||||
plugin = allPlugins[ pluginName ];
|
|
||||||
if ( plugin.onLoad && !plugin.onLoad._called ) {
|
|
||||||
// Make it possible to return false from plugin::onLoad to disable it.
|
|
||||||
if ( plugin.onLoad() === false )
|
|
||||||
delete allPlugins[ pluginName ];
|
|
||||||
|
|
||||||
plugin.onLoad._called = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the callback.
|
|
||||||
if ( callback )
|
|
||||||
callback.call( scope || window, allPlugins );
|
|
||||||
}
|
|
||||||
}, this );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
loadPlugins.call( this, name );
|
|
||||||
};
|
|
||||||
} );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specific language file, or auto detect it. A callback is
|
|
||||||
* then called when the file gets loaded.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.setLang( 'myPlugin', 'en', {
|
|
||||||
* title: 'My plugin',
|
|
||||||
* selectOption: 'Please select an option'
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {String} pluginName The name of the plugin to which the provided translation
|
|
||||||
* should be attached.
|
|
||||||
* @param {String} languageCode The code of the language translation provided.
|
|
||||||
* @param {Object} languageEntries An object that contains pairs of label and
|
|
||||||
* the respective translation.
|
|
||||||
*/
|
|
||||||
CKEDITOR.plugins.setLang = function( pluginName, languageCode, languageEntries ) {
|
|
||||||
var plugin = this.get( pluginName ),
|
|
||||||
pluginLangEntries = plugin.langEntries || ( plugin.langEntries = {} ),
|
|
||||||
pluginLang = plugin.lang || ( plugin.lang = [] );
|
|
||||||
|
|
||||||
if ( pluginLang.split )
|
|
||||||
pluginLang = pluginLang.split( ',' );
|
|
||||||
|
|
||||||
if ( CKEDITOR.tools.indexOf( pluginLang, languageCode ) == -1 )
|
|
||||||
pluginLang.push( languageCode );
|
|
||||||
|
|
||||||
pluginLangEntries[ languageCode ] = languageEntries;
|
|
||||||
};
|
|
||||||
@ -1,227 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.resourceManager} class, which is
|
|
||||||
* the base for resource managers, like plugins.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for resource managers, like plugins. This class is not
|
|
||||||
* intended to be used out of the CKEditor core code.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a resourceManager class instance.
|
|
||||||
* @param {String} basePath The path for the resources folder.
|
|
||||||
* @param {String} fileName The name used for resource files.
|
|
||||||
*/
|
|
||||||
CKEDITOR.resourceManager = function( basePath, fileName ) {
|
|
||||||
/**
|
|
||||||
* The base directory containing all resources.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.basePath = basePath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name used for resource files.
|
|
||||||
*
|
|
||||||
* @property {String}
|
|
||||||
*/
|
|
||||||
this.fileName = fileName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains references to all resources that have already been registered
|
|
||||||
* with {@link #add}.
|
|
||||||
*/
|
|
||||||
this.registered = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains references to all resources that have already been loaded
|
|
||||||
* with {@link #load}.
|
|
||||||
*/
|
|
||||||
this.loaded = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains references to all resources that have already been registered
|
|
||||||
* with {@link #addExternal}.
|
|
||||||
*/
|
|
||||||
this.externals = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._ = {
|
|
||||||
// List of callbacks waiting for plugins to be loaded.
|
|
||||||
waitingList: {}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.resourceManager.prototype = {
|
|
||||||
/**
|
|
||||||
* Registers a resource.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.add( 'sample', { ... plugin definition ... } );
|
|
||||||
*
|
|
||||||
* @param {String} name The resource name.
|
|
||||||
* @param {Object} [definition] The resource definition.
|
|
||||||
* @see CKEDITOR.pluginDefinition
|
|
||||||
*/
|
|
||||||
add: function( name, definition ) {
|
|
||||||
if ( this.registered[ name ] )
|
|
||||||
throw '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.';
|
|
||||||
|
|
||||||
var resource = this.registered[ name ] = definition || {};
|
|
||||||
resource.name = name;
|
|
||||||
resource.path = this.getPath( name );
|
|
||||||
|
|
||||||
CKEDITOR.fire( name + CKEDITOR.tools.capitalize( this.fileName ) + 'Ready', resource );
|
|
||||||
|
|
||||||
return this.get( name );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the definition of a specific resource.
|
|
||||||
*
|
|
||||||
* var definition = CKEDITOR.plugins.get( 'sample' );
|
|
||||||
*
|
|
||||||
* @param {String} name The resource name.
|
|
||||||
* @returns {Object} The registered object.
|
|
||||||
*/
|
|
||||||
get: function( name ) {
|
|
||||||
return this.registered[ name ] || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the folder path for a specific loaded resource.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.plugins.getPath( 'sample' ) ); // '<editor path>/plugins/sample/'
|
|
||||||
*
|
|
||||||
* @param {String} name The resource name.
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
getPath: function( name ) {
|
|
||||||
var external = this.externals[ name ];
|
|
||||||
return CKEDITOR.getUrl( ( external && external.dir ) || this.basePath + name + '/' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file path for a specific loaded resource.
|
|
||||||
*
|
|
||||||
* alert( CKEDITOR.plugins.getFilePath( 'sample' ) ); // '<editor path>/plugins/sample/plugin.js'
|
|
||||||
*
|
|
||||||
* @param {String} name The resource name.
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
getFilePath: function( name ) {
|
|
||||||
var external = this.externals[ name ];
|
|
||||||
return CKEDITOR.getUrl( this.getPath( name ) + ( external ? external.file : this.fileName + '.js' ) );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers one or more resources to be loaded from an external path
|
|
||||||
* instead of the core base path.
|
|
||||||
*
|
|
||||||
* // Loads a plugin from '/myplugin/samples/plugin.js'.
|
|
||||||
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/' );
|
|
||||||
*
|
|
||||||
* // Loads a plugin from '/myplugin/samples/my_plugin.js'.
|
|
||||||
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/', 'my_plugin.js' );
|
|
||||||
*
|
|
||||||
* // Loads a plugin from '/myplugin/samples/my_plugin.js'.
|
|
||||||
* CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/my_plugin.js', '' );
|
|
||||||
*
|
|
||||||
* @param {String} names The resource names, separated by commas.
|
|
||||||
* @param {String} path The path of the folder containing the resource.
|
|
||||||
* @param {String} [fileName] The resource file name. If not provided, the
|
|
||||||
* default name is used. If provided with a empty string, will implicitly indicates that `path` argument
|
|
||||||
* is already the full path.
|
|
||||||
*/
|
|
||||||
addExternal: function( names, path, fileName ) {
|
|
||||||
names = names.split( ',' );
|
|
||||||
for ( var i = 0; i < names.length; i++ ) {
|
|
||||||
var name = names[ i ];
|
|
||||||
|
|
||||||
// If "fileName" is not provided, we assume that it may be available
|
|
||||||
// in "path". Try to extract it in this case.
|
|
||||||
if ( !fileName ) {
|
|
||||||
path = path.replace( /[^\/]+$/, function( match ) {
|
|
||||||
fileName = match;
|
|
||||||
return '';
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.externals[ name ] = {
|
|
||||||
dir: path,
|
|
||||||
|
|
||||||
// Use the default file name if there is no "fileName" and it
|
|
||||||
// was not found in "path".
|
|
||||||
file: fileName || ( this.fileName + '.js' )
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads one or more resources.
|
|
||||||
*
|
|
||||||
* CKEDITOR.plugins.load( 'myplugin', function( plugins ) {
|
|
||||||
* alert( plugins[ 'myplugin' ] ); // object
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {String/Array} name The name of the resource to load. It may be a
|
|
||||||
* string with a single resource name, or an array with several names.
|
|
||||||
* @param {Function} callback A function to be called when all resources
|
|
||||||
* are loaded. The callback will receive an array containing all loaded names.
|
|
||||||
* @param {Object} [scope] The scope object to be used for the callback call.
|
|
||||||
*/
|
|
||||||
load: function( names, callback, scope ) {
|
|
||||||
// Ensure that we have an array of names.
|
|
||||||
if ( !CKEDITOR.tools.isArray( names ) )
|
|
||||||
names = names ? [ names ] : [];
|
|
||||||
|
|
||||||
var loaded = this.loaded,
|
|
||||||
registered = this.registered,
|
|
||||||
urls = [],
|
|
||||||
urlsNames = {},
|
|
||||||
resources = {};
|
|
||||||
|
|
||||||
// Loop through all names.
|
|
||||||
for ( var i = 0; i < names.length; i++ ) {
|
|
||||||
var name = names[ i ];
|
|
||||||
|
|
||||||
if ( !name )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If not available yet.
|
|
||||||
if ( !loaded[ name ] && !registered[ name ] ) {
|
|
||||||
var url = this.getFilePath( name );
|
|
||||||
urls.push( url );
|
|
||||||
if ( !( url in urlsNames ) )
|
|
||||||
urlsNames[ url ] = [];
|
|
||||||
urlsNames[ url ].push( name );
|
|
||||||
} else
|
|
||||||
resources[ name ] = this.get( name );
|
|
||||||
}
|
|
||||||
|
|
||||||
CKEDITOR.scriptLoader.load( urls, function( completed, failed ) {
|
|
||||||
if ( failed.length ) {
|
|
||||||
throw '[CKEDITOR.resourceManager.load] Resource name "' + urlsNames[ failed[ 0 ] ].join( ',' )
|
|
||||||
+ '" was not found at "' + failed[ 0 ] + '".';
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var i = 0; i < completed.length; i++ ) {
|
|
||||||
var nameList = urlsNames[ completed[ i ] ];
|
|
||||||
for ( var j = 0; j < nameList.length; j++ ) {
|
|
||||||
var name = nameList[ j ];
|
|
||||||
resources[ name ] = this.get( name );
|
|
||||||
|
|
||||||
loaded[ name ] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.call( scope, resources );
|
|
||||||
}, this );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,202 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.scriptLoader} object, used to load scripts
|
|
||||||
* asynchronously.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load scripts asynchronously.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.scriptLoader = ( function() {
|
|
||||||
var uniqueScripts = {},
|
|
||||||
waitingList = {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Loads one or more external script checking if not already loaded
|
|
||||||
* previously by this function.
|
|
||||||
*
|
|
||||||
* CKEDITOR.scriptLoader.load( '/myscript.js' );
|
|
||||||
*
|
|
||||||
* CKEDITOR.scriptLoader.load( '/myscript.js', function( success ) {
|
|
||||||
* // Alerts true if the script has been properly loaded.
|
|
||||||
* // HTTP error 404 should return false.
|
|
||||||
* alert( success );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* CKEDITOR.scriptLoader.load( [ '/myscript1.js', '/myscript2.js' ], function( completed, failed ) {
|
|
||||||
* alert( 'Number of scripts loaded: ' + completed.length );
|
|
||||||
* alert( 'Number of failures: ' + failed.length );
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {String/Array} scriptUrl One or more URLs pointing to the
|
|
||||||
* scripts to be loaded.
|
|
||||||
* @param {Function} [callback] A function to be called when the script
|
|
||||||
* is loaded and executed. If a string is passed to `scriptUrl`, a
|
|
||||||
* boolean parameter is passed to the callback, indicating the
|
|
||||||
* success of the load. If an array is passed instead, two arrays
|
|
||||||
* parameters are passed to the callback - the first contains the
|
|
||||||
* URLs that have been properly loaded and the second the failed ones.
|
|
||||||
* @param {Object} [scope] The scope (`this` reference) to be used for
|
|
||||||
* the callback call. Defaults to {@link CKEDITOR}.
|
|
||||||
* @param {Boolean} [showBusy] Changes the cursor of the document while
|
|
||||||
* the script is loaded.
|
|
||||||
*/
|
|
||||||
load: function( scriptUrl, callback, scope, showBusy ) {
|
|
||||||
var isString = ( typeof scriptUrl == 'string' );
|
|
||||||
|
|
||||||
if ( isString )
|
|
||||||
scriptUrl = [ scriptUrl ];
|
|
||||||
|
|
||||||
if ( !scope )
|
|
||||||
scope = CKEDITOR;
|
|
||||||
|
|
||||||
var scriptCount = scriptUrl.length,
|
|
||||||
completed = [],
|
|
||||||
failed = [];
|
|
||||||
|
|
||||||
var doCallback = function( success ) {
|
|
||||||
if ( callback ) {
|
|
||||||
if ( isString )
|
|
||||||
callback.call( scope, success );
|
|
||||||
else
|
|
||||||
callback.call( scope, completed, failed );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( scriptCount === 0 ) {
|
|
||||||
doCallback( true );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkLoaded = function( url, success ) {
|
|
||||||
( success ? completed : failed ).push( url );
|
|
||||||
|
|
||||||
if ( --scriptCount <= 0 ) {
|
|
||||||
showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' );
|
|
||||||
doCallback( success );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var onLoad = function( url, success ) {
|
|
||||||
// Mark this script as loaded.
|
|
||||||
uniqueScripts[ url ] = 1;
|
|
||||||
|
|
||||||
// Get the list of callback checks waiting for this file.
|
|
||||||
var waitingInfo = waitingList[ url ];
|
|
||||||
delete waitingList[ url ];
|
|
||||||
|
|
||||||
// Check all callbacks waiting for this file.
|
|
||||||
for ( var i = 0; i < waitingInfo.length; i++ )
|
|
||||||
waitingInfo[ i ]( url, success );
|
|
||||||
};
|
|
||||||
|
|
||||||
var loadScript = function( url ) {
|
|
||||||
if ( uniqueScripts[ url ] ) {
|
|
||||||
checkLoaded( url, true );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var waitingInfo = waitingList[ url ] || ( waitingList[ url ] = [] );
|
|
||||||
waitingInfo.push( checkLoaded );
|
|
||||||
|
|
||||||
// Load it only for the first request.
|
|
||||||
if ( waitingInfo.length > 1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Create the <script> element.
|
|
||||||
var script = new CKEDITOR.dom.element( 'script' );
|
|
||||||
script.setAttributes( {
|
|
||||||
type: 'text/javascript',
|
|
||||||
src: url } );
|
|
||||||
|
|
||||||
if ( callback ) {
|
|
||||||
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 ) {
|
|
||||||
// FIXME: For IE, we are not able to return false on error (like 404).
|
|
||||||
script.$.onreadystatechange = function() {
|
|
||||||
if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' ) {
|
|
||||||
script.$.onreadystatechange = null;
|
|
||||||
onLoad( url, true );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
script.$.onload = function() {
|
|
||||||
// Some browsers, such as Safari, may call the onLoad function
|
|
||||||
// immediately. Which will break the loading sequence. (#3661)
|
|
||||||
setTimeout( function() {
|
|
||||||
onLoad( url, true );
|
|
||||||
}, 0 );
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: Opera and Safari will not fire onerror.
|
|
||||||
script.$.onerror = function() {
|
|
||||||
onLoad( url, false );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append it to <head>.
|
|
||||||
script.appendTo( CKEDITOR.document.getHead() );
|
|
||||||
|
|
||||||
CKEDITOR.fire( 'download', url ); // %REMOVE_LINE%
|
|
||||||
};
|
|
||||||
|
|
||||||
showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' );
|
|
||||||
for ( var i = 0; i < scriptCount; i++ ) {
|
|
||||||
loadScript( scriptUrl[ i ] );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a script in a queue, so only one is loaded at the same time.
|
|
||||||
*
|
|
||||||
* @since 4.1.2
|
|
||||||
* @param {String} scriptUrl URL pointing to the script to be loaded.
|
|
||||||
* @param {Function} [callback] A function to be called when the script
|
|
||||||
* is loaded and executed. A boolean parameter is passed to the callback,
|
|
||||||
* indicating the success of the load.
|
|
||||||
*
|
|
||||||
* @see CKEDITOR.scriptLoader#load
|
|
||||||
*/
|
|
||||||
queue: ( function() {
|
|
||||||
var pending = [];
|
|
||||||
|
|
||||||
// Loads the very first script from queue and removes it.
|
|
||||||
function loadNext() {
|
|
||||||
var script;
|
|
||||||
|
|
||||||
if ( ( script = pending[ 0 ] ) )
|
|
||||||
this.load( script.scriptUrl, script.callback, CKEDITOR, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return function( scriptUrl, callback ) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
// This callback calls the standard callback for the script
|
|
||||||
// and loads the very next script from pending list.
|
|
||||||
function callbackWrapper() {
|
|
||||||
callback && callback.apply( this, arguments );
|
|
||||||
|
|
||||||
// Removed the just loaded script from the queue.
|
|
||||||
pending.shift();
|
|
||||||
|
|
||||||
loadNext.call( that );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's add this script to the queue
|
|
||||||
pending.push( { scriptUrl: scriptUrl, callback: callbackWrapper } );
|
|
||||||
|
|
||||||
// If the queue was empty, then start loading.
|
|
||||||
if ( pending.length == 1 )
|
|
||||||
loadNext.call( this );
|
|
||||||
};
|
|
||||||
} )()
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,335 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.skin} class that is used to manage skin parts.
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var cssLoaded = {};
|
|
||||||
|
|
||||||
function getName() {
|
|
||||||
return CKEDITOR.skinName.split( ',' )[ 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getConfigPath() {
|
|
||||||
return CKEDITOR.getUrl( CKEDITOR.skinName.split( ',' )[ 1 ] || ( 'skins/' + getName() + '/' ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages the loading of skin parts among all editor instances.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
CKEDITOR.skin = {
|
|
||||||
/**
|
|
||||||
* Returns the root path to the skin directory.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
path: getConfigPath,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a skin part into the page. Does nothing if the part has already been loaded.
|
|
||||||
*
|
|
||||||
* **Note:** The "editor" part is always auto loaded upon instance creation,
|
|
||||||
* thus this function is mainly used to **lazy load** other parts of the skin
|
|
||||||
* that do not have to be displayed until requested.
|
|
||||||
*
|
|
||||||
* // Load the dialog part.
|
|
||||||
* editor.skin.loadPart( 'dialog' );
|
|
||||||
*
|
|
||||||
* @param {String} part The name of the skin part CSS file that resides in the skin directory.
|
|
||||||
* @param {Function} fn The provided callback function which is invoked after the part is loaded.
|
|
||||||
*/
|
|
||||||
loadPart: function( part, fn ) {
|
|
||||||
if ( CKEDITOR.skin.name != getName() ) {
|
|
||||||
CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( getConfigPath() + 'skin.js' ), function() {
|
|
||||||
loadCss( part, fn );
|
|
||||||
} );
|
|
||||||
} else
|
|
||||||
loadCss( part, fn );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the real URL of a (CSS) skin part.
|
|
||||||
*
|
|
||||||
* @param {String} part
|
|
||||||
*/
|
|
||||||
getPath: function( part ) {
|
|
||||||
return CKEDITOR.getUrl( getCssPath( part ) );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of registered icons. To add new icons to this list, use {@link #addIcon}.
|
|
||||||
*/
|
|
||||||
icons: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers an icon.
|
|
||||||
*
|
|
||||||
* @param {String} name The icon name.
|
|
||||||
* @param {String} path The path to the icon image file.
|
|
||||||
* @param {Number} [offset] The vertical offset position of the icon, if
|
|
||||||
* available inside a strip image.
|
|
||||||
* @param {String} [bgsize] The value of the CSS "background-size" property to
|
|
||||||
* use for this icon
|
|
||||||
*/
|
|
||||||
addIcon: function( name, path, offset, bgsize ) {
|
|
||||||
name = name.toLowerCase();
|
|
||||||
if ( !this.icons[ name ] ) {
|
|
||||||
this.icons[ name ] = {
|
|
||||||
path: path,
|
|
||||||
offset: offset || 0,
|
|
||||||
bgsize : bgsize || '16px'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the CSS background styles to be used to render a specific icon.
|
|
||||||
*
|
|
||||||
* @param {String} name The icon name, as registered with {@link #addIcon}.
|
|
||||||
* @param {Boolean} [rtl] Indicates that the RTL version of the icon is
|
|
||||||
* to be used, if available.
|
|
||||||
* @param {String} [overridePath] The path to the icon image file. It
|
|
||||||
* overrides the path defined by the named icon, if available, and is
|
|
||||||
* used if the named icon was not registered.
|
|
||||||
* @param {Number} [overrideOffset] The vertical offset position of the
|
|
||||||
* icon. It overrides the offset defined by the named icon, if
|
|
||||||
* available, and is used if the named icon was not registered.
|
|
||||||
* @param {String} [overrideBgsize] The value of the CSS "background-size" property
|
|
||||||
* to use for the icon. It overrides the value defined by the named icon,
|
|
||||||
* if available, and is used if the named icon was not registered.
|
|
||||||
*/
|
|
||||||
getIconStyle: function( name, rtl, overridePath, overrideOffset, overrideBgsize ) {
|
|
||||||
var icon, path, offset, bgsize;
|
|
||||||
|
|
||||||
if ( name ) {
|
|
||||||
name = name.toLowerCase();
|
|
||||||
// If we're in RTL, try to get the RTL version of the icon.
|
|
||||||
if ( rtl )
|
|
||||||
icon = this.icons[ name + '-rtl' ];
|
|
||||||
|
|
||||||
// If not in LTR or no RTL version available, get the generic one.
|
|
||||||
if ( !icon )
|
|
||||||
icon = this.icons[ name ];
|
|
||||||
}
|
|
||||||
|
|
||||||
path = overridePath || ( icon && icon.path ) || '';
|
|
||||||
offset = overrideOffset || ( icon && icon.offset );
|
|
||||||
bgsize = overrideBgsize || ( icon && icon.bgsize ) || '16px';
|
|
||||||
|
|
||||||
return path &&
|
|
||||||
( 'background-image:url(' + CKEDITOR.getUrl( path ) + ');background-position:0 ' + offset + 'px;background-size:' + bgsize + ';' );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getCssPath( part ) {
|
|
||||||
// Check for ua-specific version of skin part.
|
|
||||||
var uas = CKEDITOR.skin[ 'ua_' + part ], env = CKEDITOR.env;
|
|
||||||
if ( uas ) {
|
|
||||||
|
|
||||||
// Having versioned UA checked first.
|
|
||||||
uas = uas.split( ',' ).sort( function( a, b ) { return a > b ? -1 : 1; } );
|
|
||||||
|
|
||||||
// Loop through all ua entries, checking is any of them match the current ua.
|
|
||||||
for ( var i = 0, ua; i < uas.length; i++ ) {
|
|
||||||
ua = uas[ i ];
|
|
||||||
|
|
||||||
if ( env.ie ) {
|
|
||||||
if ( ( ua.replace( /^ie/, '' ) == env.version ) || ( env.quirks && ua == 'iequirks' ) )
|
|
||||||
ua = 'ie';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( env[ ua ] ) {
|
|
||||||
part += '_' + uas[ i ];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CKEDITOR.getUrl( getConfigPath() + part + '.css' );
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadCss( part, callback ) {
|
|
||||||
// Avoid reload.
|
|
||||||
if ( !cssLoaded[ part ] ) {
|
|
||||||
CKEDITOR.document.appendStyleSheet( getCssPath( part ) );
|
|
||||||
cssLoaded[ part ] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSS loading should not be blocking.
|
|
||||||
callback && callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
|
|
||||||
/** Gets the color of the editor user interface.
|
|
||||||
*
|
|
||||||
* CKEDITOR.instances.editor1.getUiColor();
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
* @returns {String} uiColor The editor UI color or `undefined` if the UI color is not set.
|
|
||||||
*/
|
|
||||||
getUiColor: function() {
|
|
||||||
return this.uiColor;
|
|
||||||
},
|
|
||||||
|
|
||||||
/** Sets the color of the editor user interface. This method accepts a color value in
|
|
||||||
* hexadecimal notation, with a `#` character (e.g. #ffffff).
|
|
||||||
*
|
|
||||||
* CKEDITOR.instances.editor1.setUiColor( '#ff00ff' );
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @member CKEDITOR.editor
|
|
||||||
* @param {String} color The desired editor UI color in hexadecimal notation.
|
|
||||||
*/
|
|
||||||
setUiColor: function( color ) {
|
|
||||||
var uiStyle = getStylesheet( CKEDITOR.document );
|
|
||||||
|
|
||||||
return ( this.setUiColor = function( color ) {
|
|
||||||
var chameleon = CKEDITOR.skin.chameleon;
|
|
||||||
|
|
||||||
var replace = [ [ uiColorRegexp, color ] ];
|
|
||||||
this.uiColor = color;
|
|
||||||
|
|
||||||
// Update general style.
|
|
||||||
updateStylesheets( [ uiStyle ], chameleon( this, 'editor' ), replace );
|
|
||||||
|
|
||||||
// Update panel styles.
|
|
||||||
updateStylesheets( uiColorMenus, chameleon( this, 'panel' ), replace );
|
|
||||||
} ).call( this, color );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
var uiColorStylesheetId = 'cke_ui_color',
|
|
||||||
uiColorMenus = [],
|
|
||||||
uiColorRegexp = /\$color/g;
|
|
||||||
|
|
||||||
function getStylesheet( document ) {
|
|
||||||
var node = document.getById( uiColorStylesheetId );
|
|
||||||
if ( !node ) {
|
|
||||||
node = document.getHead().append( 'style' );
|
|
||||||
node.setAttribute( "id", uiColorStylesheetId );
|
|
||||||
node.setAttribute( "type", "text/css" );
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStylesheets( styleNodes, styleContent, replace ) {
|
|
||||||
var r, i, content;
|
|
||||||
|
|
||||||
// We have to split CSS declarations for webkit.
|
|
||||||
if ( CKEDITOR.env.webkit ) {
|
|
||||||
styleContent = styleContent.split( '}' ).slice( 0, -1 );
|
|
||||||
for ( i = 0; i < styleContent.length; i++ )
|
|
||||||
styleContent[ i ] = styleContent[ i ].split( '{' );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var id = 0; id < styleNodes.length; id++ ) {
|
|
||||||
if ( CKEDITOR.env.webkit ) {
|
|
||||||
for ( i = 0; i < styleContent.length; i++ ) {
|
|
||||||
content = styleContent[ i ][ 1 ];
|
|
||||||
for ( r = 0; r < replace.length; r++ )
|
|
||||||
content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
|
|
||||||
|
|
||||||
styleNodes[ id ].$.sheet.addRule( styleContent[ i ][ 0 ], content );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content = styleContent;
|
|
||||||
for ( r = 0; r < replace.length; r++ )
|
|
||||||
content = content.replace( replace[ r ][ 0 ], replace[ r ][ 1 ] );
|
|
||||||
|
|
||||||
if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 )
|
|
||||||
styleNodes[ id ].$.styleSheet.cssText += content;
|
|
||||||
else
|
|
||||||
styleNodes[ id ].$.innerHTML += content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CKEDITOR.on( 'instanceLoaded', function( evt ) {
|
|
||||||
// The chameleon feature is not for IE quirks.
|
|
||||||
if ( CKEDITOR.env.ie && CKEDITOR.env.quirks )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var editor = evt.editor,
|
|
||||||
showCallback = function( event ) {
|
|
||||||
var panel = event.data[ 0 ] || event.data;
|
|
||||||
var iframe = panel.element.getElementsByTag( 'iframe' ).getItem( 0 ).getFrameDocument();
|
|
||||||
|
|
||||||
// Add stylesheet if missing.
|
|
||||||
if ( !iframe.getById( 'cke_ui_color' ) ) {
|
|
||||||
var node = getStylesheet( iframe );
|
|
||||||
uiColorMenus.push( node );
|
|
||||||
|
|
||||||
var color = editor.getUiColor();
|
|
||||||
// Set uiColor for new panel.
|
|
||||||
if ( color )
|
|
||||||
updateStylesheets( [ node ], CKEDITOR.skin.chameleon( editor, 'panel' ), [ [ uiColorRegexp, color ] ] );
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
editor.on( 'panelShow', showCallback );
|
|
||||||
editor.on( 'menuShow', showCallback );
|
|
||||||
|
|
||||||
// Apply UI color if specified in config.
|
|
||||||
if ( editor.config.uiColor )
|
|
||||||
editor.setUiColor( editor.config.uiColor );
|
|
||||||
} );
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of file names matching the browser user agent string from
|
|
||||||
* {@link CKEDITOR.env}. This is used to load the skin part file in addition
|
|
||||||
* to the "main" skin file for a particular browser.
|
|
||||||
*
|
|
||||||
* **Note:** For each of the defined skin parts the corresponding
|
|
||||||
* CSS file with the same name as the user agent must exist inside
|
|
||||||
* the skin directory.
|
|
||||||
*
|
|
||||||
* @property ua
|
|
||||||
* @todo type?
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the skin that is currently used.
|
|
||||||
*
|
|
||||||
* @property {String} name
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The editor skin name. Note that it is not possible to have editors with
|
|
||||||
* different skin settings in the same page. In such case just one of the
|
|
||||||
* skins will be used for all editors.
|
|
||||||
*
|
|
||||||
* This is a shortcut to {@link CKEDITOR#skinName}.
|
|
||||||
*
|
|
||||||
* It is possible to install skins outside the default `skin` folder in the
|
|
||||||
* editor installation. In that case, the absolute URL path to that folder
|
|
||||||
* should be provided, separated by a comma (`'skin_name,skin_path'`).
|
|
||||||
*
|
|
||||||
* config.skin = 'moono';
|
|
||||||
*
|
|
||||||
* config.skin = 'myskin,/customstuff/myskin/';
|
|
||||||
*
|
|
||||||
* @cfg {String} skin
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A function that supports the chameleon (skin color switch) feature, providing
|
|
||||||
* the skin color style updates to be applied in runtime.
|
|
||||||
*
|
|
||||||
* **Note:** The embedded `$color` variable is to be substituted with a specific UI color.
|
|
||||||
*
|
|
||||||
* @method chameleon
|
|
||||||
* @param {String} editor The editor instance that the color changes apply to.
|
|
||||||
* @param {String} part The name of the skin part where the color changes take place.
|
|
||||||
*/
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Defines the {@link CKEDITOR.template} class, which represents
|
|
||||||
* an UI template for an editor instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var cache = {},
|
|
||||||
rePlaceholder = /{([^}]+)}/g,
|
|
||||||
reQuote = /'/g,
|
|
||||||
reEscapableChars = /([\\'])/g,
|
|
||||||
reNewLine = /\n/g,
|
|
||||||
reCarriageReturn = /\r/g;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lightweight template used to build the output string from variables.
|
|
||||||
*
|
|
||||||
* // HTML template for presenting a label UI.
|
|
||||||
* var tpl = new CKEDITOR.template( '<div class="{cls}">{label}</div>' );
|
|
||||||
* alert( tpl.output( { cls: 'cke-label', label: 'foo'} ) ); // '<div class="cke-label">foo</div>'
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor Creates a template class instance.
|
|
||||||
* @param {String} source The template source.
|
|
||||||
*/
|
|
||||||
CKEDITOR.template = function( source ) {
|
|
||||||
// Builds an optimized function body for the output() method, focused on performance.
|
|
||||||
// For example, if we have this "source":
|
|
||||||
// '<div style="{style}">{editorName}</div>'
|
|
||||||
// ... the resulting function body will be (apart from the "buffer" handling):
|
|
||||||
// return [ '<div style="', data['style'] == undefined ? '{style}' : data['style'], '">', data['editorName'] == undefined ? '{editorName}' : data['editorName'], '</div>' ].join('');
|
|
||||||
|
|
||||||
// Try to read from the cache.
|
|
||||||
if ( cache[ source ] )
|
|
||||||
this.output = cache[ source ];
|
|
||||||
else {
|
|
||||||
var fn = source
|
|
||||||
// Escape chars like slash "\" or single quote "'".
|
|
||||||
.replace( reEscapableChars, '\\$1' )
|
|
||||||
.replace( reNewLine, '\\n' )
|
|
||||||
.replace( reCarriageReturn, '\\r' )
|
|
||||||
// Inject the template keys replacement.
|
|
||||||
.replace( rePlaceholder, function( m, key ) {
|
|
||||||
return "',data['" + key + "']==undefined?'{" + key + "}':data['" + key + "'],'";
|
|
||||||
} );
|
|
||||||
|
|
||||||
fn = "return buffer?buffer.push('" + fn + "'):['" + fn + "'].join('');";
|
|
||||||
this.output = cache[ source ] = Function( 'data', 'buffer', fn );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the template, filling its variables with the provided data.
|
|
||||||
*
|
|
||||||
* @method output
|
|
||||||
* @param {Object} data An object containing properties which values will be
|
|
||||||
* used to fill the template variables. The property names must match the
|
|
||||||
* template variables names. Variables without matching properties will be
|
|
||||||
* kept untouched.
|
|
||||||
* @param {Array} [buffer] An array into which the output data will be pushed into.
|
|
||||||
* The number of entries appended to the array is unknown.
|
|
||||||
* @returns {String/Number} If `buffer` has not been provided, the processed
|
|
||||||
* template output data, otherwise the new length of `buffer`.
|
|
||||||
*/
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* @license Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains UI features related to an editor instance.
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @mixins CKEDITOR.event
|
|
||||||
* @constructor Creates an ui class instance.
|
|
||||||
* @param {CKEDITOR.editor} editor The editor instance.
|
|
||||||
*/
|
|
||||||
CKEDITOR.ui = function( editor ) {
|
|
||||||
if ( editor.ui )
|
|
||||||
return editor.ui;
|
|
||||||
|
|
||||||
this.items = {};
|
|
||||||
this.instances = {};
|
|
||||||
this.editor = editor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object used to hold private stuff.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._ = {
|
|
||||||
handlers: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
// PACKAGER_RENAME( CKEDITOR.ui )
|
|
||||||
|
|
||||||
CKEDITOR.ui.prototype = {
|
|
||||||
/**
|
|
||||||
* Adds a UI item to the items collection. These items can be later used in
|
|
||||||
* the interface.
|
|
||||||
*
|
|
||||||
* // Add a new button named 'MyBold'.
|
|
||||||
* editorInstance.ui.add( 'MyBold', CKEDITOR.UI_BUTTON, {
|
|
||||||
* label: 'My Bold',
|
|
||||||
* command: 'bold'
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @param {String} name The UI item name.
|
|
||||||
* @param {Object} type The item type.
|
|
||||||
* @param {Object} definition The item definition. The properties of this
|
|
||||||
* object depend on the item type.
|
|
||||||
*/
|
|
||||||
add: function( name, type, definition ) {
|
|
||||||
// Compensate the unique name of this ui item to definition.
|
|
||||||
definition.name = name.toLowerCase();
|
|
||||||
|
|
||||||
var item = this.items[ name ] = {
|
|
||||||
type: type,
|
|
||||||
// The name of {@link CKEDITOR.command} which associate with this UI.
|
|
||||||
command: definition.command || null,
|
|
||||||
args: Array.prototype.slice.call( arguments, 2 )
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.tools.extend( item, definition );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the created ui objects by name.
|
|
||||||
*
|
|
||||||
* @param {String} name The name of the UI definition.
|
|
||||||
*/
|
|
||||||
get: function( name ) {
|
|
||||||
return this.instances[ name ];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a UI object.
|
|
||||||
*
|
|
||||||
* @param {String} name The UI item hame.
|
|
||||||
* @returns {Object} The UI element.
|
|
||||||
*/
|
|
||||||
create: function( name ) {
|
|
||||||
var item = this.items[ name ],
|
|
||||||
handler = item && this._.handlers[ item.type ],
|
|
||||||
command = item && item.command && this.editor.getCommand( item.command );
|
|
||||||
|
|
||||||
var result = handler && handler.create.apply( this, item.args );
|
|
||||||
|
|
||||||
this.instances[ name ] = result;
|
|
||||||
|
|
||||||
// Add reference inside command object.
|
|
||||||
if ( command )
|
|
||||||
command.uiItems.push( result );
|
|
||||||
|
|
||||||
if ( result && !result.type )
|
|
||||||
result.type = item.type;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a handler for a UI item type. The handler is responsible for
|
|
||||||
* transforming UI item definitions in UI objects.
|
|
||||||
*
|
|
||||||
* @param {Object} type The item type.
|
|
||||||
* @param {Object} handler The handler definition.
|
|
||||||
*/
|
|
||||||
addHandler: function( type, handler ) {
|
|
||||||
this._.handlers[ type ] = handler;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the unique DOM element that represents one editor's UI part, as
|
|
||||||
* the editor UI is made completely decoupled from DOM (no DOM reference hold),
|
|
||||||
* this method is mainly used to retrieve the rendered DOM part by name.
|
|
||||||
*
|
|
||||||
* // Hide the bottom space in the UI.
|
|
||||||
* var bottom = editor.ui.getSpace( 'bottom' );
|
|
||||||
* bottom.setStyle( 'display', 'none' );
|
|
||||||
*
|
|
||||||
* @param {String} name The space name.
|
|
||||||
* @returns {CKEDITOR.dom.element} The element that represents the space.
|
|
||||||
*/
|
|
||||||
space: function( name ) {
|
|
||||||
return CKEDITOR.document.getById( this.spaceId( name ) );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the HTML ID from a specific UI space name.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @todo param and return types?
|
|
||||||
*/
|
|
||||||
spaceId: function( name ) {
|
|
||||||
return this.editor.id + '_' + name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CKEDITOR.event.implementOn( CKEDITOR.ui );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal event fired when a new UI element is ready.
|
|
||||||
*
|
|
||||||
* @event ready
|
|
||||||
* @param {Object} data The new element.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual class which just illustrates the features of handler objects to be
|
|
||||||
* passed to the {@link CKEDITOR.ui#addHandler} function.
|
|
||||||
* This class is not really part of the API, so don't call its constructor.
|
|
||||||
*
|
|
||||||
* @class CKEDITOR.ui.handlerDefinition
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms an item definition into an UI item object.
|
|
||||||
*
|
|
||||||
* editorInstance.ui.addHandler( CKEDITOR.UI_BUTTON, {
|
|
||||||
* create: function( definition ) {
|
|
||||||
* return new CKEDITOR.ui.button( definition );
|
|
||||||
* }
|
|
||||||
* } );
|
|
||||||
*
|
|
||||||
* @method create
|
|
||||||
* @param {Object} definition The item definition.
|
|
||||||
* @returns {Object} The UI element.
|
|
||||||
* @todo We lack the "UI element" abstract super class.
|
|
||||||
*/
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved.
|
|
||||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
|
||||||
|
|
||||||
af.js Found: 62 Missing: 4
|
|
||||||
ar.js Found: 51 Missing: 15
|
|
||||||
bg.js Found: 58 Missing: 8
|
|
||||||
bn.js Found: 40 Missing: 26
|
|
||||||
bs.js Found: 29 Missing: 37
|
|
||||||
ca.js Found: 61 Missing: 5
|
|
||||||
cs.js Found: 66 Missing: 0
|
|
||||||
cy.js Found: 66 Missing: 0
|
|
||||||
da.js Found: 66 Missing: 0
|
|
||||||
de.js Found: 66 Missing: 0
|
|
||||||
el.js Found: 59 Missing: 7
|
|
||||||
en-au.js Found: 38 Missing: 28
|
|
||||||
en-ca.js Found: 37 Missing: 29
|
|
||||||
en-gb.js Found: 61 Missing: 5
|
|
||||||
eo.js Found: 66 Missing: 0
|
|
||||||
es.js Found: 66 Missing: 0
|
|
||||||
et.js Found: 66 Missing: 0
|
|
||||||
eu.js Found: 48 Missing: 18
|
|
||||||
fa.js Found: 66 Missing: 0
|
|
||||||
fi.js Found: 66 Missing: 0
|
|
||||||
fo.js Found: 66 Missing: 0
|
|
||||||
fr-ca.js Found: 42 Missing: 24
|
|
||||||
fr.js Found: 66 Missing: 0
|
|
||||||
gl.js Found: 40 Missing: 26
|
|
||||||
gu.js Found: 66 Missing: 0
|
|
||||||
he.js Found: 66 Missing: 0
|
|
||||||
hi.js Found: 43 Missing: 23
|
|
||||||
hr.js Found: 66 Missing: 0
|
|
||||||
hu.js Found: 63 Missing: 3
|
|
||||||
is.js Found: 41 Missing: 25
|
|
||||||
it.js Found: 66 Missing: 0
|
|
||||||
ja.js Found: 62 Missing: 4
|
|
||||||
ka.js Found: 62 Missing: 4
|
|
||||||
km.js Found: 40 Missing: 26
|
|
||||||
ko.js Found: 40 Missing: 26
|
|
||||||
lt.js Found: 66 Missing: 0
|
|
||||||
lv.js Found: 40 Missing: 26
|
|
||||||
mk.js Found: 0 Missing: 66
|
|
||||||
mn.js Found: 40 Missing: 26
|
|
||||||
ms.js Found: 39 Missing: 27
|
|
||||||
nb.js Found: 66 Missing: 0
|
|
||||||
nl.js Found: 65 Missing: 1
|
|
||||||
no.js Found: 66 Missing: 0
|
|
||||||
pl.js Found: 66 Missing: 0
|
|
||||||
pt-br.js Found: 66 Missing: 0
|
|
||||||
pt.js Found: 52 Missing: 14
|
|
||||||
ro.js Found: 61 Missing: 5
|
|
||||||
ru.js Found: 66 Missing: 0
|
|
||||||
sk.js Found: 49 Missing: 17
|
|
||||||
sl.js Found: 48 Missing: 18
|
|
||||||
sr-latn.js Found: 40 Missing: 26
|
|
||||||
sr.js Found: 40 Missing: 26
|
|
||||||
sv.js Found: 62 Missing: 4
|
|
||||||
th.js Found: 40 Missing: 26
|
|
||||||
tr.js Found: 66 Missing: 0
|
|
||||||
ug.js Found: 66 Missing: 0
|
|
||||||
uk.js Found: 66 Missing: 0
|
|
||||||
vi.js Found: 66 Missing: 0
|
|
||||||
zh-cn.js Found: 66 Missing: 0
|
|
||||||
zh.js Found: 58 Missing: 8
|
|
||||||
102
scripts/ckeditor/lang/af.js
Executable file → Normal file
102
scripts/ckeditor/lang/af.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/ar.js
Executable file → Normal file
102
scripts/ckeditor/lang/ar.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/bg.js
Executable file → Normal file
102
scripts/ckeditor/lang/bg.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/bn.js
Executable file → Normal file
102
scripts/ckeditor/lang/bn.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/bs.js
Executable file → Normal file
102
scripts/ckeditor/lang/bs.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/ca.js
Executable file → Normal file
102
scripts/ckeditor/lang/ca.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/cs.js
Executable file → Normal file
102
scripts/ckeditor/lang/cs.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/cy.js
Executable file → Normal file
102
scripts/ckeditor/lang/cy.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/da.js
Executable file → Normal file
102
scripts/ckeditor/lang/da.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/de.js
Executable file → Normal file
102
scripts/ckeditor/lang/de.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/el.js
Executable file → Normal file
102
scripts/ckeditor/lang/el.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/en-au.js
Executable file → Normal file
102
scripts/ckeditor/lang/en-au.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/en-ca.js
Executable file → Normal file
102
scripts/ckeditor/lang/en-ca.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/en-gb.js
Executable file → Normal file
102
scripts/ckeditor/lang/en-gb.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
103
scripts/ckeditor/lang/en.js
Executable file → Normal file
103
scripts/ckeditor/lang/en.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/eo.js
Executable file → Normal file
102
scripts/ckeditor/lang/eo.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/es.js
Executable file → Normal file
102
scripts/ckeditor/lang/es.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/et.js
Executable file → Normal file
102
scripts/ckeditor/lang/et.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/eu.js
Executable file → Normal file
102
scripts/ckeditor/lang/eu.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/fa.js
Executable file → Normal file
102
scripts/ckeditor/lang/fa.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/fi.js
Executable file → Normal file
102
scripts/ckeditor/lang/fi.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/fo.js
Executable file → Normal file
102
scripts/ckeditor/lang/fo.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/fr-ca.js
Executable file → Normal file
102
scripts/ckeditor/lang/fr-ca.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/fr.js
Executable file → Normal file
102
scripts/ckeditor/lang/fr.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/gl.js
Executable file → Normal file
102
scripts/ckeditor/lang/gl.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/gu.js
Executable file → Normal file
102
scripts/ckeditor/lang/gu.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/he.js
Executable file → Normal file
102
scripts/ckeditor/lang/he.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/hi.js
Executable file → Normal file
102
scripts/ckeditor/lang/hi.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/hr.js
Executable file → Normal file
102
scripts/ckeditor/lang/hr.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/hu.js
Executable file → Normal file
102
scripts/ckeditor/lang/hu.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
101
scripts/ckeditor/lang/id.js
Executable file → Normal file
101
scripts/ckeditor/lang/id.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
102
scripts/ckeditor/lang/is.js
Executable file → Normal file
102
scripts/ckeditor/lang/is.js
Executable file → Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user