* Given a DOM subtree, wraps it in a list, and puts each line into its own * list item. * * @param {Node} node modified in place. Its content is pulled into an * HTMLOListElement, and each line is moved into a separate list item. * This requires cloning elements, so the input
(node, opt_startLineNum, isPreformatted)
| 967 | * be treated as significant. |
| 968 | */ |
| 969 | function numberLines(node, opt_startLineNum, isPreformatted) { |
| 970 | var nocode = /(?:^|\s)nocode(?:\s|$)/; |
| 971 | var lineBreak = /\r\n?|\n/; |
| 972 | |
| 973 | var document = node.ownerDocument; |
| 974 | |
| 975 | var li = document.createElement('li'); |
| 976 | while (node.firstChild) { |
| 977 | li.appendChild(node.firstChild); |
| 978 | } |
| 979 | // An array of lines. We split below, so this is initialized to one |
| 980 | // un-split line. |
| 981 | var listItems = [li]; |
| 982 | |
| 983 | function walk(node) { |
| 984 | switch (node.nodeType) { |
| 985 | case 1: // Element |
| 986 | if (nocode.test(node.className)) { break; } |
| 987 | if ('br' === node.nodeName) { |
| 988 | breakAfter(node); |
| 989 | // Discard the <BR> since it is now flush against a </LI>. |
| 990 | if (node.parentNode) { |
| 991 | node.parentNode.removeChild(node); |
| 992 | } |
| 993 | } else { |
| 994 | for (var child = node.firstChild; child; child = child.nextSibling) { |
| 995 | walk(child); |
| 996 | } |
| 997 | } |
| 998 | break; |
| 999 | case 3: case 4: // Text |
| 1000 | if (isPreformatted) { |
| 1001 | var text = node.nodeValue; |
| 1002 | var match = text.match(lineBreak); |
| 1003 | if (match) { |
| 1004 | var firstLine = text.substring(0, match.index); |
| 1005 | node.nodeValue = firstLine; |
| 1006 | var tail = text.substring(match.index + match[0].length); |
| 1007 | if (tail) { |
| 1008 | var parent = node.parentNode; |
| 1009 | parent.insertBefore( |
| 1010 | document.createTextNode(tail), node.nextSibling); |
| 1011 | } |
| 1012 | breakAfter(node); |
| 1013 | if (!firstLine) { |
| 1014 | // Don't leave blank text nodes in the DOM. |
| 1015 | node.parentNode.removeChild(node); |
| 1016 | } |
| 1017 | } |
| 1018 | } |
| 1019 | break; |
| 1020 | } |
| 1021 | } |
| 1022 | |
| 1023 | // Split a line after the given node. |
| 1024 | function breakAfter(lineEndNode) { |
| 1025 | // If there's nothing to the right, then we can skip ending the line |
| 1026 | // here, and move root-wards since splitting just before an end-tag |
no test coverage detected