Editor.js 44.3 KB
Newer Older
C
campaign 已提交
1 2 3 4 5 6 7 8
/**
 * @file
 * @name UE.Editor
 * @short Editor
 * @import editor.js,core/utils.js,core/EventBase.js,core/browser.js,core/dom/dtd.js,core/dom/domUtils.js,core/dom/Range.js,core/dom/Selection.js,plugins/serialize.js
 * @desc 编辑器主类,包含编辑器提供的大部分公用接口
 */
(function () {
C
campaign 已提交
9 10
    var uid = 0, _selectionChangeTimer;

C
campaign 已提交
11 12 13 14 15 16
    /**
     * @private
     * @ignore
     * @param form  编辑器所在的form元素
     * @param editor  编辑器实例对象
     */
C
campaign 已提交
17
    function setValue(form, editor) {
C
campaign 已提交
18
        var textarea;
C
campaign 已提交
19 20 21 22
        if (editor.textarea) {
            if (utils.isString(editor.textarea)) {
                for (var i = 0, ti, tis = domUtils.getElementsByTagName(form, 'textarea'); ti = tis[i++];) {
                    if (ti.id == 'ueditor_textarea_' + editor.options.textarea) {
C
campaign 已提交
23 24 25 26 27 28 29 30
                        textarea = ti;
                        break;
                    }
                }
            } else {
                textarea = editor.textarea;
            }
        }
C
campaign 已提交
31 32
        if (!textarea) {
            form.appendChild(textarea = domUtils.createElement(document, 'textarea', {
C
campaign 已提交
33 34 35
                'name': editor.options.textarea,
                'id': 'ueditor_textarea_' + editor.options.textarea,
                'style': "display:none"
C
campaign 已提交
36
            }));
C
campaign 已提交
37 38 39 40
            //不要产生多个textarea
            editor.textarea = textarea;
        }
        textarea.value = editor.hasContents() ?
C
campaign 已提交
41
            (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) :
C
campaign 已提交
42 43
            ''
    }
C
campaign 已提交
44 45 46 47 48 49
    function loadPlugins(me){
        //初始化插件
        for (var pi in UE.plugins) {
            UE.plugins[pi].call(me);
        }
        me.langIsReady = true;
C
campaign 已提交
50

C
campaign 已提交
51 52
        me.fireEvent("langReady");
    }
C
campaign 已提交
53 54 55 56 57
    function checkCurLang(I18N){
        for(var lang in I18N){
            return lang
        }
    }
C
campaign 已提交
58 59 60 61 62 63 64 65 66 67 68
    /**
     * UEditor编辑器类
     * @name Editor
     * @desc 创建一个跟编辑器实例
     * - ***container*** 编辑器容器对象
     * - ***iframe*** 编辑区域所在的iframe对象
     * - ***window*** 编辑区域所在的window
     * - ***document*** 编辑区域所在的document对象
     * - ***body*** 编辑区域所在的body对象
     * - ***selection*** 编辑区域的选区对象
     */
C
campaign 已提交
69
    var Editor = UE.Editor = function (options) {
C
campaign 已提交
70 71
        var me = this;
        me.uid = uid++;
C
campaign 已提交
72
        EventBase.call(me);
C
campaign 已提交
73
        me.commands = {};
C
campaign 已提交
74
        me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
C
campaign 已提交
75
        me.shortcutkeys = {};
C
campaign 已提交
76 77
        me.inputRules = [];
        me.outputRules = [];
C
campaign 已提交
78
        //设置默认的常用属性
C
campaign 已提交
79
        me.setOpt({
C
campaign 已提交
80
            isShow: true,
C
campaign 已提交
81
            initialContent: '',
C
campaign 已提交
82
            initialStyle:'',
C
campaign 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
            autoClearinitialContent: false,
            iframeCssUrl: me.options.UEDITOR_HOME_URL + 'themes/iframe.css',
            textarea: 'editorValue',
            focus: false,
            focusInEnd: true,
            autoClearEmptyNode: true,
            fullscreen: false,
            readonly: false,
            zIndex: 999,
            imagePopup: true,
            enterTag: 'p',
            customDomain: false,
            lang: 'zh-cn',
            langPath: me.options.UEDITOR_HOME_URL + 'lang/',
            theme: 'default',
            themePath: me.options.UEDITOR_HOME_URL + 'themes/',
            allHtmlEnabled: false,
            scaleEnabled: false,
C
campaign 已提交
101 102
            tableNativeEditInFF: false,
            autoSyncData : true
C
campaign 已提交
103
        });
C
campaign 已提交
104

C
campaign 已提交
105
        if(!utils.isEmptyObject(UE.I18N)){
C
campaign 已提交
106 107
            //修改默认的语言类型
            me.options.lang = checkCurLang(UE.I18N);
C
campaign 已提交
108
            loadPlugins(me)
C
campaign 已提交
109 110 111 112 113 114 115
        }else{
            utils.loadFile(document, {
                src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
                tag: "script",
                type: "text/javascript",
                defer: "defer"
            }, function () {
C
campaign 已提交
116
                loadPlugins(me)
C
campaign 已提交
117 118
            });
        }
C
campaign 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134

        UE.instants['ueditorInstant' + me.uid] = me;
    };
    Editor.prototype = {
        /**
         * 当编辑器ready后执行传入的fn,如果编辑器已经完成ready,就马上执行fn,fn的中的this是编辑器实例。
         * 大部分的实例接口都需要放在该方法内部执行,否则在IE下可能会报错。
         * @name ready
         * @grammar editor.ready(fn) fn是当编辑器渲染好后执行的function
         * @example
         * var editor = new UE.ui.Editor();
         * editor.render("myEditor");
         * editor.ready(function(){
         *     editor.setContent("欢迎使用UEditor!");
         * })
         */
C
campaign 已提交
135
        ready: function (fn) {
C
campaign 已提交
136
            var me = this;
C
campaign 已提交
137 138
            if (fn) {
                me.isReady ? fn.apply(me) : me.addListener('ready', fn);
C
campaign 已提交
139 140 141 142 143 144 145
            }
        },
        /**
         * 为编辑器设置默认参数值。若用户配置为空,则以默认配置为准
         * @grammar editor.setOpt(key,value);      //传入一个键、值对
         * @grammar editor.setOpt({ key:value});   //传入一个json对象
         */
C
campaign 已提交
146
        setOpt: function (key, val) {
C
campaign 已提交
147
            var obj = {};
C
campaign 已提交
148
            if (utils.isString(key)) {
C
campaign 已提交
149 150 151 152
                obj[key] = val
            } else {
                obj = key;
            }
C
campaign 已提交
153
            utils.extend(this.options, obj, true);
C
campaign 已提交
154 155 156 157 158 159
        },
        /**
         * 销毁编辑器实例对象
         * @name destroy
         * @grammar editor.destroy();
         */
C
campaign 已提交
160
        destroy: function () {
C
campaign 已提交
161 162

            var me = this;
C
campaign 已提交
163
            me.fireEvent('destroy');
C
campaign 已提交
164 165
            var container = me.container.parentNode;
            var textarea = me.textarea;
C
campaign 已提交
166
            if (!textarea) {
C
campaign 已提交
167
                textarea = document.createElement('textarea');
C
campaign 已提交
168 169
                container.parentNode.insertBefore(textarea, container);
            } else {
C
campaign 已提交
170 171
                textarea.style.display = ''
            }
C
campaign 已提交
172 173 174

            textarea.style.width = me.iframe.offsetWidth + 'px';
            textarea.style.height = me.iframe.offsetHeight + 'px';
C
campaign 已提交
175 176 177
            textarea.value = me.getContent();
            textarea.id = me.key;
            container.innerHTML = '';
C
campaign 已提交
178
            domUtils.remove(container);
C
campaign 已提交
179 180
            var key = me.key;
            //trace:2004
C
campaign 已提交
181 182
            for (var p in me) {
                if (me.hasOwnProperty(p)) {
C
campaign 已提交
183 184 185 186 187 188 189 190 191 192 193
                    delete this[p];
                }
            }
            UE.delEditor(key);
        },
        /**
         * 渲染编辑器的DOM到指定容器,必须且只能调用一次
         * @name render
         * @grammar editor.render(containerId);    //可以指定一个容器ID
         * @grammar editor.render(containerDom);   //也可以直接指定容器对象
         */
C
campaign 已提交
194
        render: function (container) {
许恒 已提交
195 196 197 198 199
            var me = this,
                options = me.options,
                getStyleValue=function(attr){
                   return parseInt(domUtils.getComputedStyle(container,attr));
                };
C
campaign 已提交
200 201
            if (utils.isString(container)) {
                container = document.getElementById(container);
C
campaign 已提交
202
            }
C
campaign 已提交
203
            if (container) {
C
campaign 已提交
204 205 206 207 208 209 210 211 212 213
                if(options.initialFrameWidth){
                    options.minFrameWidth = options.initialFrameWidth
                }else{
                    options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
                }
                if(options.initialFrameHeight){
                    options.minFrameHeight = options.initialFrameHeight
                }else{
                    options.initialFrameHeight = options.minFrameHeight = container.offsetHeight;
                }
C
campaign 已提交
214

许恒 已提交
215 216 217 218 219
                container.style.width = /%$/.test(options.initialFrameWidth) ?  '100%' : options.initialFrameWidth-
                   getStyleValue("padding-left")- getStyleValue("padding-right") +'px';
                container.style.height = /%$/.test(options.initialFrameHeight) ?  '100%' : options.initialFrameHeight -
                    getStyleValue("padding-top")- getStyleValue("padding-bottom") +'px';

C
campaign 已提交
220 221 222 223
                container.style.zIndex = options.zIndex;

                var html = ( ie && browser.version < 9  ? '' : '<!DOCTYPE html>') +
                        '<html xmlns=\'http://www.w3.org/1999/xhtml\' class=\'view\' ><head>' +
C
campaign 已提交
224 225
                        '<style type=\'text/css\'>' +
                        //设置四周的留边
C
campaign 已提交
226
                        '.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +
C
campaign 已提交
227 228 229 230
                        //设置默认字体和字号
                        //font-family不能呢随便改,在safari下fillchar会有解析问题
                        'body{margin:8px;font-family:sans-serif;font-size:16px;}' +
                        //设置段落间距
C
campaign 已提交
231 232 233
                        'p{margin:5px 0;}</style>' +
                        ( options.iframeCssUrl ? '<link rel=\'stylesheet\' type=\'text/css\' href=\'' + utils.unhtml(options.iframeCssUrl) + '\'/>' : '' ) +
                        (options.initialStyle ? '<style>' + options.initialStyle + '</style>' : '') +
C
campaign 已提交
234
                        '</head><body class=\'view\' ></body>' +
C
campaign 已提交
235 236 237 238 239 240 241 242 243 244 245
                        '<script type=\'text/javascript\' ' + (ie ? 'defer=\'defer\'' : '' ) +' id=\'_initialScript\'>' +
                        'setTimeout(function(){window.parent.UE.instants[\'ueditorInstant' + me.uid + '\']._setup(document);},0);' +
                        'var _tmpScript = document.getElementById(\'_initialScript\');_tmpScript.parentNode.removeChild(_tmpScript);</script></html>';
                container.appendChild(domUtils.createElement(document, 'iframe', {
                    id: 'ueditor_' + me.uid,
                    width: "100%",
                    height: "100%",
                    frameborder: "0",
                    src: 'javascript:void(function(){document.open();' + (options.customDomain && document.domain != location.hostname ?  'document.domain="' + document.domain + '";' : '') +
                        'document.write("' + html + '");document.close();}())'
                }));
C
campaign 已提交
246
                container.style.overflow = 'hidden';
C
campaign 已提交
247 248 249 250 251 252 253 254 255 256 257
                //解决如果是给定的百分比,会导致高度算不对的问题
                setTimeout(function(){
                    if( /%$/.test(options.initialFrameWidth)){
                        options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
                        container.style.width = options.initialFrameWidth + 'px';
                    }
                    if(/%$/.test(options.initialFrameHeight)){
                        options.minFrameHeight = options.initialFrameHeight = container.offsetHeight;
                        container.style.height = options.initialFrameHeight + 'px';
                    }
                })
C
campaign 已提交
258 259 260 261 262 263 264 265
            }
        },
        /**
         * 编辑器初始化
         * @private
         * @ignore
         * @param {Element} doc 编辑器Iframe中的文档对象
         */
C
campaign 已提交
266
        _setup: function (doc) {
C
campaign 已提交
267

C
campaign 已提交
268
            var me = this,
C
campaign 已提交
269 270
                options = me.options;
            if (ie) {
C
campaign 已提交
271 272 273 274 275 276
                doc.body.disabled = true;
                doc.body.contentEditable = true;
                doc.body.disabled = false;
            } else {
                doc.body.contentEditable = true;
            }
C
campaign 已提交
277
            doc.body.spellcheck = false;
C
campaign 已提交
278 279 280 281
            me.document = doc;
            me.window = doc.defaultView || doc.parentWindow;
            me.iframe = me.window.frameElement;
            me.body = doc.body;
C
campaign 已提交
282

C
campaign 已提交
283
            me.selection = new dom.Selection(doc);
C
campaign 已提交
284 285
            //gecko初始化就能得到range,无法判断isFocus了
            var geckoSel;
C
campaign 已提交
286
            if (browser.gecko && (geckoSel = this.selection.getNative())) {
C
campaign 已提交
287 288 289 290
                geckoSel.removeAllRanges();
            }
            this._initEvents();
            //为form提交提供一个隐藏的textarea
C
campaign 已提交
291 292
            for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) {
                if (form.tagName == 'FORM') {
C
campaign 已提交
293
                    me.form = form;
C
campaign 已提交
294 295 296 297 298 299 300 301 302
                    if(me.options.autoSyncData){
                        domUtils.on(me.window,'blur',function(){
                            setValue(form,me);
                        });
                    }else{
                        domUtils.on(form, 'submit', function () {
                            setValue(this, me);
                        });
                    }
C
campaign 已提交
303 304 305
                    break;
                }
            }
C
campaign 已提交
306 307 308 309 310 311 312 313 314 315 316 317
            if (options.initialContent) {
                if (options.autoClearinitialContent) {
                    var oldExecCommand = me.execCommand;
                    me.execCommand = function () {
                        me.fireEvent('firstBeforeExecCommand');
                        return oldExecCommand.apply(me, arguments);
                    };
                    this._setDefaultContent(options.initialContent);
                } else
                    this.setContent(options.initialContent, false, true);
            }

C
campaign 已提交
318
            //编辑器不能为空内容
C
campaign 已提交
319

C
campaign 已提交
320
            if (domUtils.isEmptyNode(me.body)) {
C
campaign 已提交
321 322 323
                me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
            }
            //如果要求focus, 就把光标定位到内容开始
C
campaign 已提交
324 325 326
            if (options.focus) {
                setTimeout(function () {
                    me.focus(me.options.focusInEnd);
C
campaign 已提交
327 328
                    //如果自动清除开着,就不需要做selectionchange;
                    !me.options.autoClearinitialContent && me._selectionChange();
C
campaign 已提交
329
                }, 0);
C
campaign 已提交
330
            }
C
campaign 已提交
331
            if (!me.container) {
C
campaign 已提交
332 333
                me.container = this.iframe.parentNode;
            }
C
campaign 已提交
334 335
            if (options.fullscreen && me.ui) {
                me.ui.setFullScreen(true);
C
campaign 已提交
336
            }
C
campaign 已提交
337

C
campaign 已提交
338
            try {
C
campaign 已提交
339 340 341
                me.document.execCommand('2D-position', false, false);
            } catch (e) {
            }
C
campaign 已提交
342
            try {
C
campaign 已提交
343 344 345
                me.document.execCommand('enableInlineTableEditing', false, false);
            } catch (e) {
            }
C
campaign 已提交
346
            try {
C
campaign 已提交
347 348
                me.document.execCommand('enableObjectResizing', false, false);
            } catch (e) {
C
campaign 已提交
349 350 351
//                domUtils.on(me.body,browser.ie ? 'resizestart' : 'resize', function( evt ) {
//                    domUtils.preventDefault(evt)
//                });
C
campaign 已提交
352
            }
C
campaign 已提交
353
            me._bindshortcutKeys();
C
campaign 已提交
354
            me.isReady = 1;
C
campaign 已提交
355
            me.fireEvent('ready');
C
campaign 已提交
356
            options.onready && options.onready.call(me);
C
campaign 已提交
357
            if (!browser.ie9under) {
C
campaign 已提交
358
                domUtils.on(me.window, ['blur', 'focus'], function (e) {
C
campaign 已提交
359
                    //chrome下会出现alt+tab切换时,导致选区位置不对
C
campaign 已提交
360
                    if (e.type == 'blur') {
C
campaign 已提交
361
                        me._bakRange = me.selection.getRange();
C
campaign 已提交
362
                        try {
C
campaign 已提交
363
                            me._bakNativeRange = me.selection.getNative().getRangeAt(0);
C
campaign 已提交
364
                            me.selection.getNative().removeAllRanges();
C
campaign 已提交
365
                        } catch (e) {
C
campaign 已提交
366
                            me._bakNativeRange = null;
C
campaign 已提交
367
                        }
C
campaign 已提交
368 369 370 371

                    } else {
                        try {
                            me._bakRange && me._bakRange.select();
C
campaign 已提交
372
                        } catch (e) {
C
campaign 已提交
373 374
                        }
                    }
C
campaign 已提交
375
                });
C
campaign 已提交
376 377
            }
            //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
C
campaign 已提交
378
            if (browser.gecko && browser.version <= 10902) {
C
campaign 已提交
379 380
                //修复ff3.6初始化进来,不能点击获得焦点
                me.body.contentEditable = false;
C
campaign 已提交
381
                setTimeout(function () {
C
campaign 已提交
382
                    me.body.contentEditable = true;
C
campaign 已提交
383 384
                }, 100);
                setInterval(function () {
C
campaign 已提交
385
                    me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
C
campaign 已提交
386
                }, 100)
C
campaign 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
            }
            !options.isShow && me.setHide();
            options.readonly && me.setDisabled();
        },
        /**
         * 同步编辑器的数据,为提交数据做准备,主要用于你是手动提交的情况
         * @name sync
         * @grammar editor.sync(); //从编辑器的容器向上查找,如果找到就同步数据
         * @grammar editor.sync(formID); //formID制定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
         * @desc
         * 后台取得数据得键值使用你容器上得''name''属性,如果没有就使用参数传入的''textarea''
         * @example
         * editor.sync();
         * form.sumbit(); //form变量已经指向了form元素
         *
         */
C
campaign 已提交
403
        sync: function (formId) {
C
campaign 已提交
404
            var me = this,
C
campaign 已提交
405 406 407 408 409
                form = formId ? document.getElementById(formId) :
                    domUtils.findParent(me.iframe.parentNode, function (node) {
                        return node.tagName == 'FORM'
                    }, true);
            form && setValue(form, me);
C
campaign 已提交
410 411 412 413 414 415
        },
        /**
         * 设置编辑器高度
         * @name setHeight
         * @grammar editor.setHeight(number);  //纯数值,不带单位
         */
C
campaign 已提交
416
        setHeight: function (height,notSetHeight) {
C
campaign 已提交
417
            if (height !== parseInt(this.iframe.parentNode.style.height)) {
C
campaign 已提交
418 419
                this.iframe.parentNode.style.height = height + 'px';
            }
C
campaign 已提交
420
            !notSetHeight && (this.options.minFrameHeight = this.options.initialFrameHeight = height);
C
campaign 已提交
421 422

            this.body.style.height = height + 'px';
C
campaign 已提交
423 424
        },

C
campaign 已提交
425
        addshortcutkey: function (cmd, keys) {
C
campaign 已提交
426
            var obj = {};
C
campaign 已提交
427
            if (keys) {
C
campaign 已提交
428
                obj[cmd] = keys
C
campaign 已提交
429
            } else {
C
campaign 已提交
430 431
                obj = cmd;
            }
C
campaign 已提交
432
            utils.extend(this.shortcutkeys, obj)
C
campaign 已提交
433
        },
C
campaign 已提交
434
        _bindshortcutKeys: function () {
C
campaign 已提交
435 436
            var me = this, shortcutkeys = this.shortcutkeys;
            me.addListener('keydown', function (type, e) {
C
campaign 已提交
437
                var keyCode = e.keyCode || e.which;
C
campaign 已提交
438
                for (var i in shortcutkeys) {
C
campaign 已提交
439
                    var tmp = shortcutkeys[i].split(',');
C
campaign 已提交
440
                    for (var t = 0, ti; ti = tmp[t++];) {
C
campaign 已提交
441
                        ti = ti.split(':');
C
campaign 已提交
442 443 444
                        var key = ti[0], param = ti[1];
                        if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/.test(key)) {
                            if (( (RegExp.$1 == 'ctrl' ? (e.ctrlKey || e.metaKey) : 0)
C
campaign 已提交
445 446 447 448
                                && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
                                && keyCode == RegExp.$3
                                ) ||
                                keyCode == RegExp.$1
C
campaign 已提交
449
                                ) {
C
campaign 已提交
450 451
                                if (me.queryCommandState(i,param) != -1)
                                    me.execCommand(i, param);
C
campaign 已提交
452 453
                                domUtils.preventDefault(e);
                            }
C
campaign 已提交
454 455
                        }
                    }
C
campaign 已提交
456

C
campaign 已提交
457 458 459
                }
            });
        },
C
campaign 已提交
460 461 462 463 464 465 466 467 468 469 470 471
        /**
         * 获取编辑器内容
         * @name getContent
         * @grammar editor.getContent()  => String //若编辑器中只包含字符"&lt;p&gt;&lt;br /&gt;&lt;/p/&gt;"会返回空。
         * @grammar editor.getContent(fn)  => String
         * @example
         * getContent默认是会现调用hasContents来判断编辑器是否为空,如果是,就直接返回空字符串
         * 你也可以传入一个fn来接替hasContents的工作,定制判断的规则
         * editor.getContent(function(){
         *     return false //编辑器没有内容 ,getContent直接返回空
         * })
         */
C
campaign 已提交
472
        getContent: function (cmd, fn,notSetCursor,ignoreBlank,formatter) {
C
campaign 已提交
473
            var me = this;
C
campaign 已提交
474
            if (cmd && utils.isFunction(cmd)) {
C
campaign 已提交
475 476 477
                fn = cmd;
                cmd = '';
            }
C
campaign 已提交
478
            if (fn ? !fn() : !this.hasContents()) {
C
campaign 已提交
479 480
                return '';
            }
C
campaign 已提交
481
            me.fireEvent('beforegetcontent');
C
campaign 已提交
482
            var root = UE.htmlparser(me.body.innerHTML,ignoreBlank);
C
campaign 已提交
483
            me.filterOutputRule(root);
C
campaign 已提交
484
            me.fireEvent('aftergetcontent', cmd);
C
campaign 已提交
485
            return  root.toHtml(formatter);
C
campaign 已提交
486 487 488 489 490 491
        },
        /**
         * 取得完整的html代码,可以直接显示成完整的html文档
         * @name getAllHtml
         * @grammar editor.getAllHtml()  => String
         */
C
campaign 已提交
492
        getAllHtml: function () {
C
campaign 已提交
493
            var me = this,
C
campaign 已提交
494 495 496 497 498 499 500
                headHtml = [],
                html = '';
            me.fireEvent('getAllHtml', headHtml);
            if (browser.ie && browser.version > 8) {
                var headHtmlForIE9 = '';
                utils.each(me.document.styleSheets, function (si) {
                    headHtmlForIE9 += ( si.href ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />' : '<style>' + si.cssText + '</style>');
C
campaign 已提交
501
                });
C
campaign 已提交
502
                utils.each(me.document.getElementsByTagName('script'), function (si) {
C
campaign 已提交
503 504 505
                    headHtmlForIE9 += si.outerHTML;
                });

C
campaign 已提交
506
            }
C
campaign 已提交
507
            return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '')
C
campaign 已提交
508 509
                + (headHtmlForIE9 || me.document.getElementsByTagName('head')[0].innerHTML) + headHtml.join('\n') + '</head>'
                + '<body ' + (ie && browser.version < 9 ? 'class="view"' : '') + '>' + me.getContent(null, null, true) + '</body></html>';
C
campaign 已提交
510 511 512 513 514 515
        },
        /**
         * 得到编辑器的纯文本内容,但会保留段落格式
         * @name getPlainTxt
         * @grammar editor.getPlainTxt()  => String
         */
C
campaign 已提交
516
        getPlainTxt: function () {
C
campaign 已提交
517 518 519 520 521 522 523 524
            var reg = new RegExp(domUtils.fillChar, 'g'),
                html = this.body.innerHTML.replace(/[\n\r]/g, '');//ie要先去了\n在处理
            html = html.replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, '\n')
                .replace(/<br\/?>/gi, '\n')
                .replace(/<[^>/]+>/g, '')
                .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
                    return dtd.$block[c] ? '\n' : b ? b : '';
                });
C
campaign 已提交
525
            //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
C
campaign 已提交
526
            return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/&nbsp;/g, ' ');
C
campaign 已提交
527 528 529 530 531 532 533
        },

        /**
         * 获取编辑器中的纯文本内容,没有段落格式
         * @name getContentTxt
         * @grammar editor.getContentTxt()  => String
         */
C
campaign 已提交
534
        getContentTxt: function () {
C
campaign 已提交
535
            var reg = new RegExp(domUtils.fillChar, 'g');
C
campaign 已提交
536
            //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
C
campaign 已提交
537
            return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' ');
C
campaign 已提交
538 539 540 541 542 543 544 545 546 547 548 549 550
        },

        /**
         * 将html设置到编辑器中, 如果是用于初始化时给编辑器赋初值,则必须放在ready方法内部执行
         * @name setContent
         * @grammar editor.setContent(html)
         * @example
         * var editor = new UE.ui.Editor()
         * editor.ready(function(){
         *     //需要ready后执行,否则可能报错
         *     editor.setContent("欢迎使用UEditor!");
         * })
         */
C
campaign 已提交
551
        setContent: function (html, isAppendTo, notFireSelectionchange) {
C
campaign 已提交
552
            var me = this;
C
campaign 已提交
553

C
campaign 已提交
554
            me.fireEvent('beforesetcontent', html);
C
campaign 已提交
555 556 557 558
            var root = UE.htmlparser(html);
            me.filterInputRule(root);
            html = root.toHtml();

C
campaign 已提交
559

C
campaign 已提交
560 561
            me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html;

C
campaign 已提交
562

C
campaign 已提交
563 564 565
            function isCdataDiv(node){
                return  node.tagName == 'DIV' && node.getAttribute('cdata_tag');
            }
C
campaign 已提交
566
            //给文本或者inline节点套p标签
C
campaign 已提交
567
            if (me.options.enterTag == 'p') {
C
campaign 已提交
568 569

                var child = this.body.firstChild, tmpNode;
C
campaign 已提交
570
                if (!child || child.nodeType == 1 &&
C
campaign 已提交
571
                    (dtd.$cdata[child.tagName] || isCdataDiv(child) ||
C
campaign 已提交
572 573 574
                        domUtils.isCustomeNode(child)
                        )
                    && child === this.body.lastChild) {
C
campaign 已提交
575 576 577
                    this.body.innerHTML = '<p>' + (browser.ie ? '&nbsp;' : '<br/>') + '</p>' + this.body.innerHTML;

                } else {
C
campaign 已提交
578 579 580
                    var p = me.document.createElement('p');
                    while (child) {
                        while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName])) {
C
campaign 已提交
581
                            tmpNode = child.nextSibling;
C
campaign 已提交
582
                            p.appendChild(child);
C
campaign 已提交
583 584
                            child = tmpNode;
                        }
C
campaign 已提交
585 586 587
                        if (p.firstChild) {
                            if (!child) {
                                me.body.appendChild(p);
C
campaign 已提交
588 589
                                break;
                            } else {
C
campaign 已提交
590 591
                                child.parentNode.insertBefore(p, child);
                                p = me.document.createElement('p');
C
campaign 已提交
592 593 594 595 596 597
                            }
                        }
                        child = child.nextSibling;
                    }
                }
            }
C
campaign 已提交
598
            me.fireEvent('aftersetcontent');
C
campaign 已提交
599 600
            me.fireEvent('contentchange');

C
campaign 已提交
601 602
            !notFireSelectionchange && me._selectionChange();
            //清除保存的选区
C
campaign 已提交
603
            me._bakRange = me._bakIERange = me._bakNativeRange = null;
C
campaign 已提交
604 605
            //trace:1742 setContent后gecko能得到焦点问题
            var geckoSel;
C
campaign 已提交
606
            if (browser.gecko && (geckoSel = this.selection.getNative())) {
C
campaign 已提交
607 608
                geckoSel.removeAllRanges();
            }
C
campaign 已提交
609
            if(me.options.autoSyncData){
C
campaign 已提交
610
                me.form && setValue(me.form,me);
C
campaign 已提交
611
            }
C
campaign 已提交
612 613 614 615 616 617 618
        },

        /**
         * 让编辑器获得焦点,toEnd确定focus位置
         * @name focus
         * @grammar editor.focus([toEnd])   //默认focus到编辑器头部,toEnd为true时focus到内容尾部
         */
C
campaign 已提交
619
        focus: function (toEnd) {
C
campaign 已提交
620 621
            try {
                var me = this,
C
campaign 已提交
622 623 624
                    rng = me.selection.getRange();
                if (toEnd) {
                    rng.setStartAtLast(me.body.lastChild).setCursor(false, true);
C
campaign 已提交
625
                } else {
C
campaign 已提交
626
                    rng.select(true);
C
campaign 已提交
627
                }
C
campaign 已提交
628
                this.fireEvent('focus');
C
campaign 已提交
629
            } catch (e) {
C
campaign 已提交
630 631 632 633 634 635 636 637
            }
        },

        /**
         * 初始化UE事件及部分事件代理
         * @private
         * @ignore
         */
