Index: Source/core/dom/ProcessingInstruction.js |
diff --git a/Source/core/dom/ProcessingInstruction.js b/Source/core/dom/ProcessingInstruction.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..23d529b0a031061f8c1bfc045feb2ede72571328 |
--- /dev/null |
+++ b/Source/core/dom/ProcessingInstruction.js |
@@ -0,0 +1,167 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+"use strict"; |
+ |
+installClass("ProcessingInstruction", function(ProcessingInstructionPrototype) { |
+ |
+ // Should be implemented as HTMLSerializer / XMLSerializer. |
+ function serializeAttributes(node) { |
+ var attributes = node.attributes; |
+ if (!attributes) |
+ return ''; |
+ var sink = ''; |
+ var attrs = []; |
+ for (var index = 0; index < attributes.length; ++index) { |
+ attrs.push(attributes[index]); |
+ } |
+ |
+ attrs.sort(function(a, b) { |
+ return a.name <= b.name ? -1 : 0; |
+ }).forEach(function(attr) { |
+ var attrName = attr.name; |
+ if (attrName.indexOf('_moz') == 0) |
+ return; |
+ var attrValue = attr.value; |
+ if (attrValue){ |
+ attrValue = String(attrValue).replace(/&/g, '&') |
+ .replace(/\u0022/g, '"') |
+ sink += ' ' + attrName + '="' + attrValue + '"'; |
+ } else { |
+ sink += ' ' + attrName; |
+ } |
+ }); |
+ return sink; |
+ } |
+ |
+ function serializeChildren(node, isXML) { |
+ var sink = ''; |
+ var child = node.firstChild; |
+ while (child) { |
+ sink += serialize(child, isXML); |
+ var nextSibling = child.nextSibling; |
+ if (child.nodeType == Node.TEXT_NODE && nextSibling && |
+ nextSibling.nodeType == Node.TEXT_NODE) { |
+ sink += '_'; |
+ } |
+ child = nextSibling; |
+ } |
+ return sink; |
+ } |
+ |
+ var _END_TAG_MISSIBLE = {'area':true,'base':true,'br':true,'col':true,'command':true,'embed':true,'frame':true, |
+ 'hr':true,'img':true,'input':true,'keygen':true,'link':true,'meta':true,'param':true, |
+ 'source':true,'track':true,'wbr':true}; |
+ |
+ // FIXME: should implement this as HTMLSerializer to share the code with editing? |
+ function serialize(node, isXML) { |
+ if (node.nodeType == Node.TEXT_NODE) { |
+ if (node.parentNode && node.parentNode.nodeType == Node.ELEMENT_NODE && node.parentNode.nodeName.toLowerCase() == 'script') |
+ return node.nodeValue; |
+ // Need to escape: &, < |
+ return node.nodeValue.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
+ } |
+ if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { |
+ var sink = '<!DOCTYPE ' + node.name; |
+ if (node.publicId) { |
+ sink += ' PUBLIC "' + node.publicId + '"'; |
+ if (node.systemId) |
+ sink += ' "' + node.systemId + '"'; |
+ } |
+ sink += '>'; |
+ return sink; |
+ } |
+ if (node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) { |
+ var sink = '<?' + node.target; |
+ if (node.nodeValue) |
+ sink += ' ' + node.nodeValue; |
+ sink += '?>'; |
+ return sink; |
+ } |
+ if (node.nodeType == Node.COMMENT_NODE) { |
+ return '<!-- ' + node.nodeValue + ' -->'; |
+ } |
+ if (node.nodeType != Node.ELEMENT_NODE) { |
+ // To support |Document| node, we iterate over child nodes. |
+ var sink = ''; |
+ for (var child = node.firstChild; child; child = child.nextSibling) { |
+ sink += serialize(child, isXML); |
+ } |
+ return sink.length ? sink : node.nodeValue; |
+ } |
+ |
+ var tagName = node.nodeName.toLowerCase(); |
+ var sink = '<' + node.nodeName + serializeAttributes(node) + '>'; |
+ |
+ if (tagName == 'template') { |
+ sink += serializeChildren(node.content, node.content instanceof XMLDocument); |
+ } else if (tagName == 'iframe') { |
+ sink += serialize(node.contentDocument, node.contentDocument instanceof XMLDocument); |
+ } else { |
+ sink += serializeChildren(node, isXML); |
+ } |
+ |
+ if (!_END_TAG_MISSIBLE[tagName] || isXML) |
+ sink += '</' + node.nodeName + '>'; |
+ return sink; |
+ } |
+ |
+ function applyXSLTransformToCurrentDocument(pi) { |
+ var processor = new XSLTProcessor; |
+ processor.importStylesheet(pi.styleSheetRootNode_); |
+ var transformedDocument = processor.transformToDocument(window.document); |
+ if (!transformedDocument) |
+ return; |
+ var content = serialize(transformedDocument, transformedDocument instanceof XMLDocument); |
+ window.replaceDocument(content, transformedDocument.contentType, transformedDocument.characterSet); |
+ } |
+ |
+ function findFirstStyleSheet() { |
+ for (var child = document.firstChild; child; child = child.nextSibling) { |
+ if (child.nodeName == 'xml-stylesheet') |
+ return child.styleSheetRootNode_ ? child : null; |
+ } |
+ return null; |
+ } |
+ |
+ function initializeForXSLT(parsing) { |
+ window.document.parsing_ = parsing; |
+ window.document.addEventListener('DOMContentLoaded', function() { |
+ window.document.parsing_ = false; |
+ if (window.document.transformSourceDocument_) |
+ return; |
+ var pi = findFirstStyleSheet(); |
+ if (!pi) |
+ return; |
+ applyXSLTransformToCurrentDocument(pi); |
+ }, false); |
+ } |
+ |
+ ProcessingInstructionPrototype.onProcessingInstructionAvailable = function(href, parsing) { |
+ if (!window.document.xslStyleSheetInitialized_) |
+ initializeForXSLT(parsing); |
+ |
+ var request = new XMLHttpRequest(); |
+ request.pi_ = this; |
+ request.onload = function() { |
+ var xmldoc = request.responseXML; |
+ if (!xmldoc) |
+ xmldoc = new DOMParser().parseFromString(request.responseText, 'text/xml'); |
+ var regex = new RegExp('#[^/#?]+$'); |
+ var match = regex.exec(href); |
+ if (match && xmldoc) { |
+ this.pi_.styleSheetRootNode_ = xmldoc.getElementById(match[0].substring(1)); |
+ } else { |
+ this.pi_.styleSheetRootNode_ = xmldoc; |
+ } |
+ if (window.document.transformSourceDocument_ || window.document.parsing_) |
+ return; |
+ if (findFirstStyleSheet() == this.pi_) |
+ applyXSLTransformToCurrentDocument(this.pi_); |
+ }; |
+ request.open("GET", href, true); |
+ request.send(); |
+ } |
+}); |
+ |