* Split markup into a string of source code and an array mapping ranges in * that string to the text nodes in which they appear. * * * The HTML DOM structure: * * (Element "p" * (Element "b" * (Text "print ")) ; #1 * (Text "'Hello '")
(node, isPreformatted)
| 517 | * @return {Object} source code and the text nodes in which they occur. |
| 518 | */ |
| 519 | function extractSourceSpans(node, isPreformatted) { |
| 520 | var nocode = /(?:^|\s)nocode(?:\s|$)/; |
| 521 | |
| 522 | var chunks = []; |
| 523 | var length = 0; |
| 524 | var spans = []; |
| 525 | var k = 0; |
| 526 | |
| 527 | function walk(node) { |
| 528 | switch (node.nodeType) { |
| 529 | case 1: // Element |
| 530 | if (nocode.test(node.className)) { return; } |
| 531 | for (var child = node.firstChild; child; child = child.nextSibling) { |
| 532 | walk(child); |
| 533 | } |
| 534 | var nodeName = node.nodeName.toLowerCase(); |
| 535 | if ('br' === nodeName || 'li' === nodeName) { |
| 536 | chunks[k] = '\n'; |
| 537 | spans[k << 1] = length++; |
| 538 | spans[(k++ << 1) | 1] = node; |
| 539 | } |
| 540 | break; |
| 541 | case 3: case 4: // Text |
| 542 | var text = node.nodeValue; |
| 543 | if (text.length) { |
| 544 | if (!isPreformatted) { |
| 545 | text = text.replace(/[ \t\r\n]+/g, ' '); |
| 546 | } else { |
| 547 | text = text.replace(/\r\n?/g, '\n'); // Normalize newlines. |
| 548 | } |
| 549 | // TODO: handle tabs here? |
| 550 | chunks[k] = text; |
| 551 | spans[k << 1] = length; |
| 552 | length += text.length; |
| 553 | spans[(k++ << 1) | 1] = node; |
| 554 | } |
| 555 | break; |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | walk(node); |
| 560 | |
| 561 | return { |
| 562 | sourceCode: chunks.join('').replace(/\n$/, ''), |
| 563 | spans: spans |
| 564 | }; |
| 565 | } |
| 566 | |
| 567 | |
| 568 | /** |
no test coverage detected