C
campaign 已提交
638
        _initEvents: function () {
C
campaign 已提交
639
            var me = this,
C
campaign 已提交
640 641 642 643 644 645
                doc = me.document,
                win = me.window;
            me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
            domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent);
            domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent);
            domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
C
campaign 已提交
646
                //特殊键不触发selectionchange
C
campaign 已提交
647
                if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
C
campaign 已提交
648 649
                    return;
                }
C
campaign 已提交
650 651 652
                if (evt.button == 2)return;
                me._selectionChange(250, evt);
            });
C
campaign 已提交
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
//            //处理拖拽
//            //ie ff不能从外边拖入
//            //chrome只针对从外边拖入的内容过滤
//            var innerDrag = 0, source = browser.ie ? me.body : me.document, dragoverHandler;
//            domUtils.on(source, 'dragstart', function () {
//                innerDrag = 1;
//            });
//            domUtils.on(source, browser.webkit ? 'dragover' : 'drop', function () {
//                return browser.webkit ?
//                    function () {
//                        clearTimeout(dragoverHandler);
//                        dragoverHandler = setTimeout(function () {
//                            if (!innerDrag) {
//                                var sel = me.selection,
//                                    range = sel.getRange();
//                                if (range) {
//                                    var common = range.getCommonAncestor();
//                                    if (common && me.serialize) {
//                                        var f = me.serialize,
//                                            node =
//                                                f.filter(
//                                                    f.transformInput(
//                                                        f.parseHTML(
//                                                            f.word(common.innerHTML)
//                                                        )
//                                                    )
//                                                );
//                                        common.innerHTML = f.toHTML(node);
//                                    }
//                                }
//                            }
//                            innerDrag = 0;
//                        }, 200);
//                    } :
//                    function (e) {
//                        if (!innerDrag) {
//                            e.preventDefault ? e.preventDefault() : (e.returnValue = false);
//                        }
//                        innerDrag = 0;
//                    }
//            }());
C
campaign 已提交
694 695 696 697 698 699
        },
        /**
         * 触发事件代理
         * @private
         * @ignore
         */
