| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @fileoverview | 
					
						
							|  |  |  |  * @suppress {globalThis} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as webSocketPatch from './websocket'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function propertyDescriptorLegacyPatch(api: _ZonePrivate, _global: any) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |   const {isNode, isMix} = api.getGlobalObjects()!; | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |   if (isNode && !isMix) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!canPatchViaPropertyDescriptor(api, _global)) { | 
					
						
							|  |  |  |     const supportsWebSocket = typeof WebSocket !== 'undefined'; | 
					
						
							|  |  |  |     // Safari, Android browsers (Jelly Bean)
 | 
					
						
							|  |  |  |     patchViaCapturingAllTheEvents(api); | 
					
						
							|  |  |  |     api.patchClass('XMLHttpRequest'); | 
					
						
							|  |  |  |     if (supportsWebSocket) { | 
					
						
							|  |  |  |       webSocketPatch.apply(api, _global); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     (Zone as any)[api.symbol('patchEvents')] = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function canPatchViaPropertyDescriptor(api: _ZonePrivate, _global: any) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |   const {isBrowser, isMix} = api.getGlobalObjects()!; | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |   if ((isBrowser || isMix) && | 
					
						
							|  |  |  |       !api.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && | 
					
						
							|  |  |  |       typeof Element !== 'undefined') { | 
					
						
							|  |  |  |     // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364
 | 
					
						
							|  |  |  |     // IDL interface attributes are not configurable
 | 
					
						
							|  |  |  |     const desc = api.ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick'); | 
					
						
							|  |  |  |     if (desc && !desc.configurable) return false; | 
					
						
							|  |  |  |     // try to use onclick to detect whether we can patch via propertyDescriptor
 | 
					
						
							|  |  |  |     // because XMLHttpRequest is not available in service worker
 | 
					
						
							|  |  |  |     if (desc) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |       api.ObjectDefineProperty(Element.prototype, 'onclick', { | 
					
						
							|  |  |  |         enumerable: true, | 
					
						
							|  |  |  |         configurable: true, | 
					
						
							|  |  |  |         get: function() { | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |       const div = document.createElement('div'); | 
					
						
							|  |  |  |       const result = !!div.onclick; | 
					
						
							|  |  |  |       api.ObjectDefineProperty(Element.prototype, 'onclick', desc); | 
					
						
							|  |  |  |       return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const XMLHttpRequest = _global['XMLHttpRequest']; | 
					
						
							|  |  |  |   if (!XMLHttpRequest) { | 
					
						
							|  |  |  |     // XMLHttpRequest is not available in service worker
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const ON_READY_STATE_CHANGE = 'onreadystatechange'; | 
					
						
							|  |  |  |   const XMLHttpRequestPrototype = XMLHttpRequest.prototype; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const xhrDesc = | 
					
						
							|  |  |  |       api.ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // add enumerable and configurable here because in opera
 | 
					
						
							|  |  |  |   // by default XMLHttpRequest.prototype.onreadystatechange is undefined
 | 
					
						
							|  |  |  |   // without adding enumerable and configurable will cause onreadystatechange
 | 
					
						
							|  |  |  |   // non-configurable
 | 
					
						
							|  |  |  |   // and if XMLHttpRequest.prototype.onreadystatechange is undefined,
 | 
					
						
							|  |  |  |   // we should set a real desc instead a fake one
 | 
					
						
							|  |  |  |   if (xhrDesc) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |     api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { | 
					
						
							|  |  |  |       enumerable: true, | 
					
						
							|  |  |  |       configurable: true, | 
					
						
							|  |  |  |       get: function() { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |     const req = new XMLHttpRequest(); | 
					
						
							|  |  |  |     const result = !!req.onreadystatechange; | 
					
						
							|  |  |  |     // restore original desc
 | 
					
						
							|  |  |  |     api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {}); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     const SYMBOL_FAKE_ONREADYSTATECHANGE = api.symbol('fake'); | 
					
						
							|  |  |  |     api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { | 
					
						
							|  |  |  |       enumerable: true, | 
					
						
							|  |  |  |       configurable: true, | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |       get: function() { | 
					
						
							|  |  |  |         return this[SYMBOL_FAKE_ONREADYSTATECHANGE]; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       set: function(value) { | 
					
						
							|  |  |  |         this[SYMBOL_FAKE_ONREADYSTATECHANGE] = value; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |     }); | 
					
						
							|  |  |  |     const req = new XMLHttpRequest(); | 
					
						
							|  |  |  |     const detectFunc = () => {}; | 
					
						
							|  |  |  |     req.onreadystatechange = detectFunc; | 
					
						
							|  |  |  |     const result = (req as any)[SYMBOL_FAKE_ONREADYSTATECHANGE] === detectFunc; | 
					
						
							|  |  |  |     req.onreadystatechange = null as any; | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Whenever any eventListener fires, we check the eventListener target and all parents
 | 
					
						
							|  |  |  | // for `onwhatever` properties and replace them with zone-bound functions
 | 
					
						
							|  |  |  | // - Chrome (for now)
 | 
					
						
							|  |  |  | function patchViaCapturingAllTheEvents(api: _ZonePrivate) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |   const {eventNames} = api.getGlobalObjects()!; | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |   const unboundKey = api.symbol('unbound'); | 
					
						
							|  |  |  |   for (let i = 0; i < eventNames.length; i++) { | 
					
						
							|  |  |  |     const property = eventNames[i]; | 
					
						
							|  |  |  |     const onproperty = 'on' + property; | 
					
						
							|  |  |  |     self.addEventListener(property, function(event) { | 
					
						
							|  |  |  |       let elt: any = <Node>event.target, bound, source; | 
					
						
							|  |  |  |       if (elt) { | 
					
						
							|  |  |  |         source = elt.constructor['name'] + '.' + onproperty; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         source = 'unknown.' + onproperty; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       while (elt) { | 
					
						
							|  |  |  |         if (elt[onproperty] && !elt[onproperty][unboundKey]) { | 
					
						
							|  |  |  |           bound = api.wrapWithCurrentZone(elt[onproperty], source); | 
					
						
							|  |  |  |           bound[unboundKey] = elt[onproperty]; | 
					
						
							|  |  |  |           elt[onproperty] = bound; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         elt = elt.parentElement; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |