1 /** 2 * list Utils 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add('editor/plugin/listUtils/index', function (S, Editor) { 6 var listNodeNames = {ol:1, ul:1}, 7 Node = S.Node, 8 DOM = S.DOM, 9 UA = S.UA, 10 list = { 11 /* 12 * Convert a DOM list tree into a data structure that is easier to 13 * manipulate. This operation should be non-intrusive in the sense that it 14 * does not change the DOM tree, with the exception that it may add some 15 * markers to the list item nodes when database is specified. 16 * 扁平化处理,深度遍历,利用 indent 和顺序来表示一棵树 17 */ 18 listToArray:function (listNode, database, baseArray, baseIndentLevel, grandparentNode) { 19 if (!listNodeNames[ listNode.nodeName() ]) { 20 return []; 21 } 22 if (!baseIndentLevel) 23 baseIndentLevel = 0; 24 if (!baseArray) { 25 baseArray = []; 26 } 27 // Iterate over all list items to and look for inner lists. 28 for (var i = 0, count = listNode[0].childNodes.length; 29 i < count; i++) { 30 var listItem = new Node(listNode[0].childNodes[i]); 31 32 // It may be a text node or some funny stuff. 33 if (listItem.nodeName() != 'li') { 34 continue; 35 } 36 var itemObj = { 'parent':listNode, 37 indent:baseIndentLevel, 38 element:listItem, contents:[] }; 39 if (!grandparentNode) { 40 itemObj.grandparent = listNode.parent(); 41 if (itemObj.grandparent && itemObj.grandparent.nodeName() == 'li') 42 itemObj.grandparent = itemObj.grandparent.parent(); 43 } 44 else { 45 itemObj.grandparent = grandparentNode; 46 } 47 if (database) { 48 listItem._4e_setMarker(database, 'listarray_index', baseArray.length, undefined); 49 } 50 baseArray.push(itemObj); 51 52 for (var j = 0, itemChildCount = listItem[0].childNodes.length, child; 53 j < itemChildCount; j++) { 54 child = new Node(listItem[0].childNodes[j]); 55 if (child[0].nodeType == DOM.ELEMENT_NODE && 56 listNodeNames[ child.nodeName() ]) { 57 // Note the recursion here, it pushes inner list items with 58 // +1 indentation in the correct order. 59 list.listToArray(child, database, baseArray, 60 baseIndentLevel + 1, itemObj.grandparent); 61 } else { 62 itemObj.contents.push(child); 63 } 64 } 65 } 66 return baseArray; 67 }, 68 69 // Convert our internal representation of a list back to a DOM forest. 70 //根据包含indent属性的元素数组来生成树 71 arrayToList:function (listArray, database, baseIndex, paragraphMode) { 72 if (!baseIndex) { 73 baseIndex = 0; 74 } 75 if (!listArray || listArray.length < baseIndex + 1) { 76 return null; 77 } 78 var doc = listArray[ baseIndex ].parent[0].ownerDocument, 79 retval = doc.createDocumentFragment(), 80 rootNode = null, 81 currentIndex = baseIndex, 82 indentLevel = Math.max(listArray[ baseIndex ].indent, 0), 83 currentListItem = null; 84 //,paragraphName = paragraphMode; 85 86 while (true) { 87 var item = listArray[ currentIndex ]; 88 if (item.indent == indentLevel) { 89 if (!rootNode 90 || 91 //用于替换标签,ul->ol ,ol->ul 92 listArray[ currentIndex ].parent.nodeName() != rootNode.nodeName()) { 93 rootNode = listArray[ currentIndex ].parent.clone(false); 94 retval.appendChild(rootNode[0]); 95 } 96 currentListItem = rootNode[0].appendChild(item.element.clone(false)[0]); 97 for (var i = 0; i < item.contents.length; i++) { 98 currentListItem.appendChild(item.contents[i].clone(true)[0]); 99 } 100 currentIndex++; 101 } else if (item.indent == Math.max(indentLevel, 0) + 1) { 102 //进入一个li里面,里面的嵌套li递归构造父亲ul/ol 103 var listData = list.arrayToList(listArray, null, 104 currentIndex, paragraphMode); 105 currentListItem.appendChild(listData.listNode); 106 currentIndex = listData.nextIndex; 107 } else if (item.indent == -1 && !baseIndex && 108 item.grandparent) { 109 110 if (listNodeNames[ item.grandparent.nodeName() ]) { 111 currentListItem = item.element.clone(false)[0]; 112 } else { 113 // Create completely new blocks here, attributes are dropped. 114 //为什么要把属性去掉???#3857 115 if (item.grandparent.nodeName() != 'td') { 116 currentListItem = doc.createElement(paragraphMode); 117 item.element._4e_copyAttributes(new Node(currentListItem)); 118 } 119 else 120 currentListItem = doc.createDocumentFragment(); 121 } 122 123 for (i = 0; i < item.contents.length; i++) { 124 var ic = item.contents[i].clone(true); 125 //如果是list中,应该只退出ul,保留margin-left 126 if (currentListItem.nodeType == DOM.DOCUMENT_FRAGMENT_NODE) { 127 item.element._4e_copyAttributes(new Node(ic)); 128 } 129 currentListItem.appendChild(ic[0]); 130 } 131 132 if (currentListItem.nodeType == DOM.DOCUMENT_FRAGMENT_NODE 133 && currentIndex != listArray.length - 1) { 134 if (currentListItem.lastChild 135 && currentListItem.lastChild.nodeType == DOM.ELEMENT_NODE 136 && currentListItem.lastChild.getAttribute('type') == '_moz') { 137 DOM._4e_remove(currentListItem.lastChild); 138 } 139 DOM._4e_appendBogus(currentListItem); 140 } 141 142 if (currentListItem.nodeType == DOM.ELEMENT_NODE && 143 DOM.nodeName(currentListItem) == paragraphMode && 144 currentListItem.firstChild) { 145 DOM._4e_trim(currentListItem); 146 var firstChild = currentListItem.firstChild; 147 if (firstChild.nodeType == DOM.ELEMENT_NODE && 148 DOM._4e_isBlockBoundary(firstChild)) { 149 var tmp = doc.createDocumentFragment(); 150 DOM._4e_moveChildren(currentListItem, tmp); 151 currentListItem = tmp; 152 } 153 } 154 155 var currentListItemName = DOM.nodeName(currentListItem); 156 if (!UA['ie'] && ( currentListItemName == 'div' || 157 currentListItemName == 'p' )) { 158 DOM._4e_appendBogus(currentListItem); 159 } 160 retval.appendChild(currentListItem); 161 rootNode = null; 162 currentIndex++; 163 } 164 else { 165 return null; 166 } 167 if (listArray.length <= currentIndex || 168 Math.max(listArray[ currentIndex ].indent, 0) < indentLevel) 169 break; 170 } 171 172 // Clear marker attributes for the new list tree made of cloned nodes, if any. 173 if (database) { 174 var currentNode = new Node(retval.firstChild); 175 while (currentNode && currentNode[0]) { 176 if (currentNode[0].nodeType == DOM.ELEMENT_NODE) { 177 currentNode._4e_clearMarkers(database, true); 178 } 179 currentNode = currentNode._4e_nextSourceNode(); 180 } 181 } 182 183 return { listNode:retval, nextIndex:currentIndex }; 184 } 185 }; 186 187 return list; 188 }, { 189 requires:['editor'] 190 });