C
campaign 已提交
700
        _proxyDomEvent: function (evt) {
C
campaign 已提交
701
            return this.fireEvent(evt.type.replace(/^on/, ''), evt);
C
campaign 已提交
702 703 704 705 706 707
        },
        /**
         * 变化选区
         * @private
         * @ignore
         */
C
campaign 已提交
708
        _selectionChange: function (delay, evt) {
C
campaign 已提交
709 710 711 712 713
            var me = this;
            //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
//            if ( !me.selection.isFocus() ){
//                return;
//            }
许恒 已提交
714 715


C
campaign 已提交
716 717
            var hackForMouseUp = false;
            var mouseX, mouseY;
C
campaign 已提交
718
            if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') {
C
campaign 已提交
719
                var range = this.selection.getRange();
C
campaign 已提交
720
                if (!range.collapsed) {
C
campaign 已提交
721 722 723 724 725
                    hackForMouseUp = true;
                    mouseX = evt.clientX;
                    mouseY = evt.clientY;
                }
            }
C
campaign 已提交
726 727 728
            clearTimeout(_selectionChangeTimer);
            _selectionChangeTimer = setTimeout(function () {
                if (!me.selection.getNative()) {
C
campaign 已提交
729 730 731 732 733
                    return;
                }
                //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
                //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
                var ieRange;
C
campaign 已提交
734
                if (hackForMouseUp && me.selection.getNative().type == 'None') {
C
campaign 已提交
735 736
                    ieRange = me.document.body.createTextRange();
                    try {
C
campaign 已提交
737 738
                        ieRange.moveToPoint(mouseX, mouseY);
                    } catch (ex) {
C
campaign 已提交
739 740 741 742
                        ieRange = null;
                    }
                }
                var bakGetIERange;
C
campaign 已提交
743
                if (ieRange) {
C
campaign 已提交
744 745 746 747 748 749
                    bakGetIERange = me.selection.getIERange;
                    me.selection.getIERange = function () {
                        return ieRange;
                    };
                }
                me.selection.cache();
C
campaign 已提交
750
                if (bakGetIERange) {
C
campaign 已提交
751 752
                    me.selection.getIERange = bakGetIERange;
                }
C
campaign 已提交
753 754
                if (me.selection._cachedRange && me.selection._cachedStartElement) {
                    me.fireEvent('beforeselectionchange');
C
campaign 已提交
755
                    // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
C
campaign 已提交
756
                    me.fireEvent('selectionchange', !!evt);
C
campaign 已提交
757
                    me.fireEvent('afterselectionchange');
C
campaign 已提交
758 759
                    me.selection.clear();
                }
C
campaign 已提交
760
            }, delay || 50);
