Editor.js 43.0 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,holder) {
C
campaign 已提交
195
            var me = this, options = me.options;
C
campaign 已提交
196 197
            if (utils.isString(container)) {
                container = document.getElementById(container);
C
campaign 已提交
198
            }
C
campaign 已提交
199
            if (container) {
C
campaign 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
                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;
                }
                container.style.width = options.initialFrameWidth+ (/%$/.test(options.initialFrameWidth) ? '' : 'px');
                container.style.height = options.initialFrameHeight + (/%$/.test(options.initialFrameHeight) ? '' : 'px');
                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 已提交
216 217
                        '<style type=\'text/css\'>' +
                        //设置四周的留边
C
campaign 已提交
218
                        '.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +
C
campaign 已提交
219 220 221 222
                        //设置默认字体和字号
                        //font-family不能呢随便改,在safari下fillchar会有解析问题
                        'body{margin:8px;font-family:sans-serif;font-size:16px;}' +
                        //设置段落间距
C
campaign 已提交
223 224 225
                        '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 已提交
226
                        '</head><body class=\'view\' ></body>' +
C
campaign 已提交
227 228 229 230 231 232 233 234 235 236 237
                        '<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 已提交
238 239 240 241 242 243 244 245 246
                container.style.overflow = 'hidden';
            }
        },
        /**
         * 编辑器初始化
         * @private
         * @ignore
         * @param {Element} doc 编辑器Iframe中的文档对象
         */
C
campaign 已提交
247
        _setup: function (doc) {
C
campaign 已提交
248

C
campaign 已提交
249
            var me = this,
C
campaign 已提交
250 251
                options = me.options;
            if (ie) {
C
campaign 已提交
252 253 254 255 256 257
                doc.body.disabled = true;
                doc.body.contentEditable = true;
                doc.body.disabled = false;
            } else {
                doc.body.contentEditable = true;
            }
C
campaign 已提交
258
            doc.body.spellcheck = false;
C
campaign 已提交
259 260 261 262
            me.document = doc;
            me.window = doc.defaultView || doc.parentWindow;
            me.iframe = me.window.frameElement;
            me.body = doc.body;
C
campaign 已提交
263

C
campaign 已提交
264
            me.selection = new dom.Selection(doc);
C
campaign 已提交
265 266
            //gecko初始化就能得到range,无法判断isFocus了
            var geckoSel;
C
campaign 已提交
267
            if (browser.gecko && (geckoSel = this.selection.getNative())) {
C
campaign 已提交
268 269 270 271
                geckoSel.removeAllRanges();
            }
            this._initEvents();
            //为form提交提供一个隐藏的textarea
C
campaign 已提交
272 273
            for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) {
                if (form.tagName == 'FORM') {
C
campaign 已提交
274
                    me.form = form;
C
campaign 已提交
275 276 277 278 279 280 281 282 283
                    if(me.options.autoSyncData){
                        domUtils.on(me.window,'blur',function(){
                            setValue(form,me);
                        });
                    }else{
                        domUtils.on(form, 'submit', function () {
                            setValue(this, me);
                        });
                    }
C
campaign 已提交
284 285 286
                    break;
                }
            }
C
campaign 已提交
287 288 289 290 291 292 293 294 295 296 297 298
            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 已提交
299
            //编辑器不能为空内容
C
campaign 已提交
300

C
campaign 已提交
301
            if (domUtils.isEmptyNode(me.body)) {
C
campaign 已提交
302 303 304
                me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
            }
            //如果要求focus, 就把光标定位到内容开始
C
campaign 已提交
305 306 307
            if (options.focus) {
                setTimeout(function () {
                    me.focus(me.options.focusInEnd);
C
campaign 已提交
308 309
                    //如果自动清除开着,就不需要做selectionchange;
                    !me.options.autoClearinitialContent && me._selectionChange();
C
campaign 已提交
310
                }, 0);
C
campaign 已提交
311
            }
C
campaign 已提交
312
            if (!me.container) {
C
campaign 已提交
313 314
                me.container = this.iframe.parentNode;
            }
C
campaign 已提交
315 316
            if (options.fullscreen && me.ui) {
                me.ui.setFullScreen(true);
C
campaign 已提交
317
            }
C
campaign 已提交
318

