diff options
Diffstat (limited to 'Source/WebCore/xml/XMLViewer.js')
-rw-r--r-- | Source/WebCore/xml/XMLViewer.js | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/Source/WebCore/xml/XMLViewer.js b/Source/WebCore/xml/XMLViewer.js new file mode 100644 index 0000000..22405e0 --- /dev/null +++ b/Source/WebCore/xml/XMLViewer.js @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS + * “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. + * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +var nodeParentPairs = []; + +// Script entry point. + +function prepareWebKitXMLViewer(noStyleMessage) +{ + var html = createHTMLElement('html'); + var head = createHTMLElement('head'); + html.appendChild(head); + var style = createHTMLElement('style'); + style.id = 'xml-viewer-style'; + head.appendChild(style); + var body = createHTMLElement('body'); + html.appendChild(body); + var sourceXML = createHTMLElement('div'); + sourceXML.id = 'webkit-xml-viewer-source-xml'; + body.appendChild(sourceXML); + + var child; + while (child = document.firstChild) { + document.removeChild(child); + if (child.nodeType != Node.DOCUMENT_TYPE_NODE) + sourceXML.appendChild(child); + } + document.appendChild(html); + + var header = createHTMLElement('div'); + body.appendChild(header); + header.classList.add('header'); + var headerSpan = createHTMLElement('span'); + header.appendChild(headerSpan); + headerSpan.textContent = noStyleMessage; + header.appendChild(createHTMLElement('br')); + + var tree = createHTMLElement('div'); + body.appendChild(tree); + tree.classList.add('pretty-print'); + tree.id = 'tree'; + window.onload = sourceXMLLoaded; +} + +function sourceXMLLoaded() +{ + var sourceXML = document.getElementById('webkit-xml-viewer-source-xml'); + if (!sourceXML) + return; // Stop if some XML tree extension is already processing this document + //var style = document.head.firstChild; + //document.head.removeChild(style); + //document.head.appendChild(style); + var root = document.getElementById('tree'); + + for (var child = sourceXML.firstChild; child; child = child.nextSibling) + nodeParentPairs.push({parentElement: root, node: child}); + + for (var i = 0; i < nodeParentPairs.length; i++) + processNode(nodeParentPairs[i].parentElement, nodeParentPairs[i].node); + + drawArrows(); + initButtons(); + + if (typeof(onAfterWebkitXMLViewerLoaded) == 'function') + onAfterWebkitXMLViewerLoaded(); +} + +// Tree processing. + +function processNode(parentElement, node) +{ + if (!processNode.processorsMap) { + processNode.processorsMap = {}; + processNode.processorsMap[Node.PROCESSING_INSTRUCTION_NODE] = processProcessingInstruction; + processNode.processorsMap[Node.ELEMENT_NODE] = processElement; + processNode.processorsMap[Node.COMMENT_NODE] = processComment; + processNode.processorsMap[Node.TEXT_NODE] = processText; + processNode.processorsMap[Node.CDATA_SECTION_NODE] = processCDATA; + } + if (processNode.processorsMap[node.nodeType]) + processNode.processorsMap[node.nodeType].call(this, parentElement, node); +} + +function processElement(parentElement, node) +{ + if (!node.firstChild) + processEmptyElement(parentElement, node); + else { + var child = node.firstChild; + if (child.nodeType == Node.TEXT_NODE && isShort(child.nodeValue) && !child.nextSibling) + processShortTextOnlyElement(parentElement, node); + else + processComplexElement(parentElement, node); + } +} + +function processEmptyElement(parentElement, node) +{ + var line = createLine(); + line.appendChild(createTag(node, false, true)); + parentElement.appendChild(line); +} + +function processShortTextOnlyElement(parentElement, node) +{ + var line = createLine(); + line.appendChild(createTag(node, false, false)); + for (var child = node.firstChild; child; child = child.nextSibling) + line.appendChild(createText(child.nodeValue)); + line.appendChild(createTag(node, true, false)); + parentElement.appendChild(line); +} + +function processComplexElement(parentElement, node) +{ + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createTag(node, false, false)); + for (var child = node.firstChild; child; child = child.nextSibling) + nodeParentPairs.push({parentElement: collapsible.expanded.content, node: child}); + collapsible.expanded.end.appendChild(createTag(node, true, false)); + + collapsible.collapsed.content.appendChild(createTag(node, false, false)); + collapsible.collapsed.content.appendChild(createText('...')); + collapsible.collapsed.content.appendChild(createTag(node, true, false)); + parentElement.appendChild(collapsible); +} + +function processComment(parentElement, node) +{ + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createComment('<!-- ' + node.nodeValue + ' -->')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createComment('<!--')); + collapsible.expanded.content.appendChild(createComment(node.nodeValue)); + collapsible.expanded.end.appendChild(createComment('-->')); + + collapsible.collapsed.content.appendChild(createComment('<!--')); + collapsible.collapsed.content.appendChild(createComment('...')); + collapsible.collapsed.content.appendChild(createComment('-->')); + parentElement.appendChild(collapsible); + } +} + +function processCDATA(parentElement, node) +{ + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createText('<![CDATA[ ' + node.nodeValue + ' ]]>')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createText('<![CDATA[')); + collapsible.expanded.content.appendChild(createText(node.nodeValue)); + collapsible.expanded.end.appendChild(createText(']]>')); + + collapsible.collapsed.content.appendChild(createText('<![CDATA[')); + collapsible.collapsed.content.appendChild(createText('...')); + collapsible.collapsed.content.appendChild(createText(']]>')); + parentElement.appendChild(collapsible); + } +} + +function processProcessingInstruction(parentElement, node) +{ + if (isShort(node.nodeValue)) { + var line = createLine(); + line.appendChild(createComment('<?' + node.nodeName + ' ' + node.nodeValue + '?>')); + parentElement.appendChild(line); + } else { + var collapsible = createCollapsible(); + + collapsible.expanded.start.appendChild(createComment('<?' + node.nodeName)); + collapsible.expanded.content.appendChild(createComment(node.nodeValue)); + collapsible.expanded.end.appendChild(createComment('?>')); + + collapsible.collapsed.content.appendChild(createComment('<?' + node.nodeName)); + collapsible.collapsed.content.appendChild(createComment('...')); + collapsible.collapsed.content.appendChild(createComment('?>')); + parentElement.appendChild(collapsible); + } +} + +function processText(parentElement, node) +{ + parentElement.appendChild(createText(node.nodeValue)); +} + +// Processing utils. + +function trim(value) +{ + return value.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); +} + +function isShort(value) +{ + return trim(value).length <= 50; +} + +// Tree rendering. + +function createHTMLElement(elementName) +{ + return document.createElementNS('http://www.w3.org/1999/xhtml', elementName) +} + +function createCollapsible() +{ + var collapsible = createHTMLElement('div'); + collapsible.classList.add('collapsible'); + collapsible.expanded = createHTMLElement('div'); + collapsible.expanded.classList.add('expanded'); + collapsible.appendChild(collapsible.expanded); + + collapsible.expanded.start = createLine(); + collapsible.expanded.start.appendChild(createCollapseButton()); + collapsible.expanded.appendChild(collapsible.expanded.start); + + collapsible.expanded.content = createHTMLElement('div'); + collapsible.expanded.content.classList.add('collapsible-content'); + collapsible.expanded.appendChild(collapsible.expanded.content); + + collapsible.expanded.end = createLine(); + collapsible.expanded.appendChild(collapsible.expanded.end); + + collapsible.collapsed = createHTMLElement('div'); + collapsible.collapsed.classList.add('collapsed'); + collapsible.collapsed.classList.add('hidden'); + collapsible.appendChild(collapsible.collapsed); + collapsible.collapsed.content = createLine(); + collapsible.collapsed.content.appendChild(createExpandButton()); + collapsible.collapsed.appendChild(collapsible.collapsed.content); + + return collapsible; +} + +function createButton() +{ + var button = createHTMLElement('span'); + button.classList.add('button'); + return button; +} + +function createCollapseButton(str) +{ + var button = createButton(); + button.classList.add('collapse-button'); + return button; +} + +function createExpandButton(str) +{ + var button = createButton(); + button.classList.add('expand-button'); + return button; +} + +function createComment(commentString) +{ + var comment = createHTMLElement('span'); + comment.classList.add('webkit-html-comment'); + comment.textContent = commentString; + return comment; +} + +function createText(value) +{ + var text = createHTMLElement('span'); + text.textContent = trim(value); + text.classList.add('text'); + return text; +} + +function createLine() +{ + var line = createHTMLElement('div'); + line.classList.add('line'); + return line; +} + +function createTag(node, isClosing, isEmpty) +{ + var tag = createHTMLElement('span'); + tag.classList.add('webkit-html-tag'); + + var stringBeforeAttrs = '<'; + if (isClosing) + stringBeforeAttrs += '/'; + stringBeforeAttrs += node.nodeName; + var textBeforeAttrs = document.createTextNode(stringBeforeAttrs); + tag.appendChild(textBeforeAttrs); + + if (!isClosing) { + for (var i = 0; i < node.attributes.length; i++) + tag.appendChild(createAttribute(node.attributes[i])); + } + + var stringAfterAttrs = ''; + if (isEmpty) + stringAfterAttrs += '/'; + stringAfterAttrs += '>'; + var textAfterAttrs = document.createTextNode(stringAfterAttrs); + tag.appendChild(textAfterAttrs); + + return tag; +} + +function createAttribute(attributeNode) +{ + var attribute = createHTMLElement('span'); + attribute.classList.add('webkit-html-attribute'); + + var attributeName = createHTMLElement('span'); + attributeName.classList.add('webkit-html-attribute-name'); + attributeName.textContent = attributeNode.name; + + var textBefore = document.createTextNode(' '); + var textBetween = document.createTextNode('="'); + + var attributeValue = createHTMLElement('span'); + attributeValue.classList.add('webkit-html-attribute-value'); + attributeValue.textContent = attributeNode.value; + + var textAfter = document.createTextNode('"'); + + attribute.appendChild(textBefore); + attribute.appendChild(attributeName); + attribute.appendChild(textBetween); + attribute.appendChild(attributeValue); + attribute.appendChild(textAfter); + return attribute; +} + +// Tree behaviour. + +function drawArrows() +{ + var ctx = document.getCSSCanvasContext("2d", "arrowRight", 10, 11); + + ctx.fillStyle = "rgb(90,90,90)"; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(0, 8); + ctx.lineTo(7, 4); + ctx.lineTo(0, 0); + ctx.fill(); + ctx.closePath(); + + var ctx = document.getCSSCanvasContext("2d", "arrowDown", 10, 10); + + ctx.fillStyle = "rgb(90,90,90)"; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(8, 0); + ctx.lineTo(4, 7); + ctx.lineTo(0, 0); + ctx.fill(); + ctx.closePath(); +} + +function expandFunction(sectionId) +{ + return function() + { + document.querySelector('#' + sectionId + ' > .expanded').className = 'expanded'; + document.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed hidden'; + }; +} + +function collapseFunction(sectionId) +{ + return function() + { + document.querySelector('#' + sectionId + ' > .expanded').className = 'expanded hidden'; + document.querySelector('#' + sectionId + ' > .collapsed').className = 'collapsed'; + }; +} + +function initButtons() +{ + var sections = document.querySelectorAll('.collapsible'); + for (var i = 0; i < sections.length; i++) { + var sectionId = 'collapsible' + i; + sections[i].id = sectionId; + + var expandedPart = sections[i].querySelector('#' + sectionId + ' > .expanded'); + var collapseButton = expandedPart.querySelector('.collapse-button'); + collapseButton.onclick = collapseFunction(sectionId); + collapseButton.onmousedown = handleButtonMouseDown; + + var collapsedPart = sections[i].querySelector('#' + sectionId + ' > .collapsed'); + var expandButton = collapsedPart.querySelector('.expand-button'); + expandButton.onclick = expandFunction(sectionId); + expandButton.onmousedown = handleButtonMouseDown; + } + +} + +function handleButtonMouseDown(e) +{ + // To prevent selection on double click + e.preventDefault(); +} |