C
campaign 已提交
761
        },
C
campaign 已提交
762
        _callCmdFn: function (fnName, args) {
C
campaign 已提交
763
            var cmdName = args[0].toLowerCase(),
C
campaign 已提交
764
                cmd, cmdFn;
C
campaign 已提交
765 766 767
            cmd = this.commands[cmdName] || UE.commands[cmdName];
            cmdFn = cmd && cmd[fnName];
            //没有querycommandstate或者没有command的都默认返回0
C
campaign 已提交
768
            if ((!cmd || !cmdFn) && fnName == 'queryCommandState') {
C
campaign 已提交
769
                return 0;
C
campaign 已提交
770 771
            } else if (cmdFn) {
                return cmdFn.apply(this, args);
C
campaign 已提交
772 773 774 775 776 777 778 779
            }
        },

        /**
         * 执行编辑命令cmdName,完成富文本编辑效果
         * @name execCommand
         * @grammar editor.execCommand(cmdName)   => {*}
         */
C
campaign 已提交
780
        execCommand: function (cmdName) {
C
campaign 已提交
781 782
            cmdName = cmdName.toLowerCase();
            var me = this,
C
campaign 已提交
783 784 785
                result,
                cmd = me.commands[cmdName] || UE.commands[cmdName];
            if (!cmd || !cmd.execCommand) {
C
campaign 已提交
786 787
                return null;
            }
C
campaign 已提交
788
            if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
C
campaign 已提交
789
                me.__hasEnterExecCommand = true;
C
campaign 已提交
790
                if (me.queryCommandState.apply(me,arguments) != -1) {
C
campaign 已提交
791 792
                    me.fireEvent('beforeexeccommand', cmdName);
                    result = this._callCmdFn('execCommand', arguments);
C
campaign 已提交
793
                    !me._ignoreContentChange && me.fireEvent('contentchange');
C
campaign 已提交
794
                    me.fireEvent('afterexeccommand', cmdName);
C
campaign 已提交
795 796 797
                }
                me.__hasEnterExecCommand = false;
            } else {
C
campaign 已提交
798
                result = this._callCmdFn('execCommand', arguments);
C
campaign 已提交
799
                !me._ignoreContentChange && me.fireEvent('contentchange')
C
campaign 已提交
800
            }