C
campaign 已提交
319
            try {
C
campaign 已提交
320 321 322
                me.document.execCommand('2D-position', false, false);
            } catch (e) {
            }
C
campaign 已提交
323
            try {
C
campaign 已提交
324 325 326
                me.document.execCommand('enableInlineTableEditing', false, false);
            } catch (e) {
            }
C
campaign 已提交
327
            try {
C
campaign 已提交
328 329
                me.document.execCommand('enableObjectResizing', false, false);
            } catch (e) {
C
campaign 已提交
330 331 332
//                domUtils.on(me.body,browser.ie ? 'resizestart' : 'resize', function( evt ) {
//                    domUtils.preventDefault(evt)
//                });
C
campaign 已提交
333
            }
C
campaign 已提交
334
            me._bindshortcutKeys();
C
campaign 已提交
335
            me.isReady = 1;
C
campaign 已提交
336
            me.fireEvent('ready');
C
campaign 已提交
337
            options.onready && options.onready.call(me);
C
campaign 已提交
338 339
            if (!browser.ie) {
                domUtils.on(me.window, ['blur', 'focus'], function (e) {
C
campaign 已提交
340
                    //chrome下会出现alt+tab切换时,导致选区位置不对
C
campaign 已提交
341
                    if (e.type == 'blur') {
C
campaign 已提交
342
                        me._bakRange = me.selection.getRange();
C
campaign 已提交
343
                        me._bakNativeRange = me.selection.getNative().getRangeAt(0);
C
campaign 已提交
344
                        try {
C
campaign 已提交
345
                            me.selection.getNative().removeAllRanges();
C
campaign 已提交
346 347
                        } catch (e) {
                        }
C
campaign 已提交
348 349 350 351

                    } else {
                        try {
                            me._bakRange && me._bakRange.select();
C
campaign 已提交
352
                        } catch (e) {
C
campaign 已提交
353 354
                        }
                    }
C
campaign 已提交
355
                });
C
campaign 已提交
356 357
            }
            //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
C
campaign 已提交
358
            if (browser.gecko && browser.version <= 10902) {
C
campaign 已提交
359 360
                //修复ff3.6初始化进来,不能点击获得焦点
                me.body.contentEditable = false;
C
campaign 已提交
361
                setTimeout(function () {
C
campaign 已提交
362
                    me.body.contentEditable = true;
C
campaign 已提交
363 364
                }, 100);
                setInterval(function () {
C
campaign 已提交
365
                    me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
C
campaign 已提交
366
                }, 100)
C
campaign 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
            }
            !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 已提交
383
        sync: function (formId) {
C
campaign 已提交
384
            var me = this,
C
campaign 已提交
385 386 387 388 389
                form = formId ? document.getElementById(formId) :
                    domUtils.findParent(me.iframe.parentNode, function (node) {
                        return node.tagName == 'FORM'
                    }, true);
            form && setValue(form, me);
C
campaign 已提交
390 391 392 393 394 395
        },
        /**
         * 设置编辑器高度
         * @name setHeight
         * @grammar editor.setHeight(number);  //纯数值,不带单位
         */
C
campaign 已提交
396
        setHeight: function (height) {
C
campaign 已提交
397
            if (height !== parseInt(this.iframe.parentNode.style.height)) {
C
campaign 已提交
398 399 400 401 402
                this.iframe.parentNode.style.height = height + 'px';
            }
            this.document.body.style.height = height - 20 + 'px';
        },

C
campaign 已提交
403
        addshortcutkey: function (cmd, keys) {
C
campaign 已提交
404
            var obj = {};
C
campaign 已提交
405
            if (keys) {
C
campaign 已提交
406
                obj[cmd] = keys
C
campaign 已提交
407
            } else {
C
campaign 已提交
408 409
                obj = cmd;
            }
C
campaign 已提交
410
            utils.extend(this.shortcutkeys, obj)
C
campaign 已提交
411
        },
