From d2eb4f807faa24d70ad64e40857ee99c41814712 Mon Sep 17 00:00:00 2001 From: Hristo Deshev Date: Tue, 13 Sep 2016 13:25:43 +0300 Subject: [PATCH 1/3] feat(zone): Use zone-nativescript vendored below ./zone.js Add a document describing the zone.js upgrade process. --- doc/upgrading-zonejs.md | 15 + nativescript-angular/package.json | 2 +- nativescript-angular/platform.ts | 2 +- .../zone.js/dist/zone-nativescript.js | 842 ++++++++++++++++++ ng-sample/package.json | 4 +- tests/package.json | 3 +- 6 files changed, 862 insertions(+), 6 deletions(-) create mode 100644 doc/upgrading-zonejs.md create mode 100644 nativescript-angular/zone.js/dist/zone-nativescript.js diff --git a/doc/upgrading-zonejs.md b/doc/upgrading-zonejs.md new file mode 100644 index 000000000..d99dc2083 --- /dev/null +++ b/doc/upgrading-zonejs.md @@ -0,0 +1,15 @@ +# Upgrading Zone.js + +`nativescript-angular` uses a fork of the `zone.js` package in order to work around incompatibilities between node, browser, and mobile implementations. + +The fork resides at https://github.com/NativeScript/zone.js in the `zone-nativescript` branch. It adds a separate `lib/nativescript/nativescript.ts` entry point that is used to generate a new bundle: `dist/zone-nativescript.js`. + +To upgrade to a newer release of `zone.js`: + +1. Identify the upgrade target -- most likely a release tag. +2. Rebase the `zone-nativescript` branch on top of the upgrade target. +3. Rebuild: `gulp build` +4. Run the node-based smoke tests: `gulp test/nativescript` +5. Run the browser tests: `node_modules/.bin/karma start karma.conf.js --single-run` (You need to run node `test/ws-server.js` in a separate console first) +6. Commit `dist/zone-nativescript.js`, drop the previous `dist/zone-nativescript.js` commit from the branch. Force push the new `zone-nativescript` branch to GitHub. +7. Update your copy of `nativescript-angular/zone.js/dist/zone-nativescript.js` with the bundle you just built. diff --git a/nativescript-angular/package.json b/nativescript-angular/package.json index 76d9d0068..2916f030b 100644 --- a/nativescript-angular/package.json +++ b/nativescript-angular/package.json @@ -29,7 +29,6 @@ "@angular/forms": "2.0.0-rc.6", "@angular/router": "3.0.0-rc.2", "rxjs": "5.0.0-beta.11", - "zone.js": "^0.6.17", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -38,6 +37,7 @@ }, "devDependencies": { "tns-core-modules": ">=2.2.0 || >=2.2.0-2016", + "zone.js": "^0.6.17", "typescript": "^1.8.10" }, "nativescript": {} diff --git a/nativescript-angular/platform.ts b/nativescript-angular/platform.ts index 8a6e0b37e..63aa3a1ba 100644 --- a/nativescript-angular/platform.ts +++ b/nativescript-angular/platform.ts @@ -1,5 +1,5 @@ import 'globals'; -import "zone.js/dist/zone-node"; +import "./zone.js/dist/zone-nativescript"; import 'reflect-metadata'; import './polyfills/array'; diff --git a/nativescript-angular/zone.js/dist/zone-nativescript.js b/nativescript-angular/zone.js/dist/zone-nativescript.js new file mode 100644 index 000000000..efe8c40c5 --- /dev/null +++ b/nativescript-angular/zone.js/dist/zone-nativescript.js @@ -0,0 +1,842 @@ +var Zone$1 = (function (global) { + if (global.Zone) { + throw new Error('Zone already loaded.'); + } + var Zone = (function () { + function Zone(parent, zoneSpec) { + this._properties = null; + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = zoneSpec && zoneSpec.properties || {}; + this._zoneDelegate = new ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + Zone.assertZonePatched = function () { + if (global.Promise !== ZoneAwarePromise) { + throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` " + + "has been overwritten.\n" + + "Most likely cause is that a Promise polyfill has been loaded " + + "after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. " + + "If you must load one, do so before loading zone.js.)"); + } + }; + Object.defineProperty(Zone, "current", { + get: function () { return _currentZone; }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(Zone, "currentTask", { + get: function () { return _currentTask; }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(Zone.prototype, "parent", { + get: function () { return this._parent; }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(Zone.prototype, "name", { + get: function () { return this._name; }, + enumerable: true, + configurable: true + }); + + Zone.prototype.get = function (key) { + var zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + }; + Zone.prototype.getZoneWith = function (key) { + var current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + }; + Zone.prototype.fork = function (zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + }; + Zone.prototype.wrap = function (callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + var _callback = this._zoneDelegate.intercept(this, callback, source); + var zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + }; + Zone.prototype.run = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + if (applyArgs === void 0) { applyArgs = null; } + if (source === void 0) { source = null; } + var oldZone = _currentZone; + _currentZone = this; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZone = oldZone; + } + }; + Zone.prototype.runGuarded = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + if (applyArgs === void 0) { applyArgs = null; } + if (source === void 0) { source = null; } + var oldZone = _currentZone; + _currentZone = this; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZone = oldZone; + } + }; + Zone.prototype.runTask = function (task, applyThis, applyArgs) { + task.runCount++; + if (task.zone != this) + throw new Error('A task can only be run in the zone which created it! (Creation: ' + + task.zone.name + '; Execution: ' + this.name + ')'); + var previousTask = _currentTask; + _currentTask = task; + var oldZone = _currentZone; + _currentZone = this; + try { + if (task.type == 'macroTask' && task.data && !task.data.isPeriodic) { + task.cancelFn = null; + } + try { + return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZone = oldZone; + _currentTask = previousTask; + } + }; + Zone.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { + return this._zoneDelegate.scheduleTask(this, new ZoneTask('microTask', this, source, callback, data, customSchedule, null)); + }; + Zone.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { + return this._zoneDelegate.scheduleTask(this, new ZoneTask('macroTask', this, source, callback, data, customSchedule, customCancel)); + }; + Zone.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { + return this._zoneDelegate.scheduleTask(this, new ZoneTask('eventTask', this, source, callback, data, customSchedule, customCancel)); + }; + Zone.prototype.cancelTask = function (task) { + var value = this._zoneDelegate.cancelTask(this, task); + task.runCount = -1; + task.cancelFn = null; + return value; + }; + Zone.__symbol__ = __symbol__; + return Zone; + }()); + + var ZoneDelegate = (function () { + function ZoneDelegate(zone, parentDelegate, zoneSpec) { + this._taskCounts = { microTask: 0, macroTask: 0, eventTask: 0 }; + this.zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._interceptZS = zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._handleErrorZS = zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._scheduleTaskZS = zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._invokeTaskZS = zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._cancelTaskZS = zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._hasTaskZS = zoneSpec && (zoneSpec.onHasTask ? zoneSpec : parentDelegate._hasTaskZS); + this._hasTaskDlgt = zoneSpec && (zoneSpec.onHasTask ? parentDelegate : parentDelegate._hasTaskDlgt); + } + ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new Zone(targetZone, zoneSpec); + }; + ZoneDelegate.prototype.intercept = function (targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this.zone, targetZone, callback, source) + : callback; + }; + ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this.zone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + }; + ZoneDelegate.prototype.handleError = function (targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this.zone, targetZone, error) + : true; + }; + ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { + try { + if (this._scheduleTaskZS) { + return this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this.zone, targetZone, task); + } + else if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == 'microTask') { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + return task; + } + finally { + if (targetZone == this.zone) { + this._updateTaskCount(task.type, 1); + } + } + }; + ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { + try { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this.zone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + } + finally { + if (targetZone == this.zone && (task.type != 'eventTask') && !(task.data && task.data.isPeriodic)) { + this._updateTaskCount(task.type, -1); + } + } + }; + ZoneDelegate.prototype.cancelTask = function (targetZone, task) { + var value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this.zone, targetZone, task); + } + else if (!task.cancelFn) { + throw new Error('Task does not support cancellation, or is already canceled.'); + } + else { + value = task.cancelFn(task); + } + if (targetZone == this.zone) { + // this should not be in the finally block, because exceptions assume not canceled. + this._updateTaskCount(task.type, -1); + } + return value; + }; + ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { + return this._hasTaskZS && this._hasTaskZS.onHasTask(this._hasTaskDlgt, this.zone, targetZone, isEmpty); + }; + ZoneDelegate.prototype._updateTaskCount = function (type, count) { + var counts = this._taskCounts; + var prev = counts[type]; + var next = counts[type] = prev + count; + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + var isEmpty = { + microTask: counts.microTask > 0, + macroTask: counts.macroTask > 0, + eventTask: counts.eventTask > 0, + change: type + }; + try { + this.hasTask(this.zone, isEmpty); + } + finally { + if (this._parentDelegate) { + this._parentDelegate._updateTaskCount(type, count); + } + } + } + }; + return ZoneDelegate; + }()); + var ZoneTask = (function () { + function ZoneTask(type, zone, source, callback, options, scheduleFn, cancelFn) { + this.runCount = 0; + this.type = type; + this.zone = zone; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + this.callback = callback; + var self = this; + this.invoke = function () { + _numberOfNestedTaskFrames++; + try { + return zone.runTask(self, this, arguments); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + }; + } + ZoneTask.prototype.toString = function () { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId; + } + else { + return this.toString(); + } + }; + return ZoneTask; + }()); + function __symbol__(name) { return '__zone_symbol__' + name; } + + var symbolSetTimeout = __symbol__('setTimeout'); + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var _currentZone = new Zone(null, null); + var _currentTask = null; + var _microTaskQueue = []; + var _isDrainingMicrotaskQueue = false; + var _uncaughtPromiseErrors = []; + var _numberOfNestedTaskFrames = 0; + function scheduleQueueDrain() { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames == 0 && _microTaskQueue.length == 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + if (global[symbolPromise]) { + global[symbolPromise].resolve(0)[symbolThen](drainMicroTaskQueue); + } + else { + global[symbolSetTimeout](drainMicroTaskQueue, 0); + } + } + } + function scheduleMicroTask(task) { + scheduleQueueDrain(); + _microTaskQueue.push(task); + } + function consoleError(e) { + var rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + console.error(e); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + var queue = _microTaskQueue; + _microTaskQueue = []; + for (var i = 0; i < queue.length; i++) { + var task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (e) { + consoleError(e); + } + } + } + while (_uncaughtPromiseErrors.length) { + var _loop_1 = function() { + var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(function () { throw uncaughtPromiseError; }); + } + catch (e) { + consoleError(e); + } + }; + while (_uncaughtPromiseErrors.length) { + _loop_1(); + } + } + _isDrainingMicrotaskQueue = false; + } + } + function isThenable(value) { + return value && value.then; + } + function forwardResolution(value) { return value; } + function forwardRejection(rejection) { return ZoneAwarePromise.reject(rejection); } + var symbolState = __symbol__('state'); + var symbolValue = __symbol__('value'); + var source = 'Promise.then'; + var UNRESOLVED = null; + var RESOLVED = true; + var REJECTED = false; + var REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return function (v) { + resolvePromise(promise, state, v); + // Do not return value or you will break the Promise spec. + }; + } + function resolvePromise(promise, state, value) { + if (promise[symbolState] === UNRESOLVED) { + if (value instanceof ZoneAwarePromise && value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (isThenable(value)) { + value.then(makeResolver(promise, state), makeResolver(promise, false)); + } + else { + promise[symbolState] = state; + var queue = promise[symbolValue]; + promise[symbolValue] = value; + for (var i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + try { + throw new Error("Uncaught (in promise): " + value); + } + catch (e) { + var error = e; + error.rejection = value; + error.promise = promise; + error.zone = Zone.current; + error.task = Zone.currentTask; + _uncaughtPromiseErrors.push(error); + scheduleQueueDrain(); + } + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + promise[symbolState] = REJECTED; + for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + break; + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + var delegate = promise[symbolState] ? onFulfilled || forwardResolution : onRejected || forwardRejection; + zone.scheduleMicroTask(source, function () { + try { + resolvePromise(chainPromise, true, zone.run(delegate, null, [promise[symbolValue]])); + } + catch (error) { + resolvePromise(chainPromise, false, error); + } + }); + } + var ZoneAwarePromise = (function () { + function ZoneAwarePromise(executor) { + var promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + executor && executor(makeResolver(promise, RESOLVED), makeResolver(promise, REJECTED)); + } + catch (e) { + resolvePromise(promise, false, e); + } + } + ZoneAwarePromise.resolve = function (value) { + return resolvePromise(new this(null), RESOLVED, value); + }; + ZoneAwarePromise.reject = function (error) { + return resolvePromise(new this(null), REJECTED, error); + }; + ZoneAwarePromise.race = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { resolve = res; reject = rej; }); + function onResolve(value) { promise && (promise = null || resolve(value)); } + function onReject(error) { promise && (promise = null || reject(error)); } + for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { + var value = values_1[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + }; + ZoneAwarePromise.all = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { resolve = res; reject = rej; }); + var count = 0; + var resolvedValues = []; + for (var _i = 0, values_2 = values; _i < values_2.length; _i++) { + var value = values_2[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then((function (index) { return function (value) { + resolvedValues[index] = value; + count--; + if (!count) { + resolve(resolvedValues); + } + }; })(count), reject); + count++; + } + if (!count) + resolve(resolvedValues); + return promise; + }; + ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) { + var chainPromise = new this.constructor(null); + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + }; + ZoneAwarePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); + }; + return ZoneAwarePromise; + }()); + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + var NativePromise = global[__symbol__('Promise')] = global.Promise; + global.Promise = ZoneAwarePromise; + function patchThen(NativePromise) { + var NativePromiseProtototype = NativePromise.prototype; + var NativePromiseThen = NativePromiseProtototype[__symbol__('then')] + = NativePromiseProtototype.then; + NativePromiseProtototype.then = function (onResolve, onReject) { + var nativePromise = this; + return new ZoneAwarePromise(function (resolve, reject) { + NativePromiseThen.call(nativePromise, resolve, reject); + }).then(onResolve, onReject); + }; + } + if (NativePromise) { + patchThen(NativePromise); + if (typeof global['fetch'] !== 'undefined') { + var fetchPromise = global['fetch'](); + // ignore output to prevent error; + fetchPromise.then(function () { return null; }, function () { return null; }); + if (fetchPromise.constructor != NativePromise && fetchPromise.constructor != ZoneAwarePromise) { + patchThen(fetchPromise.constructor); + } + } + } + // This is not part of public API, but it is usefull for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return global.Zone = Zone; +})(typeof window === 'object' && window || typeof self === 'object' && self || global); + +/** + * Suppress closure compiler errors about unknown 'process' variable + * @fileoverview + * @suppress {undefinedVars} + */ +var zoneSymbol = Zone['__symbol__']; +var _global = typeof window === 'object' && window || typeof self === 'object' && self || global; +function bindArguments(args, source) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = Zone.current.wrap(args[i], source + '_' + i); + } + } + return args; +} + + + + +var isNode = (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'); + +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') { + var wrapFn = function (event) { + var result; + result = fn.apply(this, arguments); + if (result != undefined && !result) + event.preventDefault(); + }; + this[_prop] = wrapFn; + this.addEventListener(eventName, wrapFn, false); + } + else { + this[_prop] = null; + } + }; + // The getter would return undefined for unassigned properties but the default value of an unassigned property is null + desc.get = function () { + return this[_prop] || null; + }; + Object.defineProperty(obj, prop, desc); +} + + + +var EVENT_TASKS = zoneSymbol('eventTasks'); +// For EventTarget +var ADD_EVENT_LISTENER = 'addEventListener'; +var REMOVE_EVENT_LISTENER = 'removeEventListener'; +function findExistingRegisteredTask(target, handler, name, capture, remove) { + var eventTasks = target[EVENT_TASKS]; + if (eventTasks) { + for (var i = 0; i < eventTasks.length; i++) { + var eventTask = eventTasks[i]; + var data = eventTask.data; + if (data.handler === handler + && data.useCapturing === capture + && data.eventName === name) { + if (remove) { + eventTasks.splice(i, 1); + } + return eventTask; + } + } + } + return null; +} +function attachRegisteredEvent(target, eventTask) { + var eventTasks = target[EVENT_TASKS]; + if (!eventTasks) { + eventTasks = target[EVENT_TASKS] = []; + } + eventTasks.push(eventTask); +} +function makeZoneAwareAddListener(addFnName, removeFnName, useCapturingParam, allowDuplicates) { + if (useCapturingParam === void 0) { useCapturingParam = true; } + if (allowDuplicates === void 0) { allowDuplicates = false; } + var addFnSymbol = zoneSymbol(addFnName); + var removeFnSymbol = zoneSymbol(removeFnName); + var defaultUseCapturing = useCapturingParam ? false : undefined; + function scheduleEventListener(eventTask) { + var meta = eventTask.data; + attachRegisteredEvent(meta.target, eventTask); + return meta.target[addFnSymbol](meta.eventName, eventTask.invoke, meta.useCapturing); + } + function cancelEventListener(eventTask) { + var meta = eventTask.data; + findExistingRegisteredTask(meta.target, eventTask.invoke, meta.eventName, meta.useCapturing, true); + meta.target[removeFnSymbol](meta.eventName, eventTask.invoke, meta.useCapturing); + } + return function zoneAwareAddListener(self, args) { + var eventName = args[0]; + var handler = args[1]; + var useCapturing = args[2] || defaultUseCapturing; + // - Inside a Web Worker, `this` is undefined, the context is `global` + // - When `addEventListener` is called on the global context in strict mode, `this` is undefined + // see https://github.com/angular/zone.js/issues/190 + var target = self || _global; + var delegate = null; + if (typeof handler == 'function') { + delegate = handler; + } + else if (handler && handler.handleEvent) { + delegate = function (event) { return handler.handleEvent(event); }; + } + var validZoneHandler = false; + try { + // In cross site contexts (such as WebDriver frameworks like Selenium), + // accessing the handler object here will cause an exception to be thrown which + // will fail tests prematurely. + validZoneHandler = handler && handler.toString() === "[object FunctionWrapper]"; + } + catch (e) { + // Returning nothing here is fine, because objects in a cross-site context are unusable + return; + } + // Ignore special listeners of IE11 & Edge dev tools, see https://github.com/angular/zone.js/issues/150 + if (!delegate || validZoneHandler) { + return target[addFnSymbol](eventName, handler, useCapturing); + } + if (!allowDuplicates) { + var eventTask = findExistingRegisteredTask(target, handler, eventName, useCapturing, false); + if (eventTask) { + // we already registered, so this will have noop. + return target[addFnSymbol](eventName, eventTask.invoke, useCapturing); + } + } + var zone = Zone.current; + var source = target.constructor['name'] + '.' + addFnName + ':' + eventName; + var data = { + target: target, + eventName: eventName, + name: eventName, + useCapturing: useCapturing, + handler: handler + }; + zone.scheduleEventTask(source, delegate, data, scheduleEventListener, cancelEventListener); + }; +} +function makeZoneAwareRemoveListener(fnName, useCapturingParam) { + if (useCapturingParam === void 0) { useCapturingParam = true; } + var symbol = zoneSymbol(fnName); + var defaultUseCapturing = useCapturingParam ? false : undefined; + return function zoneAwareRemoveListener(self, args) { + var eventName = args[0]; + var handler = args[1]; + var useCapturing = args[2] || defaultUseCapturing; + // - Inside a Web Worker, `this` is undefined, the context is `global` + // - When `addEventListener` is called on the global context in strict mode, `this` is undefined + // see https://github.com/angular/zone.js/issues/190 + var target = self || _global; + var eventTask = findExistingRegisteredTask(target, handler, eventName, useCapturing, true); + if (eventTask) { + eventTask.zone.cancelTask(eventTask); + } + else { + target[symbol](eventName, handler, useCapturing); + } + }; +} + +var zoneAwareAddEventListener = makeZoneAwareAddListener(ADD_EVENT_LISTENER, REMOVE_EVENT_LISTENER); +var zoneAwareRemoveEventListener = makeZoneAwareRemoveListener(REMOVE_EVENT_LISTENER); + +var originalInstanceKey = zoneSymbol('originalInstance'); +// wrap some native API on `window` + + +function createNamedFn(name, delegate) { + try { + return (Function('f', "return function " + name + "(){return f(this, arguments)}"))(delegate); + } + catch (e) { + // if we fail, we must be CSP, just return delegate. + return function () { + return delegate(this, arguments); + }; + } +} +function patchMethod(target, name, patchFn) { + var proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = Object.getPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + var delegateName = zoneSymbol(name); + var delegate; + if (proto && !(delegate = proto[delegateName])) { + delegate = proto[delegateName] = proto[name]; + proto[name] = createNamedFn(name, patchFn(delegate, delegateName, name)); + } + return delegate; +} + +function patchTimer(window, setName, cancelName, nameSuffix) { + var setNative = null; + var clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + function scheduleTask(task) { + var data = task.data; + data.args[0] = task.invoke; + data.handleId = setNative.apply(window, data.args); + return task; + } + function clearTask(task) { + return clearNative(task.data.handleId); + } + setNative = patchMethod(window, setName, function (delegate) { return function (self, args) { + if (typeof args[0] === 'function') { + var zone = Zone.current; + var options = { + handleId: null, + isPeriodic: nameSuffix === 'Interval', + delay: (nameSuffix === 'Timeout' || nameSuffix === 'Interval') ? args[1] || 0 : null, + args: args + }; + var task = zone.scheduleMacroTask(setName, args[0], options, scheduleTask, clearTask); + if (!task) { + return task; + } + // Node.js must additionally support the ref and unref functions. + var handle = task.data.handleId; + if (handle.ref && handle.unref) { + task.ref = handle.ref.bind(handle); + task.unref = handle.unref.bind(handle); + } + return task; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }; }); + clearNative = patchMethod(window, cancelName, function (delegate) { return function (self, args) { + var task = args[0]; + if (task && typeof task.type === 'string') { + if (task.cancelFn && task.data.isPeriodic || task.runCount === 0) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }; }); +} + +var set = 'set'; +var clear = 'clear'; +// Timers +patchTimer(global, set, clear, 'Timeout'); +patchTimer(global, set, clear, 'Interval'); +patchTimer(global, set, clear, 'Immediate'); \ No newline at end of file diff --git a/ng-sample/package.json b/ng-sample/package.json index a81513886..a77760cc1 100644 --- a/ng-sample/package.json +++ b/ng-sample/package.json @@ -35,7 +35,6 @@ "@angular/platform-server": "2.0.0-rc.6", "@angular/router": "3.0.0-rc.2", "rxjs": "5.0.0-beta.11", - "zone.js": "^0.6.17", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -43,6 +42,7 @@ "url": "0.10.3" }, "devDependencies": { + "zone.js": "^0.6.17", "babel-traverse": "6.9.0", "babel-types": "6.10.0", "babylon": "6.8.1", @@ -62,4 +62,4 @@ "version": "2.2.1" } } -} +} \ No newline at end of file diff --git a/tests/package.json b/tests/package.json index 6c4fd5c0c..9cc96aa1a 100644 --- a/tests/package.json +++ b/tests/package.json @@ -35,7 +35,6 @@ "@angular/platform-server": "2.0.0-rc.6", "@angular/router": "3.0.0-rc.2", "rxjs": "5.0.0-beta.11", - "zone.js": "^0.6.17", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -68,4 +67,4 @@ "run-appium-android": "nativescript-dev-appium android", "appium-ios-simulator": "tns build ios && nativescript-dev-appium ios-simulator" } -} \ No newline at end of file +} From 4f20e0f69e079636dd14737d3dac9a1d272fa55e Mon Sep 17 00:00:00 2001 From: Hristo Deshev Date: Tue, 13 Sep 2016 14:55:02 +0300 Subject: [PATCH 2/3] feat(ng): Upgrade to RC7 --- nativescript-angular/package.json | 22 +++++++++++----------- ng-sample/app/app.ts | 7 ++----- ng-sample/package.json | 20 ++++++++++---------- tests/app/tests/modal-dialog.ts | 2 ++ tests/package.json | 21 +++++++++++---------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/nativescript-angular/package.json b/nativescript-angular/package.json index 2916f030b..09cf507fc 100644 --- a/nativescript-angular/package.json +++ b/nativescript-angular/package.json @@ -19,16 +19,16 @@ }, "dependencies": { "nativescript-intl": "^0.0.4", - "@angular/core": "2.0.0-rc.6", - "@angular/common": "2.0.0-rc.6", - "@angular/compiler": "2.0.0-rc.6", - "@angular/http": "2.0.0-rc.6", - "@angular/platform-browser": "2.0.0-rc.6", - "@angular/platform-browser-dynamic": "2.0.0-rc.6", - "@angular/platform-server": "2.0.0-rc.6", - "@angular/forms": "2.0.0-rc.6", - "@angular/router": "3.0.0-rc.2", - "rxjs": "5.0.0-beta.11", + "@angular/core": "2.0.0-rc.7", + "@angular/common": "2.0.0-rc.7", + "@angular/compiler": "2.0.0-rc.7", + "@angular/http": "2.0.0-rc.7", + "@angular/platform-browser": "2.0.0-rc.7", + "@angular/platform-browser-dynamic": "2.0.0-rc.7", + "@angular/platform-server": "2.0.0-rc.7", + "@angular/forms": "2.0.0-rc.7", + "@angular/router": "3.0.0-rc.3", + "rxjs": "5.0.0-beta.12", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -37,7 +37,7 @@ }, "devDependencies": { "tns-core-modules": ">=2.2.0 || >=2.2.0-2016", - "zone.js": "^0.6.17", + "zone.js": "^0.6.21", "typescript": "^1.8.10" }, "nativescript": {} diff --git a/ng-sample/app/app.ts b/ng-sample/app/app.ts index 11e1bf57f..44b353f18 100644 --- a/ng-sample/app/app.ts +++ b/ng-sample/app/app.ts @@ -45,9 +45,6 @@ import { AnimationKeyframesTest } from "./examples/animation/animation-keyframes import { AnimationNgClassTest } from "./examples/animation/animation-ngclass-test"; import { AnimationStatesTest } from "./examples/animation/animation-states-test"; -//nativeScriptBootstrap(ActionBarTest, [NS_ROUTER_PROVIDERS_DEPRECATED], { startPageActionBarHidden: false }); -//nativeScriptBootstrap(ActionBarTest, [NS_ROUTER_PROVIDERS_DEPRECATED]); - @NgModule({ declarations: [ ], @@ -122,7 +119,7 @@ function makeExampleModule(componentType) { //platformNativeScriptDynamic().bootstrapModule(makeExampleModule(AnimationStatesTest)); //platformNativeScriptDynamic().bootstrapModule(makeExampleModule(AnimationNgClassTest)); //platformNativeScriptDynamic().bootstrapModule(makeExampleModule(AnimationKeyframesTest)); -platformNativeScriptDynamic().bootstrapModule(makeExampleModule(AnimationEnterLeaveTest)); +//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(AnimationEnterLeaveTest)); //Livesync test var cachedUrl: string; @@ -144,5 +141,5 @@ onAfterLivesync.subscribe((moduleRef) => { } }); -//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(LivesyncApp)); +platformNativeScriptDynamic().bootstrapModule(makeExampleModule(LivesyncApp)); console.log("APP RESTART"); diff --git a/ng-sample/package.json b/ng-sample/package.json index a77760cc1..7801b446e 100644 --- a/ng-sample/package.json +++ b/ng-sample/package.json @@ -26,15 +26,15 @@ "tns-core-modules": "2.2.1", "nativescript-angular": "file:../nativescript-angular", "nativescript-intl": "^0.0.2", - "@angular/core": "2.0.0-rc.6", - "@angular/common": "2.0.0-rc.6", - "@angular/compiler": "2.0.0-rc.6", - "@angular/http": "2.0.0-rc.6", - "@angular/platform-browser": "2.0.0-rc.6", - "@angular/platform-browser-dynamic": "2.0.0-rc.6", - "@angular/platform-server": "2.0.0-rc.6", - "@angular/router": "3.0.0-rc.2", - "rxjs": "5.0.0-beta.11", + "@angular/core": "2.0.0-rc.7", + "@angular/common": "2.0.0-rc.7", + "@angular/compiler": "2.0.0-rc.7", + "@angular/http": "2.0.0-rc.7", + "@angular/platform-browser": "2.0.0-rc.7", + "@angular/platform-browser-dynamic": "2.0.0-rc.7", + "@angular/platform-server": "2.0.0-rc.7", + "@angular/router": "3.0.0-rc.3", + "rxjs": "5.0.0-beta.12", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -42,7 +42,7 @@ "url": "0.10.3" }, "devDependencies": { - "zone.js": "^0.6.17", + "zone.js": "^0.6.21", "babel-traverse": "6.9.0", "babel-types": "6.10.0", "babylon": "6.8.1", diff --git a/tests/app/tests/modal-dialog.ts b/tests/app/tests/modal-dialog.ts index dcb5dc74c..6458e3876 100644 --- a/tests/app/tests/modal-dialog.ts +++ b/tests/app/tests/modal-dialog.ts @@ -24,6 +24,7 @@ export class ModalComponent { @Component({ selector: "fail-comp", + providers: [ModalDialogService], template: `` }) @@ -34,6 +35,7 @@ export class FailComponent { @Component({ selector: "sucess-comp", + providers: [ModalDialogService], template: ` diff --git a/tests/package.json b/tests/package.json index 9cc96aa1a..97205fa26 100644 --- a/tests/package.json +++ b/tests/package.json @@ -26,15 +26,15 @@ "nativescript-unit-test-runner": "^0.3.3", "tns-core-modules": "2.2.1", "nativescript-angular": "file:../nativescript-angular", - "@angular/core": "2.0.0-rc.6", - "@angular/common": "2.0.0-rc.6", - "@angular/compiler": "2.0.0-rc.6", - "@angular/http": "2.0.0-rc.6", - "@angular/platform-browser": "2.0.0-rc.6", - "@angular/platform-browser-dynamic": "2.0.0-rc.6", - "@angular/platform-server": "2.0.0-rc.6", - "@angular/router": "3.0.0-rc.2", - "rxjs": "5.0.0-beta.11", + "@angular/core": "2.0.0-rc.7", + "@angular/common": "2.0.0-rc.7", + "@angular/compiler": "2.0.0-rc.7", + "@angular/http": "2.0.0-rc.7", + "@angular/platform-browser": "2.0.0-rc.7", + "@angular/platform-browser-dynamic": "2.0.0-rc.7", + "@angular/platform-server": "2.0.0-rc.7", + "@angular/router": "3.0.0-rc.3", + "rxjs": "5.0.0-beta.12", "reflect-metadata": "^0.1.8", "parse5": "1.3.2", "punycode": "1.3.2", @@ -42,6 +42,7 @@ "url": "0.10.3" }, "devDependencies": { + "zone.js": "^0.6.21", "babel-traverse": "6.8.0", "babel-types": "6.8.1", "babylon": "6.8.0", @@ -67,4 +68,4 @@ "run-appium-android": "nativescript-dev-appium android", "appium-ios-simulator": "tns build ios && nativescript-dev-appium ios-simulator" } -} +} \ No newline at end of file From c29da8f1ca9582b418472b059d9e1c4607ed2466 Mon Sep 17 00:00:00 2001 From: Hristo Deshev Date: Tue, 13 Sep 2016 15:55:20 +0300 Subject: [PATCH 3/3] Version bump: 0.6.0 --- nativescript-angular/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nativescript-angular/package.json b/nativescript-angular/package.json index 09cf507fc..425b4e16f 100644 --- a/nativescript-angular/package.json +++ b/nativescript-angular/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "nativescript-angular", - "version": "0.5.1", + "version": "0.6.0", "description": "An Angular 2 renderer that lets you build mobile apps with NativeScript.", "homepage": "http://www.telerik.com", "bugs": "http://www.telerik.com",