C
campaign 已提交
801
            !me._ignoreContentChange && me._selectionChange();
C
campaign 已提交
802 803 804 805 806 807 808 809 810 811 812
            return result;
        },
        /**
         * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
         * @name  queryCommandState
         * @grammar editor.queryCommandState(cmdName)  => (-1|0|1)
         * @desc
         * * ''-1'' 当前命令不可用
         * * ''0'' 当前命令可用
         * * ''1'' 当前命令已经执行过了
         */
C
campaign 已提交
813
        queryCommandState: function (cmdName) {
C
campaign 已提交
814
            return this._callCmdFn('queryCommandState', arguments);
C
campaign 已提交
815 816 817 818 819 820 821
        },

        /**
         * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
         * @name  queryCommandValue
         * @grammar editor.queryCommandValue(cmdName)  =>  {*}
         */
C
campaign 已提交
822
        queryCommandValue: function (cmdName) {
C
campaign 已提交
823
            return this._callCmdFn('queryCommandValue', arguments);
C
campaign 已提交
824 825 826 827 828 829 830 831 832 833 834 835
        },
        /**
         * 检查编辑区域中是否有内容,若包含tags中的节点类型,直接返回true
         * @name  hasContents
         * @desc
         * 默认有文本内容,或者有以下节点都不认为是空
         * <code>{table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1}</code>
         * @grammar editor.hasContents()  => (true|false)
         * @grammar editor.hasContents(tags)  =>  (true|false)  //若文档中包含tags数组里对应的tag,直接返回true
         * @example
         * editor.hasContents(['span']) //如果编辑器里有这些,不认为是空
         */
C
campaign 已提交
836
        hasContents: function (tags) {
C
campaign 已提交
837 838 839
            if (tags) {
                for (var i = 0, ci; ci = tags[i++];) {
                    if (this.document.getElementsByTagName(ci).length > 0) {
C
campaign 已提交
840 841 842 843
                        return true;
                    }
                }
            }
C
campaign 已提交
844
            if (!domUtils.isEmptyBlock(this.body)) {
C
campaign 已提交
845 846 847 848
                return true
            }
            //随时添加,定义的特殊标签如果存在,不能认为是空
            tags = ['div'];
C
campaign 已提交
849 850 851 852
            for (i = 0; ci = tags[i++];) {
                var nodes = domUtils.getElementsByTagName(this.document, ci);
                for (var n = 0, cn; cn = nodes[n++];) {
                    if (domUtils.isCustomeNode(cn)) {
C
campaign 已提交
853 854 855 856 857 858 859 860 861 862 863 864 865 866
                        return true;
                    }
                }
            }
            return false;
        },
        /**
         * 重置编辑器,可用来做多个tab使用同一个编辑器实例
         * @name  reset
         * @desc
         * * 清空编辑器内容
         * * 清空回退列表
         * @grammar editor.reset()
         */
C
campaign 已提交
867
        reset: function () {
C
campaign 已提交
868
            this.fireEvent('reset');
C
campaign 已提交
869
        },
C
campaign 已提交
870
        setEnabled: function () {
C
campaign 已提交
871
            var me = this, range;
C
campaign 已提交
872
            if (me.body.contentEditable == 'false') {
C
campaign 已提交
873 874 875 876
                me.body.contentEditable = true;
                range = me.selection.getRange();
                //有可能内容丢失了
                try {
C
campaign 已提交
877
                    range.moveToBookmark(me.lastBk);
C
campaign 已提交
878
                    delete me.lastBk
C
campaign 已提交
879 880
                } catch (e) {
                    range.setStartAtFirst(me.body).collapse(true)
C
campaign 已提交
881
                }
C
campaign 已提交
882 883
                range.select(true);
                if (me.bkqueryCommandState) {
C
campaign 已提交
884 885 886
                    me.queryCommandState = me.bkqueryCommandState;
                    delete me.bkqueryCommandState;
                }
C
campaign 已提交
887
                me.fireEvent('selectionchange');
C
campaign 已提交
888 889 890 891 892 893 894
            }
        },
        /**
         * 设置当前编辑区域可以编辑
         * @name enable
         * @grammar editor.enable()
         */
C
campaign 已提交
895
        enable: function () {
C
campaign 已提交
896 897
            return this.setEnabled();
        },
C
campaign 已提交
898
        setDisabled: function (except) {
C
campaign 已提交
899
            var me = this;
C
campaign 已提交
900 901 902 903
            except = except ? utils.isArray(except) ? except : [except] : [];
            if (me.body.contentEditable == 'true') {
                if (!me.lastBk) {
                    me.lastBk = me.selection.getRange().createBookmark(true);
C
campaign 已提交
904 905 906
                }
                me.body.contentEditable = false;
                me.bkqueryCommandState = me.queryCommandState;
C
campaign 已提交
907 908 909
                me.queryCommandState = function (type) {
                    if (utils.indexOf(except, type) != -1) {
                        return me.bkqueryCommandState.apply(me, arguments);
C
campaign 已提交
910 911 912
                    }
                    return -1;
                };
C
campaign 已提交
913
                me.fireEvent('selectionchange');
C
campaign 已提交
914 915 916 917 918 919 920 921 922
            }
        },
        /** 设置当前编辑区域不可编辑,except中的命令除外
         * @name disable
         * @grammar editor.disable()
         * @grammar editor.disable(except)  //例外的命令,也即即使设置了disable,此处配置的命令仍然可以执行
         * @example
         * //禁用工具栏中除加粗和插入图片之外的所有功能
         * editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array
C
campaign 已提交
923
         */