C
campaign 已提交
412
        _bindshortcutKeys: function () {
C
campaign 已提交
413 414
            var me = this, shortcutkeys = this.shortcutkeys;
            me.addListener('keydown', function (type, e) {
C
campaign 已提交
415
                var keyCode = e.keyCode || e.which;
C
campaign 已提交
416
                for (var i in shortcutkeys) {
C
campaign 已提交
417
                    var tmp = shortcutkeys[i].split(',');
C
campaign 已提交
418
                    for (var t = 0, ti; ti = tmp[t++];) {
C
campaign 已提交
419
                        ti = ti.split(':');
C
campaign 已提交
420 421 422
                        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 已提交
423 424 425 426
                                && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
                                && keyCode == RegExp.$3
                                ) ||
                                keyCode == RegExp.$1
C
campaign 已提交
427
                                ) {
C
campaign 已提交
428 429
                                if (me.queryCommandState(i,param) != -1)
                                    me.execCommand(i, param);
C
campaign 已提交
430 431
                                domUtils.preventDefault(e);
                            }
C
campaign 已提交
432 433
                        }
                    }
C
campaign 已提交
434

C
campaign 已提交
435 436 437
                }
            });
        },
C
campaign 已提交
438 439 440 441 442 443 444 445 446 447 448 449
        /**
         * 获取编辑器内容
         * @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 已提交
450
        getContent: function (cmd, fn,notSetCursor,ignoreBlank,formatter) {
C
campaign 已提交
451
            var me = this;
C
campaign 已提交
452
            if (cmd && utils.isFunction(cmd)) {
C
campaign 已提交
453 454 455
                fn = cmd;
                cmd = '';
            }
C
campaign 已提交
456
            if (fn ? !fn() : !this.hasContents()) {
C
campaign 已提交
457 458
                return '';
            }
C
campaign 已提交
459
            me.fireEvent('beforegetcontent');
C
campaign 已提交
460
            var root = UE.htmlparser(me.body.innerHTML,ignoreBlank);
C
campaign 已提交
461
            me.filterOutputRule(root);
C
campaign 已提交
462
            me.fireEvent('aftergetcontent', cmd);
C
campaign 已提交
463
            return  root.toHtml(formatter);
C
campaign 已提交
464 465 466 467 468 469
        },
        /**
         * 取得完整的html代码,可以直接显示成完整的html文档
         * @name getAllHtml
         * @grammar editor.getAllHtml()  => String
         */
C
campaign 已提交
470
        getAllHtml: function () {
C
campaign 已提交
471
            var me = this,
C
campaign 已提交
472 473 474 475 476 477 478
                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 已提交
479
                });
C
campaign 已提交
480
                utils.each(me.document.getElementsByTagName('script'), function (si) {
C
campaign 已提交
481 482 483
                    headHtmlForIE9 += si.outerHTML;
                });

C
campaign 已提交
484
            }
C
campaign 已提交
485
            return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '')
C
campaign 已提交
486 487
                + (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 已提交
488 489 490 491 492 493
        },
        /**
         * 得到编辑器的纯文本内容,但会保留段落格式
         * @name getPlainTxt
         * @grammar editor.getPlainTxt()  => String
         */
C
campaign 已提交
494
        getPlainTxt: function () {
C
campaign 已提交
495 496 497 498 499 500 501 502
            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 已提交
503
            //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
C
campaign 已提交
504
            return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/&nbsp;/g, ' ');
C
campaign 已提交
505 506 507 508 509 510 511
        },

        /**
         * 获取编辑器中的纯文本内容,没有段落格式
         * @name getContentTxt
         * @grammar editor.getContentTxt()  => String
         */
C
campaign 已提交
512
        getContentTxt: function () {
C
campaign 已提交
513
            var reg = new RegExp(domUtils.fillChar, 'g');
C
campaign 已提交
514
            //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
C
campaign 已提交
515
            return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' ');
C
campaign 已提交
516 517 518 519 520 521 522 523 524 525 526 527 528
        },

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

C
campaign 已提交
532
            me.fireEvent('beforesetcontent', html);
C
campaign 已提交
533 534 535 536
            var root = UE.htmlparser(html);
            me.filterInputRule(root);
            html = root.toHtml();

C
campaign 已提交
537

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

C
campaign 已提交
540

C
campaign 已提交
541 542 543
            function isCdataDiv(node){
                return  node.tagName == 'DIV' && node.getAttribute('cdata_tag');
            }
C
campaign 已提交
544
            //给文本或者inline节点套p标签
