123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
- // Licensed under the Apache License, Version 2.0.
- // See http://www.apache.org/licenses/LICENSE-2.0.html.
- // JavaScript Dynamic Content shim for Windows Store apps
- (function () {
- if (window.MSApp && MSApp.execUnsafeLocalFunction) {
- // Some nodes will have an "attributes" property which shadows the Node.prototype.attributes property
- // and means we don't actually see the attributes of the Node (interestingly the VS debug console
- // appears to suffer from the same issue).
- //
- var Element_setAttribute = Object.getOwnPropertyDescriptor(Element.prototype, "setAttribute").value;
- var Element_removeAttribute = Object.getOwnPropertyDescriptor(Element.prototype, "removeAttribute").value;
- var HTMLElement_insertAdjacentHTMLPropertyDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "insertAdjacentHTML");
- var Node_get_attributes = Object.getOwnPropertyDescriptor(Node.prototype, "attributes").get;
- var Node_get_childNodes = Object.getOwnPropertyDescriptor(Node.prototype, "childNodes").get;
- var detectionDiv = document.createElement("div");
- function getAttributes(element) {
- return Node_get_attributes.call(element);
- }
- function setAttribute(element, attribute, value) {
- try {
- Element_setAttribute.call(element, attribute, value);
- } catch (e) {
- // ignore
- }
- }
- function removeAttribute(element, attribute) {
- Element_removeAttribute.call(element, attribute);
- }
- function childNodes(element) {
- return Node_get_childNodes.call(element);
- }
- function empty(element) {
- while (element.childNodes.length) {
- element.removeChild(element.lastChild);
- }
- }
- function insertAdjacentHTML(element, position, html) {
- HTMLElement_insertAdjacentHTMLPropertyDescriptor.value.call(element, position, html);
- }
- function inUnsafeMode() {
- var isUnsafe = true;
- try {
- detectionDiv.innerHTML = "<test/>";
- }
- catch (ex) {
- isUnsafe = false;
- }
- return isUnsafe;
- }
- function cleanse(html, targetElement) {
- var cleaner = document.implementation.createHTMLDocument("cleaner");
- empty(cleaner.documentElement);
- MSApp.execUnsafeLocalFunction(function () {
- insertAdjacentHTML(cleaner.documentElement, "afterbegin", html);
- });
- var scripts = cleaner.documentElement.querySelectorAll("script");
- Array.prototype.forEach.call(scripts, function (script) {
- switch (script.type.toLowerCase()) {
- case "":
- script.type = "text/inert";
- break;
- case "text/javascript":
- case "text/ecmascript":
- case "text/x-javascript":
- case "text/jscript":
- case "text/livescript":
- case "text/javascript1.1":
- case "text/javascript1.2":
- case "text/javascript1.3":
- script.type = "text/inert-" + script.type.slice("text/".length);
- break;
- case "application/javascript":
- case "application/ecmascript":
- case "application/x-javascript":
- script.type = "application/inert-" + script.type.slice("application/".length);
- break;
- default:
- break;
- }
- });
- function cleanseAttributes(element) {
- var attributes = getAttributes(element);
- if (attributes && attributes.length) {
- // because the attributes collection is live it is simpler to queue up the renames
- var events;
- for (var i = 0, len = attributes.length; i < len; i++) {
- var attribute = attributes[i];
- var name = attribute.name;
- if ((name[0] === "o" || name[0] === "O") &&
- (name[1] === "n" || name[1] === "N")) {
- events = events || [];
- events.push({ name: attribute.name, value: attribute.value });
- }
- }
- if (events) {
- for (var i = 0, len = events.length; i < len; i++) {
- var attribute = events[i];
- removeAttribute(element, attribute.name);
- setAttribute(element, "x-" + attribute.name, attribute.value);
- }
- }
- }
- var children = childNodes(element);
- for (var i = 0, len = children.length; i < len; i++) {
- cleanseAttributes(children[i]);
- }
- }
- cleanseAttributes(cleaner.documentElement);
- var cleanedNodes = [];
- if (targetElement.tagName === 'HTML') {
- cleanedNodes = Array.prototype.slice.call(document.adoptNode(cleaner.documentElement).childNodes);
- } else {
- if (cleaner.head) {
- cleanedNodes = cleanedNodes.concat(Array.prototype.slice.call(document.adoptNode(cleaner.head).childNodes));
- }
- if (cleaner.body) {
- cleanedNodes = cleanedNodes.concat(Array.prototype.slice.call(document.adoptNode(cleaner.body).childNodes));
- }
- }
- return cleanedNodes;
- }
- function cleansePropertySetter(property, setter) {
- var propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, property);
- var originalSetter = propertyDescriptor.set;
- Object.defineProperty(HTMLElement.prototype, property, {
- get: propertyDescriptor.get,
- set: function (value) {
- if (window.WinJS && window.WinJS._execUnsafe && inUnsafeMode()) {
- originalSetter.call(this, value);
- } else {
- var that = this;
- var nodes = cleanse(value, that);
- MSApp.execUnsafeLocalFunction(function () {
- setter(propertyDescriptor, that, nodes);
- });
- }
- },
- enumerable: propertyDescriptor.enumerable,
- configurable: propertyDescriptor.configurable,
- });
- }
- cleansePropertySetter("innerHTML", function (propertyDescriptor, target, elements) {
- empty(target);
- for (var i = 0, len = elements.length; i < len; i++) {
- target.appendChild(elements[i]);
- }
- });
- cleansePropertySetter("outerHTML", function (propertyDescriptor, target, elements) {
- for (var i = 0, len = elements.length; i < len; i++) {
- target.insertAdjacentElement("afterend", elements[i]);
- }
- target.parentNode.removeChild(target);
- });
- }
- }());
|