You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

177 lines
7.4 KiB

  1. // 版权所有 (c) Microsoft Open Technologies, Inc。保留所有权利。
  2. // 按照 Apache 许可证版本 2.0 授予许可。
  3. // 请参阅 http://www.apache.org/licenses/LICENSE-2.0.html。
  4. // 适用于 Windows 应用商店应用的 JavaScript 动态内容填充码
  5. (function () {
  6. if (window.MSApp && MSApp.execUnsafeLocalFunction) {
  7. // 一些节点将具有 "attributes" 属性,此属性会隐藏 Node.prototype.attributes 属性
  8. // 并且意味着我们实际上看不到节点的属性(有趣的是,VS 调试控制台
  9. // 似乎受到同一问题影响)。
  10. //
  11. var Element_setAttribute = Object.getOwnPropertyDescriptor(Element.prototype, "setAttribute").value;
  12. var Element_removeAttribute = Object.getOwnPropertyDescriptor(Element.prototype, "removeAttribute").value;
  13. var HTMLElement_insertAdjacentHTMLPropertyDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "insertAdjacentHTML");
  14. var Node_get_attributes = Object.getOwnPropertyDescriptor(Node.prototype, "attributes").get;
  15. var Node_get_childNodes = Object.getOwnPropertyDescriptor(Node.prototype, "childNodes").get;
  16. var detectionDiv = document.createElement("div");
  17. function getAttributes(element) {
  18. return Node_get_attributes.call(element);
  19. }
  20. function setAttribute(element, attribute, value) {
  21. try {
  22. Element_setAttribute.call(element, attribute, value);
  23. } catch (e) {
  24. // 忽略
  25. }
  26. }
  27. function removeAttribute(element, attribute) {
  28. Element_removeAttribute.call(element, attribute);
  29. }
  30. function childNodes(element) {
  31. return Node_get_childNodes.call(element);
  32. }
  33. function empty(element) {
  34. while (element.childNodes.length) {
  35. element.removeChild(element.lastChild);
  36. }
  37. }
  38. function insertAdjacentHTML(element, position, html) {
  39. HTMLElement_insertAdjacentHTMLPropertyDescriptor.value.call(element, position, html);
  40. }
  41. function inUnsafeMode() {
  42. var isUnsafe = true;
  43. try {
  44. detectionDiv.innerHTML = "<test/>";
  45. }
  46. catch (ex) {
  47. isUnsafe = false;
  48. }
  49. return isUnsafe;
  50. }
  51. function cleanse(html, targetElement) {
  52. var cleaner = document.implementation.createHTMLDocument("cleaner");
  53. empty(cleaner.documentElement);
  54. MSApp.execUnsafeLocalFunction(function () {
  55. insertAdjacentHTML(cleaner.documentElement, "afterbegin", html);
  56. });
  57. var scripts = cleaner.documentElement.querySelectorAll("script");
  58. Array.prototype.forEach.call(scripts, function (script) {
  59. switch (script.type.toLowerCase()) {
  60. case "":
  61. script.type = "text/inert";
  62. break;
  63. case "text/javascript":
  64. case "text/ecmascript":
  65. case "text/x-javascript":
  66. case "text/jscript":
  67. case "text/livescript":
  68. case "text/javascript1.1":
  69. case "text/javascript1.2":
  70. case "text/javascript1.3":
  71. script.type = "text/inert-" + script.type.slice("text/".length);
  72. break;
  73. case "application/javascript":
  74. case "application/ecmascript":
  75. case "application/x-javascript":
  76. script.type = "application/inert-" + script.type.slice("application/".length);
  77. break;
  78. default:
  79. break;
  80. }
  81. });
  82. function cleanseAttributes(element) {
  83. var attributes = getAttributes(element);
  84. if (attributes && attributes.length) {
  85. // 因为属性集合处于活动状态,将其重命名进行排队更加简单
  86. var events;
  87. for (var i = 0, len = attributes.length; i < len; i++) {
  88. var attribute = attributes[i];
  89. var name = attribute.name;
  90. if ((name[0] === "o" || name[0] === "O") &&
  91. (name[1] === "n" || name[1] === "N")) {
  92. events = events || [];
  93. events.push({ name: attribute.name, value: attribute.value });
  94. }
  95. }
  96. if (events) {
  97. for (var i = 0, len = events.length; i < len; i++) {
  98. var attribute = events[i];
  99. removeAttribute(element, attribute.name);
  100. setAttribute(element, "x-" + attribute.name, attribute.value);
  101. }
  102. }
  103. }
  104. var children = childNodes(element);
  105. for (var i = 0, len = children.length; i < len; i++) {
  106. cleanseAttributes(children[i]);
  107. }
  108. }
  109. cleanseAttributes(cleaner.documentElement);
  110. var cleanedNodes = [];
  111. if (targetElement.tagName === 'HTML') {
  112. cleanedNodes = Array.prototype.slice.call(document.adoptNode(cleaner.documentElement).childNodes);
  113. } else {
  114. if (cleaner.head) {
  115. cleanedNodes = cleanedNodes.concat(Array.prototype.slice.call(document.adoptNode(cleaner.head).childNodes));
  116. }
  117. if (cleaner.body) {
  118. cleanedNodes = cleanedNodes.concat(Array.prototype.slice.call(document.adoptNode(cleaner.body).childNodes));
  119. }
  120. }
  121. return cleanedNodes;
  122. }
  123. function cleansePropertySetter(property, setter) {
  124. var propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, property);
  125. var originalSetter = propertyDescriptor.set;
  126. Object.defineProperty(HTMLElement.prototype, property, {
  127. get: propertyDescriptor.get,
  128. set: function (value) {
  129. if (window.WinJS && window.WinJS._execUnsafe && inUnsafeMode()) {
  130. originalSetter.call(this, value);
  131. } else {
  132. var that = this;
  133. var nodes = cleanse(value, that);
  134. MSApp.execUnsafeLocalFunction(function () {
  135. setter(propertyDescriptor, that, nodes);
  136. });
  137. }
  138. },
  139. enumerable: propertyDescriptor.enumerable,
  140. configurable: propertyDescriptor.configurable,
  141. });
  142. }
  143. cleansePropertySetter("innerHTML", function (propertyDescriptor, target, elements) {
  144. empty(target);
  145. for (var i = 0, len = elements.length; i < len; i++) {
  146. target.appendChild(elements[i]);
  147. }
  148. });
  149. cleansePropertySetter("outerHTML", function (propertyDescriptor, target, elements) {
  150. for (var i = 0, len = elements.length; i < len; i++) {
  151. target.insertAdjacentElement("afterend", elements[i]);
  152. }
  153. target.parentNode.removeChild(target);
  154. });
  155. }
  156. }());