【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏

【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏

索引目录:http://www.cnblogs.com/henryli/p/3439642.html

 

  浏览器提供了document.execommand的一系列命令来实现文本、格式、插入等操作,当然,浏览器厂商支持不一致、或者跟预想结果不一样。导致了前端coder需要耗费更大的精力去实现一个兼容、统一的富文本编辑。

  使用较多的浏览器api:

  • execCommand  ,设置格式样式等命令
  • queryCommandState,查询命令返回结果。ps(根据这个,可以实现当前选区格式的实时反馈)
  • queryCommandEnabled,返回布尔值,查询execCommand 命令是否可用,也就是是否可以成功执行当前命令
  • queryCommandSupported 返回表明当前命令是否在当前区域上支持的 Boolean 值。

  execCommand 命令总共有这些:

1 var CommandList = ["2D-Position", "absolutePosition", "backColor", "blockDirLTR", "blockDirRTL", "bold", "browseMode", "clearAuthenticationCache", "contentReadOnly", "copy", "createBookmark", "createLink", "cut", "decreaseFontSize", "delete", "dirLTR", "dirRTL", "editMode", "fontName", "fontSize", "foreColor", "formatBlock", "enableInlineTableEditing", "enableObjectResizing", "forwardDelete", "heading", "increaseFontSize", "indent", "inlineDirLTR", "inlineDirRTL", "insertButton", "insertFieldset", "insertIFrame", "insertInputButton", "insertInputCheckbox", "insertInputFileUpload", "insertInputHidden", "insertInputImage", "insertInputPassword", "insertInputRadio", "insertInputReset", "insertInputSubmit", "insertInputText", "insertMarquee", "insertBrOnReturn", "insertHorizontalRule", "insertImage", "insertHTML", "insertLineBreak", "insertOrderedList", "insertUnorderedList", "insertParagraph", "insertSelectDropdown", "insertSelectListbox", "insertTextArea", "insertText", "italic", "justifyCenter", "justifyLeft", "justifyRight", "justifyFull", "justifyNone", "liveResize", "multipleSelection", "open", "overWrite", "outdent", "paste", "playImage", "print", "redo", "removeFormat", "refresh", "removeParaFormat", "selectAll", "saveAs", "sizeToControl", "sizeToControlHeight", "sizeToControlWidth", "stop", "stopImage", "strikeThrough", "subscript", "superscript", "unBookmark", "underline", "undo", "unlink", "useCSS", "hiliteColor", "unselect", "styleWithCSS"]
View Code

  其中有上一篇用到的insertBrOnReturn和insertHTML。有了命令列表我们可以做一个测试页,测试命令是否受浏览器支持。当然其中还是一部分是暂时还没有任何浏览器支持的,rich editor也只用到其中的一部分命令。

  命令styleWithCSS,设置为true,如果浏览器支持,则改变格式使用表情的行内元素设置,反之使用b、i、u、font等标签设置,对于富文本来说,自然是使用标签来设置,行内样式权重过大,也不“语义”。

  设置文本、段落格式、样式需要用到:bold、italic、underline、strikethrough、superscript、subscript、removeformat、forecolor、backcolor、fontfamily、fontsize、justifyleft、justifycenter、justifyright、indent、outdent

  链接相关:createlink、unlink

  插入设置内容:insertorderedlist、insertunorderedlist、insertImage、insertHTML、insertText

  常用操作: selectAll、redo、undo、paste、print、copy

  其中有些命令与我们预期的不一样:

  1. fontsize,预期可以设置px、em文本大小,但浏览器却统一口径,只给了<font size="[0-7]"></font>,font未来要被废弃,而且无法设置自定义大小,需求兼容修正
  2. undo、redo,如果是使用iframe作为编辑器,iframe的document的undo、redo是“完整的”,如果是div,那么将与页面的操作重叠,需要定制一套undo、redo功能
  3. 待续

  

  当鼠标选择了编辑器以外的内容,这时候选择已经丢失了,使用插入图片、文本格式,如何保证操作的是编辑器的最后选择的选区呢?

  ie总是考虑的更加完善,给开发者提供了很好的api。提供了bookmark的功能;同时,ie提供了onbeforedeactivate和onactivate,来监听blur之前、focus之前的操作,在这个时间段,来获取书签和设置选区的书签最好不过了

  支持标准selection、range的浏览器就稍微麻烦了,需要我们把光标更改的时候,保存range到变量中,在需要的时候,设置回来。chrome跟ie 本身就支持document.onselectionchange,首选由ie支持的,绑定此方法,就可以监听选区改变了,

  

    //ie绑定获取书签,设置书签方法
    if ('onbeforedeactivate' in ifrWinOrEditor && document.selection) {
        var ieRangeBookMark;
        ifrWinOrEditor.attachEvent('onbeforedeactivate', function() {
            doc.selection.getBookmark();
        });
        ifrWinOrEditor.attachEvent('onactivate', function() {
            doc.selection.moveToBookmark(ieRangeBookMark);
        });
    } else {
        //反之当选区更改的时候保存range
        self._console('bind selectionchange');
        if ('onselectionchange' in doc) {
            Utils.bind(doc, 'selectionchange', function() {
                self.saveRange();
            });
        } else {
            Utils.bind(doc, 'mouseup', function() {
                self.saveRange();
            });
            Utils.bind(doc, 'keyup', function(e) {
                self.saveRange();
            });
        }
    }

 

 1 saveLastRange: function() {
 2     this.getRange() && (this.lastRange = this.getRange().range);
 3 },
 4 setLastRange: function() {
 5     if (this.lastRange && this.getRange()) {
 6         var selection = this.getRange().selection;
 7         if (selection.removeAllRanges) {
 8             selection.removeAllRanges();
 9             selection.addRange(this.lastRange);
10         }
11     }
12 }

  最终还需要判断当前的selection是否在编辑器中,因为当div作为编辑器,此时的选区可能在页面其他地方。ie支持Element.contains来判断是否包含某元素,而w3c使用compareDocumentPosition来判断,判断的代码直接放在getRange中,这样非编辑器中的选区,返回的是null。代码如下:

//如果是div编辑器,要判断range是否在编辑器中
if (this.editor != node) {
     var isChild;
     if (this.editor.contains) {
        isChild = this.editor.contains(node);
     } else {
        isChild = this.editor.compareDocumentPosition(node) == 20;
     }
     if (!isChild) {
        range = text = selection = null;
     }
}

 

 demo已完成;点击下载

预览图:

 

update @ 2013-11-25 15:37:11

BY henry

mail : liyaohui.henry@gmail.com

posted @ 2013-11-25 13:13  henry_li  阅读(1632)  评论(0编辑  收藏  举报