Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 26x 26x 10x 10x 9x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 26x 10x 10x 9x 9x 46x 10x 10x 1x 1x 10x 26x 10x 10x 46x 18x 10x | import { DocumentNode, NodeType, TagNode, NodeWithChildren, Node } from '../..'; /** * Transform an arbitrary fragment DOM into a valid HTML page. * Will create <html>, <head>, <body>, and <title> tags if not already present. * Duplicates of those tags will be merged, and the final tags will all be placed in the correct order * * @param dom DOM to transform */ export function buildPage(dom: DocumentNode): void { // extract PIs const procIns = dom.findChildNodesByNodeType(NodeType.ProcessingInstruction); for (const procIn of procIns) { procIn.removeSelf(); } // init head const headTag = createHead(dom); // init body const bodyTag = createBody(dom); // get or create html const htmlTag = createHtml(dom); // remove any left over nodes dom.clear(); // rebuild page dom.appendChildren(procIns); dom.appendChild(htmlTag); htmlTag.appendChild(headTag); htmlTag.appendChild(bodyTag); } function createHtml(dom: DocumentNode): TagNode { const htmlTag = new TagNode('html'); const sourceHtmlTags = dom.findChildTagsByTagName('html'); for (const sourceHtml of sourceHtmlTags) { // copy children htmlTag.appendChildren(sourceHtml.childNodes); // copy attributes sourceHtml.getAttributes().forEach((value, key) => { if (!htmlTag.hasAttribute(key)) { htmlTag.setRawAttribute(key, value); } }); // remove HTML tag sourceHtml.removeSelf(); } // add required "lang" attribute if missing Eif (!htmlTag.hasAttribute('lang')) { htmlTag.setAttribute('lang', 'en'); } return htmlTag; } // Tags that are only allowed (or should only be used) in the <head> section const headTags = [ 'style', 'link', 'meta', 'base' ]; function createHead(root: NodeWithChildren): TagNode { const headTag = new TagNode('head'); // extract children of head tags into new head for (const existingHead of root.findChildTagsByTagName('head')) { // move children headTag.appendChildren(existingHead.childNodes); // remove the old head when done existingHead.removeSelf(); } // move elements that can only exist in the head const headContents: Node[] = root.findChildTags((tag: TagNode) => headTags.includes(tag.tagName)); headTag.appendChildren(headContents); // add title if missing if (headTag.findChildTagByTagName('title', false) === null) { const titleTag = new TagNode('title'); headTag.appendChild(titleTag); } return headTag; } // Tags that should be "promoted" in the <body> section. // Promoting a tag means removing it but preserving its children. const bodyPromoteTags = [ 'html', 'body' ]; function createBody(root: NodeWithChildren): TagNode { const bodyTag = new TagNode('body'); // copy all remaining elements from dom bodyTag.appendChildren(root.childNodes); // "promote" children of nested <head> tags for (const childBody of bodyTag.findChildTags((tag: TagNode) => bodyPromoteTags.includes(tag.tagName))) { childBody.removeSelf(true); } return bodyTag; } |