property-descriptor.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**
  2. * @license
  3. * Copyright Google Inc. All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. /**
  9. * @fileoverview
  10. * @suppress {globalThis}
  11. */
  12. import {isBrowser, isIE, isMix, isNode, ObjectGetPrototypeOf, patchOnProperties} from '../common/utils';
  13. const globalEventHandlersEventNames = [
  14. 'abort',
  15. 'animationcancel',
  16. 'animationend',
  17. 'animationiteration',
  18. 'auxclick',
  19. 'beforeinput',
  20. 'blur',
  21. 'cancel',
  22. 'canplay',
  23. 'canplaythrough',
  24. 'change',
  25. 'compositionstart',
  26. 'compositionupdate',
  27. 'compositionend',
  28. 'cuechange',
  29. 'click',
  30. 'close',
  31. 'contextmenu',
  32. 'curechange',
  33. 'dblclick',
  34. 'drag',
  35. 'dragend',
  36. 'dragenter',
  37. 'dragexit',
  38. 'dragleave',
  39. 'dragover',
  40. 'drop',
  41. 'durationchange',
  42. 'emptied',
  43. 'ended',
  44. 'error',
  45. 'focus',
  46. 'focusin',
  47. 'focusout',
  48. 'gotpointercapture',
  49. 'input',
  50. 'invalid',
  51. 'keydown',
  52. 'keypress',
  53. 'keyup',
  54. 'load',
  55. 'loadstart',
  56. 'loadeddata',
  57. 'loadedmetadata',
  58. 'lostpointercapture',
  59. 'mousedown',
  60. 'mouseenter',
  61. 'mouseleave',
  62. 'mousemove',
  63. 'mouseout',
  64. 'mouseover',
  65. 'mouseup',
  66. 'mousewheel',
  67. 'orientationchange',
  68. 'pause',
  69. 'play',
  70. 'playing',
  71. 'pointercancel',
  72. 'pointerdown',
  73. 'pointerenter',
  74. 'pointerleave',
  75. 'pointerlockchange',
  76. 'mozpointerlockchange',
  77. 'webkitpointerlockerchange',
  78. 'pointerlockerror',
  79. 'mozpointerlockerror',
  80. 'webkitpointerlockerror',
  81. 'pointermove',
  82. 'pointout',
  83. 'pointerover',
  84. 'pointerup',
  85. 'progress',
  86. 'ratechange',
  87. 'reset',
  88. 'resize',
  89. 'scroll',
  90. 'seeked',
  91. 'seeking',
  92. 'select',
  93. 'selectionchange',
  94. 'selectstart',
  95. 'show',
  96. 'sort',
  97. 'stalled',
  98. 'submit',
  99. 'suspend',
  100. 'timeupdate',
  101. 'volumechange',
  102. 'touchcancel',
  103. 'touchmove',
  104. 'touchstart',
  105. 'touchend',
  106. 'transitioncancel',
  107. 'transitionend',
  108. 'waiting',
  109. 'wheel'
  110. ];
  111. const documentEventNames = [
  112. 'afterscriptexecute', 'beforescriptexecute', 'DOMContentLoaded', 'freeze', 'fullscreenchange',
  113. 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange', 'fullscreenerror',
  114. 'mozfullscreenerror', 'webkitfullscreenerror', 'msfullscreenerror', 'readystatechange',
  115. 'visibilitychange', 'resume'
  116. ];
  117. const windowEventNames = [
  118. 'absolutedeviceorientation',
  119. 'afterinput',
  120. 'afterprint',
  121. 'appinstalled',
  122. 'beforeinstallprompt',
  123. 'beforeprint',
  124. 'beforeunload',
  125. 'devicelight',
  126. 'devicemotion',
  127. 'deviceorientation',
  128. 'deviceorientationabsolute',
  129. 'deviceproximity',
  130. 'hashchange',
  131. 'languagechange',
  132. 'message',
  133. 'mozbeforepaint',
  134. 'offline',
  135. 'online',
  136. 'paint',
  137. 'pageshow',
  138. 'pagehide',
  139. 'popstate',
  140. 'rejectionhandled',
  141. 'storage',
  142. 'unhandledrejection',
  143. 'unload',
  144. 'userproximity',
  145. 'vrdisplyconnected',
  146. 'vrdisplaydisconnected',
  147. 'vrdisplaypresentchange'
  148. ];
  149. const htmlElementEventNames = [
  150. 'beforecopy', 'beforecut', 'beforepaste', 'copy', 'cut', 'paste', 'dragstart', 'loadend',
  151. 'animationstart', 'search', 'transitionrun', 'transitionstart', 'webkitanimationend',
  152. 'webkitanimationiteration', 'webkitanimationstart', 'webkittransitionend'
  153. ];
  154. const mediaElementEventNames =
  155. ['encrypted', 'waitingforkey', 'msneedkey', 'mozinterruptbegin', 'mozinterruptend'];
  156. const ieElementEventNames = [
  157. 'activate',
  158. 'afterupdate',
  159. 'ariarequest',
  160. 'beforeactivate',
  161. 'beforedeactivate',
  162. 'beforeeditfocus',
  163. 'beforeupdate',
  164. 'cellchange',
  165. 'controlselect',
  166. 'dataavailable',
  167. 'datasetchanged',
  168. 'datasetcomplete',
  169. 'errorupdate',
  170. 'filterchange',
  171. 'layoutcomplete',
  172. 'losecapture',
  173. 'move',
  174. 'moveend',
  175. 'movestart',
  176. 'propertychange',
  177. 'resizeend',
  178. 'resizestart',
  179. 'rowenter',
  180. 'rowexit',
  181. 'rowsdelete',
  182. 'rowsinserted',
  183. 'command',
  184. 'compassneedscalibration',
  185. 'deactivate',
  186. 'help',
  187. 'mscontentzoom',
  188. 'msmanipulationstatechanged',
  189. 'msgesturechange',
  190. 'msgesturedoubletap',
  191. 'msgestureend',
  192. 'msgesturehold',
  193. 'msgesturestart',
  194. 'msgesturetap',
  195. 'msgotpointercapture',
  196. 'msinertiastart',
  197. 'mslostpointercapture',
  198. 'mspointercancel',
  199. 'mspointerdown',
  200. 'mspointerenter',
  201. 'mspointerhover',
  202. 'mspointerleave',
  203. 'mspointermove',
  204. 'mspointerout',
  205. 'mspointerover',
  206. 'mspointerup',
  207. 'pointerout',
  208. 'mssitemodejumplistitemremoved',
  209. 'msthumbnailclick',
  210. 'stop',
  211. 'storagecommit'
  212. ];
  213. const webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror'];
  214. const formEventNames = ['autocomplete', 'autocompleteerror'];
  215. const detailEventNames = ['toggle'];
  216. const frameEventNames = ['load'];
  217. const frameSetEventNames = ['blur', 'error', 'focus', 'load', 'resize', 'scroll', 'messageerror'];
  218. const marqueeEventNames = ['bounce', 'finish', 'start'];
  219. const XMLHttpRequestEventNames = [
  220. 'loadstart', 'progress', 'abort', 'error', 'load', 'progress', 'timeout', 'loadend',
  221. 'readystatechange'
  222. ];
  223. const IDBIndexEventNames =
  224. ['upgradeneeded', 'complete', 'abort', 'success', 'error', 'blocked', 'versionchange', 'close'];
  225. const websocketEventNames = ['close', 'error', 'open', 'message'];
  226. const workerEventNames = ['error', 'message'];
  227. export const eventNames = globalEventHandlersEventNames.concat(
  228. webglEventNames, formEventNames, detailEventNames, documentEventNames, windowEventNames,
  229. htmlElementEventNames, ieElementEventNames);
  230. export interface IgnoreProperty {
  231. target: any;
  232. ignoreProperties: string[];
  233. }
  234. export function filterProperties(
  235. target: any, onProperties: string[], ignoreProperties: IgnoreProperty[]): string[] {
  236. if (!ignoreProperties || ignoreProperties.length === 0) {
  237. return onProperties;
  238. }
  239. const tip: IgnoreProperty[] = ignoreProperties.filter(ip => ip.target === target);
  240. if (!tip || tip.length === 0) {
  241. return onProperties;
  242. }
  243. const targetIgnoreProperties: string[] = tip[0].ignoreProperties;
  244. return onProperties.filter(op => targetIgnoreProperties.indexOf(op) === -1);
  245. }
  246. export function patchFilteredProperties(
  247. target: any, onProperties: string[], ignoreProperties: IgnoreProperty[], prototype?: any) {
  248. // check whether target is available, sometimes target will be undefined
  249. // because different browser or some 3rd party plugin.
  250. if (!target) {
  251. return;
  252. }
  253. const filteredProperties: string[] = filterProperties(target, onProperties, ignoreProperties);
  254. patchOnProperties(target, filteredProperties, prototype);
  255. }
  256. export function propertyDescriptorPatch(api: _ZonePrivate, _global: any) {
  257. if (isNode && !isMix) {
  258. return;
  259. }
  260. if ((Zone as any)[api.symbol('patchEvents')]) {
  261. // events are already been patched by legacy patch.
  262. return;
  263. }
  264. const supportsWebSocket = typeof WebSocket !== 'undefined';
  265. const ignoreProperties: IgnoreProperty[] = _global['__Zone_ignore_on_properties'];
  266. // for browsers that we can patch the descriptor: Chrome & Firefox
  267. if (isBrowser) {
  268. const internalWindow: any = window;
  269. const ignoreErrorProperties =
  270. isIE ? [{target: internalWindow, ignoreProperties: ['error']}] : [];
  271. // in IE/Edge, onProp not exist in window object, but in WindowPrototype
  272. // so we need to pass WindowPrototype to check onProp exist or not
  273. patchFilteredProperties(
  274. internalWindow, eventNames.concat(['messageerror']),
  275. ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties,
  276. ObjectGetPrototypeOf(internalWindow));
  277. patchFilteredProperties(Document.prototype, eventNames, ignoreProperties);
  278. if (typeof internalWindow['SVGElement'] !== 'undefined') {
  279. patchFilteredProperties(internalWindow['SVGElement'].prototype, eventNames, ignoreProperties);
  280. }
  281. patchFilteredProperties(Element.prototype, eventNames, ignoreProperties);
  282. patchFilteredProperties(HTMLElement.prototype, eventNames, ignoreProperties);
  283. patchFilteredProperties(HTMLMediaElement.prototype, mediaElementEventNames, ignoreProperties);
  284. patchFilteredProperties(
  285. HTMLFrameSetElement.prototype, windowEventNames.concat(frameSetEventNames),
  286. ignoreProperties);
  287. patchFilteredProperties(
  288. HTMLBodyElement.prototype, windowEventNames.concat(frameSetEventNames), ignoreProperties);
  289. patchFilteredProperties(HTMLFrameElement.prototype, frameEventNames, ignoreProperties);
  290. patchFilteredProperties(HTMLIFrameElement.prototype, frameEventNames, ignoreProperties);
  291. const HTMLMarqueeElement = internalWindow['HTMLMarqueeElement'];
  292. if (HTMLMarqueeElement) {
  293. patchFilteredProperties(HTMLMarqueeElement.prototype, marqueeEventNames, ignoreProperties);
  294. }
  295. const Worker = internalWindow['Worker'];
  296. if (Worker) {
  297. patchFilteredProperties(Worker.prototype, workerEventNames, ignoreProperties);
  298. }
  299. }
  300. const XMLHttpRequest = _global['XMLHttpRequest'];
  301. if (XMLHttpRequest) {
  302. // XMLHttpRequest is not available in ServiceWorker, so we need to check here
  303. patchFilteredProperties(XMLHttpRequest.prototype, XMLHttpRequestEventNames, ignoreProperties);
  304. }
  305. const XMLHttpRequestEventTarget = _global['XMLHttpRequestEventTarget'];
  306. if (XMLHttpRequestEventTarget) {
  307. patchFilteredProperties(
  308. XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype, XMLHttpRequestEventNames,
  309. ignoreProperties);
  310. }
  311. if (typeof IDBIndex !== 'undefined') {
  312. patchFilteredProperties(IDBIndex.prototype, IDBIndexEventNames, ignoreProperties);
  313. patchFilteredProperties(IDBRequest.prototype, IDBIndexEventNames, ignoreProperties);
  314. patchFilteredProperties(IDBOpenDBRequest.prototype, IDBIndexEventNames, ignoreProperties);
  315. patchFilteredProperties(IDBDatabase.prototype, IDBIndexEventNames, ignoreProperties);
  316. patchFilteredProperties(IDBTransaction.prototype, IDBIndexEventNames, ignoreProperties);
  317. patchFilteredProperties(IDBCursor.prototype, IDBIndexEventNames, ignoreProperties);
  318. }
  319. if (supportsWebSocket) {
  320. patchFilteredProperties(WebSocket.prototype, websocketEventNames, ignoreProperties);
  321. }
  322. }