C
campaign 已提交
545
            if (me.options.enterTag == 'p') {
C
campaign 已提交
546 547

                var child = this.body.firstChild, tmpNode;
C
campaign 已提交
548
                if (!child || child.nodeType == 1 &&
C
campaign 已提交
549
                    (dtd.$cdata[child.tagName] || isCdataDiv(child) ||
C
campaign 已提交
550 551 552
                        domUtils.isCustomeNode(child)
                        )
                    && child === this.body.lastChild) {
C
campaign 已提交
553 554 555
                    this.body.innerHTML = '<p>' + (browser.ie ? '&nbsp;' : '<br/>') + '</p>' + this.body.innerHTML;

                } else {
C
campaign 已提交
556 557 558
                    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 已提交
559
                            tmpNode = child.nextSibling;
C
campaign 已提交
560
                            p.appendChild(child);
C
campaign 已提交
561 562
                            child = tmpNode;
                        }
C
campaign 已提交
563 564 565
                        if (p.firstChild) {
                            if (!child) {
                                me.body.appendChild(p);
C
campaign 已提交
566 567
                                break;
                            } else {
C
campaign 已提交
568 569
                                child.parentNode.insertBefore(p, child);
                                p = me.document.createElement('p');
C
campaign 已提交
570 571 572 573 574 575
                            }
                        }
                        child = child.nextSibling;
                    }
                }
            }
C
campaign 已提交
576
            me.fireEvent('aftersetcontent');
C
campaign 已提交
577 578
            me.fireEvent('contentchange');

C
campaign 已提交
579 580 581 582 583
            !notFireSelectionchange && me._selectionChange();
            //清除保存的选区
            me._bakRange = me._bakIERange = null;
            //trace:1742 setContent后gecko能得到焦点问题
            var geckoSel;
C
campaign 已提交
584
            if (browser.gecko && (geckoSel = this.selection.getNative())) {
C
campaign 已提交
585 586
                geckoSel.removeAllRanges();
            }
C
campaign 已提交
587
            if(me.options.autoSyncData){
C
campaign 已提交
588
                me.form && setValue(me.form,me);
C
campaign 已提交
589
            }
C
campaign 已提交
590 591 592 593 594 595 596
        },

        /**
         * 让编辑器获得焦点,toEnd确定focus位置
         * @name focus
         * @grammar editor.focus([toEnd])   //默认focus到编辑器头部,toEnd为true时focus到内容尾部
         */
C
campaign 已提交
597
        focus: function (toEnd) {
C
campaign 已提交
598 599
            try {
                var me = this,
C
campaign 已提交
600 601 602
                    rng = me.selection.getRange();
                if (toEnd) {
                    rng.setStartAtLast(me.body.lastChild).setCursor(false, true);
C
campaign 已提交
603
                } else {
C
campaign 已提交
604
                    rng.select(true);
C
campaign 已提交
605
                }
C
campaign 已提交
606
                this.fireEvent('focus');
C
campaign 已提交
607
            } catch (e) {
C
campaign 已提交
608 609 610 611 612 613 614 615
            }
        },

        /**
         * 初始化UE事件及部分事件代理
         * @private
         * @ignore
         */
C
campaign 已提交
616
        _initEvents: function () {
C
campaign 已提交
617
            var me = this,
C
campaign 已提交
618 619 620 621 622 623
                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 已提交
624
                //特殊键不触发selectionchange
C
campaign 已提交
625
                if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
C
campaign 已提交
626 627
                    return;
                }
C
campaign 已提交
628 629 630
                if (evt.button == 2)return;
                me._selectionChange(250, evt);
            });
C
campaign 已提交
631 632 633 634
            //处理拖拽
            //ie ff不能从外边拖入
            //chrome只针对从外边拖入的内容过滤
            var innerDrag = 0, source = browser.ie ? me.body : me.document, dragoverHandler;
C
campaign 已提交
635
            domUtils.on(source, 'dragstart', function () {
C
campaign 已提交
636
                innerDrag = 1;
C
campaign 已提交
637 638
            });
            domUtils.on(source, browser.webkit ? 'dragover' : 'drop', function () {
C
campaign 已提交
639
                return browser.webkit ?
C
campaign 已提交
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
                    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);
C
campaign 已提交
659 660 661 662
                                    }
                                }
                            }
                            innerDrag = 0;
