From fd1d60f03b482a75adc503eda60859043c15f60a Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Thu, 30 Apr 2015 19:51:22 +0200 Subject: [PATCH] refactor(VmTurnZone): use the browser microtask queue for JS --- karma-js.conf.js | 5 +- .../angular2/src/core/zone/vm_turn_zone.dart | 38 +- .../angular2/src/core/zone/vm_turn_zone.es6 | 109 +- modules/angular2/src/test_lib/test_lib.es6 | 16 +- tools/broccoli/html-replace/SCRIPTS.html | 3 +- .../html-replace/SCRIPTS_benchmarks.html | 3 +- .../SCRIPTS_benchmarks_external.html | 3 +- tools/broccoli/trees/browser_tree.ts | 3 +- zone/{es6-promise.js => zone-microtask.js} | 1510 ++++++++++++++--- zone/zone.js | 716 -------- 10 files changed, 1336 insertions(+), 1070 deletions(-) rename zone/{es6-promise.js => zone-microtask.js} (50%) delete mode 100644 zone/zone.js diff --git a/karma-js.conf.js b/karma-js.conf.js index d91b4f223c..91a7250300 100644 --- a/karma-js.conf.js +++ b/karma-js.conf.js @@ -12,10 +12,7 @@ module.exports = function(config) { // Loaded through the es6-module-loader, in `test-main.js`. {pattern: 'dist/js/dev/es5/**', included: false, watched: false}, - // Promise monkey patch & zone should be included first - 'zone/es6-promise.js', - 'zone/zone.js', - 'zone/inner-zone.js', + 'zone/zone-microtask.js', 'zone/long-stack-trace-zone.js', 'node_modules/traceur/bin/traceur-runtime.js', diff --git a/modules/angular2/src/core/zone/vm_turn_zone.dart b/modules/angular2/src/core/zone/vm_turn_zone.dart index 76fb769bdf..7b0d3991b8 100644 --- a/modules/angular2/src/core/zone/vm_turn_zone.dart +++ b/modules/angular2/src/core/zone/vm_turn_zone.dart @@ -55,28 +55,13 @@ class VmTurnZone { // is exhausted and code has been executed in the _innerZone. if (enableLongStackTrace) { _outerZone = Chain.capture( - () { - return Zone.current.fork( - specification: new ZoneSpecification( - scheduleMicrotask: _scheduleMicrotask, - run: _outerRun, - runUnary: _outerRunUnary, - runBinary: _outerRunBinary - ), - zoneValues: {'_name': 'outer'} - ); - }, onError: _onErrorWithLongStackTrace); - } else { - _outerZone = Zone.current.fork( - specification: new ZoneSpecification( - scheduleMicrotask: _scheduleMicrotask, - run: _outerRun, - runUnary: _outerRunUnary, - runBinary: _outerRunBinary, + () => _createOuterZone(Zone.current), + onError: _onErrorWithLongStackTrace); + } else { + _outerZone = _createOuterZone( + Zone.current, handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone, error, StackTrace trace) => _onErrorWithoutLongStackTrace(error, trace) - ), - zoneValues: {'_name': 'outer'} ); } @@ -240,4 +225,17 @@ class VmTurnZone { throw error; } } + + Zone _createOuterZone(Zone zone, {handleUncaughtError}) { + return zone.fork( + specification: new ZoneSpecification( + scheduleMicrotask: _scheduleMicrotask, + run: _outerRun, + runUnary: _outerRunUnary, + runBinary: _outerRunBinary, + handleUncaughtError: handleUncaughtError + ), + zoneValues: {'_name': 'outer'} + ); + } } diff --git a/modules/angular2/src/core/zone/vm_turn_zone.es6 b/modules/angular2/src/core/zone/vm_turn_zone.es6 index f33d6d0914..72d2e500f5 100644 --- a/modules/angular2/src/core/zone/vm_turn_zone.es6 +++ b/modules/angular2/src/core/zone/vm_turn_zone.es6 @@ -13,13 +13,28 @@ import {normalizeBlank, isPresent, global} from 'angular2/src/facade/lang'; * @exportedAs angular2/core */ export class VmTurnZone { + // Code executed in _outerZone does not trigger the onTurnDone. _outerZone; + // _innerZone is the child of _outerZone. Any code executed in this zone will trigger the + // onTurnDone hook at the end of the current VM turn. _innerZone; _onTurnStart:Function; _onTurnDone:Function; _onErrorHandler:Function; + // Number of microtasks pending from _outerZone (& descendants) + _pendingMicrotask: number; + // Whether some code has been executed in the _innerZone (& descendants) in the current turn + _hasExecutedCodeInInnerZone: boolean; + // Whether the onTurnStart hook is executing + _inTurnStart: boolean; + // run() call depth in _outerZone. 0 at the end of a macrotask + // zone.run(() => { // top-level call + // zone.run(() => {}); // nested call -> in-turn + // }); + _nestedRun: number; + /** * Associates with this * @@ -33,17 +48,14 @@ export class VmTurnZone { this._onTurnStart = null; this._onTurnDone = null; this._onErrorHandler = null; - Zone._hasExecutedInnerCode = false; - this._outerZone = global.zone.fork({ - _name: 'outer', - beforeTurn: () => { this._beforeTurn(); }, - afterTurn: () => { this._afterTurn(); } - }); + this._pendingMicrotasks = 0; + this._hasExecutedCodeInInnerZone = false; + this._inTurnStart = false; + this._nestedRun = 0; + + this._outerZone = this._createOuterZone(global.zone); this._innerZone = this._createInnerZone(this._outerZone, enableLongStackTrace); - - // TODO('remove'); - Zone.debug = true; } /** @@ -97,6 +109,50 @@ export class VmTurnZone { return this._outerZone.run(fn); } + _createOuterZone(zone) { + var vmTurnZone = this; + + return zone.fork({ + _name: 'outer', + '$run': function(parentRun) { + return function() { + try { + vmTurnZone._nestedRun++; + return parentRun.apply(this, arguments); + } finally { + vmTurnZone._nestedRun--; + // If there are no more pending microtasks, we are at the end of a VM turn (or in onTurnStart) + // _nestedRun will be 0 at the end of a macrotasks (it could be > 0 when there are nested calls + // to run()). + if (vmTurnZone._pendingMicrotasks == 0 && vmTurnZone._nestedRun == 0) { + if (vmTurnZone._onTurnDone && !vmTurnZone._inTurnStart && vmTurnZone._hasExecutedCodeInInnerZone) { + try { + parentRun.call(vmTurnZone._innerZone, vmTurnZone._onTurnDone); + } finally { + vmTurnZone._hasExecutedCodeInInnerZone = false; + } + } + } + vmTurnZone._inTurnStart = false; + } + } + }, + '$scheduleMicrotask': function(parentScheduleMicrotask) { + return function(fn) { + vmTurnZone._pendingMicrotasks++; + var microtask = function() { + try { + fn(); + } finally { + vmTurnZone._pendingMicrotasks--; + } + }; + parentScheduleMicrotask.call(this, microtask); + } + } + }); + } + _createInnerZone(zone, enableLongStackTrace) { var vmTurnZone = this; var errorHandling; @@ -118,40 +174,29 @@ export class VmTurnZone { return zone .fork(errorHandling) .fork({ + // Executes code in the _innerZone & trigger the onTurnStart hook when code is executed for the + // first time in a turn. '$run': function (parentRun) { return function () { - if (!Zone._hasExecutedInnerCode) { - // Execute the beforeTurn hook when code is first executed in the inner zone in the turn - Zone._hasExecutedInnerCode = true; - var oldZone = global.zone; - global.zone = this; - this.beforeTurn(); - global.zone = oldZone; - } - - return parentRun.apply(this, arguments); + vmTurnZone._maybeStartVmTurn() + return parentRun.apply(this, arguments) } }, _name: 'inner' }); } - _beforeTurn() { - this._onTurnStart && this._onTurnStart(); - } - - _afterTurn() { - if (this._onTurnDone) { - if (Zone._hasExecutedInnerCode) { - // Execute the onTurnDone hook in the inner zone so that microtasks are enqueued there - // The hook gets executed when code has runned in the inner zone during the current turn - this._innerZone.run(this._onTurnDone, this); - Zone._hasExecutedInnerCode = false; + _maybeStartVmTurn(): void { + if (!this._hasExecutedCodeInInnerZone) { + this._hasExecutedCodeInInnerZone = true; + if (this._onTurnStart) { + this._inTurnStart = true; + this._outerZone.run.call(this._innerZone, this._onTurnStart); } } } - _onError(zone, e) { + _onError(zone, e): void { if (isPresent(this._onErrorHandler)) { var trace = [normalizeBlank(e.stack)]; @@ -161,6 +206,8 @@ export class VmTurnZone { } this._onErrorHandler(e, trace); } else { + console.log('## _onError ##'); + console.log(e.stack); throw e; } } diff --git a/modules/angular2/src/test_lib/test_lib.es6 b/modules/angular2/src/test_lib/test_lib.es6 index d68b2d35aa..f9b6595a46 100644 --- a/modules/angular2/src/test_lib/test_lib.es6 +++ b/modules/angular2/src/test_lib/test_lib.es6 @@ -1,5 +1,6 @@ import {DOM} from 'angular2/src/dom/dom_adapter'; import {StringMapWrapper} from 'angular2/src/facade/collection'; +import {global} from 'angular2/src/facade/lang'; import {bind} from 'angular2/di'; @@ -136,14 +137,11 @@ function _it(jsmFn, name, fn) { fn = inject([], fn); } - // Use setTimeout() to run tests in a macrotasks. - // Without this, tests would be executed in the context of a microtasks (a promise .then). - setTimeout(() => { - inIt = true; - fn.execute(injector); - inIt = false; - if (!async) done(); - }, 0); + inIt = true; + fn.execute(injector); + inIt = false; + + if (!async) done(); }); } @@ -357,5 +355,5 @@ function elementText(n) { } function getCurrentZoneName(): string { - return zone._name; + return global.zone._name; } diff --git a/tools/broccoli/html-replace/SCRIPTS.html b/tools/broccoli/html-replace/SCRIPTS.html index 73ed94f0da..5f356d8314 100644 --- a/tools/broccoli/html-replace/SCRIPTS.html +++ b/tools/broccoli/html-replace/SCRIPTS.html @@ -1,5 +1,4 @@ - - + diff --git a/tools/broccoli/html-replace/SCRIPTS_benchmarks.html b/tools/broccoli/html-replace/SCRIPTS_benchmarks.html index e256e49be9..3e2813b704 100644 --- a/tools/broccoli/html-replace/SCRIPTS_benchmarks.html +++ b/tools/broccoli/html-replace/SCRIPTS_benchmarks.html @@ -1,5 +1,4 @@ - - + diff --git a/tools/broccoli/html-replace/SCRIPTS_benchmarks_external.html b/tools/broccoli/html-replace/SCRIPTS_benchmarks_external.html index d9d3f91e17..4005350e4d 100644 --- a/tools/broccoli/html-replace/SCRIPTS_benchmarks_external.html +++ b/tools/broccoli/html-replace/SCRIPTS_benchmarks_external.html @@ -1,5 +1,4 @@ - - + diff --git a/tools/broccoli/trees/browser_tree.ts b/tools/broccoli/trees/browser_tree.ts index 7557f8d4ed..3078715c96 100644 --- a/tools/broccoli/trees/browser_tree.ts +++ b/tools/broccoli/trees/browser_tree.ts @@ -78,8 +78,7 @@ module.exports = function makeBrowserTree(options, destinationPath) { var vendorScriptsTree = flatten(new Funnel('.', { files: [ - 'zone/es6-promise.js', - 'zone/zone.js', + 'zone/zone-microtask.js', 'zone/long-stack-trace-zone.js', 'node_modules/es6-module-loader/dist/es6-module-loader-sans-promises.src.js', 'node_modules/systemjs/dist/system.src.js', diff --git a/zone/es6-promise.js b/zone/zone-microtask.js similarity index 50% rename from zone/es6-promise.js rename to zone/zone-microtask.js index d914a1c514..09d03d2713 100644 --- a/zone/es6-promise.js +++ b/zone/zone-microtask.js @@ -1,3 +1,153 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1; + +function asap(callback) { + queue[len] = callback; + len += 1; + if (len === 1) { + scheduleFlush(); + } +} + +var browserWindow = (typeof global.window !== 'undefined') ? global.window : undefined; +var browserGlobal = browserWindow || {}; +var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + +// test for web worker but not in IE10 +var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + +function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; +} + +// web worker +function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; +} + +function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; +} + +function usePromise() { + var resolvedPromise = Promise.resolve(void 0); + return function() { + resolvedPromise.then(flush); + } +} + +var queue = new Array(1000); + +function flush() { + for (var i = 0; i < len; i++) { + var callback = queue[i]; + callback(); + queue[i] = undefined; + } + + len = 0; +} + +var scheduleFlush; +// Decide what async method to use to triggering processing of queued callbacks: +if (hasNativePromise && !isFirefox) { + // TODO(vicb): remove '!isFirefox' when the bug is fixed: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1162013 + scheduleFlush = usePromise(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else { + scheduleFlush = useSetTimeout(); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],5:[function(require,module,exports){ +(function (global){ +'use strict'; + +var fnPatch = require('./functions'); +var promisePatch = require('./promise'); +var mutationObserverPatch = require('./mutation-observer'); +var definePropertyPatch = require('./define-property'); +var registerElementPatch = require('./register-element'); +var webSocketPatch = require('./websocket'); +var eventTargetPatch = require('./event-target'); +var propertyDescriptorPatch = require('./property-descriptor'); + +function apply() { + fnPatch.patchSetClearFunction(global, [ + 'timeout', + 'interval', + 'immediate' + ]); + + fnPatch.patchSetFunction(global, [ + 'requestAnimationFrame', + 'mozRequestAnimationFrame', + 'webkitRequestAnimationFrame' + ]); + + fnPatch.patchFunction(global, [ + 'alert', + 'prompt' + ]); + + eventTargetPatch.apply(); + + propertyDescriptorPatch.apply(); + + promisePatch.apply(); + + mutationObserverPatch.patchClass('MutationObserver'); + mutationObserverPatch.patchClass('WebKitMutationObserver'); + + definePropertyPatch.apply(); + + registerElementPatch.apply(); +} + +module.exports = { + apply: apply +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./define-property":6,"./event-target":7,"./functions":8,"./mutation-observer":9,"./promise":10,"./property-descriptor":11,"./register-element":12,"./websocket":13}],6:[function(require,module,exports){ +'use strict'; + +// might need similar for object.freeze +// i regret nothing + +var _defineProperty = Object.defineProperty; +var _getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +var _create = Object.create; + +function apply() { + Object.defineProperty = function (obj, prop, desc) { + if (isUnconfigurable(obj, prop)) { + throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj); + } + if (prop !== 'prototype') { + desc = rewriteDescriptor(obj, prop, desc); + } + return _defineProperty(obj, prop, desc); + }; + + Object.defineProperties = function (obj, props) { + Object.keys(props).forEach(function (prop) { + Object.defineProperty(obj, prop, props[prop]); + }); + return obj; + }; + + Object.create = function (obj, proto) { + if (typeof proto === 'object') { + Object.keys(proto).forEach(function (prop) { + proto[prop] = rewriteDescriptor(obj, prop, proto[prop]); + }); + } + return _create(obj, proto); + }; + + Object.getOwnPropertyDescriptor = function (obj, prop) { + var desc = _getOwnPropertyDescriptor(obj, prop); + if (isUnconfigurable(obj, prop)) { + desc.configurable = false; + } + return desc; + }; +}; + +function _redefineProperty(obj, prop, desc) { + desc = rewriteDescriptor(obj, prop, desc); + return _defineProperty(obj, prop, desc); +}; + +function isUnconfigurable (obj, prop) { + return obj && obj.__unconfigurables && obj.__unconfigurables[prop]; +} + +function rewriteDescriptor (obj, prop, desc) { + desc.configurable = true; + if (!desc.configurable) { + if (!obj.__unconfigurables) { + _defineProperty(obj, '__unconfigurables', { writable: true, value: {} }); + } + obj.__unconfigurables[prop] = true; + } + return desc; +} + +module.exports = { + apply: apply, + _redefineProperty: _redefineProperty +}; + + + +},{}],7:[function(require,module,exports){ +(function (global){ +'use strict'; + +var utils = require('../utils'); + +function apply() { + // patched properties depend on addEventListener, so this needs to come first + if (global.EventTarget) { + utils.patchEventTargetMethods(global.EventTarget.prototype); + + // Note: EventTarget is not available in all browsers, + // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget + } else { + var apis = [ 'ApplicationCache', + 'EventSource', + 'FileReader', + 'InputMethodContext', + 'MediaController', + 'MessagePort', + 'Node', + 'Performance', + 'SVGElementInstance', + 'SharedWorker', + 'TextTrack', + 'TextTrackCue', + 'TextTrackList', + 'WebKitNamedFlow', + 'Window', + 'Worker', + 'WorkerGlobalScope', + 'XMLHttpRequestEventTarget', + 'XMLHttpRequestUpload' + ]; + + apis.forEach(function(thing) { + global[thing] && utils.patchEventTargetMethods(global[thing].prototype); + }); + } +} + +module.exports = { + apply: apply +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils":14}],8:[function(require,module,exports){ +(function (global){ +'use strict'; + +var utils = require('../utils'); + +function patchSetClearFunction(obj, fnNames) { + fnNames.map(function (name) { + return name[0].toUpperCase() + name.substr(1); + }).forEach(function (name) { + var setName = 'set' + name; + var delegate = obj[setName]; + + if (delegate) { + var clearName = 'clear' + name; + var ids = {}; + + var bindArgs = setName === 'setInterval' ? utils.bindArguments : utils.bindArgumentsOnce; + + global.zone[setName] = function (fn) { + var id, fnRef = fn; + arguments[0] = function () { + delete ids[id]; + return fnRef.apply(this, arguments); + }; + var args = bindArgs(arguments); + id = delegate.apply(obj, args); + ids[id] = true; + return id; + }; + + obj[setName] = function () { + return global.zone[setName].apply(this, arguments); + }; + + var clearDelegate = obj[clearName]; + + global.zone[clearName] = function (id) { + if (ids[id]) { + delete ids[id]; + global.zone.dequeueTask(); + } + return clearDelegate.apply(this, arguments); + }; + + obj[clearName] = function () { + return global.zone[clearName].apply(this, arguments); + }; + } + }); +}; + +function patchSetFunction(obj, fnNames) { + fnNames.forEach(function (name) { + var delegate = obj[name]; + + if (delegate) { + global.zone[name] = function (fn) { + var fnRef = fn; + arguments[0] = function () { + return fnRef.apply(this, arguments); + }; + var args = utils.bindArgumentsOnce(arguments); + return delegate.apply(obj, args); + }; + + obj[name] = function () { + return zone[name].apply(this, arguments); + }; + } + }); +}; + +function patchFunction(obj, fnNames) { + fnNames.forEach(function (name) { + var delegate = obj[name]; + global.zone[name] = function () { + return delegate.apply(obj, arguments); + }; + + obj[name] = function () { + return global.zone[name].apply(this, arguments); + }; + }); +}; + + +module.exports = { + patchSetClearFunction: patchSetClearFunction, + patchSetFunction: patchSetFunction, + patchFunction: patchFunction +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils":14}],9:[function(require,module,exports){ +(function (global){ +'use strict'; + +// wrap some native API on `window` +function patchClass(className) { + var OriginalClass = global[className]; + if (!OriginalClass) return; + + global[className] = function (fn) { + this._o = new OriginalClass(zone.bind(fn, true)); + }; + + var instance = new OriginalClass(function () {}); + + global[className].prototype.disconnect = function () { + var result = this._o.disconnect.apply(this._o, arguments); + this._active && global.zone.dequeueTask(); + this._active = false; + return result; + }; + + global[className].prototype.observe = function () { + if (!this._active) { + global.zone.enqueueTask(); + } + this._active = true; + return this._o.observe.apply(this._o, arguments); + }; + + var prop; + for (prop in instance) { + (function (prop) { + if (typeof global[className].prototype !== undefined) { + return; + } + if (typeof instance[prop] === 'function') { + global[className].prototype[prop] = function () { + return this._o[prop].apply(this._o, arguments); + }; + } else { + Object.defineProperty(global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this._o[prop] = zone.bind(fn); + } else { + this._o[prop] = fn; + } + }, + get: function () { + return this._o[prop]; + } + }); + } + }(prop)); + } +}; + +module.exports = { + patchClass: patchClass +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],10:[function(require,module,exports){ +(function (global){ +'use strict'; + +var utils = require('../utils'); + +/* + * patch a fn that returns a promise + */ +var bindPromiseFn = (function() { + // if the browser natively supports Promises, we can just return a native promise + if (global.Promise) { + return function (delegate) { + return function() { + var delegatePromise = delegate.apply(this, arguments); + if (delegatePromise instanceof Promise) { + return delegatePromise; + } else { + return new Promise(function(resolve, reject) { + delegatePromise.then(resolve, reject); + }); + } + }; + }; + } else { + // if the browser does not have native promises, we have to patch each promise instance + return function (delegate) { + return function () { + return patchThenable(delegate.apply(this, arguments)); + }; + }; + } + + function patchThenable(thenable) { + var then = thenable.then; + thenable.then = function () { + var args = utils.bindArguments(arguments); + var nextThenable = then.apply(thenable, args); + return patchThenable(nextThenable); + }; + + var ocatch = thenable.catch; + thenable.catch = function () { + var args = utils.bindArguments(arguments); + var nextThenable = ocatch.apply(thenable, args); + return patchThenable(nextThenable); + }; + return thenable; + } +}()); + +function apply() { + if (global.Promise) { + utils.patchPrototype(Promise.prototype, [ + 'then', + 'catch' + ]); + } +} + +module.exports = { + apply: apply, + bindPromiseFn: bindPromiseFn +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils":14}],11:[function(require,module,exports){ +(function (global){ +'use strict'; + +var webSocketPatch = require('./websocket'); +var utils = require('../utils'); + +var eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart message mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error webglcontextrestored webglcontextlost webglcontextcreationerror'.split(' '); + +function apply() { + if (canPatchViaPropertyDescriptor()) { + // for browsers that we can patch the descriptor: Chrome & Firefox + var onEventNames = eventNames.map(function (property) { + return 'on' + property; + }); + utils.patchProperties(HTMLElement.prototype, onEventNames); + utils.patchProperties(XMLHttpRequest.prototype); + utils.patchProperties(WebSocket.prototype); + } else { + // Safari + patchViaCapturingAllTheEvents(); + utils.patchClass('XMLHttpRequest'); + webSocketPatch.apply(); + } +} + +function canPatchViaPropertyDescriptor() { + if (!Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && typeof Element !== 'undefined') { + // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 + // IDL interface attributes are not configurable + var desc = Object.getOwnPropertyDescriptor(Element.prototype, 'onclick'); + if (desc && !desc.configurable) return false; + } + + Object.defineProperty(HTMLElement.prototype, 'onclick', { + get: function () { + return true; + } + }); + var elt = document.createElement('div'); + var result = !!elt.onclick; + Object.defineProperty(HTMLElement.prototype, 'onclick', {}); + return result; +}; + +// Whenever any event fires, we check the event target and all parents +// for `onwhatever` properties and replace them with zone-bound functions +// - Chrome (for now) +function patchViaCapturingAllTheEvents() { + eventNames.forEach(function (property) { + var onproperty = 'on' + property; + document.addEventListener(property, function (event) { + var elt = event.target, bound; + while (elt) { + if (elt[onproperty] && !elt[onproperty]._unbound) { + bound = global.zone.bind(elt[onproperty]); + bound._unbound = elt[onproperty]; + elt[onproperty] = bound; + } + elt = elt.parentElement; + } + }, true); + }); +}; + +module.exports = { + apply: apply +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils":14,"./websocket":13}],12:[function(require,module,exports){ +(function (global){ +'use strict'; + +var _redefineProperty = require('./define-property')._redefineProperty; + +function apply() { + if (!('registerElement' in global.document)) { + return; + } + var _registerElement = document.registerElement; + var callbacks = [ + 'createdCallback', + 'attachedCallback', + 'detachedCallback', + 'attributeChangedCallback' + ]; + document.registerElement = function (name, opts) { + callbacks.forEach(function (callback) { + if (opts.prototype[callback]) { + var descriptor = Object.getOwnPropertyDescriptor(opts.prototype, callback); + if (descriptor.value) { + descriptor.value = zone.bind(descriptor.value || opts.prototype[callback]); + _redefineProperty(opts.prototype, callback, descriptor); + } + } + }); + return _registerElement.apply(document, [name, opts]); + }; +} + +module.exports = { + apply: apply +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./define-property":6}],13:[function(require,module,exports){ +(function (global){ +'use strict'; + +var utils = require('../utils.js'); + +// we have to patch the instance since the proto is non-configurable +function apply() { + var WS = global.WebSocket; + utils.patchEventTargetMethods(WS.prototype); + global.WebSocket = function(a, b) { + var socket = arguments.length > 1 ? new WS(a, b) : new WS(a); + var proxySocket; + + // Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance + var onmessageDesc = Object.getOwnPropertyDescriptor(socket, 'onmessage'); + if (onmessageDesc && onmessageDesc.configurable === false) { + proxySocket = Object.create(socket); + ['addEventListener', 'removeEventListener', 'send', 'close'].forEach(function(propName) { + proxySocket[propName] = function() { + return socket[propName].apply(socket, arguments); + }; + }); + } else { + // we can patch the real socket + proxySocket = socket; + } + + utils.patchProperties(proxySocket, ['onclose', 'onerror', 'onmessage', 'onopen']); + + return proxySocket; + }; +} + +module.exports = { + apply: apply +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../utils.js":14}],14:[function(require,module,exports){ +(function (global){ +'use strict'; + +function bindArguments(args) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = global.zone.bind(args[i]); + } + } + return args; +}; + +function bindArgumentsOnce(args) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = global.zone.bindOnce(args[i]); + } + } + return args; +}; + +function patchPrototype(obj, fnNames) { + fnNames.forEach(function (name) { + var delegate = obj[name]; + if (delegate) { + obj[name] = function () { + return delegate.apply(this, bindArguments(arguments)); + }; + } + }); +}; + +function patchProperty(obj, prop) { + var desc = Object.getOwnPropertyDescriptor(obj, prop) || { + enumerable: true, + configurable: true + }; + + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + + // substr(2) cuz 'onclick' -> 'click', etc + var eventName = prop.substr(2); + var _prop = '_' + prop; + + desc.set = function (fn) { + if (this[_prop]) { + this.removeEventListener(eventName, this[_prop]); + } + + if (typeof fn === 'function') { + this[_prop] = fn; + this.addEventListener(eventName, fn, false); + } else { + this[_prop] = null; + } + }; + + desc.get = function () { + return this[_prop]; + }; + + Object.defineProperty(obj, prop, desc); +}; + +function patchProperties(obj, properties) { + + (properties || (function () { + var props = []; + for (var prop in obj) { + props.push(prop); + } + return props; + }()). + filter(function (propertyName) { + return propertyName.substr(0,2) === 'on'; + })). + forEach(function (eventName) { + patchProperty(obj, eventName); + }); +}; + +function patchEventTargetMethods(obj) { + var addDelegate = obj.addEventListener; + obj.addEventListener = function (eventName, fn) { + fn._bound = fn._bound || {}; + arguments[1] = fn._bound[eventName] = zone.bind(fn); + return addDelegate.apply(this, arguments); + }; + + var removeDelegate = obj.removeEventListener; + obj.removeEventListener = function (eventName, fn) { + if(arguments[1]._bound && arguments[1]._bound[eventName]) { + var _bound = arguments[1]._bound; + arguments[1] = _bound[eventName]; + delete _bound[eventName]; + } + var result = removeDelegate.apply(this, arguments); + global.zone.dequeueTask(fn); + return result; + }; +}; + +// wrap some native API on `window` +function patchClass(className) { + var OriginalClass = global[className]; + if (!OriginalClass) return; + + global[className] = function () { + var a = bindArguments(arguments); + switch (a.length) { + case 0: this._o = new OriginalClass(); break; + case 1: this._o = new OriginalClass(a[0]); break; + case 2: this._o = new OriginalClass(a[0], a[1]); break; + case 3: this._o = new OriginalClass(a[0], a[1], a[2]); break; + case 4: this._o = new OriginalClass(a[0], a[1], a[2], a[3]); break; + default: throw new Error('what are you even doing?'); + } + }; + + var instance = new OriginalClass(className.substr(-16) === 'MutationObserver' ? function () {} : undefined); + + var prop; + for (prop in instance) { + (function (prop) { + if (typeof instance[prop] === 'function') { + global[className].prototype[prop] = function () { + return this._o[prop].apply(this._o, arguments); + }; + } else { + Object.defineProperty(global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this._o[prop] = global.zone.bind(fn); + } else { + this._o[prop] = fn; + } + }, + get: function () { + return this._o[prop]; + } + }); + } + }(prop)); + }; +}; + +module.exports = { + bindArguments: bindArguments, + bindArgumentsOnce: bindArgumentsOnce, + patchPrototype: patchPrototype, + patchProperty: patchProperty, + patchProperties: patchProperties, + patchEventTargetMethods: patchEventTargetMethods, + patchClass: patchClass +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}]},{},[1]); diff --git a/zone/zone.js b/zone/zone.js deleted file mode 100644 index 2ca5983493..0000000000 --- a/zone/zone.js +++ /dev/null @@ -1,716 +0,0 @@ -'use strict'; - -(function (exports) { - -var zone = null; - - -function Zone(parentZone, data) { - var zone = (arguments.length) ? Object.create(parentZone) : this; - - zone.parent = parentZone; - - Object.keys(data || {}).forEach(function(property) { - - var _property = property.substr(1); - - // augment the new zone with a hook decorates the parent's hook - if (property[0] === '$') { - zone[_property] = data[property](parentZone[_property] || function () {}); - - // augment the new zone with a hook that runs after the parent's hook - } else if (property[0] === '+') { - if (parentZone[_property]) { - zone[_property] = function () { - var result = parentZone[_property].apply(this, arguments); - data[property].apply(this, arguments); - return result; - }; - } else { - zone[_property] = data[property]; - } - - // augment the new zone with a hook that runs before the parent's hook - } else if (property[0] === '-') { - if (parentZone[_property]) { - zone[_property] = function () { - data[property].apply(this, arguments); - return parentZone[_property].apply(this, arguments); - }; - } else { - zone[_property] = data[property]; - } - - // set the new zone's hook (replacing the parent zone's) - } else { - zone[property] = (typeof data[property] === 'object') ? - JSON.parse(JSON.stringify(data[property])) : - data[property]; - } - }); - - zone.$id = ++Zone.nextId; - - return zone; -} - -Zone.prototype = { - constructor: Zone, - - fork: function (locals) { - this.onZoneCreated(); - return new Zone(this, locals); - }, - - bind: function (fn, skipEnqueue) { - skipEnqueue || this.enqueueTask(fn); - var zone = this.fork(); - return function zoneBoundFn() { - return zone.run(fn, this, arguments); - }; - }, - - bindOnce: function (fn) { - var boundZone = this; - return this.bind(function () { - var result = fn.apply(this, arguments); - boundZone.dequeueTask(fn); - return result; - }); - }, - - scheduleMicrotask: function (fn) { - var executionZone = this; - Zone.microtaskQueue.push(function() { - executionZone.run(fn); - }); - }, - - run: function run (fn, applyTo, applyWith) { - applyWith = applyWith || []; - - var oldZone = zone, - result; - - exports.zone = zone = this; - - try { - Zone.nestedRun++; - this.beforeTask(); - return fn.apply(applyTo, applyWith); - } catch (e) { - if (zone.onError) { - zone.onError(e); - } else { - throw e; - } - } finally { - this.afterTask(); - Zone.nestedRun--; - // Check if there are microtasks to execute unless: - // - we are already executing them (drainingMicrotasks is true), - // - we are in a recursive call to run (nesetdRun > 0) - if (!Zone.drainingMicrotasks && Zone.nestedRun == 0) { - this.runMicrotasks(); - } - exports.zone = zone = oldZone; - } - }, - - runMicrotasks: function () { - Zone.drainingMicrotasks = true; - do { - // Drain the microtask queue - while (Zone.microtaskQueue.length > 0) { - var microtask = Zone.microtaskQueue.shift(); - microtask(); - } - this.afterTurn(); - // Check the queue length again as afterTurn might have enqueued more microtasks - } while (Zone.microtaskQueue.length > 0) - Zone.drainingMicrotasks = false; - }, - - afterTurn: function() {}, - beforeTask: function () {}, - onZoneCreated: function () {}, - afterTask: function () {}, - enqueueTask: function () {}, - dequeueTask: function () {} -}; - - -Zone.patchSetClearFn = function (obj, fnNames) { - fnNames.map(function (name) { - return name[0].toUpperCase() + name.substr(1); - }). - forEach(function (name) { - var setName = 'set' + name; - var delegate = obj[setName]; - - if (delegate) { - var clearName = 'clear' + name; - var ids = {}; - - var bindArgs = setName === 'setInterval' ? Zone.bindArguments : Zone.bindArgumentsOnce; - - zone[setName] = function (fn) { - var id, fnRef = fn; - arguments[0] = function () { - delete ids[id]; - return fnRef.apply(this, arguments); - }; - var args = bindArgs(arguments); - id = delegate.apply(obj, args); - ids[id] = true; - return id; - }; - - obj[setName] = function () { - return zone[setName].apply(this, arguments); - }; - - var clearDelegate = obj[clearName]; - - zone[clearName] = function (id) { - if (ids[id]) { - delete ids[id]; - zone.dequeueTask(); - } - return clearDelegate.apply(this, arguments); - }; - - obj[clearName] = function () { - return zone[clearName].apply(this, arguments); - }; - } - }); -}; - -Zone.nextId = 1; -// Pending microtasks to be executed after the macrotask -Zone.microtaskQueue = []; -// Whether we are currently draining the microtask queue -Zone.drainingMicrotasks = false; -// Recursive calls to run -Zone.nestedRun = 0; - -Zone.patchSetFn = function (obj, fnNames) { - fnNames.forEach(function (name) { - var delegate = obj[name]; - - if (delegate) { - zone[name] = function (fn) { - var fnRef = fn; - arguments[0] = function () { - return fnRef.apply(this, arguments); - }; - var args = Zone.bindArgumentsOnce(arguments); - return delegate.apply(obj, args); - }; - - obj[name] = function () { - return zone[name].apply(this, arguments); - }; - } - }); -}; - -Zone.patchPrototype = function (obj, fnNames) { - fnNames.forEach(function (name) { - var delegate = obj[name]; - if (delegate) { - obj[name] = function () { - return delegate.apply(this, Zone.bindArguments(arguments)); - }; - } - }); -}; - -Zone.bindArguments = function (args) { - for (var i = args.length - 1; i >= 0; i--) { - if (typeof args[i] === 'function') { - args[i] = zone.bind(args[i]); - } - } - return args; -}; - - -Zone.bindArgumentsOnce = function (args) { - for (var i = args.length - 1; i >= 0; i--) { - if (typeof args[i] === 'function') { - args[i] = zone.bindOnce(args[i]); - } - } - return args; -}; - -/* - * patch a fn that returns a promise - */ -Zone.bindPromiseFn = (function() { - // if the browser natively supports Promises, we can just return a native promise - if (window.Promise) { - return function (delegate) { - return function() { - var delegatePromise = delegate.apply(this, arguments); - if (delegatePromise instanceof Promise) { - return delegatePromise; - } else { - return new Promise(function(resolve, reject) { - delegatePromise.then(resolve, reject); - }); - } - }; - }; - } else { - // if the browser does not have native promises, we have to patch each promise instance - return function (delegate) { - return function () { - return patchThenable(delegate.apply(this, arguments)); - }; - }; - } - - function patchThenable(thenable) { - var then = thenable.then; - thenable.then = function () { - var args = Zone.bindArguments(arguments); - var nextThenable = then.apply(thenable, args); - return patchThenable(nextThenable); - }; - - var ocatch = thenable.catch; - thenable.catch = function () { - var args = Zone.bindArguments(arguments); - var nextThenable = ocatch.apply(thenable, args); - return patchThenable(nextThenable); - }; - return thenable; - } -}()); - - -Zone.patchableFn = function (obj, fnNames) { - fnNames.forEach(function (name) { - var delegate = obj[name]; - zone[name] = function () { - return delegate.apply(obj, arguments); - }; - - obj[name] = function () { - return zone[name].apply(this, arguments); - }; - }); -}; - -Zone.patchProperty = function (obj, prop) { - var desc = Object.getOwnPropertyDescriptor(obj, prop) || { - enumerable: true, - configurable: true - }; - - // A property descriptor cannot have getter/setter and be writable - // deleting the writable and value properties avoids this error: - // - // TypeError: property descriptors must not specify a value or be writable when a - // getter or setter has been specified - delete desc.writable; - delete desc.value; - - // substr(2) cuz 'onclick' -> 'click', etc - var eventName = prop.substr(2); - var _prop = '_' + prop; - - desc.set = function (fn) { - if (this[_prop]) { - this.removeEventListener(eventName, this[_prop]); - } - - if (typeof fn === 'function') { - this[_prop] = fn; - this.addEventListener(eventName, fn, false); - } else { - this[_prop] = null; - } - }; - - desc.get = function () { - return this[_prop]; - }; - - Object.defineProperty(obj, prop, desc); -}; - -Zone.patchProperties = function (obj, properties) { - - (properties || (function () { - var props = []; - for (var prop in obj) { - props.push(prop); - } - return props; - }()). - filter(function (propertyName) { - return propertyName.substr(0,2) === 'on'; - })). - forEach(function (eventName) { - Zone.patchProperty(obj, eventName); - }); -}; - -Zone.patchEventTargetMethods = function (obj) { - var addDelegate = obj.addEventListener; - obj.addEventListener = function (eventName, fn) { - arguments[1] = fn._bound = zone.bind(fn); - return addDelegate.apply(this, arguments); - }; - - var removeDelegate = obj.removeEventListener; - obj.removeEventListener = function (eventName, fn) { - arguments[1] = arguments[1]._bound || arguments[1]; - var result = removeDelegate.apply(this, arguments); - zone.dequeueTask(fn); - return result; - }; -}; - -Zone.patch = function patch () { - Zone.patchSetClearFn(window, [ - 'timeout', - 'interval', - 'immediate' - ]); - - Zone.patchSetFn(window, [ - 'requestAnimationFrame', - 'mozRequestAnimationFrame', - 'webkitRequestAnimationFrame' - ]); - - Zone.patchableFn(window, ['alert', 'prompt']); - - // patched properties depend on addEventListener, so this needs to come first - if (window.EventTarget) { - Zone.patchEventTargetMethods(window.EventTarget.prototype); - - // Note: EventTarget is not available in all browsers, - // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget - } else { - [ 'ApplicationCache', - 'EventSource', - 'FileReader', - 'InputMethodContext', - 'MediaController', - 'MessagePort', - 'Node', - 'Performance', - 'SVGElementInstance', - 'SharedWorker', - 'TextTrack', - 'TextTrackCue', - 'TextTrackList', - 'WebKitNamedFlow', - 'Window', - 'Worker', - 'WorkerGlobalScope', - 'XMLHttpRequestEventTarget', - 'XMLHttpRequestUpload' - ]. - filter(function (thing) { - return window[thing]; - }). - map(function (thing) { - return window[thing].prototype; - }). - forEach(Zone.patchEventTargetMethods); - } - - if (Zone.canPatchViaPropertyDescriptor()) { - Zone.patchViaPropertyDescriptor(); - } else { - Zone.patchViaCapturingAllTheEvents(); - Zone.patchClass('XMLHttpRequest'); - Zone.patchWebSocket(); - } - - // Do not patch promises when using out own version supporting microtasks - //// patch promises - //if (window.Promise) { - // Zone.patchPrototype(Promise.prototype, [ - // 'then', - // 'catch' - // ]); - //} - Zone.patchMutationObserverClass('MutationObserver'); - Zone.patchMutationObserverClass('WebKitMutationObserver'); - Zone.patchDefineProperty(); - Zone.patchRegisterElement(); -}; - -// -Zone.canPatchViaPropertyDescriptor = function () { - if (!Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && - typeof Element !== 'undefined') { - // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 - // IDL interface attributes are not configurable - var desc = Object.getOwnPropertyDescriptor(Element.prototype, 'onclick'); - if (desc && !desc.configurable) return false; - } - - Object.defineProperty(HTMLElement.prototype, 'onclick', { - get: function () { - return true; - } - }); - var elt = document.createElement('div'); - var result = !!elt.onclick; - Object.defineProperty(HTMLElement.prototype, 'onclick', {}); - return result; -}; - -// for browsers that we can patch the descriptor: -// - eventually Chrome once this bug gets resolved -// - Firefox -Zone.patchViaPropertyDescriptor = function () { - Zone.patchProperties(HTMLElement.prototype, Zone.onEventNames); - Zone.patchProperties(XMLHttpRequest.prototype); -}; - -// Whenever any event fires, we check the event target and all parents -// for `onwhatever` properties and replace them with zone-bound functions -// - Chrome (for now) -Zone.patchViaCapturingAllTheEvents = function () { - Zone.eventNames.forEach(function (property) { - var onproperty = 'on' + property; - document.addEventListener(property, function (event) { - var elt = event.target, bound; - while (elt) { - if (elt[onproperty] && !elt[onproperty]._unbound) { - bound = zone.bind(elt[onproperty]); - bound._unbound = elt[onproperty]; - elt[onproperty] = bound; - } - elt = elt.parentElement; - } - }, true); - }); -}; - -// we have to patch the instance since the proto is non-configurable -Zone.patchWebSocket = function() { - var WS = window.WebSocket; - window.WebSocket = function(a, b) { - var socket = arguments.length > 1 ? new WS(a, b) : new WS(a); - Zone.patchProperties(socket, ['onclose', 'onerror', 'onmessage', 'onopen']); - return socket; - }; -} - - -// wrap some native API on `window` -Zone.patchClass = function (className) { - var OriginalClass = window[className]; - if (!OriginalClass) { - return; - } - window[className] = function () { - var a = Zone.bindArguments(arguments); - switch (a.length) { - case 0: this._o = new OriginalClass(); break; - case 1: this._o = new OriginalClass(a[0]); break; - case 2: this._o = new OriginalClass(a[0], a[1]); break; - case 3: this._o = new OriginalClass(a[0], a[1], a[2]); break; - case 4: this._o = new OriginalClass(a[0], a[1], a[2], a[3]); break; - default: throw new Error('what are you even doing?'); - } - }; - - var instance = new OriginalClass(className.substr(-16) === 'MutationObserver' ? function () {} : undefined); - - var prop; - for (prop in instance) { - (function (prop) { - if (typeof instance[prop] === 'function') { - window[className].prototype[prop] = function () { - return this._o[prop].apply(this._o, arguments); - }; - } else { - Object.defineProperty(window[className].prototype, prop, { - set: function (fn) { - if (typeof fn === 'function') { - this._o[prop] = zone.bind(fn); - } else { - this._o[prop] = fn; - } - }, - get: function () { - return this._o[prop]; - } - }); - } - }(prop)); - }; -}; - - -// wrap some native API on `window` -Zone.patchMutationObserverClass = function (className) { - var OriginalClass = window[className]; - if (!OriginalClass) { - return; - } - window[className] = function (fn) { - this._o = new OriginalClass(zone.bind(fn, true)); - }; - - var instance = new OriginalClass(function () {}); - - window[className].prototype.disconnect = function () { - var result = this._o.disconnect.apply(this._o, arguments); - this._active && zone.dequeueTask(); - this._active = false; - return result; - }; - - window[className].prototype.observe = function () { - if (!this._active) { - zone.enqueueTask(); - } - this._active = true; - return this._o.observe.apply(this._o, arguments); - }; - - var prop; - for (prop in instance) { - (function (prop) { - if (typeof window[className].prototype !== undefined) { - return; - } - if (typeof instance[prop] === 'function') { - window[className].prototype[prop] = function () { - return this._o[prop].apply(this._o, arguments); - }; - } else { - Object.defineProperty(window[className].prototype, prop, { - set: function (fn) { - if (typeof fn === 'function') { - this._o[prop] = zone.bind(fn); - } else { - this._o[prop] = fn; - } - }, - get: function () { - return this._o[prop]; - } - }); - } - }(prop)); - } -}; - -// might need similar for object.freeze -// i regret nothing -Zone.patchDefineProperty = function () { - var _defineProperty = Object.defineProperty; - var _getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; - var _create = Object.create; - - Object.defineProperty = function (obj, prop, desc) { - if (isUnconfigurable(obj, prop)) { - throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj); - } - if (prop !== 'prototype') { - desc = rewriteDescriptor(obj, prop, desc); - } - return _defineProperty(obj, prop, desc); - }; - - Object.defineProperties = function (obj, props) { - Object.keys(props).forEach(function (prop) { - Object.defineProperty(obj, prop, props[prop]); - }); - return obj; - }; - - Object.create = function (obj, proto) { - if (typeof proto === 'object') { - Object.keys(proto).forEach(function (prop) { - proto[prop] = rewriteDescriptor(obj, prop, proto[prop]); - }); - } - return _create(obj, proto); - }; - - Object.getOwnPropertyDescriptor = function (obj, prop) { - var desc = _getOwnPropertyDescriptor(obj, prop); - if (isUnconfigurable(obj, prop)) { - desc.configurable = false; - } - return desc; - }; - - Zone._redefineProperty = function (obj, prop, desc) { - desc = rewriteDescriptor(obj, prop, desc); - return _defineProperty(obj, prop, desc); - }; - - function isUnconfigurable (obj, prop) { - return obj && obj.__unconfigurables && obj.__unconfigurables[prop]; - } - - function rewriteDescriptor (obj, prop, desc) { - desc.configurable = true; - if (!desc.configurable) { - if (!obj.__unconfigurables) { - _defineProperty(obj, '__unconfigurables', { writable: true, value: {} }); - } - obj.__unconfigurables[prop] = true; - } - return desc; - } -}; - -Zone.patchRegisterElement = function () { - if (!('registerElement' in document)) { - return; - } - var _registerElement = document.registerElement; - var callbacks = [ - 'createdCallback', - 'attachedCallback', - 'detachedCallback', - 'attributeChangedCallback' - ]; - document.registerElement = function (name, opts) { - callbacks.forEach(function (callback) { - if (opts.prototype[callback]) { - var descriptor = Object.getOwnPropertyDescriptor(opts.prototype, callback); - if (descriptor.value) { - descriptor.value = zone.bind(descriptor.value || opts.prototype[callback]); - Zone._redefineProperty(opts.prototype, callback, descriptor); - } - } - }); - return _registerElement.apply(document, [name, opts]); - }; -} - -Zone.eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart message mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error webglcontextrestored webglcontextlost webglcontextcreationerror'.split(' '); -Zone.onEventNames = Zone.eventNames.map(function (property) { - return 'on' + property; -}); - -Zone.init = function init () { - exports.zone = zone = new Zone(); - Zone.patch(); -}; - - -Zone.init(); - -exports.Zone = Zone; - -}((typeof module !== 'undefined' && module && module.exports) ? - module.exports : window));