1 | /*
|
---|
2 | * file: ItemizeAction.js
|
---|
3 | *
|
---|
4 | * @BEGINLICENSE
|
---|
5 | * Copyright 2010 Brook Novak (email : [email protected])
|
---|
6 | * This program is free software; you can redistribute it and/or modify
|
---|
7 | * it under the terms of the GNU General Public License as published by
|
---|
8 | * the Free Software Foundation; either version 2 of the License, or
|
---|
9 | * (at your option) any later version.
|
---|
10 | * This program is distributed in the hope that it will be useful,
|
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
13 | * GNU General Public License for more details.
|
---|
14 | * You should have received a copy of the GNU General Public License
|
---|
15 | * along with this program; if not, write to the Free Software
|
---|
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
17 | * @ENDLICENSE
|
---|
18 | */
|
---|
19 |
|
---|
20 | // @DEPENDS: UndoMan
|
---|
21 | bootstrap.provides("actions.ItemizeAction");
|
---|
22 |
|
---|
23 | (function() {
|
---|
24 |
|
---|
25 | /*
|
---|
26 | * Lookup map containing element names which when itemized should be converted to a list item rather than being
|
---|
27 | * a descendant of the list items.
|
---|
28 | */
|
---|
29 | var convertContainers = $createLookupMap("p, div");
|
---|
30 |
|
---|
31 | _registerAction("Itemize", {
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * An undoable itemize action. Creates/converts/destroys a list of items in a given range
|
---|
35 | *
|
---|
36 | * @author Brook Novak
|
---|
37 | *
|
---|
38 | *
|
---|
39 | * @param {Boolean} bullets True to itemize as bullet list, false to itemize as numbered list.
|
---|
40 | *
|
---|
41 | * @param {Node} startNode (Optional) The starting dom node of the range to align.
|
---|
42 | * If not provided then the current selection will be used.
|
---|
43 | * If provieded must also provide endNode
|
---|
44 | *
|
---|
45 | * @param {Node} endNode (Optional) The ending dom node of the range to align. Can be the same as start node
|
---|
46 | * If not provided then the current selection will be used.
|
---|
47 | *
|
---|
48 | */
|
---|
49 | exec : function(bullets, startNode, endNode) {
|
---|
50 |
|
---|
51 | // Auto-set range if not provided.
|
---|
52 | if (!startNode) {
|
---|
53 |
|
---|
54 | if (!this.selBefore)
|
---|
55 | return; // Nothing to select
|
---|
56 |
|
---|
57 | if (this.selBefore.endNode) {
|
---|
58 | startNode = this.selBeforeOrdered.startNode;
|
---|
59 | endNode = this.selBeforeOrdered.endNode;
|
---|
60 | } else
|
---|
61 | startNode = endNode = this.selBefore.startNode;
|
---|
62 |
|
---|
63 | }
|
---|
64 |
|
---|
65 | debug.assert(endNode, "Supplied start node but not the end node");
|
---|
66 |
|
---|
67 | // Perfom execute (recursive operation)
|
---|
68 | (function exec(start, end, destroy, normalizedRange) {
|
---|
69 |
|
---|
70 | // Get master container
|
---|
71 | var masterContainer = _findAncestor(
|
---|
72 | _getCommonAncestor(start, end, true),
|
---|
73 | docBody,
|
---|
74 | _isBlockLevel,
|
---|
75 | true
|
---|
76 | ) || docBody, destroyListItems, itemizeContainers;
|
---|
77 |
|
---|
78 | // Deepen start/end range
|
---|
79 | var deepStart = start, deepEnd = end;
|
---|
80 | while (deepStart.firstChild) {
|
---|
81 | deepStart = deepStart.firstChild;
|
---|
82 | }
|
---|
83 | while (deepEnd.lastChild) {
|
---|
84 | deepEnd = deepEnd.lastChild;
|
---|
85 | }
|
---|
86 |
|
---|
87 | // Handle special case 1: range within tables
|
---|
88 | if (_isTableElement(masterContainer) &&
|
---|
89 | _nodeName(masterContainer) != "td" &&
|
---|
90 | _nodeName(masterContainer) != "th") {
|
---|
91 |
|
---|
92 | // Get all the table's cells within the range
|
---|
93 | var tabCells = [];
|
---|
94 | _visitAllNodes(masterContainer, masterContainer, true, function(domNode) {
|
---|
95 | if (domNode.nodeType == Node.ELEMENT_NODE &&
|
---|
96 | (_nodeName(domNode) == "td" || _nodeName(domNode) == "th")) {
|
---|
97 | tabCells.push(domNode);
|
---|
98 | return (domNode != deepEnd && !_isAncestor(domNode, deepEnd));
|
---|
99 | }
|
---|
100 | return domNode != deepEnd;
|
---|
101 | });
|
---|
102 |
|
---|
103 | // Check if all cells contains nothing but list items and normalize their contents
|
---|
104 | var areAllListEles = true, normalizedRanges = [];
|
---|
105 | for (var i in tabCells) {
|
---|
106 | var res = areAllListElements(tabCells[i], tabCells[i]);
|
---|
107 | if (res) {
|
---|
108 | areAllListEles &= res.allListEles;
|
---|
109 | normalizedRanges.push(res.nrange);
|
---|
110 | } else normalizedRanges.push(0);
|
---|
111 | }
|
---|
112 |
|
---|
113 | // Recurse on table cell
|
---|
114 | for (var i in tabCells) {
|
---|
115 | if (normalizedRanges[i])
|
---|
116 | exec(tabCells[i], tabCells[i], areAllListEles, normalizedRanges[i]);
|
---|
117 | }
|
---|
118 |
|
---|
119 | return;
|
---|
120 | }
|
---|
121 |
|
---|
122 | // If master container is a list container itself, adjust master container to its parent
|
---|
123 | if (_nodeName(masterContainer) == "ul" || _nodeName(masterContainer) == "ol")
|
---|
124 | masterContainer = masterContainer.parentNode;
|
---|
125 |
|
---|
126 | // Handle special case 2: range within a list item
|
---|
127 | var ca = masterContainer;
|
---|
128 | for (var level = 0; level < 2 && ca; level++) {
|
---|
129 | if (_nodeName(ca) == "li") {
|
---|
130 |
|
---|
131 | // Determine if need to destroy list item or convert it to a different type
|
---|
132 | if ((normalizedRange && destroy) ||
|
---|
133 | (!normalizedRange &&
|
---|
134 | ((bullets && _nodeName(ca.parentNode) == "ul") ||
|
---|
135 | (!bullets && _nodeName(ca.parentNode) == "ol")))) {
|
---|
136 | destroyListItems = [ca]; // the list item is the target type
|
---|
137 | } else {
|
---|
138 | itemizeContainers = [ca];
|
---|
139 | masterContainer = ca.parentNode;
|
---|
140 | }
|
---|
141 | break;
|
---|
142 |
|
---|
143 | }
|
---|
144 | ca = _findAncestor(ca.parentNode, docBody, _isBlockLevel, true);
|
---|
145 | }
|
---|
146 |
|
---|
147 | // Check if all containers in range are list-items/list-containers
|
---|
148 | if (!normalizedRange && !destroyListItems && !itemizeContainers) {
|
---|
149 | var res = areAllListElements(start, end);
|
---|
150 |
|
---|
151 | if (res) {
|
---|
152 |
|
---|
153 | normalizedRange = res.nrange;
|
---|
154 |
|
---|
155 | // If the range contains all list elements then destroy them
|
---|
156 | if (res.allListEles)
|
---|
157 | destroyListItems = normalizedRange;
|
---|
158 | else
|
---|
159 | itemizeContainers = normalizedRange;
|
---|
160 |
|
---|
161 | } else
|
---|
162 | return;
|
---|
163 |
|
---|
164 | } else if (normalizedRange) {
|
---|
165 | // If recursing on a table cell then the destroy/create operation will be predetermined
|
---|
166 | if (destroy)
|
---|
167 | destroyListItems = normalizedRange;
|
---|
168 | else
|
---|
169 | itemizeContainers = normalizedRange;
|
---|
170 | }
|
---|
171 |
|
---|
172 | if (destroyListItems) {
|
---|
173 |
|
---|
174 | // Tear down all list-items / list-containers.
|
---|
175 | for (var i in destroyListItems) {
|
---|
176 |
|
---|
177 | var cont = destroyListItems[i];
|
---|
178 | var contName = _nodeName(cont);
|
---|
179 |
|
---|
180 | if (contName == "li") {
|
---|
181 | convertLI(cont, true);
|
---|
182 |
|
---|
183 | } else if (contName == "ul" || contName == "ol") {
|
---|
184 |
|
---|
185 | // Determine range of list items within list container
|
---|
186 | var li = _isAncestor(cont, start) ? _findAncestor(start, cont) : cont.firstChild,
|
---|
187 | endLI = _isAncestor(cont, end) ? _findAncestor(end, cont) : cont.lastChild;
|
---|
188 |
|
---|
189 | while (li) {
|
---|
190 | var removeLI = li;
|
---|
191 | li = li == endLI ? null : li.nextSibling;
|
---|
192 | if (_nodeName(removeLI) == "li") // ensure not white space
|
---|
193 | convertLI(removeLI, true);
|
---|
194 | } // End loop: destroying range of list items in list container
|
---|
195 |
|
---|
196 | }
|
---|
197 |
|
---|
198 | } // End loop: destroying list items
|
---|
199 |
|
---|
200 | } else { // Creation of list items
|
---|
201 |
|
---|
202 | debug.assert(itemizeContainers ? true : false);
|
---|
203 |
|
---|
204 | // Create the new list container
|
---|
205 | var listContainer;
|
---|
206 |
|
---|
207 | // Itemize all containers in range
|
---|
208 | for (var i in itemizeContainers) {
|
---|
209 |
|
---|
210 | var cont = itemizeContainers[i];
|
---|
211 | var cRoot = cont == masterContainer ? cont : _findAncestor(cont, masterContainer),
|
---|
212 | contName = _nodeName(cont);
|
---|
213 |
|
---|
214 | if (contName == "li") {
|
---|
215 |
|
---|
216 | if (i == '0') {
|
---|
217 | listContainer = convertLI(cont, false);
|
---|
218 | } else {
|
---|
219 |
|
---|
220 | var liParent = cont.parentNode;
|
---|
221 | _execOp(_Operation.REMOVE_NODE, cont);
|
---|
222 | _execOp(_Operation.INSERT_NODE, cont, listContainer);
|
---|
223 |
|
---|
224 | // If the list items container is left without any other list items, remove it
|
---|
225 | var child = liParent.firstChild;
|
---|
226 | while (child && _nodeName(child) != "li") {
|
---|
227 | child = child.nextSibling;
|
---|
228 | }
|
---|
229 |
|
---|
230 | if (!child)
|
---|
231 | _execOp(_Operation.REMOVE_NODE, liParent);
|
---|
232 | }
|
---|
233 |
|
---|
234 | } else {
|
---|
235 |
|
---|
236 | if (i == '0') {
|
---|
237 |
|
---|
238 | listContainer = $createElement(bullets ? "ul" : "ol");
|
---|
239 |
|
---|
240 | // Determine where to insert the list container
|
---|
241 | if (contName == "ul" || contName == "ol") {
|
---|
242 |
|
---|
243 | var shouldInsertBefore = false;
|
---|
244 |
|
---|
245 | var firstLI = cont.firstChild;
|
---|
246 | while (firstLI && _nodeName(firstLI) != "li") {
|
---|
247 | shouldInsertBefore |= (firstLI == start); // possible start node is white space
|
---|
248 | firstLI = firstLI.nextSibling;
|
---|
249 | }
|
---|
250 |
|
---|
251 | if (firstLI)
|
---|
252 | shouldInsertBefore |= _isAncestor(firstLI, start);
|
---|
253 |
|
---|
254 | // Insert the list container before this list container if
|
---|
255 | // the range starts at the first list item.
|
---|
256 | _execOp(_Operation.INSERT_NODE, listContainer, cRoot.parentNode, _indexInParent(cRoot) + (shouldInsertBefore ? 0 : 1));
|
---|
257 |
|
---|
258 |
|
---|
259 | } else
|
---|
260 | _execOp(_Operation.INSERT_NODE, listContainer, cRoot.parentNode, _indexInParent(cRoot) + 1);
|
---|
261 |
|
---|
262 | }
|
---|
263 |
|
---|
264 | if (contName == "ul" || contName == "ol") { // List container?
|
---|
265 |
|
---|
266 | // Migrate list items in the container within the start/end range
|
---|
267 | var lcChild = _isAncestor(cont, start) ? _findAncestor(start, cont) : cont.firstChild, lcEndChild = _isAncestor(cont, end) ? _findAncestor(end, cont) : cont.lastChild;
|
---|
268 |
|
---|
269 | while (lcChild) {
|
---|
270 |
|
---|
271 | var migrateLI = _nodeName(lcChild) == "li" ? lcChild : null;
|
---|
272 | lcChild = lcChild == lcEndChild ? null : lcChild.nextSibling;
|
---|
273 |
|
---|
274 | // NB: Keeping white space... since undo history might rely on them
|
---|
275 | if (migrateLI) {
|
---|
276 |
|
---|
277 | // Migrate the list item into the new list item container
|
---|
278 | _execOp(_Operation.REMOVE_NODE, migrateLI);
|
---|
279 | _execOp(_Operation.INSERT_NODE, migrateLI, listContainer);
|
---|
280 |
|
---|
281 | // If the list-container is encapsulated by inline elements before the master container,
|
---|
282 | // then the migrated list items children must also be encapsulated.
|
---|
283 | // TODO: PHASE THIS OUT - SUPPORTS INVLAID HTML
|
---|
284 | if (cRoot != cont) {
|
---|
285 | var liChild = migrateLI.firstChild;
|
---|
286 | while (liChild) { // For all list items immediate children
|
---|
287 | if (liChild.nodeType != Node.ELEMENT_NODE && liChild.nodeType != Node.TEXT_NODE) continue;
|
---|
288 |
|
---|
289 | // Create a cloned sub-tree of the list containers inline parents
|
---|
290 | var inode = cont.parentNode, iSubTree = [];
|
---|
291 | while (inode) {
|
---|
292 | iSubTree.push(inode.cloneNode(false));
|
---|
293 | inode = inode == cRoot ? null : inode.parentNode;
|
---|
294 | }
|
---|
295 |
|
---|
296 | // Connect up unary inline tree
|
---|
297 | for (var k = iSubTree.length - 1; k > 0; k--) {
|
---|
298 | iSubTree[k].appendChild(iSubTree[k - 1]);
|
---|
299 | }
|
---|
300 |
|
---|
301 | // Insert the cloned inline sub tree in the migrated list item
|
---|
302 | // such that it encapsulated this list item child
|
---|
303 | _execOp(_Operation.INSERT_NODE, iSubTree[iSubTree.length - 1], migrateLI, _indexInParent(liChild));
|
---|
304 | _execOp(_Operation.REMOVE_NODE, liChild);
|
---|
305 | _execOp(_Operation.INSERT_NODE, liChild, iSubTree[0]);
|
---|
306 |
|
---|
307 | liChild = iSubTree[iSubTree.length - 1].nextSibling;
|
---|
308 | } // End loop: encapsulating list item's contents with inline elements
|
---|
309 | }
|
---|
310 |
|
---|
311 | }
|
---|
312 | } // End loop: migrating list items from an existing list container to the new list container
|
---|
313 | // Check if the container should be removed from the document.. if
|
---|
314 | // it no longer contains any list items
|
---|
315 | var shouldRemoveCont = true;
|
---|
316 | lcChild = cont.firstChild;
|
---|
317 | while (lcChild) {
|
---|
318 | if (_nodeName(lcChild) == "li") {
|
---|
319 | shouldRemoveCont = false;
|
---|
320 | break;
|
---|
321 | }
|
---|
322 | lcChild = lcChild.nextSibling;
|
---|
323 | }
|
---|
324 |
|
---|
325 | if (shouldRemoveCont)
|
---|
326 | _execOp(_Operation.REMOVE_NODE, cRoot); // Remove by the root
|
---|
327 |
|
---|
328 | } else {
|
---|
329 |
|
---|
330 | // Create/add a new list item
|
---|
331 | var listItem = $createElement("li");
|
---|
332 | _execOp(_Operation.INSERT_NODE, listItem, listContainer);
|
---|
333 |
|
---|
334 | // Migrate contents
|
---|
335 | _execOp(_Operation.REMOVE_NODE, cRoot);
|
---|
336 | _execOp(_Operation.INSERT_NODE, cRoot, listItem);
|
---|
337 |
|
---|
338 | // Should this container element be converted into a list item? i.e.
|
---|
339 | // removed from within the list item it was just added to?
|
---|
340 | if (convertContainers[contName]) {
|
---|
341 |
|
---|
342 | var parent = cont.parentNode; // Might not be the list container
|
---|
343 |
|
---|
344 | // Remove container from the document
|
---|
345 | _execOp(_Operation.REMOVE_NODE, cont);
|
---|
346 |
|
---|
347 | // Migrate children into the containers old parent
|
---|
348 | while (cont.firstChild) {
|
---|
349 | var miNode = cont.firstChild;
|
---|
350 | _execOp(_Operation.REMOVE_NODE, miNode);
|
---|
351 | _execOp(_Operation.INSERT_NODE, miNode, parent);
|
---|
352 | }
|
---|
353 |
|
---|
354 | }
|
---|
355 |
|
---|
356 | }
|
---|
357 |
|
---|
358 | }
|
---|
359 |
|
---|
360 | } // End loop: itemizing containes in range
|
---|
361 |
|
---|
362 | }
|
---|
363 |
|
---|
364 | /**
|
---|
365 | * Converts a list item, either migrates its contents up one level or changes the list item type from
|
---|
366 | * numbers to bullets or vice verse.
|
---|
367 | *
|
---|
368 | * @param {Node} liEle A list item ("li") element.
|
---|
369 | * @param {Boolean} destroy True to migrate contents up one level, false to change type.
|
---|
370 | *
|
---|
371 | * @return {Node} If destroy is false, it will return the new list container created for changing the list item type.
|
---|
372 | */
|
---|
373 | function convertLI(liEle, destroy) {
|
---|
374 |
|
---|
375 | var sib = liEle.previousSibling,
|
---|
376 | doesHavePreceedingLI = false,
|
---|
377 | doesHaveProceedingLI = false,
|
---|
378 | lcEle = liEle.parentNode,
|
---|
379 | didSplit = false,
|
---|
380 | newLCont = null;
|
---|
381 |
|
---|
382 | // Determine if the list item is preceeded with other list items
|
---|
383 | while(!doesHavePreceedingLI && sib) {
|
---|
384 | doesHavePreceedingLI |= _nodeName(sib) == "li";
|
---|
385 | sib = sib.previousSibling;
|
---|
386 | }
|
---|
387 |
|
---|
388 | // Determine if the list item is proceeded with other list items
|
---|
389 | sib = liEle.nextSibling
|
---|
390 | while(!doesHaveProceedingLI && sib) {
|
---|
391 | doesHaveProceedingLI |= _nodeName(sib) == "li";
|
---|
392 | sib = sib.nextSibling;
|
---|
393 | }
|
---|
394 |
|
---|
395 | if (doesHavePreceedingLI) {
|
---|
396 | lcEle = splitLIContainer(lcEle, liEle, !destroy, true);
|
---|
397 | didSplit = true;
|
---|
398 | }
|
---|
399 |
|
---|
400 | if (destroy) {
|
---|
401 |
|
---|
402 | // If the list item's contents are not going to be migrated within a lower level list item,
|
---|
403 | // then the range needs to be normalized such that inline groups are place in paragraphs.
|
---|
404 | if (_nodeName(lcEle.parentNode) != "li")
|
---|
405 | _getNormalizedContainerRange(liEle, liEle);
|
---|
406 |
|
---|
407 | // Migrate the list item's contents before its list container
|
---|
408 | while (liEle.firstChild) {
|
---|
409 | var liCh = liEle.firstChild;
|
---|
410 | _execOp(_Operation.REMOVE_NODE, liCh);
|
---|
411 | _execOp(_Operation.INSERT_NODE, liCh, lcEle.parentNode, _indexInParent(lcEle));
|
---|
412 | }
|
---|
413 |
|
---|
414 | // Remove the list item from its container
|
---|
415 | _execOp(_Operation.REMOVE_NODE, liEle);
|
---|
416 |
|
---|
417 | } else { // change type
|
---|
418 |
|
---|
419 | if (didSplit) {
|
---|
420 |
|
---|
421 | if (doesHaveProceedingLI) {
|
---|
422 | // Get next list item element in split container
|
---|
423 | var nextLI = liEle.nextSibling;
|
---|
424 | while (_nodeName(nextLI) != "li") {
|
---|
425 | nextLI = nextLI.nextSibling;
|
---|
426 | }
|
---|
427 |
|
---|
428 | // If previously split the container and migrated some remaining li's .. then split
|
---|
429 | // again on the new container - into a container of the original type.
|
---|
430 | splitLIContainer(lcEle, nextLI, true, true);
|
---|
431 | }
|
---|
432 |
|
---|
433 | newLCont = lcEle;
|
---|
434 |
|
---|
435 | } else {
|
---|
436 |
|
---|
437 | // Insert a new container before and migrate the list item
|
---|
438 | newLCont = splitLIContainer(lcEle, liEle, true, false);
|
---|
439 |
|
---|
440 | }
|
---|
441 |
|
---|
442 | }
|
---|
443 |
|
---|
444 | // Check if the list item container has any list items left
|
---|
445 | sib = lcEle.firstChild;
|
---|
446 | while (sib && _nodeName(sib) != "li") {
|
---|
447 | sib = sib.nextSibling;
|
---|
448 | }
|
---|
449 |
|
---|
450 | // If the li element's container is left without a li, remove it from the document...
|
---|
451 | if (!sib) {
|
---|
452 |
|
---|
453 | // Remove all ancestors of the container which do not have multiple children to keep html tidy
|
---|
454 | var remEle = lcEle;
|
---|
455 | while (remEle.parentNode.childNodes.length == 1 &&
|
---|
456 | !de.doc.isEditSection(remEle.parentNode) &&
|
---|
457 | remEle.parentNode != docBody) {
|
---|
458 | remEle = remEle.parentNode;
|
---|
459 | }
|
---|
460 |
|
---|
461 | _execOp(_Operation.REMOVE_NODE, remEle);
|
---|
462 |
|
---|
463 | }
|
---|
464 |
|
---|
465 | return newLCont;
|
---|
466 |
|
---|
467 | } // End inner function: convertLI
|
---|
468 |
|
---|
469 | /**
|
---|
470 | * Splits a list item container in two. Records operation.
|
---|
471 | * @param {Node} lcEle A ul or ol element
|
---|
472 | * @param {Node} liEle An li element to split from within lcEle
|
---|
473 | * @param {Boolean} flipType True to have the split container to have a different type than lcEle
|
---|
474 | * @param {Boolean} downward True to split container from liEle downward - so new container is after lcEle.
|
---|
475 | * False to split container from liEle upward - so new container is before lcEle.
|
---|
476 | *
|
---|
477 | * @return {Node} The split container.
|
---|
478 | */
|
---|
479 | function splitLIContainer(lcEle, liEle, flipType, downward) {
|
---|
480 |
|
---|
481 | // Split container in two
|
---|
482 | var splitC = flipType ? $createElement(_nodeName(lcEle) == "ol" ? "ul" : "ol") : lcEle.cloneNode(false);
|
---|
483 |
|
---|
484 | // Migrate this and all following li's into the split container
|
---|
485 | if (downward) {
|
---|
486 |
|
---|
487 | while (liEle) {
|
---|
488 | var migrateNode = liEle;
|
---|
489 | liEle = liEle.nextSibling;
|
---|
490 | _execOp(_Operation.REMOVE_NODE, migrateNode);
|
---|
491 | _execOp(_Operation.INSERT_NODE, migrateNode, splitC);
|
---|
492 | }
|
---|
493 |
|
---|
494 | _execOp(_Operation.INSERT_NODE, splitC, lcEle.parentNode, _indexInParent(lcEle) + 1);
|
---|
495 |
|
---|
496 | } else { // Upward
|
---|
497 | while (liEle) {
|
---|
498 | var migrateNode = liEle;
|
---|
499 | liEle = liEle.previousSibling;
|
---|
500 | _execOp(_Operation.REMOVE_NODE, migrateNode);
|
---|
501 | _execOp(_Operation.INSERT_NODE, migrateNode, splitC, 0);
|
---|
502 | }
|
---|
503 |
|
---|
504 | _execOp(_Operation.INSERT_NODE, splitC, lcEle.parentNode, _indexInParent(lcEle));
|
---|
505 | }
|
---|
506 |
|
---|
507 | return splitC;
|
---|
508 |
|
---|
509 | } // End inner function splitLIContainer
|
---|
510 |
|
---|
511 |
|
---|
512 | /**
|
---|
513 | * Normalizes the given range and checks if all containers are list-items/list-containers of a certain type
|
---|
514 | * (ol or ul)
|
---|
515 | *
|
---|
516 | * @param {Node} start The start of the range to normalize. This range will be deepend
|
---|
517 | * @param {Node} end The end of the range to normalize. This range will be deepend
|
---|
518 | * @return {Object} Either Null if the range does not have containers. Or an object with
|
---|
519 | * a memeber called "allListEles" which is true iff all
|
---|
520 | * containers in the normalized range are list-items/list-containers - and
|
---|
521 | * another memeber "nrange" which contains the normalized range.
|
---|
522 | */
|
---|
523 | function areAllListElements(start, end) {
|
---|
524 |
|
---|
525 | // Normalize the range
|
---|
526 | var normalizedRange = _getNormalizedContainerRange(start, end);
|
---|
527 |
|
---|
528 | // Anything to itemize?
|
---|
529 | if (normalizedRange.length == 0)
|
---|
530 | return null;
|
---|
531 |
|
---|
532 | // Check if range is all list elements
|
---|
533 | var isAllListEles = true;
|
---|
534 | for (var i in normalizedRange) {
|
---|
535 | var cname = _nodeName(normalizedRange[i]);
|
---|
536 |
|
---|
537 | // Get list item container name
|
---|
538 | if (cname == "li")
|
---|
539 | cname = _nodeName(normalizedRange[i].parentNode);
|
---|
540 |
|
---|
541 | if ((bullets && cname != "ul") || (!bullets && cname != "ol")) {
|
---|
542 | isAllListEles = false;
|
---|
543 | break;
|
---|
544 | }
|
---|
545 | }
|
---|
546 |
|
---|
547 | return {allListEles: isAllListEles, nrange: normalizedRange};
|
---|
548 |
|
---|
549 | } // End inner areAllListElements
|
---|
550 |
|
---|
551 | })(startNode, endNode); // End recursive exec function
|
---|
552 |
|
---|
553 | this.selAfter = this.selBefore;
|
---|
554 |
|
---|
555 | } // End execute function
|
---|
556 | });
|
---|
557 |
|
---|
558 | })();
|
---|