C
campaign 已提交
663 664 665 666 667
                        }, 200);
                    } :
                    function (e) {
                        if (!innerDrag) {
                            e.preventDefault ? e.preventDefault() : (e.returnValue = false);
C
campaign 已提交
668
                        }
C
campaign 已提交
669 670 671
                        innerDrag = 0;
                    }
            }());
C
campaign 已提交
672 673 674 675 676 677
        },
        /**
         * 触发事件代理
         * @private
         * @ignore
         */
C
campaign 已提交
678
        _proxyDomEvent: function (evt) {
C
campaign 已提交
679
            return this.fireEvent(evt.type.replace(/^on/, ''), evt);
C
campaign 已提交
680 681 682 683 684 685
        },
        /**
         * 变化选区
         * @private
         * @ignore
         */
C
campaign 已提交
686
        _selectionChange: function (delay, evt) {
C
campaign 已提交
687 688 689 690 691
            var me = this;
            //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
//            if ( !me.selection.isFocus() ){
//                return;
//            }
许恒 已提交
692 693


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

        /**
         * 执行编辑命令cmdName,完成富文本编辑效果
         * @name execCommand
         * @grammar editor.execCommand(cmdName)   => {*}
         */
C
campaign 已提交
758
        execCommand: function (cmdName) {
C
campaign 已提交
759 760
            cmdName = cmdName.toLowerCase();
            var me = this,
C
campaign 已提交
761 762 763
                result,
                cmd = me.commands[cmdName] || UE.commands[cmdName];
            if (!cmd || !cmd.execCommand) {
C
campaign 已提交
764 765
                return null;
            }
C
campaign 已提交
766
            if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
C
campaign 已提交
767
                me.__hasEnterExecCommand = true;
C
campaign 已提交
768
                if (me.queryCommandState.apply(me,arguments) != -1) {
C
campaign 已提交
769 770
                    me.fireEvent('beforeexeccommand', cmdName);
                    result = this._callCmdFn('execCommand', arguments);
C
campaign 已提交
771
                    !me._ignoreContentChange && me.fireEvent('contentchange');
C
campaign 已提交
772
                    me.fireEvent('afterexeccommand', cmdName);
C
campaign 已提交
773 774 775
                }
                me.__hasEnterExecCommand = false;
            } else {
C
campaign 已提交
776
                result = this._callCmdFn('execCommand', arguments);
C
campaign 已提交
777
                !me._ignoreContentChange && me.fireEvent('contentchange')
C
campaign 已提交
778
            }
C
campaign 已提交
779
            !me._ignoreContentChange && me._selectionChange();
C
campaign 已提交
780 781 782 783 784 785 786 787 788 789 790
            return result;
        },
        /**
         * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
         * @name  queryCommandState
         * @grammar editor.queryCommandState(cmdName)  => (-1|0|1)
         * @desc
         * * ''-1'' 当前命令不可用
         * * ''0'' 当前命令可用
         * * ''1'' 当前命令已经执行过了
         */
C
campaign 已提交
791
        queryCommandState: function (cmdName) {
C
campaign 已提交
792
            return this._callCmdFn('queryCommandState', arguments);
C
campaign 已提交
793 794 795 796 797 798 799
        },

        /**
         * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
         * @name  queryCommandValue
         * @grammar editor.queryCommandValue(cmdName)  =>  {*}
         */
C
campaign 已提交
800
        queryCommandValue: function (cmdName) {
C
campaign 已提交
801
            return this._callCmdFn('queryCommandValue', arguments);
C
campaign 已提交
802 803 804 805 806 807 808 809 810 811 812 813
        },
        /**
         * 检查编辑区域中是否有内容,若包含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 已提交
814
        hasContents: function (tags) {
C
campaign 已提交
815 816 817
            if (tags) {
                for (var i = 0, ci; ci = tags[i++];) {
                    if (this.document.getElementsByTagName(ci).length > 0) {
C
campaign 已提交
818 819 820 821
                        return true;
                    }
                }
            }
C
campaign 已提交
822
            if (!domUtils.isEmptyBlock(this.body)) {
C
campaign 已提交
823 824 825 826
                return true
            }
            //随时添加,定义的特殊标签如果存在,不能认为是空
            tags = ['div'];
C
campaign 已提交
827 828 829 830
            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 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844
                        return true;
                    }
                }
            }
            return false;
        },
        /**
         * 重置编辑器,可用来做多个tab使用同一个编辑器实例
         * @name  reset
         * @desc
         * * 清空编辑器内容
         * * 清空回退列表
         * @grammar editor.reset()
         */
