1 /** 2 * Add removeFormat command for KISSY Editor. 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("editor/plugin/removeFormat/cmd", function (S, Editor) { 6 var KER = Editor.RANGE, 7 ElementPath = Editor.ElementPath, 8 DOM = S.DOM, 9 /** 10 * A comma separated list of elements to be removed 11 * when executing the "remove format" command. 12 * Note that only inline elements are allowed. 13 * @type String 14 * @default 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var' 15 * @example 16 */ 17 removeFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,' + 18 'q,samp,small,span,strike,strong,sub,sup,tt,u,var,s', 19 /** 20 * A comma separated list of elements attributes to be removed 21 * when executing the "remove format" command. 22 * @type String 23 * @default 'class,style,lang,width,height,align,hspace,valign' 24 * @example 25 */ 26 removeFormatAttributes = ('class,style,lang,width,height,' + 27 'align,hspace,valign').split(/,/), 28 tagsRegex = new RegExp('^(?:' + 29 removeFormatTags.replace(/,/g, '|') + 30 ')$', 'i'); 31 32 function removeAttrs(el, attrs) { 33 for (var i = 0; i < attrs.length; i++) { 34 el.removeAttr(attrs[i]); 35 } 36 } 37 38 return { 39 init:function (editor) { 40 if (!editor.hasCommand("removeFormat")) { 41 editor.addCommand("removeFormat", { 42 exec:function () { 43 editor.focus(); 44 tagsRegex.lastIndex = 0; 45 var ranges = editor.getSelection().getRanges(); 46 editor.execCommand("save"); 47 for (var i = 0, range; range = ranges[ i ]; i++) { 48 49 if (range.collapsed) { 50 continue; 51 } 52 53 range.enlarge(KER.ENLARGE_ELEMENT); 54 55 // Bookmark the range so we can re-select it after processing. 56 var bookmark = range.createBookmark(), 57 // The style will be applied within the bookmark boundaries. 58 startNode = bookmark.startNode, 59 endNode = bookmark.endNode; 60 61 // We need to check the selection boundaries (bookmark spans) to break 62 // the code in a way that we can properly remove partially selected nodes. 63 // For example, removing a <b> style from 64 // <b>This is [some text</b> to show <b>the] problem</b> 65 // ... where [ and ] represent the selection, must result: 66 // <b>This is </b>[some text to show the]<b> problem</b> 67 // The strategy is simple, we just break the partial nodes before the 68 // removal logic, having something that could be represented this way: 69 // <b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b> 70 71 var breakParent = function (node) { 72 // Let's start checking the start boundary. 73 var path = new ElementPath(node), 74 pathElements = path.elements; 75 76 for (var i = 1, pathElement; 77 pathElement = pathElements[ i ]; 78 i++) { 79 if (pathElement.equals(path.block) || 80 pathElement.equals(path.blockLimit)) { 81 break; 82 } 83 // If this element can be removed (even partially). 84 if (tagsRegex.test(pathElement.nodeName())) { 85 node._4e_breakParent(pathElement); 86 } 87 } 88 }; 89 90 // does not make bookmark within any format tag 91 // but keep bookmark node is at original text posititon 92 breakParent(startNode); 93 breakParent(endNode); 94 95 // Navigate through all nodes between the bookmarks. 96 var currentNode = startNode 97 // start from sibling , because obvious bookmark has no children 98 ._4e_nextSourceNode(true, DOM.ELEMENT_NODE, undefined, undefined); 99 100 while (currentNode) { 101 // If we have reached the end of the selection, stop looping. 102 if (currentNode.equals(endNode)) { 103 break; 104 } 105 106 // Cache the next node to be processed. Do it now, because 107 // currentNode may be removed. 108 var nextNode = currentNode. 109 _4e_nextSourceNode(false, DOM.ELEMENT_NODE, undefined, undefined); 110 111 // This node must not be a fake element. 112 if (!( currentNode.nodeName() == 'img' && 113 currentNode.attr('_ke_realelement') )) { 114 // Remove elements nodes that match with this style rules. 115 if (tagsRegex.test(currentNode.nodeName())) 116 currentNode._4e_remove(true); 117 else { 118 removeAttrs(currentNode, removeFormatAttributes); 119 } 120 } 121 currentNode = nextNode; 122 } 123 range.moveToBookmark(bookmark); 124 } 125 editor.getSelection().selectRanges(ranges); 126 editor.execCommand("save"); 127 } 128 }); 129 } 130 } 131 } 132 133 }, { 134 requires:['editor'] 135 });