第 5 步

返回富文本编辑器的基本原理与实践

    1 if (!YAHOO.realazy)
    2     YAHOO.realazy = {};
    3 
    4 if (!YAHOO.realazy.RTE)
    5     YAHOO.realazy.RTE = {};
    6 
    7 (function(){
    8     var $D = YAHOO.util.Dom,
    9         $E = YAHOO.util.Event;
   10 
   11     var ua = YAHOO.env.ua,
   12         isIE = ua.ie,
   13         isGecko = ua.gecko,
   14         isOpera = ua.opera,
   15         isWebkit = ua.webkit;
   16 
   17     /**
   18      * 替换 textarea, 实现 user-editable 的内容区域
   19      * @param {string | HTMLElement} elTextarea 需替换的 textarea 元素的 id 或者引用
   20      * @class
   21      */
   22     YAHOO.realazy.RTE = function(elTextarea){
   23         if ('string' == typeof elTextarea) elTextarea = $D.get(elTextarea);
   24         this.textarea = elTextarea;
   25         this.toolbarItems = {};
   26     }
   27 
   28     /**
   29      * 预填充 iframe 的内容
   30      *
   31      */
   32     YAHOO.realazy.RTE.htmlContent =  ['<!DOCTYPE HTML PUBLIC "-/','/W3C/','/DTD HTML 4.01/','/EN" "http:/','/www.w3.org/TR/html4/strict.dtd"><html><head><title>编辑页面</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body>{CONTENT}</body></html>'].join('');
   33 
   34     /** @scope YAHOO.realazy.RTE.prototype */
   35     YAHOO.realazy.RTE.prototype = {
   36         
   37         /**
   38          * 生成编辑器
   39          */
   40         render: function(){
   41             // step 1: 生成 iframe 并隐藏 textarea
   42             this._createIframeAndHideTextarea();
   43             // step 2: 开启 iframe 的 designMode
   44             this._turnOnDesignMode();
   45             // step 3: 建立 toolbar
   46             this._buildToolbar();
   47             // step 4: 绑定工具条事件
   48             this._bindToolbarEvents();
   49         },
   50         /**
   51          * 生成 iframe 并隐藏 textarea
   52          * @private
   53          */
   54         _createIframeAndHideTextarea: function(){
   55             var iframe = document.createElement('iframe');
   56             $D.addClass(iframe, 'rte-iframe');
   57             this.textarea.style.display = 'none';
   58             $D.insertBefore(iframe, this.textarea);
   59             this.iframe = iframe;
   60         },
   61         /**
   62          * 获取 iframe 的 contentWindow
   63          * @private
   64          */
   65         _getWin: function(){
   66             return this.iframe.contentWindow;
   67         },
   68 
   69         /**
   70          * 获取 iframe 的 document
   71          * @private
   72          */
   73         _getDoc: function(){
   74             return this._getWin().document;
   75         },
   76 
   77         /**
   78          * 开启 iframe 的 design mode
   79          * @private
   80          */
   81         _turnOnDesignMode: function(){
   82             try {
   83                 this._getDoc().open();
   84                 this._getDoc().write(YAHOO.realazy.RTE.htmlContent.replace(/{CONTENT}/, this.textarea.value));
   85                 this._getDoc().close();
   86                 this._getDoc().designMode = 'on';
   87             } catch(ex) {
   88                 setTimeout(arguments.callee, 0);
   89                 return;
   90             }
   91         },
   92 
   93         /**
   94          * 建立 editor 的 toolbar
   95          * @private
   96          */
   97         _buildToolbar: function(){
   98             var toolbar = document.createElement('div');
   99             $D.addClass(toolbar, 'rte-toolbar');
  100 
  101             var items = {
  102                 'fontname': {
  103                     'Arial': 'Arial',
  104                     '宋体': "SimSun, STSong, 'LiSong Pro'", 
  105                     '黑体': "SimHei, STHeiti, 'LiHei Pro'"
  106                 },
  107                 'fontsize': {
  108                     '最小': 1,
  109                     '较小': 2,
  110                     '': 3,
  111                     '': 4,
  112                     '': 5,
  113                     '较大': 6,
  114                     '最大': 7
  115                 },
  116                 'bold': '加粗',
  117                 'italic': '斜体',
  118                 'underline': '下划线',
  119                 'justifyleft': '居左',
  120                 'justifycenter': '居中',
  121                 'justifyright': '居右',
  122                 'createlink': '超链接',
  123                 'insertimage': '插图'
  124             }
  125             
  126             for (var k in items){
  127                 var span = document.createElement('span');
  128                 if (k == 'fontname' || k == 'fontsize'){
  129                     var select = document.createElement('select');
  130                     $D.addClass(select, k);
  131                     for (var kk in items[k]){
  132                         var option = new Option(kk, items[k][kk]);
  133                         if (!isGecko)
  134                             select.add(option);
  135                         else
  136                             select.appendChild(option);
  137                     }
  138                     span.appendChild(select);
  139                     this.toolbarItems[k] = select;
  140                 } else {
  141                     $D.addClass(span, k);
  142                     span.innerHTML = items[k];
  143                     this.toolbarItems[k] = span;
  144                 }
  145                 toolbar.appendChild(span);
  146             }
  147             
  148             $D.insertBefore(toolbar, this.iframe);
  149             this.toolbar = toolbar;
  150         },
  151         /**
  152          * execCommand
  153          * @param {string} sCmd command name
  154          * @param {string} sVal command Value
  155          * @private
  156          */
  157         _execCommand: function(sCmd, sVal){
  158                 this._getWin().focus();
  159                   this._getDoc().execCommand(sCmd, false, sVal);
  160         },
  161 
  162         /**
  163          * 绑定 toolbar 的 events
  164          * @private
  165          */
  166         _bindToolbarEvents: function(){
  167             var _this = this,
  168                 items = this.toolbarItems,
  169                 trim = YAHOO.lang.trim;
  170             
  171             $E.on([items['fontsize'], items['fontname']], 'change', function(e){
  172                 var cmd = this.className,
  173                     val = this.options[this.selectedIndex].value;
  174                 _this._execCommand(cmd, val);
  175             });
  176             
  177             $E.on(this.toolbar, 'click', function(e){
  178                 var t = $E.getTarget(e),
  179                     cmd = t.className,
  180                     nn = t.nodeName.toLowerCase(),
  181                     val = null,
  182                     isNeedVal = false;
  183                 if (nn != 'span' && !cmd) return;
  184                 switch (cmd){
  185                 case 'createlink':
  186                 case 'insertimage':
  187                     isNeedVal = true;
  188                     val = prompt('请输入网址:', 'http://');
  189                     break;
  190                 case 'fontname':
  191                 case 'fontsize':
  192                     return;
  193                 default:
  194                     break;
  195                 }
  196                 
  197                 if (isNeedVal && (!val || (trim(val) == 'http://'))) return;
  198                 this._execCommand(cmd, val);
  199                 
  200             }, this, true);
  201         }
  202     }
  203 })();