C
campaign 已提交
845
        reset: function () {
C
campaign 已提交
846
            this.fireEvent('reset');
C
campaign 已提交
847
        },
C
campaign 已提交
848
        setEnabled: function () {
C
campaign 已提交
849
            var me = this, range;
C
campaign 已提交
850
            if (me.body.contentEditable == 'false') {
C
campaign 已提交
851 852 853 854
                me.body.contentEditable = true;
                range = me.selection.getRange();
                //有可能内容丢失了
                try {
C
campaign 已提交
855
                    range.moveToBookmark(me.lastBk);
C
campaign 已提交
856
                    delete me.lastBk
C
campaign 已提交
857 858
                } catch (e) {
                    range.setStartAtFirst(me.body).collapse(true)
C
campaign 已提交
859
                }
C
campaign 已提交
860 861
                range.select(true);
                if (me.bkqueryCommandState) {
C
campaign 已提交
862 863 864
                    me.queryCommandState = me.bkqueryCommandState;
                    delete me.bkqueryCommandState;
                }
C
campaign 已提交
865
                me.fireEvent('selectionchange');
C
campaign 已提交
866 867 868 869 870 871 872
            }
        },
        /**
         * 设置当前编辑区域可以编辑
         * @name enable
         * @grammar editor.enable()
         */
C
campaign 已提交
873
        enable: function () {
C
campaign 已提交
874 875
            return this.setEnabled();
        },
C
campaign 已提交
876
        setDisabled: function (except) {
C
campaign 已提交
877
            var me = this;
C
campaign 已提交
878 879 880 881
            except = except ? utils.isArray(except) ? except : [except] : [];
            if (me.body.contentEditable == 'true') {
                if (!me.lastBk) {
                    me.lastBk = me.selection.getRange().createBookmark(true);
C
campaign 已提交
882 883 884
                }
                me.body.contentEditable = false;
                me.bkqueryCommandState = me.queryCommandState;
C
campaign 已提交
885 886 887
                me.queryCommandState = function (type) {
                    if (utils.indexOf(except, type) != -1) {
                        return me.bkqueryCommandState.apply(me, arguments);
C
campaign 已提交
888 889 890
                    }
                    return -1;
                };
C
campaign 已提交
891
                me.fireEvent('selectionchange');
C
campaign 已提交
892 893 894 895 896 897 898 899 900
            }
        },
        /** 设置当前编辑区域不可编辑,except中的命令除外
         * @name disable
         * @grammar editor.disable()
         * @grammar editor.disable(except)  //例外的命令,也即即使设置了disable,此处配置的命令仍然可以执行
         * @example
         * //禁用工具栏中除加粗和插入图片之外的所有功能
         * editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array
C
campaign 已提交
901
         */
C
campaign 已提交
902
        disable: function (except) {
C
campaign 已提交
903 904 905 906 907 908 909 910
            return this.setDisabled(except);
        },
        /**
         * 设置默认内容
         * @ignore
         * @private
         * @param  {String} cont 要存入的内容
         */
C
campaign 已提交
911
        _setDefaultContent: function () {
C
campaign 已提交
912 913
            function clear() {
                var me = this;
C
campaign 已提交
914
                if (me.document.getElementById('initContent')) {
C
campaign 已提交
915
                    me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
C
campaign 已提交
916 917
                    me.removeListener('firstBeforeExecCommand focus', clear);
                    setTimeout(function () {
C
campaign 已提交
918 919
                        me.focus();
                        me._selectionChange();
C
campaign 已提交
920
                    }, 0)
C
campaign 已提交
921 922
                }
            }
C
campaign 已提交
923 924

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

C
campaign 已提交
928
                me.addListener('firstBeforeExecCommand focus', clear);
C
campaign 已提交
929 930 931 932 933 934 935
            }
        }(),
        /**
         * show方法的兼容版本
         * @private
         * @ignore
         */