C
campaign 已提交
924
        disable: function (except) {
C
campaign 已提交
925 926 927 928 929 930 931 932
            return this.setDisabled(except);
        },
        /**
         * 设置默认内容
         * @ignore
         * @private
         * @param  {String} cont 要存入的内容
         */
C
campaign 已提交
933
        _setDefaultContent: function () {
C
campaign 已提交
934 935
            function clear() {
                var me = this;
C
campaign 已提交
936
                if (me.document.getElementById('initContent')) {
C
campaign 已提交
937
                    me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
C
campaign 已提交
938 939
                    me.removeListener('firstBeforeExecCommand focus', clear);
                    setTimeout(function () {
C
campaign 已提交
940 941
                        me.focus();
                        me._selectionChange();
C
campaign 已提交
942
                    }, 0)
C
campaign 已提交
943 944
                }
            }
C
campaign 已提交
945 946

            return function (cont) {
C
campaign 已提交
947 948
                var me = this;
                me.body.innerHTML = '<p id="initContent">' + cont + '</p>';
C
campaign 已提交
949

C
campaign 已提交
950
                me.addListener('firstBeforeExecCommand focus', clear);
C
campaign 已提交
951 952 953 954 955 956 957
            }
        }(),
        /**
         * show方法的兼容版本
         * @private
         * @ignore
         */
C
campaign 已提交
958
        setShow: function () {
C
campaign 已提交
959 960
            var me = this, range = me.selection.getRange();
            if (me.container.style.display == 'none') {
C
campaign 已提交
961 962
                //有可能内容丢失了
                try {
C
campaign 已提交
963
                    range.moveToBookmark(me.lastBk);
C
campaign 已提交
964
                    delete me.lastBk
C
campaign 已提交
965 966
                } catch (e) {
                    range.setStartAtFirst(me.body).collapse(true)
C
campaign 已提交
967 968
                }
                //ie下focus实效,所以做了个延迟
C
campaign 已提交
969 970 971
                setTimeout(function () {
                    range.select(true);
                }, 100);
C
campaign 已提交
972 973 974 975 976 977 978 979 980
                me.container.style.display = '';
            }

        },
        /**
         * 显示编辑器
         * @name show
         * @grammar editor.show()
         */
C
campaign 已提交
981
        show: function () {
C
campaign 已提交
982 983 984 985 986 987 988
            return this.setShow();
        },
        /**
         * hide方法的兼容版本
         * @private
         * @ignore
         */
C
campaign 已提交
989
        setHide: function () {
C
campaign 已提交
990
            var me = this;
C
campaign 已提交
991 992
            if (!me.lastBk) {
                me.lastBk = me.selection.getRange().createBookmark(true);
C
campaign 已提交
993 994 995 996 997 998 999 1000
            }
            me.container.style.display = 'none'
        },
        /**
         * 隐藏编辑器
         * @name hide
         * @grammar editor.hide()
         */
C
campaign 已提交
1001
        hide: function () {
C
campaign 已提交
1002 1003 1004 1005 1006 1007 1008 1009 1010
            return this.setHide();
        },
        /**
         * 根据制定的路径,获取对应的语言资源
         * @name  getLang
         * @grammar editor.getLang(path)  =>  (JSON|String) 路径根据的是lang目录下的语言文件的路径结构
         * @example
         * editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除
         */
C
campaign 已提交
1011
        getLang: function (path) {
C
campaign 已提交
1012
            var lang = UE.I18N[this.options.lang];
C
campaign 已提交
1013
            if (!lang) {
C
campaign 已提交
1014 1015
                throw Error("not import language file");
            }
C
campaign 已提交
1016 1017
            path = (path || "").split(".");
            for (var i = 0, ci; ci = path[i++];) {
C
campaign 已提交
1018
                lang = lang[ci];
C
campaign 已提交
1019
                if (!lang)break;
C
campaign 已提交
1020 1021
            }
            return lang;
C
campaign 已提交
1022 1023 1024
        },
        /**
         * 计算编辑器当前内容的长度
C
campaign 已提交
1025 1026
         * @name  getContentLength
         * @grammar editor.getContentLength(ingoneHtml,tagNames)  =>
C
campaign 已提交
1027
         * @example
C
campaign 已提交
1028
         * editor.getLang(true)
C
campaign 已提交
1029
         */
C
campaign 已提交
1030 1031
        getContentLength: function (ingoneHtml, tagNames) {
            var count = this.getContent(false,false,true).length;
C
campaign 已提交
1032 1033 1034 1035
            if (ingoneHtml) {
                tagNames = (tagNames || []).concat([ 'hr', 'img', 'iframe']);
                count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length;
                for (var i = 0, ci; ci = tagNames[i++];) {
C
campaign 已提交
1036 1037 1038 1039
                    count += this.document.getElementsByTagName(ci).length;
                }
            }
            return count;
C
campaign 已提交
1040
        },
C
campaign 已提交
1041
        addInputRule: function (rule) {
C
campaign 已提交
1042 1043
            this.inputRules.push(rule);
        },
C
campaign 已提交
1044
        filterInputRule: function (root) {
C
campaign 已提交
1045 1046 1047 1048
            for (var i = 0, ci; ci = this.inputRules[i++];) {
                ci.call(this, root)
            }
        },
C
campaign 已提交
1049
        addOutputRule: function (rule) {
C
campaign 已提交
1050 1051
            this.outputRules.push(rule)
        },
C
campaign 已提交
1052
        filterOutputRule: function (root) {
C
campaign 已提交
1053 1054 1055
            for (var i = 0, ci; ci = this.outputRules[i++];) {
                ci.call(this, root)
            }
C
campaign 已提交
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
        }
        /**
         * 得到dialog实例对象
         * @name getDialog
         * @grammar editor.getDialog(dialogName) => Object
         * @example
         * var dialog = editor.getDialog("insertimage");
         * dialog.open();   //打开dialog
         * dialog.close();  //关闭dialog
         */
    };
C
campaign 已提交
1067
    utils.inherits(Editor, EventBase);
C
campaign 已提交
1068
})();