C
campaign 已提交
936
        setShow: function () {
C
campaign 已提交
937 938
            var me = this, range = me.selection.getRange();
            if (me.container.style.display == 'none') {
C
campaign 已提交
939 940
                //有可能内容丢失了
                try {
C
campaign 已提交
941
                    range.moveToBookmark(me.lastBk);
C
campaign 已提交
942
                    delete me.lastBk
C
campaign 已提交
943 944
                } catch (e) {
                    range.setStartAtFirst(me.body).collapse(true)
C
campaign 已提交
945 946
                }
                //ie下focus实效,所以做了个延迟
C
campaign 已提交
947 948 949
                setTimeout(function () {
                    range.select(true);
                }, 100);
C
campaign 已提交
950 951 952 953 954 955 956 957 958
                me.container.style.display = '';
            }

        },
        /**
         * 显示编辑器
         * @name show
         * @grammar editor.show()
         */
C
campaign 已提交
959
        show: function () {
C
campaign 已提交
960 961 962 963 964 965 966
            return this.setShow();
        },
        /**
         * hide方法的兼容版本
         * @private
         * @ignore
         */
C
campaign 已提交
967
        setHide: function () {
C
campaign 已提交
968
            var me = this;
C
campaign 已提交
969 970
            if (!me.lastBk) {
                me.lastBk = me.selection.getRange().createBookmark(true);
C
campaign 已提交
971 972 973 974 975 976 977 978
            }
            me.container.style.display = 'none'
        },
        /**
         * 隐藏编辑器
         * @name hide
         * @grammar editor.hide()
         */
C
campaign 已提交
979
        hide: function () {
C
campaign 已提交
980 981 982 983 984 985 986 987 988
            return this.setHide();
        },
        /**
         * 根据制定的路径,获取对应的语言资源
         * @name  getLang
         * @grammar editor.getLang(path)  =>  (JSON|String) 路径根据的是lang目录下的语言文件的路径结构
         * @example
         * editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除
         */
C
campaign 已提交
989
        getLang: function (path) {
C
campaign 已提交
990
            var lang = UE.I18N[this.options.lang];
C
campaign 已提交
991
            if (!lang) {
C
campaign 已提交
992 993
                throw Error("not import language file");
            }
C
campaign 已提交
994 995
            path = (path || "").split(".");
            for (var i = 0, ci; ci = path[i++];) {
C
campaign 已提交
996
                lang = lang[ci];
C
campaign 已提交
997
                if (!lang)break;
C
campaign 已提交
998 999
            }
            return lang;
C
campaign 已提交
1000 1001 1002
        },
        /**
         * 计算编辑器当前内容的长度
C
campaign 已提交
1003 1004
         * @name  getContentLength
         * @grammar editor.getContentLength(ingoneHtml,tagNames)  =>
C
campaign 已提交
1005
         * @example
C
campaign 已提交
1006
         * editor.getLang(true)
C
campaign 已提交
1007
         */
C
campaign 已提交
1008 1009
        getContentLength: function (ingoneHtml, tagNames) {
            var count = this.getContent(false,false,true).length;
C
campaign 已提交
1010 1011 1012 1013
            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 已提交
1014 1015 1016 1017
                    count += this.document.getElementsByTagName(ci).length;
                }
            }
            return count;
C
campaign 已提交
1018
        },
C
campaign 已提交
1019
        addInputRule: function (rule) {
C
campaign 已提交
1020 1021
            this.inputRules.push(rule);
        },
C
campaign 已提交
1022
        filterInputRule: function (root) {
C
campaign 已提交
1023 1024 1025 1026
            for (var i = 0, ci; ci = this.inputRules[i++];) {
                ci.call(this, root)
            }
        },
C
campaign 已提交
1027
        addOutputRule: function (rule) {
C
campaign 已提交
1028 1029
            this.outputRules.push(rule)
        },
C
campaign 已提交
1030
        filterOutputRule: function (root) {
C
campaign 已提交
1031 1032 1033
            for (var i = 0, ci; ci = this.outputRules[i++];) {
                ci.call(this, root)
            }
C
campaign 已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
        }
        /**
         * 得到dialog实例对象
         * @name getDialog
         * @grammar editor.getDialog(dialogName) => Object
         * @example
         * var dialog = editor.getDialog("insertimage");
         * dialog.open();   //打开dialog
         * dialog.close();  //关闭dialog
         */
    };
C
campaign 已提交
1045
    utils.inherits(Editor, EventBase);
C
campaign 已提交
1046
})();