| |
| /*! Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */ |
| (function () { |
| |
| var globalObject = |
| typeof window !== 'undefined' ? window : |
| typeof self !== 'undefined' ? self : |
| typeof global !== 'undefined' ? global : |
| {}; |
| (function (factory) { |
| if (typeof define === 'function' && define.amd) { |
| // amd |
| define([], factory); |
| } else { |
| globalObject.msWriteProfilerMark && msWriteProfilerMark('WinJS.4.4 4.4.0.winjs.2015.10.2 base.js,StartTM'); |
| if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { |
| // CommonJS |
| factory(); |
| } else { |
| // No module system |
| factory(globalObject.WinJS); |
| } |
| globalObject.msWriteProfilerMark && msWriteProfilerMark('WinJS.4.4 4.4.0.winjs.2015.10.2 base.js,StopTM'); |
| } |
| }(function (WinJS) { |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| /*jshint ignore:start */ |
| var require; |
| var define; |
| /*jshint ignore:end */ |
| |
| (function () { |
| "use strict"; |
| |
| var defined = {}; |
| define = function (id, dependencies, factory) { |
| if (!Array.isArray(dependencies)) { |
| factory = dependencies; |
| dependencies = []; |
| } |
| |
| var mod = { |
| dependencies: normalize(id, dependencies), |
| factory: factory |
| }; |
| |
| if (dependencies.indexOf('exports') !== -1) { |
| mod.exports = {}; |
| } |
| |
| defined[id] = mod; |
| }; |
| |
| // WinJS/Core depends on ./Core/_Base |
| // should return WinJS/Core/_Base |
| function normalize(id, dependencies) { |
| id = id || ""; |
| var parent = id.split('/'); |
| parent.pop(); |
| return dependencies.map(function (dep) { |
| if (dep[0] === '.') { |
| var parts = dep.split('/'); |
| var current = parent.slice(0); |
| parts.forEach(function (part) { |
| if (part === '..') { |
| current.pop(); |
| } else if (part !== '.') { |
| current.push(part); |
| } |
| }); |
| return current.join('/'); |
| } else { |
| return dep; |
| } |
| }); |
| } |
| |
| function resolve(dependencies, parent, exports) { |
| return dependencies.map(function (depName) { |
| if (depName === 'exports') { |
| return exports; |
| } |
| |
| if (depName === 'require') { |
| return function (dependencies, factory) { |
| require(normalize(parent, dependencies), factory); |
| }; |
| } |
| |
| var dep = defined[depName]; |
| if (!dep) { |
| throw new Error("Undefined dependency: " + depName); |
| } |
| |
| if (!dep.resolved) { |
| dep.resolved = load(dep.dependencies, dep.factory, depName, dep.exports); |
| if (typeof dep.resolved === "undefined") { |
| dep.resolved = dep.exports; |
| } |
| } |
| |
| return dep.resolved; |
| }); |
| } |
| |
| function load(dependencies, factory, parent, exports) { |
| var deps = resolve(dependencies, parent, exports); |
| if (factory && factory.apply) { |
| return factory.apply(null, deps); |
| } else { |
| return factory; |
| } |
| } |
| require = function (dependencies, factory) { //jshint ignore:line |
| if (!Array.isArray(dependencies)) { |
| dependencies = [dependencies]; |
| } |
| load(dependencies, factory); |
| }; |
| |
| |
| })(); |
| define("amd", function(){}); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_WinJS',{}); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Global',[], function () { |
| "use strict"; |
| |
| // Appease jshint |
| /* global window, self, global */ |
| |
| var globalObject = |
| typeof window !== 'undefined' ? window : |
| typeof self !== 'undefined' ? self : |
| typeof global !== 'undefined' ? global : |
| {}; |
| return globalObject; |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_BaseCoreUtils',[ |
| './_Global' |
| ], function baseCoreUtilsInit(_Global) { |
| "use strict"; |
| |
| var hasWinRT = !!_Global.Windows; |
| |
| function markSupportedForProcessing(func) { |
| /// <signature helpKeyword="WinJS.Utilities.markSupportedForProcessing"> |
| /// <summary locid="WinJS.Utilities.markSupportedForProcessing"> |
| /// Marks a function as being compatible with declarative processing, such as WinJS.UI.processAll |
| /// or WinJS.Binding.processAll. |
| /// </summary> |
| /// <param name="func" type="Function" locid="WinJS.Utilities.markSupportedForProcessing_p:func"> |
| /// The function to be marked as compatible with declarative processing. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Utilities.markSupportedForProcessing_returnValue"> |
| /// The input function. |
| /// </returns> |
| /// </signature> |
| func.supportedForProcessing = true; |
| return func; |
| } |
| |
| return { |
| hasWinRT: hasWinRT, |
| markSupportedForProcessing: markSupportedForProcessing, |
| _setImmediate: _Global.setImmediate ? _Global.setImmediate.bind(_Global) : function (handler) { |
| _Global.setTimeout(handler, 0); |
| } |
| }; |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_WriteProfilerMark',[ |
| './_Global' |
| ], function profilerInit(_Global) { |
| "use strict"; |
| |
| return _Global.msWriteProfilerMark || function () { }; |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Base',[ |
| './_WinJS', |
| './_Global', |
| './_BaseCoreUtils', |
| './_WriteProfilerMark' |
| ], function baseInit(_WinJS, _Global, _BaseCoreUtils, _WriteProfilerMark) { |
| "use strict"; |
| |
| function initializeProperties(target, members, prefix) { |
| var keys = Object.keys(members); |
| var isArray = Array.isArray(target); |
| var properties; |
| var i, len; |
| for (i = 0, len = keys.length; i < len; i++) { |
| var key = keys[i]; |
| var enumerable = key.charCodeAt(0) !== /*_*/95; |
| var member = members[key]; |
| if (member && typeof member === 'object') { |
| if (member.value !== undefined || typeof member.get === 'function' || typeof member.set === 'function') { |
| if (member.enumerable === undefined) { |
| member.enumerable = enumerable; |
| } |
| if (prefix && member.setName && typeof member.setName === 'function') { |
| member.setName(prefix + "." + key); |
| } |
| properties = properties || {}; |
| properties[key] = member; |
| continue; |
| } |
| } |
| if (!enumerable) { |
| properties = properties || {}; |
| properties[key] = { value: member, enumerable: enumerable, configurable: true, writable: true }; |
| continue; |
| } |
| if (isArray) { |
| target.forEach(function (target) { |
| target[key] = member; |
| }); |
| } else { |
| target[key] = member; |
| } |
| } |
| if (properties) { |
| if (isArray) { |
| target.forEach(function (target) { |
| Object.defineProperties(target, properties); |
| }); |
| } else { |
| Object.defineProperties(target, properties); |
| } |
| } |
| } |
| |
| (function () { |
| |
| var _rootNamespace = _WinJS; |
| if (!_rootNamespace.Namespace) { |
| _rootNamespace.Namespace = Object.create(Object.prototype); |
| } |
| |
| function createNamespace(parentNamespace, name) { |
| var currentNamespace = parentNamespace || {}; |
| if (name) { |
| var namespaceFragments = name.split("."); |
| if (currentNamespace === _Global && namespaceFragments[0] === "WinJS") { |
| currentNamespace = _WinJS; |
| namespaceFragments.splice(0, 1); |
| } |
| for (var i = 0, len = namespaceFragments.length; i < len; i++) { |
| var namespaceName = namespaceFragments[i]; |
| if (!currentNamespace[namespaceName]) { |
| Object.defineProperty(currentNamespace, namespaceName, |
| { value: {}, writable: false, enumerable: true, configurable: true } |
| ); |
| } |
| currentNamespace = currentNamespace[namespaceName]; |
| } |
| } |
| return currentNamespace; |
| } |
| |
| function defineWithParent(parentNamespace, name, members) { |
| /// <signature helpKeyword="WinJS.Namespace.defineWithParent"> |
| /// <summary locid="WinJS.Namespace.defineWithParent"> |
| /// Defines a new namespace with the specified name under the specified parent namespace. |
| /// </summary> |
| /// <param name="parentNamespace" type="Object" locid="WinJS.Namespace.defineWithParent_p:parentNamespace"> |
| /// The parent namespace. |
| /// </param> |
| /// <param name="name" type="String" locid="WinJS.Namespace.defineWithParent_p:name"> |
| /// The name of the new namespace. |
| /// </param> |
| /// <param name="members" type="Object" locid="WinJS.Namespace.defineWithParent_p:members"> |
| /// The members of the new namespace. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Namespace.defineWithParent_returnValue"> |
| /// The newly-defined namespace. |
| /// </returns> |
| /// </signature> |
| var currentNamespace = createNamespace(parentNamespace, name); |
| |
| if (members) { |
| initializeProperties(currentNamespace, members, name || "<ANONYMOUS>"); |
| } |
| |
| return currentNamespace; |
| } |
| |
| function define(name, members) { |
| /// <signature helpKeyword="WinJS.Namespace.define"> |
| /// <summary locid="WinJS.Namespace.define"> |
| /// Defines a new namespace with the specified name. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Namespace.define_p:name"> |
| /// The name of the namespace. This could be a dot-separated name for nested namespaces. |
| /// </param> |
| /// <param name="members" type="Object" locid="WinJS.Namespace.define_p:members"> |
| /// The members of the new namespace. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Namespace.define_returnValue"> |
| /// The newly-defined namespace. |
| /// </returns> |
| /// </signature> |
| return defineWithParent(_Global, name, members); |
| } |
| |
| var LazyStates = { |
| uninitialized: 1, |
| working: 2, |
| initialized: 3, |
| }; |
| |
| function lazy(f) { |
| var name; |
| var state = LazyStates.uninitialized; |
| var result; |
| return { |
| setName: function (value) { |
| name = value; |
| }, |
| get: function () { |
| switch (state) { |
| case LazyStates.initialized: |
| return result; |
| |
| case LazyStates.uninitialized: |
| state = LazyStates.working; |
| try { |
| _WriteProfilerMark("WinJS.Namespace._lazy:" + name + ",StartTM"); |
| result = f(); |
| } finally { |
| _WriteProfilerMark("WinJS.Namespace._lazy:" + name + ",StopTM"); |
| state = LazyStates.uninitialized; |
| } |
| f = null; |
| state = LazyStates.initialized; |
| return result; |
| |
| case LazyStates.working: |
| throw "Illegal: reentrancy on initialization"; |
| |
| default: |
| throw "Illegal"; |
| } |
| }, |
| set: function (value) { |
| switch (state) { |
| case LazyStates.working: |
| throw "Illegal: reentrancy on initialization"; |
| |
| default: |
| state = LazyStates.initialized; |
| result = value; |
| break; |
| } |
| }, |
| enumerable: true, |
| configurable: true, |
| }; |
| } |
| |
| // helper for defining AMD module members |
| function moduleDefine(exports, name, members) { |
| var target = [exports]; |
| var publicNS = null; |
| if (name) { |
| publicNS = createNamespace(_Global, name); |
| target.push(publicNS); |
| } |
| initializeProperties(target, members, name || "<ANONYMOUS>"); |
| return publicNS; |
| } |
| |
| // Establish members of the "WinJS.Namespace" namespace |
| Object.defineProperties(_rootNamespace.Namespace, { |
| |
| defineWithParent: { value: defineWithParent, writable: true, enumerable: true, configurable: true }, |
| |
| define: { value: define, writable: true, enumerable: true, configurable: true }, |
| |
| _lazy: { value: lazy, writable: true, enumerable: true, configurable: true }, |
| |
| _moduleDefine: { value: moduleDefine, writable: true, enumerable: true, configurable: true } |
| |
| }); |
| |
| })(); |
| |
| (function () { |
| |
| function define(constructor, instanceMembers, staticMembers) { |
| /// <signature helpKeyword="WinJS.Class.define"> |
| /// <summary locid="WinJS.Class.define"> |
| /// Defines a class using the given constructor and the specified instance members. |
| /// </summary> |
| /// <param name="constructor" type="Function" locid="WinJS.Class.define_p:constructor"> |
| /// A constructor function that is used to instantiate this class. |
| /// </param> |
| /// <param name="instanceMembers" type="Object" locid="WinJS.Class.define_p:instanceMembers"> |
| /// The set of instance fields, properties, and methods made available on the class. |
| /// </param> |
| /// <param name="staticMembers" type="Object" locid="WinJS.Class.define_p:staticMembers"> |
| /// The set of static fields, properties, and methods made available on the class. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Class.define_returnValue"> |
| /// The newly-defined class. |
| /// </returns> |
| /// </signature> |
| constructor = constructor || function () { }; |
| _BaseCoreUtils.markSupportedForProcessing(constructor); |
| if (instanceMembers) { |
| initializeProperties(constructor.prototype, instanceMembers); |
| } |
| if (staticMembers) { |
| initializeProperties(constructor, staticMembers); |
| } |
| return constructor; |
| } |
| |
| function derive(baseClass, constructor, instanceMembers, staticMembers) { |
| /// <signature helpKeyword="WinJS.Class.derive"> |
| /// <summary locid="WinJS.Class.derive"> |
| /// Creates a sub-class based on the supplied baseClass parameter, using prototypal inheritance. |
| /// </summary> |
| /// <param name="baseClass" type="Function" locid="WinJS.Class.derive_p:baseClass"> |
| /// The class to inherit from. |
| /// </param> |
| /// <param name="constructor" type="Function" locid="WinJS.Class.derive_p:constructor"> |
| /// A constructor function that is used to instantiate this class. |
| /// </param> |
| /// <param name="instanceMembers" type="Object" locid="WinJS.Class.derive_p:instanceMembers"> |
| /// The set of instance fields, properties, and methods to be made available on the class. |
| /// </param> |
| /// <param name="staticMembers" type="Object" locid="WinJS.Class.derive_p:staticMembers"> |
| /// The set of static fields, properties, and methods to be made available on the class. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Class.derive_returnValue"> |
| /// The newly-defined class. |
| /// </returns> |
| /// </signature> |
| if (baseClass) { |
| constructor = constructor || function () { }; |
| var basePrototype = baseClass.prototype; |
| constructor.prototype = Object.create(basePrototype); |
| _BaseCoreUtils.markSupportedForProcessing(constructor); |
| Object.defineProperty(constructor.prototype, "constructor", { value: constructor, writable: true, configurable: true, enumerable: true }); |
| if (instanceMembers) { |
| initializeProperties(constructor.prototype, instanceMembers); |
| } |
| if (staticMembers) { |
| initializeProperties(constructor, staticMembers); |
| } |
| return constructor; |
| } else { |
| return define(constructor, instanceMembers, staticMembers); |
| } |
| } |
| |
| function mix(constructor) { |
| /// <signature helpKeyword="WinJS.Class.mix"> |
| /// <summary locid="WinJS.Class.mix"> |
| /// Defines a class using the given constructor and the union of the set of instance members |
| /// specified by all the mixin objects. The mixin parameter list is of variable length. |
| /// </summary> |
| /// <param name="constructor" locid="WinJS.Class.mix_p:constructor"> |
| /// A constructor function that is used to instantiate this class. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Class.mix_returnValue"> |
| /// The newly-defined class. |
| /// </returns> |
| /// </signature> |
| constructor = constructor || function () { }; |
| var i, len; |
| for (i = 1, len = arguments.length; i < len; i++) { |
| initializeProperties(constructor.prototype, arguments[i]); |
| } |
| return constructor; |
| } |
| |
| // Establish members of "WinJS.Class" namespace |
| _WinJS.Namespace.define("WinJS.Class", { |
| define: define, |
| derive: derive, |
| mix: mix |
| }); |
| |
| })(); |
| |
| return { |
| Namespace: _WinJS.Namespace, |
| Class: _WinJS.Class |
| }; |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_ErrorFromName',[ |
| './_Base' |
| ], function errorsInit(_Base) { |
| "use strict"; |
| |
| var ErrorFromName = _Base.Class.derive(Error, function (name, message) { |
| /// <signature helpKeyword="WinJS.ErrorFromName"> |
| /// <summary locid="WinJS.ErrorFromName"> |
| /// Creates an Error object with the specified name and message properties. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.ErrorFromName_p:name">The name of this error. The name is meant to be consumed programmatically and should not be localized.</param> |
| /// <param name="message" type="String" optional="true" locid="WinJS.ErrorFromName_p:message">The message for this error. The message is meant to be consumed by humans and should be localized.</param> |
| /// <returns type="Error" locid="WinJS.ErrorFromName_returnValue">Error instance with .name and .message properties populated</returns> |
| /// </signature> |
| this.name = name; |
| this.message = message || name; |
| }, { |
| /* empty */ |
| }, { |
| supportedForProcessing: false, |
| }); |
| |
| _Base.Namespace.define("WinJS", { |
| // ErrorFromName establishes a simple pattern for returning error codes. |
| // |
| ErrorFromName: ErrorFromName |
| }); |
| |
| return ErrorFromName; |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_WinRT',[ |
| 'exports', |
| './_Global', |
| './_Base', |
| ], function winrtInit(exports, _Global, _Base) { |
| "use strict"; |
| |
| exports.msGetWeakWinRTProperty = _Global.msGetWeakWinRTProperty; |
| exports.msSetWeakWinRTProperty = _Global.msSetWeakWinRTProperty; |
| |
| var APIs = [ |
| "Windows.ApplicationModel.DesignMode.designModeEnabled", |
| "Windows.ApplicationModel.Resources.Core.ResourceContext", |
| "Windows.ApplicationModel.Resources.Core.ResourceManager", |
| "Windows.ApplicationModel.Search.SearchQueryLinguisticDetails", |
| "Windows.Data.Text.SemanticTextQuery", |
| "Windows.Foundation.Collections.CollectionChange", |
| "Windows.Foundation.Diagnostics", |
| "Windows.Foundation.Uri", |
| "Windows.Globalization.ApplicationLanguages", |
| "Windows.Globalization.Calendar", |
| "Windows.Globalization.DateTimeFormatting", |
| "Windows.Globalization.Language", |
| "Windows.Phone.UI.Input.HardwareButtons", |
| "Windows.Storage.ApplicationData", |
| "Windows.Storage.CreationCollisionOption", |
| "Windows.Storage.BulkAccess.FileInformationFactory", |
| "Windows.Storage.FileIO", |
| "Windows.Storage.FileProperties.ThumbnailType", |
| "Windows.Storage.FileProperties.ThumbnailMode", |
| "Windows.Storage.FileProperties.ThumbnailOptions", |
| "Windows.Storage.KnownFolders", |
| "Windows.Storage.Search.FolderDepth", |
| "Windows.Storage.Search.IndexerOption", |
| "Windows.Storage.Streams.RandomAccessStreamReference", |
| "Windows.UI.ApplicationSettings.SettingsEdgeLocation", |
| "Windows.UI.ApplicationSettings.SettingsCommand", |
| "Windows.UI.ApplicationSettings.SettingsPane", |
| "Windows.UI.Core.AnimationMetrics", |
| "Windows.UI.Core.SystemNavigationManager", |
| "Windows.UI.Input.EdgeGesture", |
| "Windows.UI.Input.EdgeGestureKind", |
| "Windows.UI.Input.PointerPoint", |
| "Windows.UI.ViewManagement.HandPreference", |
| "Windows.UI.ViewManagement.InputPane", |
| "Windows.UI.ViewManagement.UIColorType", |
| "Windows.UI.ViewManagement.UISettings", |
| "Windows.UI.WebUI.Core.WebUICommandBar", |
| "Windows.UI.WebUI.Core.WebUICommandBarBitmapIcon", |
| "Windows.UI.WebUI.Core.WebUICommandBarClosedDisplayMode", |
| "Windows.UI.WebUI.Core.WebUICommandBarIconButton", |
| "Windows.UI.WebUI.Core.WebUICommandBarSymbolIcon", |
| "Windows.UI.WebUI.WebUIApplication", |
| ]; |
| |
| // If getForCurrentView fails, it is an indication that we are running in a WebView without |
| // a CoreWindow where some WinRT APIs are not available. In this case, we just treat it as |
| // if no WinRT APIs are available. |
| var isCoreWindowAvailable = false; |
| try { |
| _Global.Windows.UI.ViewManagement.InputPane.getForCurrentView(); |
| isCoreWindowAvailable = true; |
| } catch (e) { } |
| |
| APIs.forEach(function (api) { |
| var parts = api.split("."); |
| var leaf = {}; |
| leaf[parts[parts.length - 1]] = { |
| get: function () { |
| if (isCoreWindowAvailable) { |
| return parts.reduce(function (current, part) { return current ? current[part] : null; }, _Global); |
| } else { |
| return null; |
| } |
| } |
| }; |
| _Base.Namespace.defineWithParent(exports, parts.slice(0, -1).join("."), leaf); |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Events',[ |
| 'exports', |
| './_Base' |
| ], function eventsInit(exports, _Base) { |
| "use strict"; |
| |
| |
| function createEventProperty(name) { |
| var eventPropStateName = "_on" + name + "state"; |
| |
| return { |
| get: function () { |
| var state = this[eventPropStateName]; |
| return state && state.userHandler; |
| }, |
| set: function (handler) { |
| var state = this[eventPropStateName]; |
| if (handler) { |
| if (!state) { |
| state = { wrapper: function (evt) { return state.userHandler(evt); }, userHandler: handler }; |
| Object.defineProperty(this, eventPropStateName, { value: state, enumerable: false, writable:true, configurable: true }); |
| this.addEventListener(name, state.wrapper, false); |
| } |
| state.userHandler = handler; |
| } else if (state) { |
| this.removeEventListener(name, state.wrapper, false); |
| this[eventPropStateName] = null; |
| } |
| }, |
| enumerable: true |
| }; |
| } |
| |
| function createEventProperties() { |
| /// <signature helpKeyword="WinJS.Utilities.createEventProperties"> |
| /// <summary locid="WinJS.Utilities.createEventProperties"> |
| /// Creates an object that has one property for each name passed to the function. |
| /// </summary> |
| /// <param name="events" locid="WinJS.Utilities.createEventProperties_p:events"> |
| /// A variable list of property names. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.createEventProperties_returnValue"> |
| /// The object with the specified properties. The names of the properties are prefixed with 'on'. |
| /// </returns> |
| /// </signature> |
| var props = {}; |
| for (var i = 0, len = arguments.length; i < len; i++) { |
| var name = arguments[i]; |
| props["on" + name] = createEventProperty(name); |
| } |
| return props; |
| } |
| |
| var EventMixinEvent = _Base.Class.define( |
| function EventMixinEvent_ctor(type, detail, target) { |
| this.detail = detail; |
| this.target = target; |
| this.timeStamp = Date.now(); |
| this.type = type; |
| }, |
| { |
| bubbles: { value: false, writable: false }, |
| cancelable: { value: false, writable: false }, |
| currentTarget: { |
| get: function () { return this.target; } |
| }, |
| defaultPrevented: { |
| get: function () { return this._preventDefaultCalled; } |
| }, |
| trusted: { value: false, writable: false }, |
| eventPhase: { value: 0, writable: false }, |
| target: null, |
| timeStamp: null, |
| type: null, |
| |
| preventDefault: function () { |
| this._preventDefaultCalled = true; |
| }, |
| stopImmediatePropagation: function () { |
| this._stopImmediatePropagationCalled = true; |
| }, |
| stopPropagation: function () { |
| } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| var eventMixin = { |
| _listeners: null, |
| |
| addEventListener: function (type, listener, useCapture) { |
| /// <signature helpKeyword="WinJS.Utilities.eventMixin.addEventListener"> |
| /// <summary locid="WinJS.Utilities.eventMixin.addEventListener"> |
| /// Adds an event listener to the control. |
| /// </summary> |
| /// <param name="type" locid="WinJS.Utilities.eventMixin.addEventListener_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" locid="WinJS.Utilities.eventMixin.addEventListener_p:listener"> |
| /// The listener to invoke when the event is raised. |
| /// </param> |
| /// <param name="useCapture" locid="WinJS.Utilities.eventMixin.addEventListener_p:useCapture"> |
| /// if true initiates capture, otherwise false. |
| /// </param> |
| /// </signature> |
| useCapture = useCapture || false; |
| this._listeners = this._listeners || {}; |
| var eventListeners = (this._listeners[type] = this._listeners[type] || []); |
| for (var i = 0, len = eventListeners.length; i < len; i++) { |
| var l = eventListeners[i]; |
| if (l.useCapture === useCapture && l.listener === listener) { |
| return; |
| } |
| } |
| eventListeners.push({ listener: listener, useCapture: useCapture }); |
| }, |
| dispatchEvent: function (type, details) { |
| /// <signature helpKeyword="WinJS.Utilities.eventMixin.dispatchEvent"> |
| /// <summary locid="WinJS.Utilities.eventMixin.dispatchEvent"> |
| /// Raises an event of the specified type and with the specified additional properties. |
| /// </summary> |
| /// <param name="type" locid="WinJS.Utilities.eventMixin.dispatchEvent_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="details" locid="WinJS.Utilities.eventMixin.dispatchEvent_p:details"> |
| /// The set of additional properties to be attached to the event object when the event is raised. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Utilities.eventMixin.dispatchEvent_returnValue"> |
| /// true if preventDefault was called on the event. |
| /// </returns> |
| /// </signature> |
| var listeners = this._listeners && this._listeners[type]; |
| if (listeners) { |
| var eventValue = new EventMixinEvent(type, details, this); |
| // Need to copy the array to protect against people unregistering while we are dispatching |
| listeners = listeners.slice(0, listeners.length); |
| for (var i = 0, len = listeners.length; i < len && !eventValue._stopImmediatePropagationCalled; i++) { |
| listeners[i].listener(eventValue); |
| } |
| return eventValue.defaultPrevented || false; |
| } |
| return false; |
| }, |
| removeEventListener: function (type, listener, useCapture) { |
| /// <signature helpKeyword="WinJS.Utilities.eventMixin.removeEventListener"> |
| /// <summary locid="WinJS.Utilities.eventMixin.removeEventListener"> |
| /// Removes an event listener from the control. |
| /// </summary> |
| /// <param name="type" locid="WinJS.Utilities.eventMixin.removeEventListener_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" locid="WinJS.Utilities.eventMixin.removeEventListener_p:listener"> |
| /// The listener to remove. |
| /// </param> |
| /// <param name="useCapture" locid="WinJS.Utilities.eventMixin.removeEventListener_p:useCapture"> |
| /// Specifies whether to initiate capture. |
| /// </param> |
| /// </signature> |
| useCapture = useCapture || false; |
| var listeners = this._listeners && this._listeners[type]; |
| if (listeners) { |
| for (var i = 0, len = listeners.length; i < len; i++) { |
| var l = listeners[i]; |
| if (l.listener === listener && l.useCapture === useCapture) { |
| listeners.splice(i, 1); |
| if (listeners.length === 0) { |
| delete this._listeners[type]; |
| } |
| // Only want to remove one element for each call to removeEventListener |
| break; |
| } |
| } |
| } |
| } |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| _createEventProperty: createEventProperty, |
| createEventProperties: createEventProperties, |
| eventMixin: eventMixin |
| }); |
| |
| }); |
| |
| |
| define('require-json',{load: function(id){throw new Error("Dynamic load not allowed: " + id);}}); |
| |
| define('require-json!strings/en-us/Microsoft.WinJS.resjson',{ |
| "tv/scrollViewerPageDown": "Page Down", |
| "tv/scrollViewerPageUp": "Page Up", |
| "ui/appBarAriaLabel": "App Bar", |
| "ui/appBarCommandAriaLabel": "App Bar Item", |
| "ui/appBarOverflowButtonAriaLabel": "View more", |
| "ui/autoSuggestBoxAriaLabel": "Autosuggestbox", |
| "ui/autoSuggestBoxAriaLabelInputNoPlaceHolder": "Autosuggestbox, enter to submit query, esc to clear text", |
| "ui/autoSuggestBoxAriaLabelInputPlaceHolder": "Autosuggestbox, {0}, enter to submit query, esc to clear text", |
| "ui/autoSuggestBoxAriaLabelQuery": "Suggestion: {0}", |
| "_ui/autoSuggestBoxAriaLabelQuery.comment": "Suggestion: query text (example: Suggestion: contoso)", |
| "ui/autoSuggestBoxAriaLabelSeparator": "Separator: {0}", |
| "_ui/autoSuggestBoxAriaLabelSeparator.comment": "Separator: separator text (example: Separator: People or Separator: Apps)", |
| "ui/autoSuggestBoxAriaLabelResult": "Result: {0}, {1}", |
| "_ui/autoSuggestBoxAriaLabelResult.comment": "Result: text, detailed text (example: Result: contoso, www.contoso.com)", |
| "ui/averageRating": "Average Rating", |
| "ui/backbuttonarialabel": "Back", |
| "ui/chapterSkipBackMediaCommandDisplayText": "Chapter back", |
| "ui/chapterSkipForwardMediaCommandDisplayText": "Chapter forward", |
| "ui/clearYourRating": "Clear your rating", |
| "ui/closedCaptionsLabelNone": "Off", |
| "ui/closedCaptionsMediaCommandDisplayText": "Closed captioning", |
| "ui/closeOverlay": "Close", |
| "ui/commandingSurfaceAriaLabel": "CommandingSurface", |
| "ui/commandingSurfaceOverflowButtonAriaLabel": "View more", |
| "ui/datePicker": "Date Picker", |
| "ui/fastForwardMediaCommandDisplayText": "Fast forward", |
| "ui/fastForwardFeedbackDisplayText": " {0}X", |
| "ui/fastForwardFeedbackSlowMotionDisplayText": "0.5X", |
| "ui/flipViewPanningContainerAriaLabel": "Scrolling Container", |
| "ui/flyoutAriaLabel": "Flyout", |
| "ui/goToFullScreenButtonLabel": "Go full screen", |
| "ui/goToLiveMediaCommandDisplayText": "LIVE", |
| "ui/hubViewportAriaLabel": "Scrolling Container", |
| "ui/listViewViewportAriaLabel": "Scrolling Container", |
| "ui/mediaErrorAborted": "Playback was interrupted. Please try again.", |
| "ui/mediaErrorNetwork": "There was a network connection error.", |
| "ui/mediaErrorDecode": "The content could not be decoded", |
| "ui/mediaErrorSourceNotSupported": "This content type is not supported.", |
| "ui/mediaErrorUnknown": "There was an unknown error.", |
| "ui/mediaPlayerAudioTracksButtonLabel": "Audio tracks", |
| "ui/mediaPlayerCastButtonLabel": "Cast", |
| "ui/mediaPlayerChapterSkipBackButtonLabel": "Previous", |
| "ui/mediaPlayerChapterSkipForwardButtonLabel": "Next", |
| "ui/mediaPlayerClosedCaptionsButtonLabel": "Closed captions", |
| "ui/mediaPlayerFastForwardButtonLabel": "Fast forward", |
| "ui/mediaPlayerFullscreenButtonLabel": "Fullscreen", |
| "ui/mediaPlayerLiveButtonLabel": "LIVE", |
| "ui/mediaPlayerNextTrackButtonLabel": "Next", |
| "ui/mediaPlayerOverlayActiveOptionIndicator": "(On)", |
| "ui/mediaPlayerPauseButtonLabel": "Pause", |
| "ui/mediaPlayerPlayButtonLabel": "Play", |
| "ui/mediaPlayerPlayFromBeginningButtonLabel": "Replay", |
| "ui/mediaPlayerPlayRateButtonLabel": "Playback rate", |
| "ui/mediaPlayerPreviousTrackButtonLabel": "Previous", |
| "ui/mediaPlayerRewindButtonLabel": "Rewind", |
| "ui/mediaPlayerStopButtonLabel": "Stop", |
| "ui/mediaPlayerTimeSkipBackButtonLabel": "8 second replay", |
| "ui/mediaPlayerTimeSkipForwardButtonLabel": "30 second skip", |
| "ui/mediaPlayerToggleSnapButtonLabel": "Snap", |
| "ui/mediaPlayerVolumeButtonLabel": "Volume", |
| "ui/mediaPlayerZoomButtonLabel": "Zoom", |
| "ui/menuCommandAriaLabel": "Menu Item", |
| "ui/menuAriaLabel": "Menu", |
| "ui/navBarContainerViewportAriaLabel": "Scrolling Container", |
| "ui/nextTrackMediaCommandDisplayText": "Next track", |
| "ui/off": "Off", |
| "ui/on": "On", |
| "ui/pauseMediaCommandDisplayText": "Pause", |
| "ui/playFromBeginningMediaCommandDisplayText": "Play again", |
| "ui/playbackRateHalfSpeedLabel": "0.5x", |
| "ui/playbackRateNormalSpeedLabel": "Normal", |
| "ui/playbackRateOneAndHalfSpeedLabel": "1.5x", |
| "ui/playbackRateDoubleSpeedLabel": "2x", |
| "ui/playMediaCommandDisplayText": "Play", |
| "ui/pivotAriaLabel": "Pivot", |
| "ui/pivotViewportAriaLabel": "Scrolling Container", |
| "ui/replayMediaCommandDisplayText": "Play again", |
| "ui/rewindMediaCommandDisplayText": "Rewind", |
| "ui/rewindFeedbackDisplayText": " {0}X", |
| "ui/rewindFeedbackSlowMotionDisplayText": "0.5X", |
| "ui/searchBoxAriaLabel": "Searchbox", |
| "ui/searchBoxAriaLabelInputNoPlaceHolder": "Searchbox, enter to submit query, esc to clear text", |
| "ui/searchBoxAriaLabelInputPlaceHolder": "Searchbox, {0}, enter to submit query, esc to clear text", |
| "ui/searchBoxAriaLabelButton": "Click to submit query", |
| "ui/seeMore": "See more", |
| "ui/selectAMPM": "Select A.M P.M", |
| "ui/selectDay": "Select Day", |
| "ui/selectHour": "Select Hour", |
| "ui/selectMinute": "Select Minute", |
| "ui/selectMonth": "Select Month", |
| "ui/selectYear": "Select Year", |
| "ui/settingsFlyoutAriaLabel": "Settings Flyout", |
| "ui/stopMediaCommandDisplayText": "Stop", |
| "ui/tentativeRating": "Tentative Rating", |
| "ui/timePicker": "Time Picker", |
| "ui/timeSeparator": ":", |
| "ui/timeSkipBackMediaCommandDisplayText": "Skip back", |
| "ui/timeSkipForwardMediaCommandDisplayText": "Skip forward", |
| "ui/toolbarAriaLabel": "ToolBar", |
| "ui/toolbarOverflowButtonAriaLabel": "View more", |
| "ui/unrated": "Unrated", |
| "ui/userRating": "User Rating", |
| "ui/zoomMediaCommandDisplayText": "Zoom", |
| // AppBar Icons follow, the format of the ui.js and ui.resjson differ for |
| // the AppBarIcon namespace. The remainder of the file therefore differs. |
| // Code point comments are the icon glyphs in the 'Segoe UI Symbol' font. |
| "ui/appBarIcons/previous": "\uE100", // group:Media |
| "_ui/appBarIcons/previous.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/next": "\uE101", // group:Media |
| "_ui/appBarIcons/next.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/play": "\uE102", // group:Media |
| "_ui/appBarIcons/play.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/pause": "\uE103", // group:Media |
| "_ui/appBarIcons/pause.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/edit": "\uE104", // group:File |
| "_ui/appBarIcons/edit.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/save": "\uE105", // group:File |
| "_ui/appBarIcons/save.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/clear": "\uE106", // group:File |
| "_ui/appBarIcons/clear.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/delete": "\uE107", // group:File |
| "_ui/appBarIcons/delete.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/remove": "\uE108", // group:File |
| "_ui/appBarIcons/remove.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/add": "\uE109", // group:File |
| "_ui/appBarIcons/add.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/cancel": "\uE10A", // group:Editing |
| "_ui/appBarIcons/cancel.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/accept": "\uE10B", // group:General |
| "_ui/appBarIcons/accept.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/more": "\uE10C", // group:General |
| "_ui/appBarIcons/more.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/redo": "\uE10D", // group:Editing |
| "_ui/appBarIcons/redo.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/undo": "\uE10E", // group:Editing |
| "_ui/appBarIcons/undo.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/home": "\uE10F", // group:General |
| "_ui/appBarIcons/home.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/up": "\uE110", // group:General |
| "_ui/appBarIcons/up.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/forward": "\uE111", // group:General |
| "_ui/appBarIcons/forward.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/right": "\uE111", // group:General |
| "_ui/appBarIcons/right.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/back": "\uE112", // group:General |
| "_ui/appBarIcons/back.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/left": "\uE112", // group:General |
| "_ui/appBarIcons/left.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/favorite": "\uE113", // group:Media |
| "_ui/appBarIcons/favorite.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/camera": "\uE114", // group:System |
| "_ui/appBarIcons/camera.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/settings": "\uE115", // group:System |
| "_ui/appBarIcons/settings.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/video": "\uE116", // group:Media |
| "_ui/appBarIcons/video.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/sync": "\uE117", // group:Media |
| "_ui/appBarIcons/sync.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/download": "\uE118", // group:Media |
| "_ui/appBarIcons/download.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mail": "\uE119", // group:Mail and calendar |
| "_ui/appBarIcons/mail.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/find": "\uE11A", // group:Data |
| "_ui/appBarIcons/find.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/help": "\uE11B", // group:General |
| "_ui/appBarIcons/help.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/upload": "\uE11C", // group:Media |
| "_ui/appBarIcons/upload.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/emoji": "\uE11D", // group:Communications |
| "_ui/appBarIcons/emoji.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/twopage": "\uE11E", // group:Layout |
| "_ui/appBarIcons/twopage.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/leavechat": "\uE11F", // group:Communications |
| "_ui/appBarIcons/leavechat.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mailforward": "\uE120", // group:Mail and calendar |
| "_ui/appBarIcons/mailforward.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/clock": "\uE121", // group:General |
| "_ui/appBarIcons/clock.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/send": "\uE122", // group:Mail and calendar |
| "_ui/appBarIcons/send.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/crop": "\uE123", // group:Editing |
| "_ui/appBarIcons/crop.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/rotatecamera": "\uE124", // group:System |
| "_ui/appBarIcons/rotatecamera.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/people": "\uE125", // group:Communications |
| "_ui/appBarIcons/people.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/closepane": "\uE126", // group:Layout |
| "_ui/appBarIcons/closepane.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/openpane": "\uE127", // group:Layout |
| "_ui/appBarIcons/openpane.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/world": "\uE128", // group:General |
| "_ui/appBarIcons/world.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/flag": "\uE129", // group:Mail and calendar |
| "_ui/appBarIcons/flag.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/previewlink": "\uE12A", // group:General |
| "_ui/appBarIcons/previewlink.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/globe": "\uE12B", // group:Communications |
| "_ui/appBarIcons/globe.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/trim": "\uE12C", // group:Editing |
| "_ui/appBarIcons/trim.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/attachcamera": "\uE12D", // group:System |
| "_ui/appBarIcons/attachcamera.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/zoomin": "\uE12E", // group:Layout |
| "_ui/appBarIcons/zoomin.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/bookmarks": "\uE12F", // group:Editing |
| "_ui/appBarIcons/bookmarks.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/document": "\uE130", // group:File |
| "_ui/appBarIcons/document.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/protecteddocument": "\uE131", // group:File |
| "_ui/appBarIcons/protecteddocument.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/page": "\uE132", // group:Layout |
| "_ui/appBarIcons/page.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/bullets": "\uE133", // group:Editing |
| "_ui/appBarIcons/bullets.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/comment": "\uE134", // group:Communications |
| "_ui/appBarIcons/comment.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mail2": "\uE135", // group:Mail and calendar |
| "_ui/appBarIcons/mail2.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/contactinfo": "\uE136", // group:Communications |
| "_ui/appBarIcons/contactinfo.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/hangup": "\uE137", // group:Communications |
| "_ui/appBarIcons/hangup.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/viewall": "\uE138", // group:Data |
| "_ui/appBarIcons/viewall.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mappin": "\uE139", // group:General |
| "_ui/appBarIcons/mappin.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/phone": "\uE13A", // group:Communications |
| "_ui/appBarIcons/phone.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/videochat": "\uE13B", // group:Communications |
| "_ui/appBarIcons/videochat.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/switch": "\uE13C", // group:Communications |
| "_ui/appBarIcons/switch.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/contact": "\uE13D", // group:Communications |
| "_ui/appBarIcons/contact.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/rename": "\uE13E", // group:File |
| "_ui/appBarIcons/rename.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/pin": "\uE141", // group:System |
| "_ui/appBarIcons/pin.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/musicinfo": "\uE142", // group:Media |
| "_ui/appBarIcons/musicinfo.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/go": "\uE143", // group:General |
| "_ui/appBarIcons/go.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/keyboard": "\uE144", // group:System |
| "_ui/appBarIcons/keyboard.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/dockleft": "\uE145", // group:Layout |
| "_ui/appBarIcons/dockleft.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/dockright": "\uE146", // group:Layout |
| "_ui/appBarIcons/dockright.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/dockbottom": "\uE147", // group:Layout |
| "_ui/appBarIcons/dockbottom.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/remote": "\uE148", // group:System |
| "_ui/appBarIcons/remote.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/refresh": "\uE149", // group:Data |
| "_ui/appBarIcons/refresh.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/rotate": "\uE14A", // group:Layout |
| "_ui/appBarIcons/rotate.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/shuffle": "\uE14B", // group:Media |
| "_ui/appBarIcons/shuffle.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/list": "\uE14C", // group:Editing |
| "_ui/appBarIcons/list.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/shop": "\uE14D", // group:General |
| "_ui/appBarIcons/shop.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/selectall": "\uE14E", // group:Data |
| "_ui/appBarIcons/selectall.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/orientation": "\uE14F", // group:Layout |
| "_ui/appBarIcons/orientation.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/import": "\uE150", // group:Data |
| "_ui/appBarIcons/import.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/importall": "\uE151", // group:Data |
| "_ui/appBarIcons/importall.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/browsephotos": "\uE155", // group:Media |
| "_ui/appBarIcons/browsephotos.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/webcam": "\uE156", // group:System |
| "_ui/appBarIcons/webcam.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/pictures": "\uE158", // group:Media |
| "_ui/appBarIcons/pictures.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/savelocal": "\uE159", // group:File |
| "_ui/appBarIcons/savelocal.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/caption": "\uE15A", // group:Media |
| "_ui/appBarIcons/caption.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/stop": "\uE15B", // group:Media |
| "_ui/appBarIcons/stop.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/showresults": "\uE15C", // group:Data |
| "_ui/appBarIcons/showresults.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/volume": "\uE15D", // group:Media |
| "_ui/appBarIcons/volume.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/repair": "\uE15E", // group:System |
| "_ui/appBarIcons/repair.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/message": "\uE15F", // group:Communications |
| "_ui/appBarIcons/message.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/page2": "\uE160", // group:Layout |
| "_ui/appBarIcons/page2.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/calendarday": "\uE161", // group:Mail and calendar |
| "_ui/appBarIcons/calendarday.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/calendarweek": "\uE162", // group:Mail and calendar |
| "_ui/appBarIcons/calendarweek.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/calendar": "\uE163", // group:Mail and calendar |
| "_ui/appBarIcons/calendar.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/characters": "\uE164", // group:Editing |
| "_ui/appBarIcons/characters.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mailreplyall": "\uE165", // group:Mail and calendar |
| "_ui/appBarIcons/mailreplyall.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/read": "\uE166", // group:Mail and calendar |
| "_ui/appBarIcons/read.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/link": "\uE167", // group:Communications |
| "_ui/appBarIcons/link.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/accounts": "\uE168", // group:Communications |
| "_ui/appBarIcons/accounts.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/showbcc": "\uE169", // group:Mail and calendar |
| "_ui/appBarIcons/showbcc.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/hidebcc": "\uE16A", // group:Mail and calendar |
| "_ui/appBarIcons/hidebcc.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/cut": "\uE16B", // group:Editing |
| "_ui/appBarIcons/cut.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/attach": "\uE16C", // group:Mail and calendar |
| "_ui/appBarIcons/attach.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/paste": "\uE16D", // group:Editing |
| "_ui/appBarIcons/paste.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/filter": "\uE16E", // group:Data |
| "_ui/appBarIcons/filter.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/copy": "\uE16F", // group:Editing |
| "_ui/appBarIcons/copy.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/emoji2": "\uE170", // group:Mail and calendar |
| "_ui/appBarIcons/emoji2.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/important": "\uE171", // group:Mail and calendar |
| "_ui/appBarIcons/important.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mailreply": "\uE172", // group:Mail and calendar |
| "_ui/appBarIcons/mailreply.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/slideshow": "\uE173", // group:Media |
| "_ui/appBarIcons/slideshow.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/sort": "\uE174", // group:Data |
| "_ui/appBarIcons/sort.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/manage": "\uE178", // group:System |
| "_ui/appBarIcons/manage.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/allapps": "\uE179", // group:System |
| "_ui/appBarIcons/allapps.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/disconnectdrive": "\uE17A", // group:System |
| "_ui/appBarIcons/disconnectdrive.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mapdrive": "\uE17B", // group:System |
| "_ui/appBarIcons/mapdrive.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/newwindow": "\uE17C", // group:System |
| "_ui/appBarIcons/newwindow.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/openwith": "\uE17D", // group:System |
| "_ui/appBarIcons/openwith.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/contactpresence": "\uE181", // group:Communications |
| "_ui/appBarIcons/contactpresence.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/priority": "\uE182", // group:Mail and calendar |
| "_ui/appBarIcons/priority.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/uploadskydrive": "\uE183", // group:File |
| "_ui/appBarIcons/uploadskydrive.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/gototoday": "\uE184", // group:Mail and calendar |
| "_ui/appBarIcons/gototoday.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/font": "\uE185", // group:Editing |
| "_ui/appBarIcons/font.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fontcolor": "\uE186", // group:Editing |
| "_ui/appBarIcons/fontcolor.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/contact2": "\uE187", // group:Communications |
| "_ui/appBarIcons/contact2.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/folder": "\uE188", // group:File |
| "_ui/appBarIcons/folder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/audio": "\uE189", // group:Media |
| "_ui/appBarIcons/audio.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/placeholder": "\uE18A", // group:General |
| "_ui/appBarIcons/placeholder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/view": "\uE18B", // group:Layout |
| "_ui/appBarIcons/view.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/setlockscreen": "\uE18C", // group:System |
| "_ui/appBarIcons/setlockscreen.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/settile": "\uE18D", // group:System |
| "_ui/appBarIcons/settile.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/cc": "\uE190", // group:Media |
| "_ui/appBarIcons/cc.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/stopslideshow": "\uE191", // group:Media |
| "_ui/appBarIcons/stopslideshow.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/permissions": "\uE192", // group:System |
| "_ui/appBarIcons/permissions.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/highlight": "\uE193", // group:Editing |
| "_ui/appBarIcons/highlight.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/disableupdates": "\uE194", // group:System |
| "_ui/appBarIcons/disableupdates.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/unfavorite": "\uE195", // group:Media |
| "_ui/appBarIcons/unfavorite.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/unpin": "\uE196", // group:System |
| "_ui/appBarIcons/unpin.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/openlocal": "\uE197", // group:File |
| "_ui/appBarIcons/openlocal.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/mute": "\uE198", // group:Media |
| "_ui/appBarIcons/mute.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/italic": "\uE199", // group:Editing |
| "_ui/appBarIcons/italic.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/underline": "\uE19A", // group:Editing |
| "_ui/appBarIcons/underline.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/bold": "\uE19B", // group:Editing |
| "_ui/appBarIcons/bold.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/movetofolder": "\uE19C", // group:File |
| "_ui/appBarIcons/movetofolder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/likedislike": "\uE19D", // group:Data |
| "_ui/appBarIcons/likedislike.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/dislike": "\uE19E", // group:Data |
| "_ui/appBarIcons/dislike.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/like": "\uE19F", // group:Data |
| "_ui/appBarIcons/like.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/alignright": "\uE1A0", // group:Editing |
| "_ui/appBarIcons/alignright.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/aligncenter": "\uE1A1", // group:Editing |
| "_ui/appBarIcons/aligncenter.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/alignleft": "\uE1A2", // group:Editing |
| "_ui/appBarIcons/alignleft.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/zoom": "\uE1A3", // group:Layout |
| "_ui/appBarIcons/zoom.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/zoomout": "\uE1A4", // group:Layout |
| "_ui/appBarIcons/zoomout.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/openfile": "\uE1A5", // group:File |
| "_ui/appBarIcons/openfile.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/otheruser": "\uE1A6", // group:System |
| "_ui/appBarIcons/otheruser.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/admin": "\uE1A7", // group:System |
| "_ui/appBarIcons/admin.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/street": "\uE1C3", // group:General |
| "_ui/appBarIcons/street.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/map": "\uE1C4", // group:General |
| "_ui/appBarIcons/map.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/clearselection": "\uE1C5", // group:Data |
| "_ui/appBarIcons/clearselection.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fontdecrease": "\uE1C6", // group:Editing |
| "_ui/appBarIcons/fontdecrease.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fontincrease": "\uE1C7", // group:Editing |
| "_ui/appBarIcons/fontincrease.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fontsize": "\uE1C8", // group:Editing |
| "_ui/appBarIcons/fontsize.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/cellphone": "\uE1C9", // group:Communications |
| "_ui/appBarIcons/cellphone.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/reshare": "\uE1CA", // group:Communications |
| "_ui/appBarIcons/reshare.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/tag": "\uE1CB", // group:Data |
| "_ui/appBarIcons/tag.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/repeatone": "\uE1CC", // group:Media |
| "_ui/appBarIcons/repeatone.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/repeatall": "\uE1CD", // group:Media |
| "_ui/appBarIcons/repeatall.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/outlinestar": "\uE1CE", // group:Data |
| "_ui/appBarIcons/outlinestar.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/solidstar": "\uE1CF", // group:Data |
| "_ui/appBarIcons/solidstar.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/calculator": "\uE1D0", // group:General |
| "_ui/appBarIcons/calculator.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/directions": "\uE1D1", // group:General |
| "_ui/appBarIcons/directions.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/target": "\uE1D2", // group:General |
| "_ui/appBarIcons/target.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/library": "\uE1D3", // group:Media |
| "_ui/appBarIcons/library.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/phonebook": "\uE1D4", // group:Communications |
| "_ui/appBarIcons/phonebook.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/memo": "\uE1D5", // group:Communications |
| "_ui/appBarIcons/memo.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/microphone": "\uE1D6", // group:System |
| "_ui/appBarIcons/microphone.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/postupdate": "\uE1D7", // group:Communications |
| "_ui/appBarIcons/postupdate.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/backtowindow": "\uE1D8", // group:Layout |
| "_ui/appBarIcons/backtowindow.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fullscreen": "\uE1D9", // group:Layout |
| "_ui/appBarIcons/fullscreen.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/newfolder": "\uE1DA", // group:File |
| "_ui/appBarIcons/newfolder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/calendarreply": "\uE1DB", // group:Mail and calendar |
| "_ui/appBarIcons/calendarreply.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/unsyncfolder": "\uE1DD", // group:File |
| "_ui/appBarIcons/unsyncfolder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/reporthacked": "\uE1DE", // group:Communications |
| "_ui/appBarIcons/reporthacked.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/syncfolder": "\uE1DF", // group:File |
| "_ui/appBarIcons/syncfolder.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/blockcontact": "\uE1E0", // group:Communications |
| "_ui/appBarIcons/blockcontact.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/switchapps": "\uE1E1", // group:System |
| "_ui/appBarIcons/switchapps.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/addfriend": "\uE1E2", // group:Communications |
| "_ui/appBarIcons/addfriend.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/touchpointer": "\uE1E3", // group:System |
| "_ui/appBarIcons/touchpointer.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/gotostart": "\uE1E4", // group:System |
| "_ui/appBarIcons/gotostart.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/zerobars": "\uE1E5", // group:System |
| "_ui/appBarIcons/zerobars.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/onebar": "\uE1E6", // group:System |
| "_ui/appBarIcons/onebar.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/twobars": "\uE1E7", // group:System |
| "_ui/appBarIcons/twobars.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/threebars": "\uE1E8", // group:System |
| "_ui/appBarIcons/threebars.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/fourbars": "\uE1E9", // group:System |
| "_ui/appBarIcons/fourbars.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/scan": "\uE294", // group:General |
| "_ui/appBarIcons/scan.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/preview": "\uE295", // group:General |
| "_ui/appBarIcons/preview.comment": "{Locked=qps-ploc,qps-plocm}", |
| "ui/appBarIcons/hamburger": "\uE700", // group:General |
| "_ui/appBarIcons/hamburger.comment": "{Locked=qps-ploc,qps-plocm}" |
| } |
| ); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Resources',[ |
| 'exports', |
| './_Global', |
| './_WinRT', |
| './_Base', |
| './_Events', |
| 'require-json!strings/en-us/Microsoft.WinJS.resjson', |
| ], function resourcesInit(exports, _Global, _WinRT, _Base, _Events, defaultStrings) { |
| "use strict"; |
| |
| function _getWinJSString(id) { |
| var result = getString("ms-resource:///Microsoft.WinJS/" + id); |
| |
| if (result.empty) { |
| result = _getStringBuiltIn(id); |
| } |
| |
| return result; |
| } |
| |
| function _getStringBuiltIn(resourceId) { |
| var str = defaultStrings[resourceId]; |
| |
| if (typeof str === "string") { |
| str = { value: str }; |
| } |
| |
| return str || { value: resourceId, empty: true }; |
| } |
| |
| var resourceMap; |
| var mrtEventHook = false; |
| var contextChangedET = "contextchanged"; |
| var resourceContext; |
| |
| var ListenerType = _Base.Class.mix(_Base.Class.define(null, { /* empty */ }, { supportedForProcessing: false }), _Events.eventMixin); |
| var listeners = new ListenerType(); |
| var createEvent = _Events._createEventProperty; |
| |
| var strings = { |
| get malformedFormatStringInput() { return "Malformed, did you mean to escape your '{0}'?"; }, |
| }; |
| |
| _Base.Namespace.define("WinJS.Resources", { |
| _getWinJSString: _getWinJSString |
| }); |
| |
| function formatString(string) { |
| var args = arguments; |
| if (args.length > 1) { |
| string = string.replace(/({{)|(}})|{(\d+)}|({)|(})/g, function (unused, left, right, index, illegalLeft, illegalRight) { |
| if (illegalLeft || illegalRight) { throw formatString(strings.malformedFormatStringInput, illegalLeft || illegalRight); } |
| return (left && "{") || (right && "}") || args[(index | 0) + 1]; |
| }); |
| } |
| return string; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Resources", { |
| addEventListener: function (type, listener, useCapture) { |
| /// <signature helpKeyword="WinJS.Resources.addEventListener"> |
| /// <summary locid="WinJS.Resources.addEventListener"> |
| /// Registers an event handler for the specified event. |
| /// </summary> |
| /// <param name='type' type="String" locid='WinJS.Resources.addEventListener_p:type'> |
| /// The name of the event to handle. |
| /// </param> |
| /// <param name='listener' type="Function" locid='WinJS.Resources.addEventListener_p:listener'> |
| /// The listener to invoke when the event gets raised. |
| /// </param> |
| /// <param name='useCapture' type="Boolean" locid='WinJS.Resources.addEventListener_p:useCapture'> |
| /// Set to true to register the event handler for the capturing phase; set to false to register for the bubbling phase. |
| /// </param> |
| /// </signature> |
| if (_WinRT.Windows.ApplicationModel.Resources.Core.ResourceManager && !mrtEventHook) { |
| if (type === contextChangedET) { |
| try { |
| var resContext = exports._getResourceContext(); |
| if (resContext) { |
| resContext.qualifierValues.addEventListener("mapchanged", function (e) { |
| exports.dispatchEvent(contextChangedET, { qualifier: e.key, changed: e.target[e.key] }); |
| }, false); |
| |
| } else { |
| // The API can be called in the Background thread (web worker). |
| _WinRT.Windows.ApplicationModel.Resources.Core.ResourceManager.current.defaultContext.qualifierValues.addEventListener("mapchanged", function (e) { |
| exports.dispatchEvent(contextChangedET, { qualifier: e.key, changed: e.target[e.key] }); |
| }, false); |
| } |
| mrtEventHook = true; |
| } catch (e) { |
| } |
| } |
| } |
| listeners.addEventListener(type, listener, useCapture); |
| }, |
| removeEventListener: listeners.removeEventListener.bind(listeners), |
| dispatchEvent: listeners.dispatchEvent.bind(listeners), |
| |
| _formatString: formatString, |
| |
| _getStringWinRT: function (resourceId) { |
| if (!resourceMap) { |
| var mainResourceMap = _WinRT.Windows.ApplicationModel.Resources.Core.ResourceManager.current.mainResourceMap; |
| try { |
| resourceMap = mainResourceMap.getSubtree('Resources'); |
| } |
| catch (e) { |
| } |
| if (!resourceMap) { |
| resourceMap = mainResourceMap; |
| } |
| } |
| |
| var stringValue; |
| var langValue; |
| var resCandidate; |
| try { |
| var resContext = exports._getResourceContext(); |
| if (resContext) { |
| resCandidate = resourceMap.getValue(resourceId, resContext); |
| } else { |
| resCandidate = resourceMap.getValue(resourceId); |
| } |
| |
| if (resCandidate) { |
| stringValue = resCandidate.valueAsString; |
| if (stringValue === undefined) { |
| stringValue = resCandidate.toString(); |
| } |
| } |
| } |
| catch (e) { } |
| |
| if (!stringValue) { |
| return exports._getStringJS(resourceId); |
| } |
| |
| try { |
| langValue = resCandidate.getQualifierValue("Language"); |
| } |
| catch (e) { |
| return { value: stringValue }; |
| } |
| |
| return { value: stringValue, lang: langValue }; |
| }, |
| |
| _getStringJS: function (resourceId) { |
| var str = _Global.strings && _Global.strings[resourceId]; |
| if (typeof str === "string") { |
| str = { value: str }; |
| } |
| return str || { value: resourceId, empty: true }; |
| }, |
| |
| _getResourceContext: function () { |
| if (_Global.document) { |
| if (typeof (resourceContext) === 'undefined') { |
| var context = _WinRT.Windows.ApplicationModel.Resources.Core.ResourceContext; |
| if (context.getForCurrentView) { |
| resourceContext = context.getForCurrentView(); |
| } else { |
| resourceContext = null; |
| } |
| |
| } |
| } |
| return resourceContext; |
| }, |
| |
| oncontextchanged: createEvent(contextChangedET) |
| |
| }); |
| |
| var getStringImpl = _WinRT.Windows.ApplicationModel.Resources.Core.ResourceManager ? exports._getStringWinRT : exports._getStringJS; |
| |
| var getString = function (resourceId) { |
| /// <signature helpKeyword="WinJS.Resources.getString"> |
| /// <summary locid='WinJS.Resources.getString'> |
| /// Retrieves the resource string that has the specified resource id. |
| /// </summary> |
| /// <param name='resourceId' type="Number" locid='WinJS.Resources.getString._p:resourceId'> |
| /// The resource id of the string to retrieve. |
| /// </param> |
| /// <returns type='Object' locid='WinJS.Resources.getString_returnValue'> |
| /// An object that can contain these properties: |
| /// |
| /// value: |
| /// The value of the requested string. This property is always present. |
| /// |
| /// empty: |
| /// A value that specifies whether the requested string wasn't found. |
| /// If its true, the string wasn't found. If its false or undefined, |
| /// the requested string was found. |
| /// |
| /// lang: |
| /// The language of the string, if specified. This property is only present |
| /// for multi-language resources. |
| /// |
| /// </returns> |
| /// </signature> |
| |
| return getStringImpl(resourceId); |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, null, { |
| _formatString: formatString, |
| _getWinJSString: _getWinJSString |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Resources", { |
| getString: { |
| get: function () { |
| return getString; |
| }, |
| set: function (value) { |
| getString = value; |
| } |
| } |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Trace',[ |
| './_Global' |
| ], function traceInit(_Global) { |
| "use strict"; |
| |
| function nop(v) { |
| return v; |
| } |
| |
| return { |
| _traceAsyncOperationStarting: (_Global.Debug && _Global.Debug.msTraceAsyncOperationStarting && _Global.Debug.msTraceAsyncOperationStarting.bind(_Global.Debug)) || nop, |
| _traceAsyncOperationCompleted: (_Global.Debug && _Global.Debug.msTraceAsyncOperationCompleted && _Global.Debug.msTraceAsyncOperationCompleted.bind(_Global.Debug)) || nop, |
| _traceAsyncCallbackStarting: (_Global.Debug && _Global.Debug.msTraceAsyncCallbackStarting && _Global.Debug.msTraceAsyncCallbackStarting.bind(_Global.Debug)) || nop, |
| _traceAsyncCallbackCompleted: (_Global.Debug && _Global.Debug.msTraceAsyncCallbackCompleted && _Global.Debug.msTraceAsyncCallbackCompleted.bind(_Global.Debug)) || nop |
| }; |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Promise/_StateMachine',[ |
| '../Core/_Global', |
| '../Core/_BaseCoreUtils', |
| '../Core/_Base', |
| '../Core/_ErrorFromName', |
| '../Core/_Events', |
| '../Core/_Trace' |
| ], function promiseStateMachineInit(_Global, _BaseCoreUtils, _Base, _ErrorFromName, _Events, _Trace) { |
| "use strict"; |
| |
| _Global.Debug && (_Global.Debug.setNonUserCodeExceptions = true); |
| |
| var ListenerType = _Base.Class.mix(_Base.Class.define(null, { /*empty*/ }, { supportedForProcessing: false }), _Events.eventMixin); |
| var promiseEventListeners = new ListenerType(); |
| // make sure there is a listeners collection so that we can do a more trivial check below |
| promiseEventListeners._listeners = {}; |
| var errorET = "error"; |
| var canceledName = "Canceled"; |
| var tagWithStack = false; |
| var tag = { |
| promise: 0x01, |
| thenPromise: 0x02, |
| errorPromise: 0x04, |
| exceptionPromise: 0x08, |
| completePromise: 0x10, |
| }; |
| tag.all = tag.promise | tag.thenPromise | tag.errorPromise | tag.exceptionPromise | tag.completePromise; |
| |
| // |
| // Global error counter, for each error which enters the system we increment this once and then |
| // the error number travels with the error as it traverses the tree of potential handlers. |
| // |
| // When someone has registered to be told about errors (WinJS.Promise.callonerror) promises |
| // which are in error will get tagged with a ._errorId field. This tagged field is the |
| // contract by which nested promises with errors will be identified as chaining for the |
| // purposes of the callonerror semantics. If a nested promise in error is encountered without |
| // a ._errorId it will be assumed to be foreign and treated as an interop boundary and |
| // a new error id will be minted. |
| // |
| var error_number = 1; |
| |
| // |
| // The state machine has a interesting hiccup in it with regards to notification, in order |
| // to flatten out notification and avoid recursion for synchronous completion we have an |
| // explicit set of *_notify states which are responsible for notifying their entire tree |
| // of children. They can do this because they know that immediate children are always |
| // ThenPromise instances and we can therefore reach into their state to access the |
| // _listeners collection. |
| // |
| // So, what happens is that a Promise will be fulfilled through the _completed or _error |
| // messages at which point it will enter a *_notify state and be responsible for to move |
| // its children into an (as appropriate) success or error state and also notify that child's |
| // listeners of the state transition, until leaf notes are reached. |
| // |
| |
| var state_created, // -> working |
| state_working, // -> error | error_notify | success | success_notify | canceled | waiting |
| state_waiting, // -> error | error_notify | success | success_notify | waiting_canceled |
| state_waiting_canceled, // -> error | error_notify | success | success_notify | canceling |
| state_canceled, // -> error | error_notify | success | success_notify | canceling |
| state_canceling, // -> error_notify |
| state_success_notify, // -> success |
| state_success, // -> . |
| state_error_notify, // -> error |
| state_error; // -> . |
| |
| // Noop function, used in the various states to indicate that they don't support a given |
| // message. Named with the somewhat cute name '_' because it reads really well in the states. |
| |
| function _() { } |
| |
| // Initial state |
| // |
| state_created = { |
| name: "created", |
| enter: function (promise) { |
| promise._setState(state_working); |
| }, |
| cancel: _, |
| done: _, |
| then: _, |
| _completed: _, |
| _error: _, |
| _notify: _, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // Ready state, waiting for a message (completed/error/progress), able to be canceled |
| // |
| state_working = { |
| name: "working", |
| enter: _, |
| cancel: function (promise) { |
| promise._setState(state_canceled); |
| }, |
| done: done, |
| then: then, |
| _completed: completed, |
| _error: error, |
| _notify: _, |
| _progress: progress, |
| _setCompleteValue: setCompleteValue, |
| _setErrorValue: setErrorValue |
| }; |
| |
| // Waiting state, if a promise is completed with a value which is itself a promise |
| // (has a then() method) it signs up to be informed when that child promise is |
| // fulfilled at which point it will be fulfilled with that value. |
| // |
| state_waiting = { |
| name: "waiting", |
| enter: function (promise) { |
| var waitedUpon = promise._value; |
| // We can special case our own intermediate promises which are not in a |
| // terminal state by just pushing this promise as a listener without |
| // having to create new indirection functions |
| if (waitedUpon instanceof ThenPromise && |
| waitedUpon._state !== state_error && |
| waitedUpon._state !== state_success) { |
| pushListener(waitedUpon, { promise: promise }); |
| } else { |
| var error = function (value) { |
| if (waitedUpon._errorId) { |
| promise._chainedError(value, waitedUpon); |
| } else { |
| // Because this is an interop boundary we want to indicate that this |
| // error has been handled by the promise infrastructure before we |
| // begin a new handling chain. |
| // |
| callonerror(promise, value, detailsForHandledError, waitedUpon, error); |
| promise._error(value); |
| } |
| }; |
| error.handlesOnError = true; |
| waitedUpon.then( |
| promise._completed.bind(promise), |
| error, |
| promise._progress.bind(promise) |
| ); |
| } |
| }, |
| cancel: function (promise) { |
| promise._setState(state_waiting_canceled); |
| }, |
| done: done, |
| then: then, |
| _completed: completed, |
| _error: error, |
| _notify: _, |
| _progress: progress, |
| _setCompleteValue: setCompleteValue, |
| _setErrorValue: setErrorValue |
| }; |
| |
| // Waiting canceled state, when a promise has been in a waiting state and receives a |
| // request to cancel its pending work it will forward that request to the child promise |
| // and then waits to be informed of the result. This promise moves itself into the |
| // canceling state but understands that the child promise may instead push it to a |
| // different state. |
| // |
| state_waiting_canceled = { |
| name: "waiting_canceled", |
| enter: function (promise) { |
| // Initiate a transition to canceling. Triggering a cancel on the promise |
| // that we are waiting upon may result in a different state transition |
| // before the state machine pump runs again. |
| promise._setState(state_canceling); |
| var waitedUpon = promise._value; |
| if (waitedUpon.cancel) { |
| waitedUpon.cancel(); |
| } |
| }, |
| cancel: _, |
| done: done, |
| then: then, |
| _completed: completed, |
| _error: error, |
| _notify: _, |
| _progress: progress, |
| _setCompleteValue: setCompleteValue, |
| _setErrorValue: setErrorValue |
| }; |
| |
| // Canceled state, moves to the canceling state and then tells the promise to do |
| // whatever it might need to do on cancelation. |
| // |
| state_canceled = { |
| name: "canceled", |
| enter: function (promise) { |
| // Initiate a transition to canceling. The _cancelAction may change the state |
| // before the state machine pump runs again. |
| promise._setState(state_canceling); |
| promise._cancelAction(); |
| }, |
| cancel: _, |
| done: done, |
| then: then, |
| _completed: completed, |
| _error: error, |
| _notify: _, |
| _progress: progress, |
| _setCompleteValue: setCompleteValue, |
| _setErrorValue: setErrorValue |
| }; |
| |
| // Canceling state, commits to the promise moving to an error state with an error |
| // object whose 'name' and 'message' properties contain the string "Canceled" |
| // |
| state_canceling = { |
| name: "canceling", |
| enter: function (promise) { |
| var error = new Error(canceledName); |
| error.name = error.message; |
| promise._value = error; |
| promise._setState(state_error_notify); |
| }, |
| cancel: _, |
| done: _, |
| then: _, |
| _completed: _, |
| _error: _, |
| _notify: _, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // Success notify state, moves a promise to the success state and notifies all children |
| // |
| state_success_notify = { |
| name: "complete_notify", |
| enter: function (promise) { |
| promise.done = CompletePromise.prototype.done; |
| promise.then = CompletePromise.prototype.then; |
| if (promise._listeners) { |
| var queue = [promise]; |
| var p; |
| while (queue.length) { |
| p = queue.shift(); |
| p._state._notify(p, queue); |
| } |
| } |
| promise._setState(state_success); |
| }, |
| cancel: _, |
| done: null, /*error to get here */ |
| then: null, /*error to get here */ |
| _completed: _, |
| _error: _, |
| _notify: notifySuccess, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // Success state, moves a promise to the success state and does NOT notify any children. |
| // Some upstream promise is owning the notification pass. |
| // |
| state_success = { |
| name: "success", |
| enter: function (promise) { |
| promise.done = CompletePromise.prototype.done; |
| promise.then = CompletePromise.prototype.then; |
| promise._cleanupAction(); |
| }, |
| cancel: _, |
| done: null, /*error to get here */ |
| then: null, /*error to get here */ |
| _completed: _, |
| _error: _, |
| _notify: notifySuccess, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // Error notify state, moves a promise to the error state and notifies all children |
| // |
| state_error_notify = { |
| name: "error_notify", |
| enter: function (promise) { |
| promise.done = ErrorPromise.prototype.done; |
| promise.then = ErrorPromise.prototype.then; |
| if (promise._listeners) { |
| var queue = [promise]; |
| var p; |
| while (queue.length) { |
| p = queue.shift(); |
| p._state._notify(p, queue); |
| } |
| } |
| promise._setState(state_error); |
| }, |
| cancel: _, |
| done: null, /*error to get here*/ |
| then: null, /*error to get here*/ |
| _completed: _, |
| _error: _, |
| _notify: notifyError, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // Error state, moves a promise to the error state and does NOT notify any children. |
| // Some upstream promise is owning the notification pass. |
| // |
| state_error = { |
| name: "error", |
| enter: function (promise) { |
| promise.done = ErrorPromise.prototype.done; |
| promise.then = ErrorPromise.prototype.then; |
| promise._cleanupAction(); |
| }, |
| cancel: _, |
| done: null, /*error to get here*/ |
| then: null, /*error to get here*/ |
| _completed: _, |
| _error: _, |
| _notify: notifyError, |
| _progress: _, |
| _setCompleteValue: _, |
| _setErrorValue: _ |
| }; |
| |
| // |
| // The statemachine implementation follows a very particular pattern, the states are specified |
| // as static stateless bags of functions which are then indirected through the state machine |
| // instance (a Promise). As such all of the functions on each state have the promise instance |
| // passed to them explicitly as a parameter and the Promise instance members do a little |
| // dance where they indirect through the state and insert themselves in the argument list. |
| // |
| // We could instead call directly through the promise states however then every caller |
| // would have to remember to do things like pumping the state machine to catch state transitions. |
| // |
| |
| var PromiseStateMachine = _Base.Class.define(null, { |
| _listeners: null, |
| _nextState: null, |
| _state: null, |
| _value: null, |
| |
| cancel: function () { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.cancel"> |
| /// <summary locid="WinJS.PromiseStateMachine.cancel"> |
| /// Attempts to cancel the fulfillment of a promised value. If the promise hasn't |
| /// already been fulfilled and cancellation is supported, the promise enters |
| /// the error state with a value of Error("Canceled"). |
| /// </summary> |
| /// </signature> |
| this._state.cancel(this); |
| this._run(); |
| }, |
| done: function Promise_done(onComplete, onError, onProgress) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.done"> |
| /// <summary locid="WinJS.PromiseStateMachine.done"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// |
| /// After the handlers have finished executing, this function throws any error that would have been returned |
| /// from then() as a promise in the error state. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.done_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The fulfilled value is passed as the single argument. If the value is null, |
| /// the fulfilled value is returned. The value returned |
| /// from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while executing the function, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function is the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onProgress"> |
| /// the function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// </signature> |
| this._state.done(this, onComplete, onError, onProgress); |
| }, |
| then: function Promise_then(onComplete, onError, onProgress) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.then"> |
| /// <summary locid="WinJS.PromiseStateMachine.then"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.then_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The value is passed as the single argument. If the value is null, the value is returned. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while this function is being executed, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onProgress"> |
| /// The function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.PromiseStateMachine.then_returnValue"> |
| /// The promise whose value is the result of executing the complete or |
| /// error function. |
| /// </returns> |
| /// </signature> |
| return this._state.then(this, onComplete, onError, onProgress); |
| }, |
| |
| _chainedError: function (value, context) { |
| var result = this._state._error(this, value, detailsForChainedError, context); |
| this._run(); |
| return result; |
| }, |
| _completed: function (value) { |
| var result = this._state._completed(this, value); |
| this._run(); |
| return result; |
| }, |
| _error: function (value) { |
| var result = this._state._error(this, value, detailsForError); |
| this._run(); |
| return result; |
| }, |
| _progress: function (value) { |
| this._state._progress(this, value); |
| }, |
| _setState: function (state) { |
| this._nextState = state; |
| }, |
| _setCompleteValue: function (value) { |
| this._state._setCompleteValue(this, value); |
| this._run(); |
| }, |
| _setChainedErrorValue: function (value, context) { |
| var result = this._state._setErrorValue(this, value, detailsForChainedError, context); |
| this._run(); |
| return result; |
| }, |
| _setExceptionValue: function (value) { |
| var result = this._state._setErrorValue(this, value, detailsForException); |
| this._run(); |
| return result; |
| }, |
| _run: function () { |
| while (this._nextState) { |
| this._state = this._nextState; |
| this._nextState = null; |
| this._state.enter(this); |
| } |
| } |
| }, { |
| supportedForProcessing: false |
| }); |
| |
| // |
| // Implementations of shared state machine code. |
| // |
| |
| function completed(promise, value) { |
| var targetState; |
| if (value && typeof value === "object" && typeof value.then === "function") { |
| targetState = state_waiting; |
| } else { |
| targetState = state_success_notify; |
| } |
| promise._value = value; |
| promise._setState(targetState); |
| } |
| function createErrorDetails(exception, error, promise, id, parent, handler) { |
| return { |
| exception: exception, |
| error: error, |
| promise: promise, |
| handler: handler, |
| id: id, |
| parent: parent |
| }; |
| } |
| function detailsForHandledError(promise, errorValue, context, handler) { |
| var exception = context._isException; |
| var errorId = context._errorId; |
| return createErrorDetails( |
| exception ? errorValue : null, |
| exception ? null : errorValue, |
| promise, |
| errorId, |
| context, |
| handler |
| ); |
| } |
| function detailsForChainedError(promise, errorValue, context) { |
| var exception = context._isException; |
| var errorId = context._errorId; |
| setErrorInfo(promise, errorId, exception); |
| return createErrorDetails( |
| exception ? errorValue : null, |
| exception ? null : errorValue, |
| promise, |
| errorId, |
| context |
| ); |
| } |
| function detailsForError(promise, errorValue) { |
| var errorId = ++error_number; |
| setErrorInfo(promise, errorId); |
| return createErrorDetails( |
| null, |
| errorValue, |
| promise, |
| errorId |
| ); |
| } |
| function detailsForException(promise, exceptionValue) { |
| var errorId = ++error_number; |
| setErrorInfo(promise, errorId, true); |
| return createErrorDetails( |
| exceptionValue, |
| null, |
| promise, |
| errorId |
| ); |
| } |
| function done(promise, onComplete, onError, onProgress) { |
| var asyncOpID = _Trace._traceAsyncOperationStarting("WinJS.Promise.done"); |
| pushListener(promise, { c: onComplete, e: onError, p: onProgress, asyncOpID: asyncOpID }); |
| } |
| function error(promise, value, onerrorDetails, context) { |
| promise._value = value; |
| callonerror(promise, value, onerrorDetails, context); |
| promise._setState(state_error_notify); |
| } |
| function notifySuccess(promise, queue) { |
| var value = promise._value; |
| var listeners = promise._listeners; |
| if (!listeners) { |
| return; |
| } |
| promise._listeners = null; |
| var i, len; |
| for (i = 0, len = Array.isArray(listeners) ? listeners.length : 1; i < len; i++) { |
| var listener = len === 1 ? listeners : listeners[i]; |
| var onComplete = listener.c; |
| var target = listener.promise; |
| |
| _Trace._traceAsyncOperationCompleted(listener.asyncOpID, _Global.Debug && _Global.Debug.MS_ASYNC_OP_STATUS_SUCCESS); |
| |
| if (target) { |
| _Trace._traceAsyncCallbackStarting(listener.asyncOpID); |
| try { |
| target._setCompleteValue(onComplete ? onComplete(value) : value); |
| } catch (ex) { |
| target._setExceptionValue(ex); |
| } finally { |
| _Trace._traceAsyncCallbackCompleted(); |
| } |
| if (target._state !== state_waiting && target._listeners) { |
| queue.push(target); |
| } |
| } else { |
| CompletePromise.prototype.done.call(promise, onComplete); |
| } |
| } |
| } |
| function notifyError(promise, queue) { |
| var value = promise._value; |
| var listeners = promise._listeners; |
| if (!listeners) { |
| return; |
| } |
| promise._listeners = null; |
| var i, len; |
| for (i = 0, len = Array.isArray(listeners) ? listeners.length : 1; i < len; i++) { |
| var listener = len === 1 ? listeners : listeners[i]; |
| var onError = listener.e; |
| var target = listener.promise; |
| |
| var errorID = _Global.Debug && (value && value.name === canceledName ? _Global.Debug.MS_ASYNC_OP_STATUS_CANCELED : _Global.Debug.MS_ASYNC_OP_STATUS_ERROR); |
| _Trace._traceAsyncOperationCompleted(listener.asyncOpID, errorID); |
| |
| if (target) { |
| var asyncCallbackStarted = false; |
| try { |
| if (onError) { |
| _Trace._traceAsyncCallbackStarting(listener.asyncOpID); |
| asyncCallbackStarted = true; |
| if (!onError.handlesOnError) { |
| callonerror(target, value, detailsForHandledError, promise, onError); |
| } |
| target._setCompleteValue(onError(value)); |
| } else { |
| target._setChainedErrorValue(value, promise); |
| } |
| } catch (ex) { |
| target._setExceptionValue(ex); |
| } finally { |
| if (asyncCallbackStarted) { |
| _Trace._traceAsyncCallbackCompleted(); |
| } |
| } |
| if (target._state !== state_waiting && target._listeners) { |
| queue.push(target); |
| } |
| } else { |
| ErrorPromise.prototype.done.call(promise, null, onError); |
| } |
| } |
| } |
| function callonerror(promise, value, onerrorDetailsGenerator, context, handler) { |
| if (promiseEventListeners._listeners[errorET]) { |
| if (value instanceof Error && value.message === canceledName) { |
| return; |
| } |
| promiseEventListeners.dispatchEvent(errorET, onerrorDetailsGenerator(promise, value, context, handler)); |
| } |
| } |
| function progress(promise, value) { |
| var listeners = promise._listeners; |
| if (listeners) { |
| var i, len; |
| for (i = 0, len = Array.isArray(listeners) ? listeners.length : 1; i < len; i++) { |
| var listener = len === 1 ? listeners : listeners[i]; |
| var onProgress = listener.p; |
| if (onProgress) { |
| try { onProgress(value); } catch (ex) { } |
| } |
| if (!(listener.c || listener.e) && listener.promise) { |
| listener.promise._progress(value); |
| } |
| } |
| } |
| } |
| function pushListener(promise, listener) { |
| var listeners = promise._listeners; |
| if (listeners) { |
| // We may have either a single listener (which will never be wrapped in an array) |
| // or 2+ listeners (which will be wrapped). Since we are now adding one more listener |
| // we may have to wrap the single listener before adding the second. |
| listeners = Array.isArray(listeners) ? listeners : [listeners]; |
| listeners.push(listener); |
| } else { |
| listeners = listener; |
| } |
| promise._listeners = listeners; |
| } |
| // The difference beween setCompleteValue()/setErrorValue() and complete()/error() is that setXXXValue() moves |
| // a promise directly to the success/error state without starting another notification pass (because one |
| // is already ongoing). |
| function setErrorInfo(promise, errorId, isException) { |
| promise._isException = isException || false; |
| promise._errorId = errorId; |
| } |
| function setErrorValue(promise, value, onerrorDetails, context) { |
| promise._value = value; |
| callonerror(promise, value, onerrorDetails, context); |
| promise._setState(state_error); |
| } |
| function setCompleteValue(promise, value) { |
| var targetState; |
| if (value && typeof value === "object" && typeof value.then === "function") { |
| targetState = state_waiting; |
| } else { |
| targetState = state_success; |
| } |
| promise._value = value; |
| promise._setState(targetState); |
| } |
| function then(promise, onComplete, onError, onProgress) { |
| var result = new ThenPromise(promise); |
| var asyncOpID = _Trace._traceAsyncOperationStarting("WinJS.Promise.then"); |
| pushListener(promise, { promise: result, c: onComplete, e: onError, p: onProgress, asyncOpID: asyncOpID }); |
| return result; |
| } |
| |
| // |
| // Internal implementation detail promise, ThenPromise is created when a promise needs |
| // to be returned from a then() method. |
| // |
| var ThenPromise = _Base.Class.derive(PromiseStateMachine, |
| function (creator) { |
| |
| if (tagWithStack && (tagWithStack === true || (tagWithStack & tag.thenPromise))) { |
| this._stack = Promise._getStack(); |
| } |
| |
| this._creator = creator; |
| this._setState(state_created); |
| this._run(); |
| }, { |
| _creator: null, |
| |
| _cancelAction: function () { if (this._creator) { this._creator.cancel(); } }, |
| _cleanupAction: function () { this._creator = null; } |
| }, { |
| supportedForProcessing: false |
| } |
| ); |
| |
| // |
| // Slim promise implementations for already completed promises, these are created |
| // under the hood on synchronous completion paths as well as by WinJS.Promise.wrap |
| // and WinJS.Promise.wrapError. |
| // |
| |
| var ErrorPromise = _Base.Class.define( |
| function ErrorPromise_ctor(value) { |
| |
| if (tagWithStack && (tagWithStack === true || (tagWithStack & tag.errorPromise))) { |
| this._stack = Promise._getStack(); |
| } |
| |
| this._value = value; |
| callonerror(this, value, detailsForError); |
| }, { |
| cancel: function () { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.cancel"> |
| /// <summary locid="WinJS.PromiseStateMachine.cancel"> |
| /// Attempts to cancel the fulfillment of a promised value. If the promise hasn't |
| /// already been fulfilled and cancellation is supported, the promise enters |
| /// the error state with a value of Error("Canceled"). |
| /// </summary> |
| /// </signature> |
| }, |
| done: function ErrorPromise_done(unused, onError) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.done"> |
| /// <summary locid="WinJS.PromiseStateMachine.done"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// |
| /// After the handlers have finished executing, this function throws any error that would have been returned |
| /// from then() as a promise in the error state. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.done_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The fulfilled value is passed as the single argument. If the value is null, |
| /// the fulfilled value is returned. The value returned |
| /// from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while executing the function, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function is the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onProgress"> |
| /// the function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// </signature> |
| var value = this._value; |
| if (onError) { |
| try { |
| if (!onError.handlesOnError) { |
| callonerror(null, value, detailsForHandledError, this, onError); |
| } |
| var result = onError(value); |
| if (result && typeof result === "object" && typeof result.done === "function") { |
| // If a promise is returned we need to wait on it. |
| result.done(); |
| } |
| return; |
| } catch (ex) { |
| value = ex; |
| } |
| } |
| if (value instanceof Error && value.message === canceledName) { |
| // suppress cancel |
| return; |
| } |
| // force the exception to be thrown asyncronously to avoid any try/catch blocks |
| // |
| Promise._doneHandler(value); |
| }, |
| then: function ErrorPromise_then(unused, onError) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.then"> |
| /// <summary locid="WinJS.PromiseStateMachine.then"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.then_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The value is passed as the single argument. If the value is null, the value is returned. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while this function is being executed, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onProgress"> |
| /// The function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.PromiseStateMachine.then_returnValue"> |
| /// The promise whose value is the result of executing the complete or |
| /// error function. |
| /// </returns> |
| /// </signature> |
| |
| // If the promise is already in a error state and no error handler is provided |
| // we optimize by simply returning the promise instead of creating a new one. |
| // |
| if (!onError) { return this; } |
| var result; |
| var value = this._value; |
| try { |
| if (!onError.handlesOnError) { |
| callonerror(null, value, detailsForHandledError, this, onError); |
| } |
| result = new CompletePromise(onError(value)); |
| } catch (ex) { |
| // If the value throw from the error handler is the same as the value |
| // provided to the error handler then there is no need for a new promise. |
| // |
| if (ex === value) { |
| result = this; |
| } else { |
| result = new ExceptionPromise(ex); |
| } |
| } |
| return result; |
| } |
| }, { |
| supportedForProcessing: false |
| } |
| ); |
| |
| var ExceptionPromise = _Base.Class.derive(ErrorPromise, |
| function ExceptionPromise_ctor(value) { |
| |
| if (tagWithStack && (tagWithStack === true || (tagWithStack & tag.exceptionPromise))) { |
| this._stack = Promise._getStack(); |
| } |
| |
| this._value = value; |
| callonerror(this, value, detailsForException); |
| }, { |
| /* empty */ |
| }, { |
| supportedForProcessing: false |
| } |
| ); |
| |
| var CompletePromise = _Base.Class.define( |
| function CompletePromise_ctor(value) { |
| |
| if (tagWithStack && (tagWithStack === true || (tagWithStack & tag.completePromise))) { |
| this._stack = Promise._getStack(); |
| } |
| |
| if (value && typeof value === "object" && typeof value.then === "function") { |
| var result = new ThenPromise(null); |
| result._setCompleteValue(value); |
| return result; |
| } |
| this._value = value; |
| }, { |
| cancel: function () { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.cancel"> |
| /// <summary locid="WinJS.PromiseStateMachine.cancel"> |
| /// Attempts to cancel the fulfillment of a promised value. If the promise hasn't |
| /// already been fulfilled and cancellation is supported, the promise enters |
| /// the error state with a value of Error("Canceled"). |
| /// </summary> |
| /// </signature> |
| }, |
| done: function CompletePromise_done(onComplete) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.done"> |
| /// <summary locid="WinJS.PromiseStateMachine.done"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// |
| /// After the handlers have finished executing, this function throws any error that would have been returned |
| /// from then() as a promise in the error state. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.done_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The fulfilled value is passed as the single argument. If the value is null, |
| /// the fulfilled value is returned. The value returned |
| /// from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while executing the function, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function is the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.done_p:onProgress"> |
| /// the function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// </signature> |
| if (!onComplete) { return; } |
| try { |
| var result = onComplete(this._value); |
| if (result && typeof result === "object" && typeof result.done === "function") { |
| result.done(); |
| } |
| } catch (ex) { |
| // force the exception to be thrown asynchronously to avoid any try/catch blocks |
| Promise._doneHandler(ex); |
| } |
| }, |
| then: function CompletePromise_then(onComplete) { |
| /// <signature helpKeyword="WinJS.PromiseStateMachine.then"> |
| /// <summary locid="WinJS.PromiseStateMachine.then"> |
| /// Allows you to specify the work to be done on the fulfillment of the promised value, |
| /// the error handling to be performed if the promise fails to fulfill |
| /// a value, and the handling of progress notifications along the way. |
| /// </summary> |
| /// <param name='onComplete' type='Function' locid="WinJS.PromiseStateMachine.then_p:onComplete"> |
| /// The function to be called if the promise is fulfilled successfully with a value. |
| /// The value is passed as the single argument. If the value is null, the value is returned. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by |
| /// then(). If an exception is thrown while this function is being executed, the promise returned |
| /// by then() moves into the error state. |
| /// </param> |
| /// <param name='onError' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onError"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. If it is null, the error is forwarded. |
| /// The value returned from the function becomes the fulfilled value of the promise returned by then(). |
| /// </param> |
| /// <param name='onProgress' type='Function' optional='true' locid="WinJS.PromiseStateMachine.then_p:onProgress"> |
| /// The function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.PromiseStateMachine.then_returnValue"> |
| /// The promise whose value is the result of executing the complete or |
| /// error function. |
| /// </returns> |
| /// </signature> |
| try { |
| // If the value returned from the completion handler is the same as the value |
| // provided to the completion handler then there is no need for a new promise. |
| // |
| var newValue = onComplete ? onComplete(this._value) : this._value; |
| return newValue === this._value ? this : new CompletePromise(newValue); |
| } catch (ex) { |
| return new ExceptionPromise(ex); |
| } |
| } |
| }, { |
| supportedForProcessing: false |
| } |
| ); |
| |
| // |
| // Promise is the user-creatable WinJS.Promise object. |
| // |
| |
| function timeout(timeoutMS) { |
| var id; |
| return new Promise( |
| function (c) { |
| if (timeoutMS) { |
| id = _Global.setTimeout(c, timeoutMS); |
| } else { |
| _BaseCoreUtils._setImmediate(c); |
| } |
| }, |
| function () { |
| if (id) { |
| _Global.clearTimeout(id); |
| } |
| } |
| ); |
| } |
| |
| function timeoutWithPromise(timeout, promise) { |
| var cancelPromise = function () { promise.cancel(); }; |
| var cancelTimeout = function () { timeout.cancel(); }; |
| timeout.then(cancelPromise); |
| promise.then(cancelTimeout, cancelTimeout); |
| return promise; |
| } |
| |
| var staticCanceledPromise; |
| |
| var Promise = _Base.Class.derive(PromiseStateMachine, |
| function Promise_ctor(init, oncancel) { |
| /// <signature helpKeyword="WinJS.Promise"> |
| /// <summary locid="WinJS.Promise"> |
| /// A promise provides a mechanism to schedule work to be done on a value that |
| /// has not yet been computed. It is a convenient abstraction for managing |
| /// interactions with asynchronous APIs. |
| /// </summary> |
| /// <param name="init" type="Function" locid="WinJS.Promise_p:init"> |
| /// The function that is called during construction of the promise. The function |
| /// is given three arguments (complete, error, progress). Inside this function |
| /// you should add event listeners for the notifications supported by this value. |
| /// </param> |
| /// <param name="oncancel" optional="true" locid="WinJS.Promise_p:oncancel"> |
| /// The function to call if a consumer of this promise wants |
| /// to cancel its undone work. Promises are not required to |
| /// support cancellation. |
| /// </param> |
| /// </signature> |
| |
| if (tagWithStack && (tagWithStack === true || (tagWithStack & tag.promise))) { |
| this._stack = Promise._getStack(); |
| } |
| |
| this._oncancel = oncancel; |
| this._setState(state_created); |
| this._run(); |
| |
| try { |
| var complete = this._completed.bind(this); |
| var error = this._error.bind(this); |
| var progress = this._progress.bind(this); |
| init(complete, error, progress); |
| } catch (ex) { |
| this._setExceptionValue(ex); |
| } |
| }, { |
| _oncancel: null, |
| |
| _cancelAction: function () { |
| if (this._oncancel) { |
| try { this._oncancel(); } catch (ex) { } |
| } |
| }, |
| _cleanupAction: function () { this._oncancel = null; } |
| }, { |
| |
| addEventListener: function Promise_addEventListener(eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Promise.addEventListener"> |
| /// <summary locid="WinJS.Promise.addEventListener"> |
| /// Adds an event listener to the control. |
| /// </summary> |
| /// <param name="eventType" locid="WinJS.Promise.addEventListener_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" locid="WinJS.Promise.addEventListener_p:listener"> |
| /// The listener to invoke when the event is raised. |
| /// </param> |
| /// <param name="capture" locid="WinJS.Promise.addEventListener_p:capture"> |
| /// Specifies whether or not to initiate capture. |
| /// </param> |
| /// </signature> |
| promiseEventListeners.addEventListener(eventType, listener, capture); |
| }, |
| any: function Promise_any(values) { |
| /// <signature helpKeyword="WinJS.Promise.any"> |
| /// <summary locid="WinJS.Promise.any"> |
| /// Returns a promise that is fulfilled when one of the input promises |
| /// has been fulfilled. |
| /// </summary> |
| /// <param name="values" type="Array" locid="WinJS.Promise.any_p:values"> |
| /// An array that contains promise objects or objects whose property |
| /// values include promise objects. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.any_returnValue"> |
| /// A promise that on fulfillment yields the value of the input (complete or error). |
| /// </returns> |
| /// </signature> |
| return new Promise( |
| function (complete, error) { |
| var keys = Object.keys(values); |
| if (keys.length === 0) { |
| complete(); |
| } |
| var canceled = 0; |
| keys.forEach(function (key) { |
| Promise.as(values[key]).then( |
| function () { complete({ key: key, value: values[key] }); }, |
| function (e) { |
| if (e instanceof Error && e.name === canceledName) { |
| if ((++canceled) === keys.length) { |
| complete(Promise.cancel); |
| } |
| return; |
| } |
| error({ key: key, value: values[key] }); |
| } |
| ); |
| }); |
| }, |
| function () { |
| var keys = Object.keys(values); |
| keys.forEach(function (key) { |
| var promise = Promise.as(values[key]); |
| if (typeof promise.cancel === "function") { |
| promise.cancel(); |
| } |
| }); |
| } |
| ); |
| }, |
| as: function Promise_as(value) { |
| /// <signature helpKeyword="WinJS.Promise.as"> |
| /// <summary locid="WinJS.Promise.as"> |
| /// Returns a promise. If the object is already a promise it is returned; |
| /// otherwise the object is wrapped in a promise. |
| /// </summary> |
| /// <param name="value" locid="WinJS.Promise.as_p:value"> |
| /// The value to be treated as a promise. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.as_returnValue"> |
| /// A promise. |
| /// </returns> |
| /// </signature> |
| if (value && typeof value === "object" && typeof value.then === "function") { |
| return value; |
| } |
| return new CompletePromise(value); |
| }, |
| /// <field type="WinJS.Promise" helpKeyword="WinJS.Promise.cancel" locid="WinJS.Promise.cancel"> |
| /// Canceled promise value, can be returned from a promise completion handler |
| /// to indicate cancelation of the promise chain. |
| /// </field> |
| cancel: { |
| get: function () { |
| return (staticCanceledPromise = staticCanceledPromise || new ErrorPromise(new _ErrorFromName(canceledName))); |
| } |
| }, |
| dispatchEvent: function Promise_dispatchEvent(eventType, details) { |
| /// <signature helpKeyword="WinJS.Promise.dispatchEvent"> |
| /// <summary locid="WinJS.Promise.dispatchEvent"> |
| /// Raises an event of the specified type and properties. |
| /// </summary> |
| /// <param name="eventType" locid="WinJS.Promise.dispatchEvent_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="details" locid="WinJS.Promise.dispatchEvent_p:details"> |
| /// The set of additional properties to be attached to the event object. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Promise.dispatchEvent_returnValue"> |
| /// Specifies whether preventDefault was called on the event. |
| /// </returns> |
| /// </signature> |
| return promiseEventListeners.dispatchEvent(eventType, details); |
| }, |
| is: function Promise_is(value) { |
| /// <signature helpKeyword="WinJS.Promise.is"> |
| /// <summary locid="WinJS.Promise.is"> |
| /// Determines whether a value fulfills the promise contract. |
| /// </summary> |
| /// <param name="value" locid="WinJS.Promise.is_p:value"> |
| /// A value that may be a promise. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Promise.is_returnValue"> |
| /// true if the specified value is a promise, otherwise false. |
| /// </returns> |
| /// </signature> |
| return value && typeof value === "object" && typeof value.then === "function"; |
| }, |
| join: function Promise_join(values) { |
| /// <signature helpKeyword="WinJS.Promise.join"> |
| /// <summary locid="WinJS.Promise.join"> |
| /// Creates a promise that is fulfilled when all the values are fulfilled. |
| /// </summary> |
| /// <param name="values" type="Object" locid="WinJS.Promise.join_p:values"> |
| /// An object whose fields contain values, some of which may be promises. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.join_returnValue"> |
| /// A promise whose value is an object with the same field names as those of the object in the values parameter, where |
| /// each field value is the fulfilled value of a promise. |
| /// </returns> |
| /// </signature> |
| return new Promise( |
| function (complete, error, progress) { |
| var keys = Object.keys(values); |
| var errors = Array.isArray(values) ? [] : {}; |
| var results = Array.isArray(values) ? [] : {}; |
| var undefineds = 0; |
| var pending = keys.length; |
| var argDone = function (key) { |
| if ((--pending) === 0) { |
| var errorCount = Object.keys(errors).length; |
| if (errorCount === 0) { |
| complete(results); |
| } else { |
| var canceledCount = 0; |
| keys.forEach(function (key) { |
| var e = errors[key]; |
| if (e instanceof Error && e.name === canceledName) { |
| canceledCount++; |
| } |
| }); |
| if (canceledCount === errorCount) { |
| complete(Promise.cancel); |
| } else { |
| error(errors); |
| } |
| } |
| } else { |
| progress({ Key: key, Done: true }); |
| } |
| }; |
| keys.forEach(function (key) { |
| var value = values[key]; |
| if (value === undefined) { |
| undefineds++; |
| } else { |
| Promise.then(value, |
| function (value) { results[key] = value; argDone(key); }, |
| function (value) { errors[key] = value; argDone(key); } |
| ); |
| } |
| }); |
| pending -= undefineds; |
| if (pending === 0) { |
| complete(results); |
| return; |
| } |
| }, |
| function () { |
| Object.keys(values).forEach(function (key) { |
| var promise = Promise.as(values[key]); |
| if (typeof promise.cancel === "function") { |
| promise.cancel(); |
| } |
| }); |
| } |
| ); |
| }, |
| removeEventListener: function Promise_removeEventListener(eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Promise.removeEventListener"> |
| /// <summary locid="WinJS.Promise.removeEventListener"> |
| /// Removes an event listener from the control. |
| /// </summary> |
| /// <param name='eventType' locid="WinJS.Promise.removeEventListener_eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name='listener' locid="WinJS.Promise.removeEventListener_listener"> |
| /// The listener to remove. |
| /// </param> |
| /// <param name='capture' locid="WinJS.Promise.removeEventListener_capture"> |
| /// Specifies whether or not to initiate capture. |
| /// </param> |
| /// </signature> |
| promiseEventListeners.removeEventListener(eventType, listener, capture); |
| }, |
| supportedForProcessing: false, |
| then: function Promise_then(value, onComplete, onError, onProgress) { |
| /// <signature helpKeyword="WinJS.Promise.then"> |
| /// <summary locid="WinJS.Promise.then"> |
| /// A static version of the promise instance method then(). |
| /// </summary> |
| /// <param name="value" locid="WinJS.Promise.then_p:value"> |
| /// the value to be treated as a promise. |
| /// </param> |
| /// <param name="onComplete" type="Function" locid="WinJS.Promise.then_p:complete"> |
| /// The function to be called if the promise is fulfilled with a value. |
| /// If it is null, the promise simply |
| /// returns the value. The value is passed as the single argument. |
| /// </param> |
| /// <param name="onError" type="Function" optional="true" locid="WinJS.Promise.then_p:error"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. |
| /// </param> |
| /// <param name="onProgress" type="Function" optional="true" locid="WinJS.Promise.then_p:progress"> |
| /// The function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.then_returnValue"> |
| /// A promise whose value is the result of executing the provided complete function. |
| /// </returns> |
| /// </signature> |
| return Promise.as(value).then(onComplete, onError, onProgress); |
| }, |
| thenEach: function Promise_thenEach(values, onComplete, onError, onProgress) { |
| /// <signature helpKeyword="WinJS.Promise.thenEach"> |
| /// <summary locid="WinJS.Promise.thenEach"> |
| /// Performs an operation on all the input promises and returns a promise |
| /// that has the shape of the input and contains the result of the operation |
| /// that has been performed on each input. |
| /// </summary> |
| /// <param name="values" locid="WinJS.Promise.thenEach_p:values"> |
| /// A set of values (which could be either an array or an object) of which some or all are promises. |
| /// </param> |
| /// <param name="onComplete" type="Function" locid="WinJS.Promise.thenEach_p:complete"> |
| /// The function to be called if the promise is fulfilled with a value. |
| /// If the value is null, the promise returns the value. |
| /// The value is passed as the single argument. |
| /// </param> |
| /// <param name="onError" type="Function" optional="true" locid="WinJS.Promise.thenEach_p:error"> |
| /// The function to be called if the promise is fulfilled with an error. The error |
| /// is passed as the single argument. |
| /// </param> |
| /// <param name="onProgress" type="Function" optional="true" locid="WinJS.Promise.thenEach_p:progress"> |
| /// The function to be called if the promise reports progress. Data about the progress |
| /// is passed as the single argument. Promises are not required to support |
| /// progress. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.thenEach_returnValue"> |
| /// A promise that is the result of calling Promise.join on the values parameter. |
| /// </returns> |
| /// </signature> |
| var result = Array.isArray(values) ? [] : {}; |
| Object.keys(values).forEach(function (key) { |
| result[key] = Promise.as(values[key]).then(onComplete, onError, onProgress); |
| }); |
| return Promise.join(result); |
| }, |
| timeout: function Promise_timeout(time, promise) { |
| /// <signature helpKeyword="WinJS.Promise.timeout"> |
| /// <summary locid="WinJS.Promise.timeout"> |
| /// Creates a promise that is fulfilled after a timeout. |
| /// </summary> |
| /// <param name="timeout" type="Number" optional="true" locid="WinJS.Promise.timeout_p:timeout"> |
| /// The timeout period in milliseconds. If this value is zero or not specified |
| /// setImmediate is called, otherwise setTimeout is called. |
| /// </param> |
| /// <param name="promise" type="Promise" optional="true" locid="WinJS.Promise.timeout_p:promise"> |
| /// A promise that will be canceled if it doesn't complete before the |
| /// timeout has expired. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.timeout_returnValue"> |
| /// A promise that is completed asynchronously after the specified timeout. |
| /// </returns> |
| /// </signature> |
| var to = timeout(time); |
| return promise ? timeoutWithPromise(to, promise) : to; |
| }, |
| wrap: function Promise_wrap(value) { |
| /// <signature helpKeyword="WinJS.Promise.wrap"> |
| /// <summary locid="WinJS.Promise.wrap"> |
| /// Wraps a non-promise value in a promise. You can use this function if you need |
| /// to pass a value to a function that requires a promise. |
| /// </summary> |
| /// <param name="value" locid="WinJS.Promise.wrap_p:value"> |
| /// Some non-promise value to be wrapped in a promise. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.wrap_returnValue"> |
| /// A promise that is successfully fulfilled with the specified value |
| /// </returns> |
| /// </signature> |
| return new CompletePromise(value); |
| }, |
| wrapError: function Promise_wrapError(error) { |
| /// <signature helpKeyword="WinJS.Promise.wrapError"> |
| /// <summary locid="WinJS.Promise.wrapError"> |
| /// Wraps a non-promise error value in a promise. You can use this function if you need |
| /// to pass an error to a function that requires a promise. |
| /// </summary> |
| /// <param name="error" locid="WinJS.Promise.wrapError_p:error"> |
| /// A non-promise error value to be wrapped in a promise. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Promise.wrapError_returnValue"> |
| /// A promise that is in an error state with the specified value. |
| /// </returns> |
| /// </signature> |
| return new ErrorPromise(error); |
| }, |
| |
| _veryExpensiveTagWithStack: { |
| get: function () { return tagWithStack; }, |
| set: function (value) { tagWithStack = value; } |
| }, |
| _veryExpensiveTagWithStack_tag: tag, |
| _getStack: function () { |
| if (_Global.Debug && _Global.Debug.debuggerEnabled) { |
| try { throw new Error(); } catch (e) { return e.stack; } |
| } |
| }, |
| |
| _cancelBlocker: function Promise__cancelBlocker(input, oncancel) { |
| // |
| // Returns a promise which on cancelation will still result in downstream cancelation while |
| // protecting the promise 'input' from being canceled which has the effect of allowing |
| // 'input' to be shared amoung various consumers. |
| // |
| if (!Promise.is(input)) { |
| return Promise.wrap(input); |
| } |
| var complete; |
| var error; |
| var output = new Promise( |
| function (c, e) { |
| complete = c; |
| error = e; |
| }, |
| function () { |
| complete = null; |
| error = null; |
| oncancel && oncancel(); |
| } |
| ); |
| input.then( |
| function (v) { complete && complete(v); }, |
| function (e) { error && error(e); } |
| ); |
| return output; |
| }, |
| |
| } |
| ); |
| Object.defineProperties(Promise, _Events.createEventProperties(errorET)); |
| |
| Promise._doneHandler = function (value) { |
| _BaseCoreUtils._setImmediate(function Promise_done_rethrow() { |
| throw value; |
| }); |
| }; |
| |
| return { |
| PromiseStateMachine: PromiseStateMachine, |
| Promise: Promise, |
| state_created: state_created |
| }; |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Promise',[ |
| './Core/_Base', |
| './Promise/_StateMachine' |
| ], function promiseInit( _Base, _StateMachine) { |
| "use strict"; |
| |
| _Base.Namespace.define("WinJS", { |
| Promise: _StateMachine.Promise |
| }); |
| |
| return _StateMachine.Promise; |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_Log',[ |
| 'exports', |
| './_Global', |
| './_Base', |
| ], function logInit(exports, _Global, _Base) { |
| "use strict"; |
| |
| var spaceR = /\s+/g; |
| var typeR = /^(error|warn|info|log)$/; |
| var WinJSLog = null; |
| |
| function format(message, tag, type) { |
| /// <signature helpKeyword="WinJS.Utilities.formatLog"> |
| /// <summary locid="WinJS.Utilities.formatLog"> |
| /// Adds tags and type to a logging message. |
| /// </summary> |
| /// <param name="message" type="String" locid="WinJS.Utilities.startLog_p:message">The message to format.</param> |
| /// <param name="tag" type="String" locid="WinJS.Utilities.startLog_p:tag"> |
| /// The tag(s) to apply to the message. Separate multiple tags with spaces. |
| /// </param> |
| /// <param name="type" type="String" locid="WinJS.Utilities.startLog_p:type">The type of the message.</param> |
| /// <returns type="String" locid="WinJS.Utilities.startLog_returnValue">The formatted message.</returns> |
| /// </signature> |
| var m = message; |
| if (typeof (m) === "function") { m = m(); } |
| |
| return ((type && typeR.test(type)) ? ("") : (type ? (type + ": ") : "")) + |
| (tag ? tag.replace(spaceR, ":") + ": " : "") + |
| m; |
| } |
| function defAction(message, tag, type) { |
| var m = exports.formatLog(message, tag, type); |
| if (_Global.console) { |
| _Global.console[(type && typeR.test(type)) ? type : "log"](m); |
| } |
| } |
| function escape(s) { |
| // \s (whitespace) is used as separator, so don't escape it |
| return s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); |
| } |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| startLog: function (options) { |
| /// <signature helpKeyword="WinJS.Utilities.startLog"> |
| /// <summary locid="WinJS.Utilities.startLog"> |
| /// Configures a logger that writes messages containing the specified tags from WinJS.log to console.log. |
| /// </summary> |
| /// <param name="options" type="String" locid="WinJS.Utilities.startLog_p:options"> |
| /// The tags for messages to log. Separate multiple tags with spaces. |
| /// </param> |
| /// </signature> |
| /// <signature> |
| /// <summary locid="WinJS.Utilities.startLog2"> |
| /// Configure a logger to write WinJS.log output. |
| /// </summary> |
| /// <param name="options" type="Object" locid="WinJS.Utilities.startLog_p:options2"> |
| /// May contain .type, .tags, .excludeTags and .action properties. |
| /// - .type is a required tag. |
| /// - .excludeTags is a space-separated list of tags, any of which will result in a message not being logged. |
| /// - .tags is a space-separated list of tags, any of which will result in a message being logged. |
| /// - .action is a function that, if present, will be called with the log message, tags and type. The default is to log to the console. |
| /// </param> |
| /// </signature> |
| options = options || {}; |
| if (typeof options === "string") { |
| options = { tags: options }; |
| } |
| var el = options.type && new RegExp("^(" + escape(options.type).replace(spaceR, " ").split(" ").join("|") + ")$"); |
| var not = options.excludeTags && new RegExp("(^|\\s)(" + escape(options.excludeTags).replace(spaceR, " ").split(" ").join("|") + ")(\\s|$)", "i"); |
| var has = options.tags && new RegExp("(^|\\s)(" + escape(options.tags).replace(spaceR, " ").split(" ").join("|") + ")(\\s|$)", "i"); |
| var action = options.action || defAction; |
| |
| if (!el && !not && !has && !exports.log) { |
| exports.log = action; |
| return; |
| } |
| |
| var result = function (message, tag, type) { |
| if (!((el && !el.test(type)) // if the expected log level is not satisfied |
| || (not && not.test(tag)) // if any of the excluded categories exist |
| || (has && !has.test(tag)))) { // if at least one of the included categories doesn't exist |
| action(message, tag, type); |
| } |
| |
| result.next && result.next(message, tag, type); |
| }; |
| result.next = exports.log; |
| exports.log = result; |
| }, |
| stopLog: function () { |
| /// <signature helpKeyword="WinJS.Utilities.stopLog"> |
| /// <summary locid="WinJS.Utilities.stopLog"> |
| /// Removes the previously set up logger. |
| /// </summary> |
| /// </signature> |
| exports.log = null; |
| }, |
| formatLog: format |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS", { |
| log: { |
| get: function () { |
| return WinJSLog; |
| }, |
| set: function (value) { |
| WinJSLog = value; |
| } |
| } |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Scheduler',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_Base', |
| './Core/_ErrorFromName', |
| './Core/_Log', |
| './Core/_Resources', |
| './Core/_Trace', |
| './Core/_WriteProfilerMark', |
| './Promise' |
| ], function schedulerInit(exports, _Global, _Base, _ErrorFromName, _Log, _Resources, _Trace, _WriteProfilerMark, Promise) { |
| "use strict"; |
| |
| function linkedListMixin(name) { |
| var mixin = {}; |
| var PREV = "_prev" + name; |
| var NEXT = "_next" + name; |
| mixin["_remove" + name] = function () { |
| // Assumes we always have a static head and tail. |
| // |
| var prev = this[PREV]; |
| var next = this[NEXT]; |
| // PREV <-> NEXT |
| // |
| next && (next[PREV] = prev); |
| prev && (prev[NEXT] = next); |
| // null <- this -> null |
| // |
| this[PREV] = null; |
| this[NEXT] = null; |
| }; |
| mixin["_insert" + name + "Before"] = function (node) { |
| var prev = this[PREV]; |
| // PREV -> node -> this |
| // |
| prev && (prev[NEXT] = node); |
| node[NEXT] = this; |
| // PREV <- node <- this |
| // |
| node[PREV] = prev; |
| this[PREV] = node; |
| |
| return node; |
| }; |
| mixin["_insert" + name + "After"] = function (node) { |
| var next = this[NEXT]; |
| // this -> node -> NEXT |
| // |
| this[NEXT] = node; |
| node[NEXT] = next; |
| // this <- node <- NEXT |
| // |
| node[PREV] = this; |
| next && (next[PREV] = node); |
| |
| return node; |
| }; |
| return mixin; |
| } |
| |
| _Base.Namespace.define("WinJS.Utilities", { |
| |
| _linkedListMixin: linkedListMixin |
| |
| }); |
| |
| var strings = { |
| get jobInfoIsNoLongerValid() { return "The job info object can only be used while the job is running"; } |
| }; |
| |
| // |
| // Profiler mark helpers |
| // |
| // markerType must be one of the following: info, StartTM, StopTM |
| // |
| |
| function profilerMarkArgs(arg0, arg1, arg2) { |
| if (arg2 !== undefined) { |
| return "(" + arg0 + ";" + arg1 + ";" + arg2 + ")"; |
| } else if (arg1 !== undefined) { |
| return "(" + arg0 + ";" + arg1 + ")"; |
| } else if (arg0 !== undefined) { |
| return "(" + arg0 + ")"; |
| } else { |
| return ""; |
| } |
| } |
| |
| function schedulerProfilerMark(operation, markerType, arg0, arg1) { |
| _WriteProfilerMark( |
| "WinJS.Scheduler:" + operation + |
| profilerMarkArgs(arg0, arg1) + |
| "," + markerType |
| ); |
| } |
| |
| function jobProfilerMark(job, operation, markerType, arg0, arg1) { |
| var argProvided = job.name || arg0 !== undefined || arg1 !== undefined; |
| |
| _WriteProfilerMark( |
| "WinJS.Scheduler:" + operation + ":" + job.id + |
| (argProvided ? profilerMarkArgs(job.name, arg0, arg1) : "") + |
| "," + markerType |
| ); |
| } |
| |
| // |
| // Job type. This cannot be instantiated by developers and is instead handed back by the scheduler |
| // schedule method. Its public interface is what is used when interacting with a job. |
| // |
| |
| var JobNode = _Base.Class.define(function (id, work, priority, context, name, asyncOpID) { |
| this._id = id; |
| this._work = work; |
| this._context = context; |
| this._name = name; |
| this._asyncOpID = asyncOpID; |
| this._setPriority(priority); |
| this._setState(state_created); |
| jobProfilerMark(this, "job-scheduled", "info"); |
| }, { |
| |
| /// <field type="Boolean" locid="WinJS.Utilities.Scheduler._JobNode.completed" helpKeyword="WinJS.Utilities.Scheduler._JobNode.completed"> |
| /// Gets a value that indicates whether the job has completed. This value is true if job has run to completion |
| /// and false if it hasn't yet run or was canceled. |
| /// </field> |
| completed: { |
| get: function () { return !!this._state.completed; } |
| }, |
| |
| /// <field type="Number" locid="WinJS.Utilities.Scheduler._JobNode.id" helpKeyword="WinJS.Utilities.Scheduler._JobNode.id"> |
| /// Gets the unique identifier for this job. |
| /// </field> |
| id: { |
| get: function () { return this._id; } |
| }, |
| |
| /// <field type="String" locid="WinJS.Utilities.Scheduler._JobNode.name" helpKeyword="WinJS.Utilities.Scheduler._JobNode.name"> |
| /// Gets or sets a string that specifies the diagnostic name for this job. |
| /// </field> |
| name: { |
| get: function () { return this._name; }, |
| set: function (value) { this._name = value; } |
| }, |
| |
| /// <field type="WinJS.Utilities.Scheduler._OwnerToken" locid="WinJS.Utilities.Scheduler._JobNode.owner" helpKeyword="WinJS.Utilities.Scheduler._JobNode.owner"> |
| /// Gets an owner token for the job. You can use this owner token's cancelAll method to cancel related jobs. |
| /// </field> |
| owner: { |
| get: function () { return this._owner; }, |
| set: function (value) { |
| this._owner && this._owner._remove(this); |
| this._owner = value; |
| this._owner && this._owner._add(this); |
| } |
| }, |
| |
| /// <field type="WinJS.Utilities.Scheduler.Priority" locid="WinJS.Utilities.Scheduler._JobNode.priority" helpKeyword="WinJS.Utilities.Scheduler._JobNode.priority"> |
| /// Gets or sets the priority at which this job is executed by the scheduler. |
| /// </field> |
| priority: { |
| get: function () { return this._priority; }, |
| set: function (value) { |
| value = clampPriority(value); |
| this._state.setPriority(this, value); |
| } |
| }, |
| |
| cancel: function () { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._JobNode.cancel"> |
| /// <summary locid="WinJS.Utilities.Scheduler._JobNode.cancel">Cancels the job.</summary> |
| /// </signature> |
| this._state.cancel(this); |
| }, |
| |
| pause: function () { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._JobNode.pause"> |
| /// <summary locid="WinJS.Utilities.Scheduler._JobNode.pause">Pauses the job.</summary> |
| /// </signature> |
| this._state.pause(this); |
| }, |
| |
| resume: function () { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._JobNode.resume"> |
| /// <summary locid="WinJS.Utilities.Scheduler._JobNode.resume">Resumes the job if it's been paused.</summary> |
| /// </signature> |
| this._state.resume(this); |
| }, |
| |
| _execute: function (shouldYield) { |
| this._state.execute(this, shouldYield); |
| }, |
| |
| _executeDone: function (result) { |
| return this._state.executeDone(this, result); |
| }, |
| |
| _blockedDone: function (result) { |
| return this._state.blockedDone(this, result); |
| }, |
| |
| _setPriority: function (value) { |
| if (+this._priority === this._priority && this._priority !== value) { |
| jobProfilerMark(this, "job-priority-changed", "info", |
| markerFromPriority(this._priority).name, |
| markerFromPriority(value).name); |
| } |
| this._priority = value; |
| }, |
| |
| _setState: function (state, arg0, arg1) { |
| if (this._state) { |
| _Log.log && _Log.log("Transitioning job (" + this.id + ") from: " + this._state.name + " to: " + state.name, "winjs scheduler", "log"); |
| } |
| this._state = state; |
| this._state.enter(this, arg0, arg1); |
| }, |
| |
| }); |
| _Base.Class.mix(JobNode, linkedListMixin("Job")); |
| |
| var YieldPolicy = { |
| complete: 1, |
| continue: 2, |
| block: 3, |
| }; |
| |
| // |
| // JobInfo object is passed to a work item when it is executed and allows the work to ask whether it |
| // should cooperatively yield and in that event provide a continuation work function to run the |
| // next time this job is scheduled. The JobInfo object additionally allows access to the job itself |
| // and the ability to provide a Promise for a future continuation work function in order to have |
| // jobs easily block on async work. |
| // |
| |
| var JobInfo = _Base.Class.define(function (shouldYield, job) { |
| this._job = job; |
| this._result = null; |
| this._yieldPolicy = YieldPolicy.complete; |
| this._shouldYield = shouldYield; |
| }, { |
| |
| /// <field type="WinJS.Utilities.Scheduler._JobNode" locid="WinJS.Utilities.Scheduler._JobInfo.job" helpKeyword="WinJS.Utilities.Scheduler._JobInfo.job"> |
| /// The job instance for which the work is currently being executed. |
| /// </field> |
| job: { |
| get: function () { |
| this._throwIfDisabled(); |
| return this._job; |
| } |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Utilities.Scheduler._JobInfo.shouldYield" helpKeyword="WinJS.Utilities.Scheduler._JobInfo.shouldYield"> |
| /// A boolean which will become true when the work item is requested to cooperatively yield by the scheduler. |
| /// </field> |
| shouldYield: { |
| get: function () { |
| this._throwIfDisabled(); |
| return this._shouldYield(); |
| } |
| }, |
| |
| setPromise: function (promise) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._JobInfo.setPromise"> |
| /// <summary locid="WinJS.Utilities.Scheduler._JobInfo.setPromise"> |
| /// Called when the work item is blocked on asynchronous work. |
| /// The scheduler waits for the specified Promise to complete before rescheduling the job. |
| /// </summary> |
| /// <param name="promise" type="WinJS.Promise" locid="WinJS.Utilities.Scheduler._JobInfo.setPromise_p:promise"> |
| /// A Promise value which, when completed, provides a work item function to be re-scheduled. |
| /// </param> |
| /// </signature> |
| this._throwIfDisabled(); |
| this._result = promise; |
| this._yieldPolicy = YieldPolicy.block; |
| }, |
| |
| setWork: function (work) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._JobInfo.setWork"> |
| /// <summary locid="WinJS.Utilities.Scheduler._JobInfo.setWork"> |
| /// Called when the work item is cooperatively yielding to the scheduler and has more work to complete in the future. |
| /// Use this method to schedule additonal work for when the work item is about to yield. |
| /// </summary> |
| /// <param name="work" type="Function" locid="WinJS.Utilities.Scheduler._JobInfo.setWork_p:work"> |
| /// The work function which will be re-scheduled. |
| /// </param> |
| /// </signature> |
| this._throwIfDisabled(); |
| this._result = work; |
| this._yieldPolicy = YieldPolicy.continue; |
| }, |
| |
| _disablePublicApi: function () { |
| // _disablePublicApi should be called as soon as the job yields. This |
| // says that the job info object should no longer be used by the |
| // job and if the job tries to use it, job info will throw. |
| // |
| this._publicApiDisabled = true; |
| }, |
| |
| _throwIfDisabled: function () { |
| if (this._publicApiDisabled) { |
| throw new _ErrorFromName("WinJS.Utilities.Scheduler.JobInfoIsNoLongerValid", strings.jobInfoIsNoLongerValid); |
| } |
| } |
| |
| }); |
| |
| // |
| // Owner type. Made available to developers through the createOwnerToken method. |
| // Allows cancelation of jobs in bulk. |
| // |
| |
| var OwnerToken = _Base.Class.define(function OwnerToken_ctor() { |
| this._jobs = {}; |
| }, { |
| cancelAll: function OwnerToken_cancelAll() { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler._OwnerToken.cancelAll"> |
| /// <summary locid="WinJS.Utilities.Scheduler._OwnerToken.cancelAll"> |
| /// Cancels all jobs that are associated with this owner token. |
| /// </summary> |
| /// </signature> |
| var jobs = this._jobs, |
| jobIds = Object.keys(jobs); |
| this._jobs = {}; |
| |
| for (var i = 0, len = jobIds.length; i < len; i++) { |
| jobs[jobIds[i]].cancel(); |
| } |
| }, |
| |
| _add: function OwnerToken_add(job) { |
| this._jobs[job.id] = job; |
| }, |
| |
| _remove: function OwnerToken_remove(job) { |
| delete this._jobs[job.id]; |
| } |
| }); |
| |
| function _() { |
| // Noop function, used in the various states to indicate that they don't support a given |
| // message. Named with the somewhat cute name '_' because it reads really well in the states. |
| // |
| return false; |
| } |
| function illegal(job) { |
| /*jshint validthis: true */ |
| throw "Illegal call by job(" + job.id + ") in state: " + this.name; |
| } |
| |
| // |
| // Scheduler job state machine. |
| // |
| // A job normally goes through a lifecycle which is created -> scheduled -> running -> complete. The |
| // Scheduler decides when to transition a job from scheduled to running based on its policies and |
| // the other work which is scheduled. |
| // |
| // Additionally there are various operations which can be performed on a job which will change its |
| // state like: cancel, pause, resume and setting the job's priority. |
| // |
| // Additionally when in the running state a job may either cooperatively yield, or block. |
| // |
| // The job state machine accounts for these various states and interactions. |
| // |
| |
| var State = _Base.Class.define(function (name) { |
| this.name = name; |
| this.enter = illegal; |
| this.execute = illegal; |
| this.executeDone = illegal; |
| this.blockedDone = illegal; |
| this.cancel = illegal; |
| this.pause = illegal; |
| this.resume = illegal; |
| this.setPriority = illegal; |
| }); |
| |
| var state_created = new State("created"), // -> scheduled |
| state_scheduled = new State("scheduled"), // -> running | canceled | paused |
| state_paused = new State("paused"), // -> canceled | scheduled |
| state_canceled = new State("canceled"), // -> . |
| state_running = new State("running"), // -> cooperative_yield | blocked | complete | running_canceled | running_paused |
| state_running_paused = new State("running_paused"), // -> cooperative_yield_paused | blocked_paused | complete | running_canceled | running_resumed |
| state_running_resumed = new State("running_resumed"), // -> cooperative_yield | blocked | complete | running_canceled | running_paused |
| state_running_canceled = new State("running_canceled"), // -> canceled | running_canceled_blocked |
| state_running_canceled_blocked = new State("running_canceled_blocked"), // -> canceled |
| state_cooperative_yield = new State("cooperative_yield"), // -> scheduled |
| state_cooperative_yield_paused = new State("cooperative_yield_paused"), // -> paused |
| state_blocked = new State("blocked"), // -> blocked_waiting |
| state_blocked_waiting = new State("blocked_waiting"), // -> cooperative_yield | complete | blocked_canceled | blocked_paused_waiting |
| state_blocked_paused = new State("blocked_paused"), // -> blocked_paused_waiting |
| state_blocked_paused_waiting = new State("blocked_paused_waiting"), // -> cooperative_yield_paused | complete | blocked_canceled | blocked_waiting |
| state_blocked_canceled = new State("blocked_canceled"), // -> canceled |
| state_complete = new State("complete"); // -> . |
| |
| // A given state may include implementations for the following operations: |
| // |
| // - enter(job, arg0, arg1) |
| // - execute(job, shouldYield) |
| // - executeDone(job, result) --> next state |
| // - blockedDone(job, result, initialPriority) |
| // - cancel(job) |
| // - pause(job) |
| // - resume(job) |
| // - setPriority(job, priority) |
| // |
| // Any functions which are not implemented are illegal in that state. |
| // Any functions which have an implementation of _ are a nop in that state. |
| // |
| |
| // Helper which yields a function that transitions to the specified state |
| // |
| function setState(state) { |
| return function (job, arg0, arg1) { |
| job._setState(state, arg0, arg1); |
| }; |
| } |
| |
| // Helper which sets the priority of a job. |
| // |
| function changePriority(job, priority) { |
| job._setPriority(priority); |
| } |
| |
| // Created |
| // |
| state_created.enter = function (job) { |
| addJobAtTailOfPriority(job, job.priority); |
| job._setState(state_scheduled); |
| }; |
| |
| // Scheduled |
| // |
| state_scheduled.enter = function () { |
| startRunning(); |
| }; |
| state_scheduled.execute = setState(state_running); |
| state_scheduled.cancel = setState(state_canceled); |
| state_scheduled.pause = setState(state_paused); |
| state_scheduled.resume = _; |
| state_scheduled.setPriority = function (job, priority) { |
| if (job.priority !== priority) { |
| job._setPriority(priority); |
| job.pause(); |
| job.resume(); |
| } |
| }; |
| |
| // Paused |
| // |
| state_paused.enter = function (job) { |
| jobProfilerMark(job, "job-paused", "info"); |
| job._removeJob(); |
| }; |
| state_paused.cancel = setState(state_canceled); |
| state_paused.pause = _; |
| state_paused.resume = function (job) { |
| jobProfilerMark(job, "job-resumed", "info"); |
| addJobAtTailOfPriority(job, job.priority); |
| job._setState(state_scheduled); |
| }; |
| state_paused.setPriority = changePriority; |
| |
| // Canceled |
| // |
| state_canceled.enter = function (job) { |
| jobProfilerMark(job, "job-canceled", "info"); |
| _Trace._traceAsyncOperationCompleted(job._asyncOpID, _Global.Debug && _Global.Debug.MS_ASYNC_OP_STATUS_CANCELED); |
| job._removeJob(); |
| job._work = null; |
| job._context = null; |
| job.owner = null; |
| }; |
| state_canceled.cancel = _; |
| state_canceled.pause = _; |
| state_canceled.resume = _; |
| state_canceled.setPriority = _; |
| |
| // Running |
| // |
| state_running.enter = function (job, shouldYield) { |
| // Remove the job from the list in case it throws an exception, this means in the |
| // yield case we have to add it back. |
| // |
| job._removeJob(); |
| |
| var priority = job.priority; |
| var work = job._work; |
| var context = job._context; |
| |
| // Null out the work and context so they aren't leaked if the job throws an exception. |
| // |
| job._work = null; |
| job._context = null; |
| |
| var jobInfo = new JobInfo(shouldYield, job); |
| |
| _Trace._traceAsyncCallbackStarting(job._asyncOpID); |
| try { |
| MSApp.execAtPriority(function () { |
| work.call(context, jobInfo); |
| }, toWwaPriority(priority)); |
| } finally { |
| _Trace._traceAsyncCallbackCompleted(); |
| jobInfo._disablePublicApi(); |
| } |
| |
| // Restore the context in case it is needed due to yielding or blocking. |
| // |
| job._context = context; |
| |
| var targetState = job._executeDone(jobInfo._yieldPolicy); |
| |
| job._setState(targetState, jobInfo._result, priority); |
| }; |
| state_running.executeDone = function (job, yieldPolicy) { |
| switch (yieldPolicy) { |
| case YieldPolicy.complete: |
| return state_complete; |
| case YieldPolicy.continue: |
| return state_cooperative_yield; |
| case YieldPolicy.block: |
| return state_blocked; |
| } |
| }; |
| state_running.cancel = function (job) { |
| // Interaction with the singleton scheduler. The act of canceling a job pokes the scheduler |
| // and tells it to start asking the job to yield. |
| // |
| immediateYield = true; |
| job._setState(state_running_canceled); |
| }; |
| state_running.pause = function (job) { |
| // Interaction with the singleton scheduler. The act of pausing a job pokes the scheduler |
| // and tells it to start asking the job to yield. |
| // |
| immediateYield = true; |
| job._setState(state_running_paused); |
| }; |
| state_running.resume = _; |
| state_running.setPriority = changePriority; |
| |
| // Running paused |
| // |
| state_running_paused.enter = _; |
| state_running_paused.executeDone = function (job, yieldPolicy) { |
| switch (yieldPolicy) { |
| case YieldPolicy.complete: |
| return state_complete; |
| case YieldPolicy.continue: |
| return state_cooperative_yield_paused; |
| case YieldPolicy.block: |
| return state_blocked_paused; |
| } |
| }; |
| state_running_paused.cancel = setState(state_running_canceled); |
| state_running_paused.pause = _; |
| state_running_paused.resume = setState(state_running_resumed); |
| state_running_paused.setPriority = changePriority; |
| |
| // Running resumed |
| // |
| state_running_resumed.enter = _; |
| state_running_resumed.executeDone = function (job, yieldPolicy) { |
| switch (yieldPolicy) { |
| case YieldPolicy.complete: |
| return state_complete; |
| case YieldPolicy.continue: |
| return state_cooperative_yield; |
| case YieldPolicy.block: |
| return state_blocked; |
| } |
| }; |
| state_running_resumed.cancel = setState(state_running_canceled); |
| state_running_resumed.pause = setState(state_running_paused); |
| state_running_resumed.resume = _; |
| state_running_resumed.setPriority = changePriority; |
| |
| // Running canceled |
| // |
| state_running_canceled.enter = _; |
| state_running_canceled.executeDone = function (job, yieldPolicy) { |
| switch (yieldPolicy) { |
| case YieldPolicy.complete: |
| case YieldPolicy.continue: |
| return state_canceled; |
| case YieldPolicy.block: |
| return state_running_canceled_blocked; |
| } |
| }; |
| state_running_canceled.cancel = _; |
| state_running_canceled.pause = _; |
| state_running_canceled.resume = _; |
| state_running_canceled.setPriority = _; |
| |
| // Running canceled -> blocked |
| // |
| state_running_canceled_blocked.enter = function (job, work) { |
| work.cancel(); |
| job._setState(state_canceled); |
| }; |
| |
| // Cooperative yield |
| // |
| state_cooperative_yield.enter = function (job, work, initialPriority) { |
| jobProfilerMark(job, "job-yielded", "info"); |
| if (initialPriority === job.priority) { |
| addJobAtHeadOfPriority(job, job.priority); |
| } else { |
| addJobAtTailOfPriority(job, job.priority); |
| } |
| job._work = work; |
| job._setState(state_scheduled); |
| }; |
| |
| // Cooperative yield paused |
| // |
| state_cooperative_yield_paused.enter = function (job, work) { |
| jobProfilerMark(job, "job-yielded", "info"); |
| job._work = work; |
| job._setState(state_paused); |
| }; |
| |
| // Blocked |
| // |
| state_blocked.enter = function (job, work, initialPriority) { |
| jobProfilerMark(job, "job-blocked", "StartTM"); |
| job._work = work; |
| job._setState(state_blocked_waiting); |
| |
| // Sign up for a completion from the provided promise, after the completion occurs |
| // transition from the current state at the completion time to the target state |
| // depending on the completion value. |
| // |
| work.done( |
| function (newWork) { |
| jobProfilerMark(job, "job-blocked", "StopTM"); |
| var targetState = job._blockedDone(newWork); |
| job._setState(targetState, newWork, initialPriority); |
| }, |
| function (error) { |
| if (!(error && error.name === "Canceled")) { |
| jobProfilerMark(job, "job-error", "info"); |
| } |
| jobProfilerMark(job, "job-blocked", "StopTM"); |
| job._setState(state_canceled); |
| return Promise.wrapError(error); |
| } |
| ); |
| }; |
| |
| // Blocked waiting |
| // |
| state_blocked_waiting.enter = _; |
| state_blocked_waiting.blockedDone = function (job, result) { |
| if (typeof result === "function") { |
| return state_cooperative_yield; |
| } else { |
| return state_complete; |
| } |
| }; |
| state_blocked_waiting.cancel = setState(state_blocked_canceled); |
| state_blocked_waiting.pause = setState(state_blocked_paused_waiting); |
| state_blocked_waiting.resume = _; |
| state_blocked_waiting.setPriority = changePriority; |
| |
| // Blocked paused |
| // |
| state_blocked_paused.enter = function (job, work, initialPriority) { |
| jobProfilerMark(job, "job-blocked", "StartTM"); |
| job._work = work; |
| job._setState(state_blocked_paused_waiting); |
| |
| // Sign up for a completion from the provided promise, after the completion occurs |
| // transition from the current state at the completion time to the target state |
| // depending on the completion value. |
| // |
| work.done( |
| function (newWork) { |
| jobProfilerMark(job, "job-blocked", "StopTM"); |
| var targetState = job._blockedDone(newWork); |
| job._setState(targetState, newWork, initialPriority); |
| }, |
| function (error) { |
| if (!(error && error.name === "Canceled")) { |
| jobProfilerMark(job, "job-error", "info"); |
| } |
| jobProfilerMark(job, "job-blocked", "StopTM"); |
| job._setState(state_canceled); |
| return Promise.wrapError(error); |
| } |
| ); |
| }; |
| |
| // Blocked paused waiting |
| // |
| state_blocked_paused_waiting.enter = _; |
| state_blocked_paused_waiting.blockedDone = function (job, result) { |
| if (typeof result === "function") { |
| return state_cooperative_yield_paused; |
| } else { |
| return state_complete; |
| } |
| }; |
| state_blocked_paused_waiting.cancel = setState(state_blocked_canceled); |
| state_blocked_paused_waiting.pause = _; |
| state_blocked_paused_waiting.resume = setState(state_blocked_waiting); |
| state_blocked_paused_waiting.setPriority = changePriority; |
| |
| // Blocked canceled |
| // |
| state_blocked_canceled.enter = function (job) { |
| // Cancel the outstanding promise and then eventually it will complete, presumably with a 'canceled' |
| // error at which point we will transition to the canceled state. |
| // |
| job._work.cancel(); |
| job._work = null; |
| }; |
| state_blocked_canceled.blockedDone = function () { |
| return state_canceled; |
| }; |
| state_blocked_canceled.cancel = _; |
| state_blocked_canceled.pause = _; |
| state_blocked_canceled.resume = _; |
| state_blocked_canceled.setPriority = _; |
| |
| // Complete |
| // |
| state_complete.completed = true; |
| state_complete.enter = function (job) { |
| _Trace._traceAsyncOperationCompleted(job._asyncOpID, _Global.Debug && _Global.Debug.MS_ASYNC_OP_STATUS_SUCCESS); |
| job._work = null; |
| job._context = null; |
| job.owner = null; |
| jobProfilerMark(job, "job-completed", "info"); |
| }; |
| state_complete.cancel = _; |
| state_complete.pause = _; |
| state_complete.resume = _; |
| state_complete.setPriority = _; |
| |
| // Private Priority marker node in the Job list. The marker nodes are linked both into the job |
| // list and a separate marker list. This is used so that jobs can be easily added into a given |
| // priority level by simply traversing to the next marker in the list and inserting before it. |
| // |
| // Markers may either be "static" or "dynamic". Static markers are the set of things which are |
| // named and are always in the list, they may exist with or without jobs at their priority |
| // level. Dynamic markers are added as needed. |
| // |
| // @NOTE: Dynamic markers are NYI |
| // |
| var MarkerNode = _Base.Class.define(function (priority, name) { |
| this.priority = priority; |
| this.name = name; |
| }, { |
| |
| // NYI |
| // |
| //dynamic: { |
| // get: function () { return !this.name; } |
| //}, |
| |
| }); |
| _Base.Class.mix(MarkerNode, linkedListMixin("Job"), linkedListMixin("Marker")); |
| |
| // |
| // Scheduler state |
| // |
| |
| // Unique ID per job. |
| // |
| var globalJobId = 0; |
| |
| // Unique ID per drain request. |
| var globalDrainId = 0; |
| |
| // Priority is: -15 ... 0 ... 15 where that maps to: 'min' ... 'normal' ... 'max' |
| // |
| var MIN_PRIORITY = -15; |
| var MAX_PRIORITY = 15; |
| |
| // Named priorities |
| // |
| var Priority = { |
| max: 15, |
| high: 13, |
| aboveNormal: 9, |
| normal: 0, |
| belowNormal: -9, |
| idle: -13, |
| min: -15, |
| }; |
| |
| // Definition of the priorities, named have static markers. |
| // |
| var priorities = [ |
| new MarkerNode(15, "max"), // Priority.max |
| new MarkerNode(14, "14"), |
| new MarkerNode(13, "high"), // Priority.high |
| new MarkerNode(12, "12"), |
| new MarkerNode(11, "11"), |
| new MarkerNode(10, "10"), |
| new MarkerNode(9, "aboveNormal"), // Priority.aboveNormal |
| new MarkerNode(8, "8"), |
| new MarkerNode(7, "7"), |
| new MarkerNode(6, "6"), |
| new MarkerNode(5, "5"), |
| new MarkerNode(4, "4"), |
| new MarkerNode(3, "3"), |
| new MarkerNode(2, "2"), |
| new MarkerNode(1, "1"), |
| new MarkerNode(0, "normal"), // Priority.normal |
| new MarkerNode(-1, "-1"), |
| new MarkerNode(-2, "-2"), |
| new MarkerNode(-3, "-3"), |
| new MarkerNode(-4, "-4"), |
| new MarkerNode(-5, "-5"), |
| new MarkerNode(-6, "-6"), |
| new MarkerNode(-7, "-7"), |
| new MarkerNode(-8, "-8"), |
| new MarkerNode(-9, "belowNormal"), // Priority.belowNormal |
| new MarkerNode(-10, "-10"), |
| new MarkerNode(-11, "-11"), |
| new MarkerNode(-12, "-12"), |
| new MarkerNode(-13, "idle"), // Priority.idle |
| new MarkerNode(-14, "-14"), |
| new MarkerNode(-15, "min"), // Priority.min |
| new MarkerNode(-16, "<TAIL>") |
| ]; |
| |
| function dumpList(type, reverse) { |
| function dumpMarker(marker, pos) { |
| _Log.log && _Log.log(pos + ": MARKER: " + marker.name, "winjs scheduler", "log"); |
| } |
| function dumpJob(job, pos) { |
| _Log.log && _Log.log(pos + ": JOB(" + job.id + "): state: " + (job._state ? job._state.name : "") + (job.name ? ", name: " + job.name : ""), "winjs scheduler", "log"); |
| } |
| _Log.log && _Log.log("highWaterMark: " + highWaterMark, "winjs scheduler", "log"); |
| var pos = 0; |
| var head = reverse ? priorities[priorities.length - 1] : priorities[0]; |
| var current = head; |
| do { |
| if (current instanceof MarkerNode) { |
| dumpMarker(current, pos); |
| } |
| if (current instanceof JobNode) { |
| dumpJob(current, pos); |
| } |
| pos++; |
| current = reverse ? current["_prev" + type] : current["_next" + type]; |
| } while (current); |
| } |
| |
| function retrieveState() { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.retrieveState"> |
| /// <summary locid="WinJS.Utilities.Scheduler.retrieveState"> |
| /// Returns a string representation of the scheduler's state for diagnostic |
| /// purposes. The jobs and drain requests are displayed in the order in which |
| /// they are currently expected to be processed. The current job and drain |
| /// request are marked by an asterisk. |
| /// </summary> |
| /// </signature> |
| var output = ""; |
| |
| function logJob(job, isRunning) { |
| output += |
| " " + (isRunning ? "*" : " ") + |
| "id: " + job.id + |
| ", priority: " + markerFromPriority(job.priority).name + |
| (job.name ? ", name: " + job.name : "") + |
| "\n"; |
| } |
| |
| output += "Jobs:\n"; |
| var current = markerFromPriority(highWaterMark); |
| var jobCount = 0; |
| if (runningJob) { |
| logJob(runningJob, true); |
| jobCount++; |
| } |
| while (current.priority >= Priority.min) { |
| if (current instanceof JobNode) { |
| logJob(current, false); |
| jobCount++; |
| } |
| current = current._nextJob; |
| } |
| if (jobCount === 0) { |
| output += " None\n"; |
| } |
| |
| output += "Drain requests:\n"; |
| for (var i = 0, len = drainQueue.length; i < len; i++) { |
| output += |
| " " + (i === 0 ? "*" : " ") + |
| "priority: " + markerFromPriority(drainQueue[i].priority).name + |
| ", name: " + drainQueue[i].name + |
| "\n"; |
| } |
| if (drainQueue.length === 0) { |
| output += " None\n"; |
| } |
| |
| return output; |
| } |
| |
| function isEmpty() { |
| var current = priorities[0]; |
| do { |
| if (current instanceof JobNode) { |
| return false; |
| } |
| current = current._nextJob; |
| } while (current); |
| |
| return true; |
| } |
| |
| // The WWA priority at which the pump is currently scheduled on the WWA scheduler. |
| // null when the pump is not scheduled. |
| // |
| var scheduledWwaPriority = null; |
| |
| // Whether the scheduler pump is currently on the stack |
| // |
| var pumping; |
| // What priority is currently being pumped |
| // |
| var pumpingPriority; |
| |
| // A reference to the job object that is currently running. |
| // null when no job is running. |
| // |
| var runningJob = null; |
| |
| // Whether we are using the WWA scheduler. |
| // |
| var usingWwaScheduler = !!(_Global.MSApp && _Global.MSApp.execAtPriority); |
| |
| // Queue of drain listeners |
| // |
| var drainQueue = []; |
| |
| // Bit indicating that we should yield immediately |
| // |
| var immediateYield; |
| |
| // time slice for scheduler |
| // |
| var TIME_SLICE = 30; |
| |
| // high-water-mark is maintained any time priorities are adjusted, new jobs are |
| // added or the scheduler pumps itself down through a priority marker. The goal |
| // of the high-water-mark is to be a fast check as to whether a job may exist |
| // at a higher priority level than we are currently at. It may be wrong but it |
| // may only be wrong by being higher than the current highest priority job, not |
| // lower as that would cause the system to pump things out of order. |
| // |
| var highWaterMark = Priority.min; |
| |
| // |
| // Initialize the scheduler |
| // |
| |
| // Wire up the markers |
| // |
| priorities.reduce(function (prev, current) { |
| if (prev) { |
| prev._insertJobAfter(current); |
| prev._insertMarkerAfter(current); |
| } |
| return current; |
| }); |
| |
| // |
| // Draining mechanism |
| // |
| // For each active drain request, there is a unique drain listener in the |
| // drainQueue. Requests are processed in FIFO order. The scheduler is in |
| // drain mode precisely when the drainQueue is non-empty. |
| // |
| |
| // Returns priority of the current drain request |
| // |
| function currentDrainPriority() { |
| return drainQueue.length === 0 ? null : drainQueue[0].priority; |
| } |
| |
| function drainStarting(listener) { |
| schedulerProfilerMark("drain", "StartTM", listener.name, markerFromPriority(listener.priority).name); |
| } |
| function drainStopping(listener, canceled) { |
| if (canceled) { |
| schedulerProfilerMark("drain-canceled", "info", listener.name, markerFromPriority(listener.priority).name); |
| } |
| schedulerProfilerMark("drain", "StopTM", listener.name, markerFromPriority(listener.priority).name); |
| } |
| |
| function addDrainListener(priority, complete, name) { |
| drainQueue.push({ priority: priority, complete: complete, name: name }); |
| if (drainQueue.length === 1) { |
| drainStarting(drainQueue[0]); |
| if (priority > highWaterMark) { |
| highWaterMark = priority; |
| immediateYield = true; |
| } |
| } |
| } |
| |
| function removeDrainListener(complete, canceled) { |
| var i, |
| len = drainQueue.length; |
| |
| for (i = 0; i < len; i++) { |
| if (drainQueue[i].complete === complete) { |
| if (i === 0) { |
| drainStopping(drainQueue[0], canceled); |
| drainQueue[1] && drainStarting(drainQueue[1]); |
| } |
| drainQueue.splice(i, 1); |
| break; |
| } |
| } |
| } |
| |
| // Notifies and removes the current drain listener |
| // |
| function notifyCurrentDrainListener() { |
| var listener = drainQueue.shift(); |
| |
| if (listener) { |
| drainStopping(listener); |
| drainQueue[0] && drainStarting(drainQueue[0]); |
| listener.complete(); |
| } |
| } |
| |
| // Notifies all drain listeners which are at a priority > highWaterMark. |
| // Returns whether or not any drain listeners were notified. This |
| // function sets pumpingPriority and reads highWaterMark. Note that |
| // it may call into user code which may call back into the scheduler. |
| // |
| function notifyDrainListeners() { |
| var notifiedSomebody = false; |
| if (!!drainQueue.length) { |
| // As we exhaust priority levels, notify the appropriate drain listeners. |
| // |
| var drainPriority = currentDrainPriority(); |
| while (+drainPriority === drainPriority && drainPriority > highWaterMark) { |
| pumpingPriority = drainPriority; |
| notifyCurrentDrainListener(); |
| notifiedSomebody = true; |
| drainPriority = currentDrainPriority(); |
| } |
| } |
| return notifiedSomebody; |
| } |
| |
| // |
| // Interfacing with the WWA Scheduler |
| // |
| |
| // The purpose of yielding to the host is to give the host the opportunity to do some work. |
| // setImmediate has this guarantee built-in so we prefer that. Otherwise, we do setTimeout 16 |
| // which should give the host a decent amount of time to do work. |
| // |
| var scheduleWithHost = _Global.setImmediate ? _Global.setImmediate.bind(_Global) : function (callback) { |
| _Global.setTimeout(callback, 16); |
| }; |
| |
| // Stubs for the parts of the WWA scheduler APIs that we use. These stubs are |
| // used in contexts where the WWA scheduler is not available. |
| // |
| var MSAppStubs = { |
| execAsyncAtPriority: function (callback, priority) { |
| // If it's a high priority callback then we additionally schedule using setTimeout(0) |
| // |
| if (priority === MSApp.HIGH) { |
| _Global.setTimeout(callback, 0); |
| } |
| // We always schedule using setImmediate |
| // |
| scheduleWithHost(callback); |
| }, |
| |
| execAtPriority: function (callback) { |
| return callback(); |
| }, |
| |
| getCurrentPriority: function () { |
| return MSAppStubs.NORMAL; |
| }, |
| |
| isTaskScheduledAtPriorityOrHigher: function () { |
| return false; |
| }, |
| |
| HIGH: "high", |
| NORMAL: "normal", |
| IDLE: "idle" |
| }; |
| |
| var MSApp = (usingWwaScheduler ? _Global.MSApp : MSAppStubs); |
| |
| function toWwaPriority(winjsPriority) { |
| if (winjsPriority >= Priority.aboveNormal + 1) { return MSApp.HIGH; } |
| if (winjsPriority >= Priority.belowNormal) { return MSApp.NORMAL; } |
| return MSApp.IDLE; |
| } |
| |
| var wwaPriorityToInt = {}; |
| wwaPriorityToInt[MSApp.IDLE] = 1; |
| wwaPriorityToInt[MSApp.NORMAL] = 2; |
| wwaPriorityToInt[MSApp.HIGH] = 3; |
| |
| function isEqualOrHigherWwaPriority(priority1, priority2) { |
| return wwaPriorityToInt[priority1] >= wwaPriorityToInt[priority2]; |
| } |
| |
| function isHigherWwaPriority(priority1, priority2) { |
| return wwaPriorityToInt[priority1] > wwaPriorityToInt[priority2]; |
| } |
| |
| function wwaTaskScheduledAtPriorityHigherThan(wwaPriority) { |
| switch (wwaPriority) { |
| case MSApp.HIGH: |
| return false; |
| case MSApp.NORMAL: |
| return MSApp.isTaskScheduledAtPriorityOrHigher(MSApp.HIGH); |
| case MSApp.IDLE: |
| return MSApp.isTaskScheduledAtPriorityOrHigher(MSApp.NORMAL); |
| } |
| } |
| |
| // |
| // Mechanism for the scheduler |
| // |
| |
| function addJobAtHeadOfPriority(node, priority) { |
| var marker = markerFromPriority(priority); |
| if (marker.priority > highWaterMark) { |
| highWaterMark = marker.priority; |
| immediateYield = true; |
| } |
| marker._insertJobAfter(node); |
| } |
| |
| function addJobAtTailOfPriority(node, priority) { |
| var marker = markerFromPriority(priority); |
| if (marker.priority > highWaterMark) { |
| highWaterMark = marker.priority; |
| immediateYield = true; |
| } |
| marker._nextMarker._insertJobBefore(node); |
| } |
| |
| function clampPriority(priority) { |
| priority = priority | 0; |
| priority = Math.max(priority, MIN_PRIORITY); |
| priority = Math.min(priority, MAX_PRIORITY); |
| return priority; |
| } |
| |
| function markerFromPriority(priority) { |
| priority = clampPriority(priority); |
| |
| // The priority skip list is from high -> idle, add the offset and then make it positive. |
| // |
| return priorities[-1 * (priority - MAX_PRIORITY)]; |
| } |
| |
| // Performance.now is not defined in web workers. |
| // |
| var now = (_Global.performance && _Global.performance.now && _Global.performance.now.bind(_Global.performance)) || Date.now.bind(Date); |
| |
| // Main scheduler pump. |
| // |
| function run(scheduled) { |
| pumping = true; |
| schedulerProfilerMark("timeslice", "StartTM"); |
| var didWork; |
| var ranJobSuccessfully = true; |
| var current; |
| var lastLoggedPriority; |
| var timesliceExhausted = false; |
| var yieldForPriorityBoundary = false; |
| |
| // Reset per-run state |
| // |
| immediateYield = false; |
| |
| try { |
| var start = now(); |
| var end = start + TIME_SLICE; |
| |
| // Yielding policy |
| // |
| // @TODO, should we have a different scheduler policy when the debugger is attached. Today if you |
| // break in user code we will generally yield immediately after that job due to the fact that any |
| // breakpoint will take longer than TIME_SLICE to process. |
| // |
| |
| var shouldYield = function () { |
| timesliceExhausted = false; |
| if (immediateYield) { return true; } |
| if (wwaTaskScheduledAtPriorityHigherThan(toWwaPriority(highWaterMark))) { return true; } |
| if (!!drainQueue.length) { return false; } |
| if (now() > end) { |
| timesliceExhausted = true; |
| return true; |
| } |
| return false; |
| }; |
| |
| // Run until we run out of jobs or decide it is time to yield |
| // |
| while (highWaterMark >= Priority.min && !shouldYield() && !yieldForPriorityBoundary) { |
| |
| didWork = false; |
| current = markerFromPriority(highWaterMark)._nextJob; |
| do { |
| // Record the priority currently being pumped |
| // |
| pumpingPriority = current.priority; |
| |
| if (current instanceof JobNode) { |
| if (lastLoggedPriority !== current.priority) { |
| if (+lastLoggedPriority === lastLoggedPriority) { |
| schedulerProfilerMark("priority", "StopTM", markerFromPriority(lastLoggedPriority).name); |
| } |
| schedulerProfilerMark("priority", "StartTM", markerFromPriority(current.priority).name); |
| lastLoggedPriority = current.priority; |
| } |
| |
| // Important that we update this state before calling execute because the |
| // job may throw an exception and we don't want to stall the queue. |
| // |
| didWork = true; |
| ranJobSuccessfully = false; |
| runningJob = current; |
| jobProfilerMark(runningJob, "job-running", "StartTM", markerFromPriority(pumpingPriority).name); |
| current._execute(shouldYield); |
| jobProfilerMark(runningJob, "job-running", "StopTM", markerFromPriority(pumpingPriority).name); |
| runningJob = null; |
| ranJobSuccessfully = true; |
| } else { |
| // As we pass marker nodes update our high water mark. It's important to do |
| // this before notifying drain listeners because they may schedule new jobs |
| // which will affect the highWaterMark. |
| // |
| var wwaPrevHighWaterMark = toWwaPriority(highWaterMark); |
| highWaterMark = current.priority; |
| |
| didWork = notifyDrainListeners(); |
| |
| var wwaHighWaterMark = toWwaPriority(highWaterMark); |
| if (isHigherWwaPriority(wwaPrevHighWaterMark, wwaHighWaterMark) && |
| (!usingWwaScheduler || MSApp.isTaskScheduledAtPriorityOrHigher(wwaHighWaterMark))) { |
| // Timeslice is moving to a lower WWA priority and the host |
| // has equally or more important work to do. Time to yield. |
| // |
| yieldForPriorityBoundary = true; |
| } |
| } |
| |
| current = current._nextJob; |
| |
| // When didWork is true we exit the loop because: |
| // - We've called into user code which may have modified the |
| // scheduler's queue. We need to restart at the high water mark. |
| // - We need to check if it's time for the scheduler to yield. |
| // |
| } while (current && !didWork && !yieldForPriorityBoundary && !wwaTaskScheduledAtPriorityHigherThan(toWwaPriority(highWaterMark))); |
| |
| // Reset per-item state |
| // |
| immediateYield = false; |
| |
| } |
| |
| } finally { |
| runningJob = null; |
| |
| // If a job was started and did not run to completion due to an exception |
| // we should transition it to a terminal state. |
| // |
| if (!ranJobSuccessfully) { |
| jobProfilerMark(current, "job-error", "info"); |
| jobProfilerMark(current, "job-running", "StopTM", markerFromPriority(pumpingPriority).name); |
| current.cancel(); |
| } |
| |
| if (+lastLoggedPriority === lastLoggedPriority) { |
| schedulerProfilerMark("priority", "StopTM", markerFromPriority(lastLoggedPriority).name); |
| } |
| // Update high water mark to be the priority of the highest priority job. |
| // |
| var foundAJob = false; |
| while (highWaterMark >= Priority.min && !foundAJob) { |
| |
| didWork = false; |
| current = markerFromPriority(highWaterMark)._nextJob; |
| do { |
| |
| if (current instanceof JobNode) { |
| // We found a job. High water mark is now set to the priority |
| // of this job. |
| // |
| foundAJob = true; |
| } else { |
| // As we pass marker nodes update our high water mark. It's important to do |
| // this before notifying drain listeners because they may schedule new jobs |
| // which will affect the highWaterMark. |
| // |
| highWaterMark = current.priority; |
| |
| didWork = notifyDrainListeners(); |
| } |
| |
| current = current._nextJob; |
| |
| // When didWork is true we exit the loop because: |
| // - We've called into user code which may have modified the |
| // scheduler's queue. We need to restart at the high water mark. |
| // |
| } while (current && !didWork && !foundAJob); |
| } |
| |
| var reasonForYielding; |
| if (!ranJobSuccessfully) { |
| reasonForYielding = "job error"; |
| } else if (timesliceExhausted) { |
| reasonForYielding = "timeslice exhausted"; |
| } else if (highWaterMark < Priority.min) { |
| reasonForYielding = "jobs exhausted"; |
| } else if (yieldForPriorityBoundary) { |
| reasonForYielding = "reached WWA priority boundary"; |
| } else { |
| reasonForYielding = "WWA host work"; |
| } |
| |
| // If this was a scheduled call to the pump, then the pump is no longer |
| // scheduled to be called and we should clear its scheduled priority. |
| // |
| if (scheduled) { |
| scheduledWwaPriority = null; |
| } |
| |
| // If the high water mark has not reached the end of the queue then |
| // we re-queue in order to see if there are more jobs to run. |
| // |
| pumping = false; |
| if (highWaterMark >= Priority.min) { |
| startRunning(); |
| } |
| schedulerProfilerMark("yielding", "info", reasonForYielding); |
| schedulerProfilerMark("timeslice", "StopTM"); |
| } |
| } |
| |
| // When we schedule the pump we assign it a version. When we start executing one we check |
| // to see what the max executed version is. If we have superseded it then we skip the call. |
| // |
| var scheduledVersion = 0; |
| var executedVersion = 0; |
| |
| function startRunning(priority) { |
| if (+priority !== priority) { |
| priority = highWaterMark; |
| } |
| var priorityWwa = toWwaPriority(priority); |
| |
| // Don't schedule the pump while pumping. The pump will be scheduled |
| // immediately before yielding if necessary. |
| // |
| if (pumping) { |
| return; |
| } |
| |
| // If the pump is already scheduled at priority or higher, then there |
| // is no need to schedule the pump again. |
| // However, when we're not using the WWA scheduler, we fallback to immediate/timeout |
| // which do not have a notion of priority. In this case, if the pump is scheduled, |
| // there is no need to schedule another pump. |
| // |
| if (scheduledWwaPriority && (!usingWwaScheduler || isEqualOrHigherWwaPriority(scheduledWwaPriority, priorityWwa))) { |
| return; |
| } |
| var current = ++scheduledVersion; |
| var runner = function () { |
| if (executedVersion < current) { |
| executedVersion = scheduledVersion; |
| run(true); |
| } |
| }; |
| |
| MSApp.execAsyncAtPriority(runner, priorityWwa); |
| scheduledWwaPriority = priorityWwa; |
| } |
| |
| function requestDrain(priority, name) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.requestDrain"> |
| /// <summary locid="WinJS.Utilities.Scheduler.requestDrain"> |
| /// Runs jobs in the scheduler without timeslicing until all jobs at the |
| /// specified priority and higher have executed. |
| /// </summary> |
| /// <param name="priority" isOptional="true" type="WinJS.Utilities.Scheduler.Priority" locid="WinJS.Utilities.Scheduler.requestDrain_p:priority"> |
| /// The priority to which the scheduler should drain. The default is Priority.min, which drains all jobs in the queue. |
| /// </param> |
| /// <param name="name" isOptional="true" type="String" locid="WinJS.Utilities.Scheduler.requestDrain_p:name"> |
| /// An optional description of the drain request for diagnostics. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Utilities.Scheduler.requestDrain_returnValue"> |
| /// A promise which completes when the drain has finished. Canceling this |
| /// promise cancels the drain request. This promise will never enter an error state. |
| /// </returns> |
| /// </signature> |
| |
| var id = globalDrainId++; |
| if (name === undefined) { |
| name = "Drain Request " + id; |
| } |
| priority = (+priority === priority) ? priority : Priority.min; |
| priority = clampPriority(priority); |
| |
| var complete; |
| var promise = new Promise(function (c) { |
| complete = c; |
| addDrainListener(priority, complete, name); |
| }, function () { |
| removeDrainListener(complete, true); |
| }); |
| |
| if (!pumping) { |
| startRunning(); |
| } |
| |
| return promise; |
| } |
| |
| function execHigh(callback) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.execHigh"> |
| /// <summary locid="WinJS.Utilities.Scheduler.execHigh"> |
| /// Runs the specified callback in a high priority context. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Utilities.Scheduler.execHigh_p:callback"> |
| /// The callback to run in a high priority context. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.Scheduler.execHigh_returnValue"> |
| /// The return value of the callback. |
| /// </returns> |
| /// </signature> |
| |
| return MSApp.execAtPriority(callback, MSApp.HIGH); |
| } |
| |
| function createOwnerToken() { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.createOwnerToken"> |
| /// <summary locid="WinJS.Utilities.Scheduler.createOwnerToken"> |
| /// Creates and returns a new owner token which can be set to the owner property of one or more jobs. |
| /// It can then be used to cancel all jobs it "owns". |
| /// </summary> |
| /// <returns type="WinJS.Utilities.Scheduler._OwnerToken" locid="WinJS.Utilities.Scheduler.createOwnerToken_returnValue"> |
| /// The new owner token. You can use this token to control jobs that it owns. |
| /// </returns> |
| /// </signature> |
| |
| return new OwnerToken(); |
| } |
| |
| function schedule(work, priority, thisArg, name) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.schedule"> |
| /// <summary locid="WinJS.Utilities.Scheduler.schedule"> |
| /// Schedules the specified function to execute asynchronously. |
| /// </summary> |
| /// <param name="work" type="Function" locid="WinJS.Utilities.Scheduler.schedule_p:work"> |
| /// A function that represents the work item to be scheduled. When called the work item will receive as its first argument |
| /// a JobInfo object which allows the work item to ask the scheduler if it should yield cooperatively and if so allows the |
| /// work item to either provide a function to be run as a continuation or a WinJS.Promise which will when complete |
| /// provide a function to run as a continuation. |
| /// </param> |
| /// <param name="priority" isOptional="true" type="WinJS.Utilities.Scheduler.Priority" locid="WinJS.Utilities.Scheduler.schedule_p:priority"> |
| /// The priority at which to schedule the work item. The default value is Priority.normal. |
| /// </param> |
| /// <param name="thisArg" isOptional="true" type="Object" locid="WinJS.Utilities.Scheduler.schedule_p:thisArg"> |
| /// A 'this' instance to be bound into the work item. The default value is null. |
| /// </param> |
| /// <param name="name" isOptional="true" type="String" locid="WinJS.Utilities.Scheduler.schedule_p:name"> |
| /// A description of the work item for diagnostics. The default value is an empty string. |
| /// </param> |
| /// <returns type="WinJS.Utilities.Scheduler._JobNode" locid="WinJS.Utilities.Scheduler.schedule_returnValue"> |
| /// The Job instance which represents this work item. |
| /// </returns> |
| /// </signature> |
| |
| priority = priority || Priority.normal; |
| thisArg = thisArg || null; |
| var jobId = ++globalJobId; |
| var asyncOpID = _Trace._traceAsyncOperationStarting("WinJS.Utilities.Scheduler.schedule: " + jobId + profilerMarkArgs(name)); |
| name = name || ""; |
| return new JobNode(jobId, work, priority, thisArg, name, asyncOpID); |
| } |
| |
| function getCurrentPriority() { |
| if (pumping) { |
| return pumpingPriority; |
| } else { |
| switch (MSApp.getCurrentPriority()) { |
| case MSApp.HIGH: return Priority.high; |
| case MSApp.NORMAL: return Priority.normal; |
| case MSApp.IDLE: return Priority.idle; |
| } |
| } |
| } |
| |
| function makeSchedulePromise(priority) { |
| return function (promiseValue, jobName) { |
| /// <signature helpKeyword="WinJS.Utilities.Scheduler.schedulePromise"> |
| /// <summary locid="WinJS.Utilities.Scheduler.schedulePromise"> |
| /// Schedules a job to complete a returned Promise. |
| /// There are four versions of this method for different commonly used priorities: schedulePromiseHigh, |
| /// schedulePromiseAboveNormal, schedulePromiseNormal, schedulePromiseBelowNormal, |
| /// and schedulePromiseIdle. |
| /// Example usage which shows how to |
| /// ensure that the last link in a promise chain is run on the scheduler at high priority: |
| /// asyncOp().then(Scheduler.schedulePromiseHigh).then(function (valueOfAsyncOp) { }); |
| /// </summary> |
| /// <param name="promiseValue" isOptional="true" type="Object" locid="WinJS.Utilities.Scheduler.schedulePromise_p:promiseValue"> |
| /// The value with which the returned promise will complete. |
| /// </param> |
| /// <param name="jobName" isOptional="true" type="String" locid="WinJS.Utilities.Scheduler.schedulePromise_p:jobName"> |
| /// A string that describes the job for diagnostic purposes. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Utilities.Scheduler.schedulePromise_returnValue"> |
| /// A promise which completes within a job of the desired priority. |
| /// </returns> |
| /// </signature> |
| var job; |
| return new Promise( |
| function (c) { |
| job = schedule(function schedulePromise() { |
| c(promiseValue); |
| }, priority, null, jobName); |
| }, |
| function () { |
| job.cancel(); |
| } |
| ); |
| }; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities.Scheduler", { |
| |
| Priority: Priority, |
| |
| schedule: schedule, |
| |
| createOwnerToken: createOwnerToken, |
| |
| execHigh: execHigh, |
| |
| requestDrain: requestDrain, |
| |
| /// <field type="WinJS.Utilities.Scheduler.Priority" locid="WinJS.Utilities.Scheduler.currentPriority" helpKeyword="WinJS.Utilities.Scheduler.currentPriority"> |
| /// Gets the current priority at which the caller is executing. |
| /// </field> |
| currentPriority: { |
| get: getCurrentPriority |
| }, |
| |
| // Promise helpers |
| // |
| schedulePromiseHigh: makeSchedulePromise(Priority.high), |
| schedulePromiseAboveNormal: makeSchedulePromise(Priority.aboveNormal), |
| schedulePromiseNormal: makeSchedulePromise(Priority.normal), |
| schedulePromiseBelowNormal: makeSchedulePromise(Priority.belowNormal), |
| schedulePromiseIdle: makeSchedulePromise(Priority.idle), |
| |
| retrieveState: retrieveState, |
| |
| _JobNode: JobNode, |
| |
| _JobInfo: JobInfo, |
| |
| _OwnerToken: OwnerToken, |
| |
| _dumpList: dumpList, |
| |
| _isEmpty: { |
| get: isEmpty |
| }, |
| |
| // The properties below are used for testing. |
| // |
| |
| _usingWwaScheduler: { |
| get: function () { |
| return usingWwaScheduler; |
| }, |
| set: function (value) { |
| usingWwaScheduler = value; |
| MSApp = (usingWwaScheduler ? _Global.MSApp : MSAppStubs); |
| } |
| }, |
| |
| _MSApp: { |
| get: function () { |
| return MSApp; |
| }, |
| set: function (value) { |
| MSApp = value; |
| } |
| }, |
| |
| _TIME_SLICE: TIME_SLICE |
| |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Core/_BaseUtils',[ |
| 'exports', |
| './_Global', |
| './_Base', |
| './_BaseCoreUtils', |
| './_ErrorFromName', |
| './_Resources', |
| './_Trace', |
| '../Promise', |
| '../Scheduler' |
| ], function baseUtilsInit(exports, _Global, _Base, _BaseCoreUtils, _ErrorFromName, _Resources, _Trace, Promise, Scheduler) { |
| "use strict"; |
| |
| var strings = { |
| get notSupportedForProcessing() { return "Value is not supported within a declarative processing context, if you want it to be supported mark it using WinJS.Utilities.markSupportedForProcessing. The value was: '{0}'"; } |
| }; |
| |
| var requestAnimationWorker; |
| var requestAnimationId = 0; |
| var requestAnimationHandlers = {}; |
| var validation = false; |
| var platform = _Global.navigator.platform; |
| var isiOS = platform === "iPhone" || platform === "iPad" || platform === "iPod"; |
| |
| function nop(v) { |
| return v; |
| } |
| |
| function getMemberFiltered(name, root, filter) { |
| return name.split(".").reduce(function (currentNamespace, name) { |
| if (currentNamespace) { |
| return filter(currentNamespace[name]); |
| } |
| return null; |
| }, root); |
| } |
| |
| function getMember(name, root) { |
| /// <signature helpKeyword="WinJS.Utilities.getMember"> |
| /// <summary locid="WinJS.Utilities.getMember"> |
| /// Gets the leaf-level type or namespace specified by the name parameter. |
| /// </summary> |
| /// <param name="name" locid="WinJS.Utilities.getMember_p:name"> |
| /// The name of the member. |
| /// </param> |
| /// <param name="root" locid="WinJS.Utilities.getMember_p:root"> |
| /// The root to start in. Defaults to the global object. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.getMember_returnValue"> |
| /// The leaf-level type or namespace in the specified parent namespace. |
| /// </returns> |
| /// </signature> |
| if (!name) { |
| return null; |
| } |
| return getMemberFiltered(name, root || _Global, nop); |
| } |
| |
| function getCamelCasedName(styleName) { |
| // special case -moz prefixed styles because their JS property name starts with Moz |
| if (styleName.length > 0 && styleName.indexOf("-moz") !== 0 && styleName.charAt(0) === "-") { |
| styleName = styleName.slice(1); |
| } |
| return styleName.replace(/\-[a-z]/g, function (x) { return x[1].toUpperCase(); }); |
| } |
| |
| function addPrefixToCamelCasedName(prefix, name) { |
| if (prefix === "") { |
| return name; |
| } |
| |
| return prefix + name.charAt(0).toUpperCase() + name.slice(1); |
| } |
| |
| function addPrefixToCSSName(prefix, name) { |
| return (prefix !== "" ? "-" + prefix.toLowerCase() + "-" : "") + name; |
| } |
| |
| function getBrowserStyleEquivalents() { |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return {}; |
| } |
| |
| var equivalents = {}, |
| docStyle = _Global.document.documentElement.style, |
| stylePrefixesToTest = ["", "webkit", "ms", "Moz"], |
| styles = ["animation", |
| "transition", |
| "transform", |
| "animation-name", |
| "animation-duration", |
| "animation-delay", |
| "animation-timing-function", |
| "animation-iteration-count", |
| "animation-direction", |
| "animation-fill-mode", |
| "grid-column", |
| "grid-columns", |
| "grid-column-span", |
| "grid-row", |
| "grid-rows", |
| "grid-row-span", |
| "transform-origin", |
| "transition-property", |
| "transition-duration", |
| "transition-delay", |
| "transition-timing-function", |
| "scroll-snap-points-x", |
| "scroll-snap-points-y", |
| "scroll-chaining", |
| "scroll-limit", |
| "scroll-limit-x-max", |
| "scroll-limit-x-min", |
| "scroll-limit-y-max", |
| "scroll-limit-y-min", |
| "scroll-snap-type", |
| "scroll-snap-x", |
| "scroll-snap-y", |
| "touch-action", |
| "overflow-style", |
| "user-select" // used for Template Compiler test |
| ], |
| prefixesUsedOnStyles = {}; |
| |
| for (var i = 0, len = styles.length; i < len; i++) { |
| var originalName = styles[i], |
| styleToTest = getCamelCasedName(originalName); |
| for (var j = 0, prefixLen = stylePrefixesToTest.length; j < prefixLen; j++) { |
| var prefix = stylePrefixesToTest[j]; |
| var styleName = addPrefixToCamelCasedName(prefix, styleToTest); |
| if (styleName in docStyle) { |
| // Firefox doesn't support dashed style names being get/set via script. (eg, something like element.style["transform-origin"] = "" wouldn't work). |
| // For each style translation we create, we'll make a CSS name version and a script name version for it so each can be used where appropriate. |
| var cssName = addPrefixToCSSName(prefix, originalName); |
| equivalents[originalName] = { |
| cssName: cssName, |
| scriptName: styleName |
| }; |
| prefixesUsedOnStyles[originalName] = prefix; |
| break; |
| } |
| } |
| } |
| |
| // Special cases: |
| equivalents.animationPrefix = addPrefixToCSSName(prefixesUsedOnStyles["animation"], ""); |
| equivalents.keyframes = addPrefixToCSSName(prefixesUsedOnStyles["animation"], "keyframes"); |
| |
| return equivalents; |
| } |
| |
| function getBrowserEventEquivalents() { |
| var equivalents = {}; |
| var animationEventPrefixes = ["", "WebKit"], |
| animationEvents = [ |
| { |
| eventObject: "TransitionEvent", |
| events: ["transitionStart", "transitionEnd"] |
| }, |
| { |
| eventObject: "AnimationEvent", |
| events: ["animationStart", "animationEnd"] |
| } |
| ]; |
| |
| for (var i = 0, len = animationEvents.length; i < len; i++) { |
| var eventToTest = animationEvents[i], |
| chosenPrefix = ""; |
| for (var j = 0, prefixLen = animationEventPrefixes.length; j < prefixLen; j++) { |
| var prefix = animationEventPrefixes[j]; |
| if ((prefix + eventToTest.eventObject) in _Global) { |
| chosenPrefix = prefix.toLowerCase(); |
| break; |
| } |
| } |
| for (var j = 0, eventsLen = eventToTest.events.length; j < eventsLen; j++) { |
| var eventName = eventToTest.events[j]; |
| equivalents[eventName] = addPrefixToCamelCasedName(chosenPrefix, eventName); |
| if (chosenPrefix === "") { |
| // Transition and animation events are case sensitive. When there's no prefix, the event name should be in lowercase. |
| // In IE, Chrome and Firefox, an event handler listening to transitionend will be triggered properly, but transitionEnd will not. |
| // When a prefix is provided, though, the event name needs to be case sensitive. |
| // IE and Firefox will trigger an animationend event handler correctly, but Chrome won't trigger webkitanimationend -- it has to be webkitAnimationEnd. |
| equivalents[eventName] = equivalents[eventName].toLowerCase(); |
| } |
| } |
| } |
| |
| // Non-standardized events |
| equivalents["manipulationStateChanged"] = ("MSManipulationEvent" in _Global ? "ManipulationEvent" : null); |
| return equivalents; |
| } |
| |
| // Returns a function which, when called, will call *fn*. However, |
| // if called multiple times, it will only call *fn* at most once every |
| // *delay* milliseconds. Multiple calls during the throttling period |
| // will be coalesced into a single call to *fn* with the arguments being |
| // the ones from the last call received during the throttling period. |
| // Note that, due to the throttling period, *fn* may be invoked asynchronously |
| // relative to the time it was called so make sure its arguments are still valid |
| // (for example, eventObjects will not be valid). |
| // |
| // Example usage. If you want your key down handler to run once every 100 ms, |
| // you could do this: |
| // var onKeyDown = throttledFunction(function (keyCode) { |
| // // do something with keyCode |
| // }); |
| // element.addEventListener("keydown", function (eventObject) { onKeyDown(eventObject.keyCode); }); |
| // |
| function throttledFunction(delay, fn) { |
| var throttlePromise = null; |
| var pendingCallPromise = null; |
| var nextContext = null; |
| var nextArgs = null; |
| |
| function makeThrottlePromise() { |
| return Promise.timeout(delay).then(function () { |
| throttlePromise = null; |
| }); |
| } |
| |
| return function () { |
| if (pendingCallPromise) { |
| nextContext = this; |
| nextArgs = [].slice.call(arguments, 0); |
| } else if (throttlePromise) { |
| nextContext = this; |
| nextArgs = [].slice.call(arguments, 0); |
| pendingCallPromise = throttlePromise.then(function () { |
| var context = nextContext; |
| nextContext = null; |
| var args = nextArgs; |
| nextArgs = null; |
| throttlePromise = makeThrottlePromise(); |
| pendingCallPromise = null; |
| fn.apply(context, args); |
| }); |
| } else { |
| throttlePromise = makeThrottlePromise(); |
| fn.apply(this, arguments); |
| } |
| }; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| // Used for mocking in tests |
| _setHasWinRT: { |
| value: function (value) { |
| _BaseCoreUtils.hasWinRT = value; |
| }, |
| configurable: false, |
| writable: false, |
| enumerable: false |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Utilities.hasWinRT" helpKeyword="WinJS.Utilities.hasWinRT">Determine if WinRT is accessible in this script context.</field> |
| hasWinRT: { |
| get: function () { return _BaseCoreUtils.hasWinRT; }, |
| configurable: false, |
| enumerable: true |
| }, |
| |
| // Used for mocking in tests |
| _setIsiOS: { |
| value: function (value) { |
| isiOS = value; |
| }, |
| configurable: false, |
| writable: false, |
| enumerable: false |
| }, |
| |
| _isiOS: { |
| get: function () { return isiOS; }, |
| configurable: false, |
| enumerable: true |
| }, |
| |
| _getMemberFiltered: getMemberFiltered, |
| |
| getMember: getMember, |
| |
| _browserStyleEquivalents: getBrowserStyleEquivalents(), |
| _browserEventEquivalents: getBrowserEventEquivalents(), |
| _getCamelCasedName: getCamelCasedName, |
| |
| ready: function ready(callback, async) { |
| /// <signature helpKeyword="WinJS.Utilities.ready"> |
| /// <summary locid="WinJS.Utilities.ready"> |
| /// Ensures that the specified function executes only after the DOMContentLoaded event has fired |
| /// for the current page. |
| /// </summary> |
| /// <returns type="WinJS.Promise" locid="WinJS.Utilities.ready_returnValue">A promise that completes after DOMContentLoaded has occurred.</returns> |
| /// <param name="callback" optional="true" locid="WinJS.Utilities.ready_p:callback"> |
| /// A function that executes after DOMContentLoaded has occurred. |
| /// </param> |
| /// <param name="async" optional="true" locid="WinJS.Utilities.ready_p:async"> |
| /// If true, the callback is executed asynchronously. |
| /// </param> |
| /// </signature> |
| return new Promise(function (c, e) { |
| function complete() { |
| if (callback) { |
| try { |
| callback(); |
| c(); |
| } |
| catch (err) { |
| e(err); |
| } |
| } else { |
| c(); |
| } |
| } |
| |
| var readyState = ready._testReadyState; |
| if (!readyState) { |
| if (_Global.document) { |
| readyState = _Global.document.readyState; |
| } else { |
| readyState = "complete"; |
| } |
| } |
| if (readyState === "complete" || (_Global.document && _Global.document.body !== null)) { |
| if (async) { |
| Scheduler.schedule(function WinJS_Utilities_ready() { |
| complete(); |
| }, Scheduler.Priority.normal, null, "WinJS.Utilities.ready"); |
| } else { |
| complete(); |
| } |
| } else { |
| _Global.addEventListener("DOMContentLoaded", complete, false); |
| } |
| }); |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Utilities.strictProcessing" helpKeyword="WinJS.Utilities.strictProcessing">Determines if strict declarative processing is enabled in this script context.</field> |
| strictProcessing: { |
| get: function () { return true; }, |
| configurable: false, |
| enumerable: true, |
| }, |
| |
| markSupportedForProcessing: { |
| value: _BaseCoreUtils.markSupportedForProcessing, |
| configurable: false, |
| writable: false, |
| enumerable: true |
| }, |
| |
| requireSupportedForProcessing: { |
| value: function (value) { |
| /// <signature helpKeyword="WinJS.Utilities.requireSupportedForProcessing"> |
| /// <summary locid="WinJS.Utilities.requireSupportedForProcessing"> |
| /// Asserts that the value is compatible with declarative processing, such as WinJS.UI.processAll |
| /// or WinJS.Binding.processAll. If it is not compatible an exception will be thrown. |
| /// </summary> |
| /// <param name="value" type="Object" locid="WinJS.Utilities.requireSupportedForProcessing_p:value"> |
| /// The value to be tested for compatibility with declarative processing. If the |
| /// value is a function it must be marked with a property 'supportedForProcessing' |
| /// with a value of true. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.requireSupportedForProcessing_returnValue"> |
| /// The input value. |
| /// </returns> |
| /// </signature> |
| var supportedForProcessing = true; |
| |
| supportedForProcessing = supportedForProcessing && value !== _Global; |
| supportedForProcessing = supportedForProcessing && value !== _Global.location; |
| supportedForProcessing = supportedForProcessing && !(value instanceof _Global.HTMLIFrameElement); |
| supportedForProcessing = supportedForProcessing && !(typeof value === "function" && !value.supportedForProcessing); |
| |
| switch (_Global.frames.length) { |
| case 0: |
| break; |
| |
| case 1: |
| supportedForProcessing = supportedForProcessing && value !== _Global.frames[0]; |
| break; |
| |
| default: |
| for (var i = 0, len = _Global.frames.length; supportedForProcessing && i < len; i++) { |
| supportedForProcessing = supportedForProcessing && value !== _Global.frames[i]; |
| } |
| break; |
| } |
| |
| if (supportedForProcessing) { |
| return value; |
| } |
| |
| throw new _ErrorFromName("WinJS.Utilities.requireSupportedForProcessing", _Resources._formatString(strings.notSupportedForProcessing, value)); |
| }, |
| configurable: false, |
| writable: false, |
| enumerable: true |
| }, |
| |
| _setImmediate: _BaseCoreUtils._setImmediate, |
| |
| _requestAnimationFrame: _Global.requestAnimationFrame ? _Global.requestAnimationFrame.bind(_Global) : function (handler) { |
| var handle = ++requestAnimationId; |
| requestAnimationHandlers[handle] = handler; |
| requestAnimationWorker = requestAnimationWorker || _Global.setTimeout(function () { |
| var toProcess = requestAnimationHandlers; |
| var now = Date.now(); |
| requestAnimationHandlers = {}; |
| requestAnimationWorker = null; |
| Object.keys(toProcess).forEach(function (key) { |
| toProcess[key](now); |
| }); |
| }, 16); |
| return handle; |
| }, |
| |
| _cancelAnimationFrame: _Global.cancelAnimationFrame ? _Global.cancelAnimationFrame.bind(_Global) : function (handle) { |
| delete requestAnimationHandlers[handle]; |
| }, |
| |
| // Allows the browser to finish dispatching its current set of events before running |
| // the callback. |
| _yieldForEvents: _Global.setImmediate ? _Global.setImmediate.bind(_Global) : function (handler) { |
| _Global.setTimeout(handler, 0); |
| }, |
| |
| // Allows the browser to notice a DOM modification before running the callback. |
| _yieldForDomModification: _Global.setImmediate ? _Global.setImmediate.bind(_Global) : function (handler) { |
| _Global.setTimeout(handler, 0); |
| }, |
| |
| _throttledFunction: throttledFunction, |
| |
| _shallowCopy: function _shallowCopy(a) { |
| // Shallow copy a single object. |
| return this._mergeAll([a]); |
| }, |
| |
| _merge: function _merge(a, b) { |
| // Merge 2 objects together into a new object |
| return this._mergeAll([a, b]); |
| }, |
| |
| _mergeAll: function _mergeAll(list) { |
| // Merge a list of objects together |
| var o = {}; |
| list.forEach(function (part) { |
| Object.keys(part).forEach(function (k) { |
| o[k] = part[k]; |
| }); |
| }); |
| return o; |
| }, |
| |
| _getProfilerMarkIdentifier: function _getProfilerMarkIdentifier(element) { |
| var profilerMarkIdentifier = ""; |
| if (element.id) { |
| profilerMarkIdentifier += " id='" + element.id + "'"; |
| } |
| if (element.className) { |
| profilerMarkIdentifier += " class='" + element.className + "'"; |
| } |
| return profilerMarkIdentifier; |
| }, |
| |
| _now: function _now() { |
| return (_Global.performance && _Global.performance.now && _Global.performance.now()) || Date.now(); |
| }, |
| |
| _traceAsyncOperationStarting: _Trace._traceAsyncOperationStarting, |
| _traceAsyncOperationCompleted: _Trace._traceAsyncOperationCompleted, |
| _traceAsyncCallbackStarting: _Trace._traceAsyncCallbackStarting, |
| _traceAsyncCallbackCompleted: _Trace._traceAsyncCallbackCompleted, |
| |
| _version: "4.4.0" |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS", { |
| validation: { |
| get: function () { |
| return validation; |
| }, |
| set: function (value) { |
| validation = value; |
| } |
| } |
| }); |
| |
| // strictProcessing also exists as a module member |
| _Base.Namespace.define("WinJS", { |
| strictProcessing: { |
| value: function () { |
| /// <signature helpKeyword="WinJS.strictProcessing"> |
| /// <summary locid="WinJS.strictProcessing"> |
| /// Strict processing is always enforced, this method has no effect. |
| /// </summary> |
| /// </signature> |
| }, |
| configurable: false, |
| writable: false, |
| enumerable: false |
| } |
| }); |
| }); |
| |
| |
| define('WinJS/Core',[ |
| './Core/_Base', |
| './Core/_BaseCoreUtils', |
| './Core/_BaseUtils', |
| './Core/_ErrorFromName', |
| './Core/_Events', |
| './Core/_Global', |
| './Core/_Log', |
| './Core/_Resources', |
| './Core/_Trace', |
| './Core/_WinRT', |
| './Core/_WriteProfilerMark' |
| ], function () { |
| // Wrapper module |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/_Signal',[ |
| './Core/_Base', |
| './Promise/_StateMachine' |
| ], function signalInit(_Base, _StateMachine) { |
| "use strict"; |
| |
| var SignalPromise = _Base.Class.derive(_StateMachine.PromiseStateMachine, |
| function (cancel) { |
| this._oncancel = cancel; |
| this._setState(_StateMachine.state_created); |
| this._run(); |
| }, { |
| _cancelAction: function () { this._oncancel && this._oncancel(); }, |
| _cleanupAction: function () { this._oncancel = null; } |
| }, { |
| supportedForProcessing: false |
| } |
| ); |
| |
| var Signal = _Base.Class.define( |
| function Signal_ctor(oncancel) { |
| this._promise = new SignalPromise(oncancel); |
| }, { |
| promise: { |
| get: function () { return this._promise; } |
| }, |
| |
| cancel: function Signal_cancel() { |
| this._promise.cancel(); |
| }, |
| complete: function Signal_complete(value) { |
| this._promise._completed(value); |
| }, |
| error: function Signal_error(value) { |
| this._promise._error(value); |
| }, |
| progress: function Signal_progress(value) { |
| this._promise._progress(value); |
| } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| _Base.Namespace.define("WinJS", { |
| _Signal: Signal |
| }); |
| |
| return Signal; |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Control',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base' |
| ], function controlInit(exports, _Global, _Base) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| function setOptions(control, options) { |
| /// <signature helpKeyword="WinJS.UI.setOptions"> |
| /// <summary locid="WinJS.UI.setOptions"> |
| /// Adds the set of declaratively specified options (properties and events) to the specified control. |
| /// If name of the options property begins with "on", the property value is a function and the control |
| /// supports addEventListener. The setOptions method calls the addEventListener method on the control. |
| /// </summary> |
| /// <param name="control" type="Object" domElement="false" locid="WinJS.UI.setOptions_p:control"> |
| /// The control on which the properties and events are to be applied. |
| /// </param> |
| /// <param name="options" type="Object" domElement="false" locid="WinJS.UI.setOptions_p:options"> |
| /// The set of options that are specified declaratively. |
| /// </param> |
| /// </signature> |
| _setOptions(control, options); |
| } |
| |
| function _setOptions(control, options, eventsOnly) { |
| if (typeof options === "object") { |
| var keys = Object.keys(options); |
| for (var i = 0, len = keys.length; i < len; i++) { |
| var key = keys[i]; |
| var value = options[key]; |
| if (key.length > 2) { |
| var ch1 = key[0]; |
| var ch2 = key[1]; |
| if ((ch1 === 'o' || ch1 === 'O') && (ch2 === 'n' || ch2 === 'N')) { |
| if (typeof value === "function") { |
| if (control.addEventListener) { |
| control.addEventListener(key.substr(2), value); |
| continue; |
| } |
| } |
| } |
| } |
| |
| if (!eventsOnly) { |
| control[key] = value; |
| } |
| } |
| } |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| DOMEventMixin: _Base.Namespace._lazy(function () { |
| return { |
| _domElement: null, |
| |
| addEventListener: function (type, listener, useCapture) { |
| /// <signature helpKeyword="WinJS.UI.DOMEventMixin.addEventListener"> |
| /// <summary locid="WinJS.UI.DOMEventMixin.addEventListener"> |
| /// Adds an event listener to the control. |
| /// </summary> |
| /// <param name="type" type="String" locid="WinJS.UI.DOMEventMixin.addEventListener_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" type="Function" locid="WinJS.UI.DOMEventMixin.addEventListener_p:listener"> |
| /// The listener to invoke when the event gets raised. |
| /// </param> |
| /// <param name="useCapture" type="Boolean" locid="WinJS.UI.DOMEventMixin.addEventListener_p:useCapture"> |
| /// true to initiate capture; otherwise, false. |
| /// </param> |
| /// </signature> |
| (this.element || this._domElement).addEventListener(type, listener, useCapture || false); |
| }, |
| dispatchEvent: function (type, eventProperties) { |
| /// <signature helpKeyword="WinJS.UI.DOMEventMixin.dispatchEvent"> |
| /// <summary locid="WinJS.UI.DOMEventMixin.dispatchEvent"> |
| /// Raises an event of the specified type, adding the specified additional properties. |
| /// </summary> |
| /// <param name="type" type="String" locid="WinJS.UI.DOMEventMixin.dispatchEvent_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="eventProperties" type="Object" locid="WinJS.UI.DOMEventMixin.dispatchEvent_p:eventProperties"> |
| /// The set of additional properties to be attached to the event object when the event is raised. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.UI.DOMEventMixin.dispatchEvent_returnValue"> |
| /// true if preventDefault was called on the event, otherwise false. |
| /// </returns> |
| /// </signature> |
| var eventValue = _Global.document.createEvent("Event"); |
| eventValue.initEvent(type, false, false); |
| eventValue.detail = eventProperties; |
| if (typeof eventProperties === "object") { |
| Object.keys(eventProperties).forEach(function (key) { |
| eventValue[key] = eventProperties[key]; |
| }); |
| } |
| return (this.element || this._domElement).dispatchEvent(eventValue); |
| }, |
| removeEventListener: function (type, listener, useCapture) { |
| /// <signature helpKeyword="WinJS.UI.DOMEventMixin.removeEventListener"> |
| /// <summary locid="WinJS.UI.DOMEventMixin.removeEventListener"> |
| /// Removes an event listener from the control. |
| /// </summary> |
| /// <param name="type" type="String" locid="WinJS.UI.DOMEventMixin.removeEventListener_p:type"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" type="Function" locid="WinJS.UI.DOMEventMixin.removeEventListener_p:listener"> |
| /// The listener to remove. |
| /// </param> |
| /// <param name="useCapture" type="Boolean" locid="WinJS.UI.DOMEventMixin.removeEventListener_p:useCapture"> |
| /// true to initiate capture; otherwise, false. |
| /// </param> |
| /// </signature> |
| (this.element || this._domElement).removeEventListener(type, listener, useCapture || false); |
| } |
| }; |
| }), |
| |
| setOptions: setOptions, |
| |
| _setOptions: _setOptions |
| }); |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_ElementUtilities',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_WinRT', |
| '../Promise', |
| '../Scheduler' |
| ], function elementUtilities(exports, _Global, _Base, _BaseUtils, _WinRT, Promise, Scheduler) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var _zoomToDuration = 167; |
| |
| // Firefox's implementation of getComputedStyle returns null when called within |
| // an iframe that is display:none. This is a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=548397 |
| // _getComputedStyle is a helper which is guaranteed to return an object whose keys |
| // map to strings. |
| var defaultComputedStyle = null; |
| function getDefaultComputedStyle() { |
| if (!defaultComputedStyle) { |
| defaultComputedStyle = {}; |
| Object.keys(_Global.CSS2Properties.prototype).forEach(function (cssProperty) { |
| defaultComputedStyle[cssProperty] = ""; |
| }); |
| } |
| return defaultComputedStyle; |
| } |
| function _getComputedStyle(element, pseudoElement) { |
| // jscs:disable disallowDirectGetComputedStyle |
| return _Global.getComputedStyle(element, pseudoElement) || getDefaultComputedStyle(); |
| // jscs:enable disallowDirectGetComputedStyle |
| } |
| |
| function removeEmpties(arr) { |
| var len = arr.length; |
| for (var i = len - 1; i >= 0; i--) { |
| if (!arr[i]) { |
| arr.splice(i, 1); |
| len--; |
| } |
| } |
| return len; |
| } |
| |
| function getClassName(e) { |
| var name = e.className || ""; |
| if (typeof (name) === "string") { |
| return name; |
| } else { |
| return name.baseVal || ""; |
| } |
| } |
| function setClassName(e, value) { |
| // SVG elements (which use e.className.baseVal) are never undefined, |
| // so this logic makes the comparison a bit more compact. |
| // |
| var name = e.className || ""; |
| if (typeof (name) === "string") { |
| e.className = value; |
| } else { |
| e.className.baseVal = value; |
| } |
| return e; |
| } |
| function addClass(e, name) { |
| /// <signature helpKeyword="WinJS.Utilities.addClass"> |
| /// <summary locid="WinJS.Utilities.addClass"> |
| /// Adds the specified class(es) to the specified element. Multiple classes can be added using space delimited names. |
| /// </summary> |
| /// <param name="e" type="HTMLElement" locid="WinJS.Utilities.addClass_p:e"> |
| /// The element to which to add the class. |
| /// </param> |
| /// <param name="name" type="String" locid="WinJS.Utilities.addClass_p:name"> |
| /// The name of the class to add, multiple classes can be added using space delimited names |
| /// </param> |
| /// <returns type="HTMLElement" locid="WinJS.Utilities.addClass_returnValue"> |
| /// The element. |
| /// </returns> |
| /// </signature> |
| if (e.classList) { |
| // Fastpath: adding a single class, no need to string split the argument |
| if (name.indexOf(" ") < 0) { |
| e.classList.add(name); |
| } else { |
| var namesToAdd = name.split(" "); |
| removeEmpties(namesToAdd); |
| |
| for (var i = 0, len = namesToAdd.length; i < len; i++) { |
| e.classList.add(namesToAdd[i]); |
| } |
| } |
| return e; |
| } else { |
| var className = getClassName(e); |
| var names = className.split(" "); |
| var l = removeEmpties(names); |
| var toAdd; |
| |
| // we have a fast path for the common case of a single name in the class name |
| // |
| if (name.indexOf(" ") >= 0) { |
| var namesToAdd = name.split(" "); |
| removeEmpties(namesToAdd); |
| for (var i = 0; i < l; i++) { |
| var found = namesToAdd.indexOf(names[i]); |
| if (found >= 0) { |
| namesToAdd.splice(found, 1); |
| } |
| } |
| if (namesToAdd.length > 0) { |
| toAdd = namesToAdd.join(" "); |
| } |
| } else { |
| var saw = false; |
| for (var i = 0; i < l; i++) { |
| if (names[i] === name) { |
| saw = true; |
| break; |
| } |
| } |
| if (!saw) { toAdd = name; } |
| |
| } |
| if (toAdd) { |
| if (l > 0 && names[0].length > 0) { |
| setClassName(e, className + " " + toAdd); |
| } else { |
| setClassName(e, toAdd); |
| } |
| } |
| return e; |
| } |
| } |
| function removeClass(e, name) { |
| /// <signature helpKeyword="WinJS.Utilities.removeClass"> |
| /// <summary locid="WinJS.Utilities.removeClass"> |
| /// Removes the specified class from the specified element. |
| /// </summary> |
| /// <param name="e" type="HTMLElement" locid="WinJS.Utilities.removeClass_p:e"> |
| /// The element from which to remove the class. |
| /// </param> |
| /// <param name="name" type="String" locid="WinJS.Utilities.removeClass_p:name"> |
| /// The name of the class to remove. |
| /// </param> |
| /// <returns type="HTMLElement" locid="WinJS.Utilities.removeClass_returnValue"> |
| /// The element. |
| /// </returns> |
| /// </signature> |
| if (e.classList) { |
| |
| // Fastpath: Nothing to remove |
| if (e.classList.length === 0) { |
| return e; |
| } |
| var namesToRemove = name.split(" "); |
| removeEmpties(namesToRemove); |
| |
| for (var i = 0, len = namesToRemove.length; i < len; i++) { |
| e.classList.remove(namesToRemove[i]); |
| } |
| return e; |
| } else { |
| var original = getClassName(e); |
| var namesToRemove; |
| var namesToRemoveLen; |
| |
| if (name.indexOf(" ") >= 0) { |
| namesToRemove = name.split(" "); |
| namesToRemoveLen = removeEmpties(namesToRemove); |
| } else { |
| // early out for the case where you ask to remove a single |
| // name and that name isn't found. |
| // |
| if (original.indexOf(name) < 0) { |
| return e; |
| } |
| namesToRemove = [name]; |
| namesToRemoveLen = 1; |
| } |
| var removed; |
| var names = original.split(" "); |
| var namesLen = removeEmpties(names); |
| |
| for (var i = namesLen - 1; i >= 0; i--) { |
| if (namesToRemove.indexOf(names[i]) >= 0) { |
| names.splice(i, 1); |
| removed = true; |
| } |
| } |
| |
| if (removed) { |
| setClassName(e, names.join(" ")); |
| } |
| return e; |
| } |
| } |
| function toggleClass(e, name) { |
| /// <signature helpKeyword="WinJS.Utilities.toggleClass"> |
| /// <summary locid="WinJS.Utilities.toggleClass"> |
| /// Toggles (adds or removes) the specified class on the specified element. |
| /// If the class is present, it is removed; if it is absent, it is added. |
| /// </summary> |
| /// <param name="e" type="HTMLElement" locid="WinJS.Utilities.toggleClass_p:e"> |
| /// The element on which to toggle the class. |
| /// </param> |
| /// <param name="name" type="String" locid="WinJS.Utilities.toggleClass_p:name"> |
| /// The name of the class to toggle. |
| /// </param> |
| /// <returns type="HTMLElement" locid="WinJS.Utilities.toggleClass_returnValue"> |
| /// The element. |
| /// </returns> |
| /// </signature> |
| if (e.classList) { |
| e.classList.toggle(name); |
| return e; |
| } else { |
| var className = getClassName(e); |
| var names = className.trim().split(" "); |
| var l = names.length; |
| var found = false; |
| for (var i = 0; i < l; i++) { |
| if (names[i] === name) { |
| found = true; |
| } |
| } |
| if (!found) { |
| if (l > 0 && names[0].length > 0) { |
| setClassName(e, className + " " + name); |
| } else { |
| setClassName(e, className + name); |
| } |
| } else { |
| setClassName(e, names.reduce(function (r, e) { |
| if (e === name) { |
| return r; |
| } else if (r && r.length > 0) { |
| return r + " " + e; |
| } else { |
| return e; |
| } |
| }, "")); |
| } |
| return e; |
| } |
| } |
| |
| // Only set the attribute if its value has changed |
| function setAttribute(element, attribute, value) { |
| if (element.getAttribute(attribute) !== "" + value) { |
| element.setAttribute(attribute, value); |
| } |
| } |
| |
| function _clamp(value, lowerBound, upperBound, defaultValue) { |
| var n = Math.max(lowerBound, Math.min(upperBound, +value)); |
| return n === 0 ? 0 : n || Math.max(lowerBound, Math.min(upperBound, defaultValue)); |
| } |
| var _pixelsRE = /^-?\d+\.?\d*(px)?$/i; |
| var _numberRE = /^-?\d+/i; |
| function convertToPixels(element, value) { |
| /// <signature helpKeyword="WinJS.Utilities.convertToPixels"> |
| /// <summary locid="WinJS.Utilities.convertToPixels"> |
| /// Converts a CSS positioning string for the specified element to pixels. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.convertToPixels_p:element"> |
| /// The element. |
| /// </param> |
| /// <param name="value" type="String" locid="WinJS.Utilities.convertToPixels_p:value"> |
| /// The CSS positioning string. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.convertToPixels_returnValue"> |
| /// The number of pixels. |
| /// </returns> |
| /// </signature> |
| if (!_pixelsRE.test(value) && _numberRE.test(value)) { |
| var previousValue = element.style.left; |
| |
| element.style.left = value; |
| value = element.style.pixelLeft; |
| |
| element.style.left = previousValue; |
| |
| return value; |
| } else { |
| return Math.round(parseFloat(value)) || 0; |
| } |
| } |
| |
| function getDimension(element, property) { |
| return convertToPixels(element, _getComputedStyle(element, null)[property]); |
| } |
| |
| function _convertToPrecisePixels(value) { |
| return parseFloat(value) || 0; |
| } |
| function _getPreciseDimension(element, property) { |
| return _convertToPrecisePixels(_getComputedStyle(element, null)[property]); |
| } |
| function _getPreciseMargins(element) { |
| var style = _getComputedStyle(element); |
| return { |
| top: _convertToPrecisePixels(style.marginTop), |
| right: _convertToPrecisePixels(style.marginRight), |
| bottom: _convertToPrecisePixels(style.marginBottom), |
| left: _convertToPrecisePixels(style.marginLeft), |
| }; |
| } |
| |
| var _MSGestureEvent = _Global.MSGestureEvent || { |
| MSGESTURE_FLAG_BEGIN: 1, |
| MSGESTURE_FLAG_CANCEL: 4, |
| MSGESTURE_FLAG_END: 2, |
| MSGESTURE_FLAG_INERTIA: 8, |
| MSGESTURE_FLAG_NONE: 0 |
| }; |
| |
| var _MSManipulationEvent = _Global.MSManipulationEvent || { |
| MS_MANIPULATION_STATE_ACTIVE: 1, |
| MS_MANIPULATION_STATE_CANCELLED: 6, |
| MS_MANIPULATION_STATE_COMMITTED: 7, |
| MS_MANIPULATION_STATE_DRAGGING: 5, |
| MS_MANIPULATION_STATE_INERTIA: 2, |
| MS_MANIPULATION_STATE_PRESELECT: 3, |
| MS_MANIPULATION_STATE_SELECTING: 4, |
| MS_MANIPULATION_STATE_STOPPED: 0 |
| }; |
| |
| var _MSPointerEvent = _Global.MSPointerEvent || { |
| MSPOINTER_TYPE_TOUCH: "touch", |
| MSPOINTER_TYPE_PEN: "pen", |
| MSPOINTER_TYPE_MOUSE: "mouse", |
| }; |
| |
| // Helpers for managing element._eventsMap for custom events |
| // |
| |
| function addListenerToEventMap(element, type, listener, useCapture, data) { |
| var eventNameLowercase = type.toLowerCase(); |
| if (!element._eventsMap) { |
| element._eventsMap = {}; |
| } |
| if (!element._eventsMap[eventNameLowercase]) { |
| element._eventsMap[eventNameLowercase] = []; |
| } |
| element._eventsMap[eventNameLowercase].push({ |
| listener: listener, |
| useCapture: useCapture, |
| data: data |
| }); |
| } |
| |
| function removeListenerFromEventMap(element, type, listener, useCapture) { |
| var eventNameLowercase = type.toLowerCase(); |
| var mappedEvents = element._eventsMap && element._eventsMap[eventNameLowercase]; |
| if (mappedEvents) { |
| for (var i = mappedEvents.length - 1; i >= 0; i--) { |
| var mapping = mappedEvents[i]; |
| if (mapping.listener === listener && (!!useCapture === !!mapping.useCapture)) { |
| mappedEvents.splice(i, 1); |
| return mapping; |
| } |
| } |
| } |
| return null; |
| } |
| |
| function lookupListeners(element, type) { |
| var eventNameLowercase = type.toLowerCase(); |
| return element._eventsMap && element._eventsMap[eventNameLowercase] && element._eventsMap[eventNameLowercase].slice(0) || []; |
| } |
| |
| // Custom focusin/focusout events |
| // Generally, use these instead of using the browser's blur/focus/focusout/focusin events directly. |
| // However, this doesn't support the window object. If you need to listen to focus events on the window, |
| // use the browser's events directly. |
| // |
| // In order to send our custom focusin/focusout events synchronously on every browser, we feature detect |
| // for native "focusin" and "focusout" since every browser that supports them will fire them synchronously. |
| // Every browser in our support matrix, except for IE, also fires focus/blur synchronously, we fall back to |
| // those events in browsers such as Firefox that do not have native support for focusin/focusout. |
| |
| function bubbleEvent(element, type, eventObject) { |
| while (element) { |
| var handlers = lookupListeners(element, type); |
| for (var i = 0, len = handlers.length; i < len; i++) { |
| handlers[i].listener.call(element, eventObject); |
| } |
| |
| element = element.parentNode; |
| } |
| } |
| |
| function prepareFocusEvent(eventObject) { |
| // If an iframe is involved, then relatedTarget should be null. |
| if (eventObject.relatedTarget && eventObject.relatedTarget.tagName === "IFRAME" || |
| eventObject.target && eventObject.target.tagName === "IFRAME") { |
| eventObject.relatedTarget = null; |
| } |
| |
| return eventObject; |
| } |
| |
| var nativeSupportForFocusIn = "onfocusin" in _Global.document.documentElement; |
| var activeElement = null; |
| _Global.addEventListener(nativeSupportForFocusIn ? "focusout" : "blur", function (eventObject) { |
| // Fires focusout when focus move to another window or into an iframe. |
| if (eventObject.target === _Global) { |
| var previousActiveElement = activeElement; |
| if (previousActiveElement) { |
| bubbleEvent(previousActiveElement, "focusout", prepareFocusEvent({ |
| type: "focusout", |
| target: previousActiveElement, |
| relatedTarget: null |
| })); |
| } |
| activeElement = null; |
| } |
| }); |
| |
| _Global.document.documentElement.addEventListener(nativeSupportForFocusIn ? "focusin" : "focus", function (eventObject) { |
| var previousActiveElement = activeElement; |
| activeElement = eventObject.target; |
| if (previousActiveElement) { |
| bubbleEvent(previousActiveElement, "focusout", prepareFocusEvent({ |
| type: "focusout", |
| target: previousActiveElement, |
| relatedTarget: activeElement |
| })); |
| } |
| if (activeElement) { |
| bubbleEvent(activeElement, "focusin", prepareFocusEvent({ |
| type: "focusin", |
| target: activeElement, |
| relatedTarget: previousActiveElement |
| })); |
| } |
| }, true); |
| |
| function registerBubbleListener(element, type, listener, useCapture) { |
| if (useCapture) { |
| throw "This custom WinJS event only supports bubbling"; |
| } |
| addListenerToEventMap(element, type, listener, useCapture); |
| } |
| |
| // Custom pointer events |
| // |
| |
| // Sets the properties in *overrideProperties* on the object. Delegates all other |
| // property accesses to *eventObject*. |
| // |
| // The purpose of PointerEventProxy is that it allows us to customize properties on |
| // an eventObject despite those properties being unwritable and unconfigurable. |
| var PointerEventProxy = function (eventObject, overrideProperties) { |
| overrideProperties = overrideProperties || {}; |
| this.__eventObject = eventObject; |
| var that = this; |
| Object.keys(overrideProperties).forEach(function (propertyName) { |
| Object.defineProperty(that, propertyName, { |
| value: overrideProperties[propertyName] |
| }); |
| }); |
| }; |
| |
| // Define PointerEventProxy properties which should be delegated to the original eventObject. |
| [ |
| "altKey", "AT_TARGET", "bubbles", "BUBBLING_PHASE", "button", "buttons", |
| "cancelable", "cancelBubble", "CAPTURING_PHASE", "clientX", "clientY", |
| "ctrlKey", "currentTarget", "defaultPrevented", "detail", "eventPhase", |
| "fromElement", "getModifierState", "height", "hwTimestamp", "initEvent", |
| "initMouseEvent", "initPointerEvent", "initUIEvent", "isPrimary", "isTrusted", |
| "layerX", "layerY", "metaKey", "offsetX", "offsetY", "pageX", "pageY", |
| "pointerId", "pointerType", "pressure", "preventDefault", "relatedTarget", |
| "rotation", "screenX", "screenY", "shiftKey", "srcElement", "stopImmediatePropagation", |
| "stopPropagation", "target", "tiltX", "tiltY", "timeStamp", "toElement", "type", |
| "view", "which", "width", "x", "y", "_normalizedType", "_fakedBySemanticZoom" |
| ].forEach(function (propertyName) { |
| Object.defineProperty(PointerEventProxy.prototype, propertyName, { |
| get: function () { |
| var value = this.__eventObject[propertyName]; |
| return typeof value === "function" ? value.bind(this.__eventObject) : value; |
| }, |
| configurable: true |
| }); |
| }); |
| |
| function touchEventTranslator(callback, eventObject) { |
| var changedTouches = eventObject.changedTouches, |
| retVal = null; |
| |
| if (!changedTouches) { |
| return retVal; |
| } |
| |
| for (var i = 0, len = changedTouches.length; i < len; i++) { |
| var touchObject = changedTouches[i]; |
| var pointerEventObject = new PointerEventProxy(eventObject, { |
| pointerType: _MSPointerEvent.MSPOINTER_TYPE_TOUCH, |
| pointerId: touchObject.identifier, |
| isPrimary: i === 0, |
| screenX: touchObject.screenX, |
| screenY: touchObject.screenY, |
| clientX: touchObject.clientX, |
| clientY: touchObject.clientY, |
| pageX: touchObject.pageX, |
| pageY: touchObject.pageY, |
| radiusX: touchObject.radiusX, |
| radiusY: touchObject.radiusY, |
| rotationAngle: touchObject.rotationAngle, |
| force: touchObject.force, |
| _currentTouch: touchObject |
| }); |
| var newRetVal = callback(pointerEventObject); |
| retVal = retVal || newRetVal; |
| } |
| return retVal; |
| } |
| |
| function mouseEventTranslator(callback, eventObject) { |
| eventObject.pointerType = _MSPointerEvent.MSPOINTER_TYPE_MOUSE; |
| eventObject.pointerId = -1; |
| eventObject.isPrimary = true; |
| return callback(eventObject); |
| } |
| |
| function mspointerEventTranslator(callback, eventObject) { |
| return callback(eventObject); |
| } |
| |
| var eventTranslations = { |
| pointerdown: { |
| touch: "touchstart", |
| mspointer: "MSPointerDown", |
| mouse: "mousedown" |
| }, |
| pointerup: { |
| touch: "touchend", |
| mspointer: "MSPointerUp", |
| mouse: "mouseup" |
| }, |
| pointermove: { |
| touch: "touchmove", |
| mspointer: "MSPointerMove", |
| mouse: "mousemove" |
| }, |
| pointerenter: { |
| touch: "touchenter", |
| mspointer: "MSPointerEnter", |
| mouse: "mouseenter" |
| }, |
| pointerover: { |
| touch: null, |
| mspointer: "MSPointerOver", |
| mouse: "mouseover" |
| }, |
| pointerout: { |
| touch: "touchleave", |
| mspointer: "MSPointerOut", |
| mouse: "mouseout" |
| }, |
| pointercancel: { |
| touch: "touchcancel", |
| mspointer: "MSPointerCancel", |
| mouse: null |
| } |
| }; |
| |
| function registerPointerEvent(element, type, callback, capture) { |
| var eventNameLowercase = type.toLowerCase(); |
| |
| var mouseWrapper, |
| touchWrapper, |
| mspointerWrapper; |
| var translations = eventTranslations[eventNameLowercase]; |
| |
| // Browsers fire a touch event and then a mouse event when the input is touch. touchHandled is used to prevent invoking the pointer callback twice. |
| var touchHandled; |
| |
| // If we are in IE10, we should use MSPointer as it provides a better interface than touch events |
| if (_Global.MSPointerEvent) { |
| mspointerWrapper = function (eventObject) { |
| eventObject._normalizedType = eventNameLowercase; |
| touchHandled = true; |
| return mspointerEventTranslator(callback, eventObject); |
| }; |
| element.addEventListener(translations.mspointer, mspointerWrapper, capture); |
| } else { |
| // Otherwise, use a mouse and touch event |
| if (translations.mouse) { |
| mouseWrapper = function (eventObject) { |
| eventObject._normalizedType = eventNameLowercase; |
| if (!touchHandled) { |
| return mouseEventTranslator(callback, eventObject); |
| } |
| touchHandled = false; |
| }; |
| element.addEventListener(translations.mouse, mouseWrapper, capture); |
| } |
| if (translations.touch) { |
| touchWrapper = function (eventObject) { |
| eventObject._normalizedType = eventNameLowercase; |
| touchHandled = true; |
| return touchEventTranslator(callback, eventObject); |
| }; |
| element.addEventListener(translations.touch, touchWrapper, capture); |
| } |
| } |
| |
| addListenerToEventMap(element, type, callback, capture, { |
| mouseWrapper: mouseWrapper, |
| touchWrapper: touchWrapper, |
| mspointerWrapper: mspointerWrapper |
| }); |
| } |
| |
| function unregisterPointerEvent(element, type, callback, capture) { |
| var eventNameLowercase = type.toLowerCase(); |
| |
| var mapping = removeListenerFromEventMap(element, type, callback, capture); |
| if (mapping) { |
| var translations = eventTranslations[eventNameLowercase]; |
| if (mapping.data.mouseWrapper) { |
| element.removeEventListener(translations.mouse, mapping.data.mouseWrapper, capture); |
| } |
| if (mapping.data.touchWrapper) { |
| element.removeEventListener(translations.touch, mapping.data.touchWrapper, capture); |
| } |
| if (mapping.data.mspointerWrapper) { |
| element.removeEventListener(translations.mspointer, mapping.data.mspointerWrapper, capture); |
| } |
| } |
| } |
| |
| // Custom events dispatch table. Event names should be lowercased. |
| // |
| |
| var customEvents = { |
| focusout: { |
| register: registerBubbleListener, |
| unregister: removeListenerFromEventMap |
| }, |
| focusin: { |
| register: registerBubbleListener, |
| unregister: removeListenerFromEventMap |
| }, |
| }; |
| if (!_Global.PointerEvent) { |
| var pointerEventEntry = { |
| register: registerPointerEvent, |
| unregister: unregisterPointerEvent |
| }; |
| |
| customEvents.pointerdown = pointerEventEntry; |
| customEvents.pointerup = pointerEventEntry; |
| customEvents.pointermove = pointerEventEntry; |
| customEvents.pointerenter = pointerEventEntry; |
| customEvents.pointerover = pointerEventEntry; |
| customEvents.pointerout = pointerEventEntry; |
| customEvents.pointercancel = pointerEventEntry; |
| } |
| |
| // The MutationObserverShim only supports the following configuration: |
| // attributes |
| // attributeFilter |
| var MutationObserverShim = _Base.Class.define( |
| function MutationObserverShim_ctor(callback) { |
| this._callback = callback; |
| this._toDispose = []; |
| this._attributeFilter = []; |
| this._scheduled = false; |
| this._pendingChanges = []; |
| this._observerCount = 0; |
| this._handleCallback = this._handleCallback.bind(this); |
| this._targetElements = []; |
| }, |
| { |
| observe: function MutationObserverShim_observe(element, configuration) { |
| if (this._targetElements.indexOf(element) === -1) { |
| this._targetElements.push(element); |
| } |
| this._observerCount++; |
| if (configuration.attributes) { |
| this._addRemovableListener(element, "DOMAttrModified", this._handleCallback); |
| } |
| if (configuration.attributeFilter) { |
| this._attributeFilter = configuration.attributeFilter; |
| } |
| }, |
| disconnect: function MutationObserverShim_disconnect() { |
| this._observerCount = 0; |
| this._targetElements = []; |
| this._toDispose.forEach(function (disposeFunc) { |
| disposeFunc(); |
| }); |
| }, |
| _addRemovableListener: function MutationObserverShim_addRemovableListener(target, event, listener) { |
| target.addEventListener(event, listener); |
| this._toDispose.push(function () { |
| target.removeEventListener(event, listener); |
| }); |
| }, |
| _handleCallback: function MutationObserverShim_handleCallback(evt) { |
| |
| // prevent multiple events from firing when nesting observers |
| evt.stopPropagation(); |
| |
| var attrName = evt.attrName; |
| if (this._attributeFilter.length && this._attributeFilter.indexOf(attrName) === -1) { |
| return; |
| } |
| |
| // subtree:true is not currently supported |
| if (this._targetElements.indexOf(evt.target) === -1) { |
| return; |
| } |
| |
| var isAriaMutation = attrName.indexOf("aria") >= 0; |
| |
| // DOM mutation events use different naming for this attribute |
| if (attrName === 'tabindex') { |
| attrName = 'tabIndex'; |
| } |
| |
| this._pendingChanges.push({ |
| type: 'attributes', |
| target: evt.target, |
| attributeName: attrName |
| }); |
| |
| if (this._observerCount === 1 && !isAriaMutation) { |
| this._dispatchEvent(); |
| } else if (this._scheduled === false) { |
| this._scheduled = true; |
| _BaseUtils._setImmediate(this._dispatchEvent.bind(this)); |
| } |
| |
| }, |
| _dispatchEvent: function MutationObserverShim_dispatchEvent() { |
| try { |
| this._callback(this._pendingChanges); |
| } |
| finally { |
| this._pendingChanges = []; |
| this._scheduled = false; |
| } |
| } |
| }, |
| { |
| _isShim: true |
| } |
| ); |
| |
| var _MutationObserver = _Global.MutationObserver || MutationObserverShim; |
| |
| // Lazily init singleton on first access. |
| var _resizeNotifier = null; |
| |
| // Class to provide a global listener for window.onresize events. |
| // This keeps individual elements from having to listen to window.onresize |
| // and having to dispose themselves to avoid leaks. |
| var ResizeNotifier = _Base.Class.define( |
| function ElementResizer_ctor() { |
| _Global.addEventListener("resize", this._handleResize.bind(this)); |
| }, |
| { |
| subscribe: function ElementResizer_subscribe(element, handler) { |
| element.addEventListener(this._resizeEvent, handler); |
| addClass(element, this._resizeClass); |
| }, |
| unsubscribe: function ElementResizer_unsubscribe(element, handler) { |
| removeClass(element, this._resizeClass); |
| element.removeEventListener(this._resizeEvent, handler); |
| }, |
| _handleResize: function ElementResizer_handleResize() { |
| var resizables = _Global.document.querySelectorAll('.' + this._resizeClass); |
| var length = resizables.length; |
| for (var i = 0; i < length; i++) { |
| var event = _Global.document.createEvent("Event"); |
| event.initEvent(this._resizeEvent, false, true); |
| resizables[i].dispatchEvent(event); |
| } |
| }, |
| _resizeClass: { get: function () { return 'win-element-resize'; } }, |
| _resizeEvent: { get: function () { return 'WinJSElementResize'; } } |
| } |
| ); |
| |
| // - object: The object on which GenericListener will listen for events. |
| // - objectName: A string representing the name of *object*. This will be |
| // incorporated into the names of the events and classNames created by |
| // GenericListener. |
| // - options |
| // - registerThruWinJSCustomEvents: If true, will register for events using |
| // _exports._addEventListener so that you can take advantage of WinJS's custom |
| // events (e.g. focusin, pointer*). Otherwise, registers directly on *object* |
| // using its add/removeEventListener methods. |
| var GenericListener = _Base.Class.define( |
| function GenericListener_ctor(objectName, object, options) { |
| options = options || {}; |
| this.registerThruWinJSCustomEvents = !!options.registerThruWinJSCustomEvents; |
| |
| this.objectName = objectName; |
| this.object = object; |
| this.capture = {}; |
| this.bubble = {}; |
| }, |
| { |
| addEventListener: function GenericListener_addEventListener(element, name, listener, capture) { |
| name = name.toLowerCase(); |
| var handlers = this._getHandlers(capture); |
| var handler = handlers[name]; |
| |
| if (!handler) { |
| handler = this._getListener(name, capture); |
| handler.refCount = 0; |
| handlers[name] = handler; |
| |
| if (this.registerThruWinJSCustomEvents) { |
| exports._addEventListener(this.object, name, handler, capture); |
| } else { |
| this.object.addEventListener(name, handler, capture); |
| } |
| } |
| |
| handler.refCount++; |
| element.addEventListener(this._getEventName(name, capture), listener); |
| addClass(element, this._getClassName(name, capture)); |
| }, |
| removeEventListener: function GenericListener_removeEventListener(element, name, listener, capture) { |
| name = name.toLowerCase(); |
| var handlers = this._getHandlers(capture); |
| var handler = handlers[name]; |
| |
| if (handler) { |
| handler.refCount--; |
| if (handler.refCount === 0) { |
| if (this.registerThruWinJSCustomEvents) { |
| exports._removeEventListener(this.object, name, handler, capture); |
| } else { |
| this.object.removeEventListener(name, handler, capture); |
| } |
| delete handlers[name]; |
| } |
| } |
| |
| removeClass(element, this._getClassName(name, capture)); |
| element.removeEventListener(this._getEventName(name, capture), listener); |
| }, |
| |
| _getHandlers: function GenericListener_getHandlers(capture) { |
| if (capture) { |
| return this.capture; |
| } else { |
| return this.bubble; |
| } |
| }, |
| |
| _getClassName: function GenericListener_getClassName(name, capture) { |
| var captureSuffix = capture ? 'capture' : 'bubble'; |
| return 'win-' + this.objectName.toLowerCase() + '-event-' + name + captureSuffix; |
| }, |
| |
| _getEventName: function GenericListener_getEventName(name, capture) { |
| var captureSuffix = capture ? 'capture' : 'bubble'; |
| return 'WinJS' + this.objectName + 'Event-' + name + captureSuffix; |
| }, |
| |
| _getListener: function GenericListener_getListener(name, capture) { |
| var listener = function GenericListener_generatedListener(ev) { |
| |
| var targets = _Global.document.querySelectorAll('.' + this._getClassName(name, capture)); |
| var length = targets.length; |
| var handled = false; |
| for (var i = 0; i < length; i++) { |
| var event = _Global.document.createEvent("Event"); |
| event.initEvent(this._getEventName(name, capture), false, true); |
| event.detail = { originalEvent: ev }; |
| var doDefault = targets[i].dispatchEvent(event); |
| handled = handled || !doDefault; |
| } |
| return handled; |
| }; |
| |
| return listener.bind(this); |
| } |
| } |
| ); |
| |
| var determinedRTLEnvironment = false, |
| usingWebkitScrollCoordinates = false, |
| usingFirefoxScrollCoordinates = false; |
| function determineRTLEnvironment() { |
| var element = _Global.document.createElement("div"); |
| element.style.direction = "rtl"; |
| element.innerHTML = "" + |
| "<div style='width: 100px; height: 100px; overflow: scroll; visibility:hidden'>" + |
| "<div style='width: 10000px; height: 100px;'></div>" + |
| "</div>"; |
| _Global.document.body.appendChild(element); |
| var elementScroller = element.firstChild; |
| if (elementScroller.scrollLeft > 0) { |
| usingWebkitScrollCoordinates = true; |
| } |
| elementScroller.scrollLeft += 100; |
| if (elementScroller.scrollLeft === 0) { |
| usingFirefoxScrollCoordinates = true; |
| } |
| _Global.document.body.removeChild(element); |
| determinedRTLEnvironment = true; |
| } |
| |
| function getAdjustedScrollPosition(element) { |
| var computedStyle = _getComputedStyle(element), |
| scrollLeft = element.scrollLeft; |
| if (computedStyle.direction === "rtl") { |
| if (!determinedRTLEnvironment) { |
| determineRTLEnvironment(); |
| } |
| if (usingWebkitScrollCoordinates) { |
| scrollLeft = element.scrollWidth - element.clientWidth - scrollLeft; |
| } |
| scrollLeft = Math.abs(scrollLeft); |
| } |
| |
| return { |
| scrollLeft: scrollLeft, |
| scrollTop: element.scrollTop |
| }; |
| } |
| |
| function setAdjustedScrollPosition(element, scrollLeft, scrollTop) { |
| if (scrollLeft !== undefined) { |
| var computedStyle = _getComputedStyle(element); |
| if (computedStyle.direction === "rtl") { |
| if (!determinedRTLEnvironment) { |
| determineRTLEnvironment(); |
| } |
| if (usingFirefoxScrollCoordinates) { |
| scrollLeft = -scrollLeft; |
| } else if (usingWebkitScrollCoordinates) { |
| scrollLeft = element.scrollWidth - element.clientWidth - scrollLeft; |
| } |
| } |
| element.scrollLeft = scrollLeft; |
| } |
| |
| if (scrollTop !== undefined) { |
| element.scrollTop = scrollTop; |
| } |
| } |
| |
| function getScrollPosition(element) { |
| /// <signature helpKeyword="WinJS.Utilities.getScrollPosition"> |
| /// <summary locid="WinJS.Utilities.getScrollPosition"> |
| /// Gets the scrollLeft and scrollTop of the specified element, adjusting the scrollLeft to change from browser specific coordinates to logical coordinates when in RTL. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" domElement="true" locid="WinJS.Utilities.getScrollPosition_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.getScrollPosition_returnValue"> |
| /// An object with two properties: scrollLeft and scrollTop |
| /// </returns> |
| /// </signature> |
| return getAdjustedScrollPosition(element); |
| } |
| |
| function setScrollPosition(element, position) { |
| /// <signature helpKeyword="WinJS.Utilities.setScrollPosition"> |
| /// <summary locid="WinJS.Utilities.setScrollPosition"> |
| /// Sets the scrollLeft and scrollTop of the specified element, changing the scrollLeft from logical coordinates to browser-specific coordinates when in RTL. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" domElement="true" locid="WinJS.Utilities.setScrollPosition_p:element"> |
| /// The element. |
| /// </param> |
| /// <param name="position" type="Object" domElement="true" locid="WinJS.Utilities.setScrollPosition_p:position"> |
| /// The element. |
| /// </param> |
| /// </signature> |
| position = position || {}; |
| setAdjustedScrollPosition(element, position.scrollLeft, position.scrollTop); |
| } |
| |
| // navigator.msManipulationViewsEnabled tells us whether snap points work or not regardless of whether the style properties exist, however, |
| // on Phone WWAs, this check returns false even though snap points are supported. To work around this bug, we check for the presence of |
| // 'MSAppHost' in the user agent string which indicates that we are in a WWA environment; all WWA environments support snap points. |
| var supportsSnapPoints = _Global.navigator.msManipulationViewsEnabled || _Global.navigator.userAgent.indexOf("MSAppHost") >= 0; |
| var supportsTouchDetection = !!(_Global.MSPointerEvent || _Global.TouchEvent); |
| |
| var uniqueElementIDCounter = 0; |
| |
| function uniqueID(e) { |
| if (!(e.uniqueID || e._uniqueID)) { |
| e._uniqueID = "element__" + (++uniqueElementIDCounter); |
| } |
| |
| return e.uniqueID || e._uniqueID; |
| } |
| |
| function ensureId(element) { |
| if (!element.id) { |
| element.id = uniqueID(element); |
| } |
| } |
| |
| function _getCursorPos(eventObject) { |
| var docElement = _Global.document.documentElement; |
| var docScrollPos = getScrollPosition(docElement); |
| |
| return { |
| left: eventObject.clientX + (_Global.document.body.dir === "rtl" ? -docScrollPos.scrollLeft : docScrollPos.scrollLeft), |
| top: eventObject.clientY + docElement.scrollTop |
| }; |
| } |
| |
| function _getElementsByClasses(parent, classes) { |
| var retVal = []; |
| |
| for (var i = 0, len = classes.length; i < len; i++) { |
| var element = parent.querySelector("." + classes[i]); |
| if (element) { |
| retVal.push(element); |
| } |
| } |
| return retVal; |
| } |
| |
| var _selectionPartsSelector = ".win-selectionborder, .win-selectionbackground, .win-selectioncheckmark, .win-selectioncheckmarkbackground"; |
| var _dataKey = "_msDataKey"; |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| _dataKey: _dataKey, |
| |
| _supportsSnapPoints: { |
| get: function () { |
| return supportsSnapPoints; |
| } |
| }, |
| |
| _supportsTouchDetection: { |
| get: function () { |
| return supportsTouchDetection; |
| } |
| }, |
| |
| _uniqueID: uniqueID, |
| |
| _ensureId: ensureId, |
| |
| _clamp: _clamp, |
| |
| _getCursorPos: _getCursorPos, |
| |
| _getElementsByClasses: _getElementsByClasses, |
| |
| _createGestureRecognizer: function () { |
| if (_Global.MSGesture) { |
| return new _Global.MSGesture(); |
| } |
| |
| var doNothing = function () { |
| }; |
| return { |
| addEventListener: doNothing, |
| removeEventListener: doNothing, |
| addPointer: doNothing, |
| stop: doNothing |
| }; |
| }, |
| |
| _MSGestureEvent: _MSGestureEvent, |
| _MSManipulationEvent: _MSManipulationEvent, |
| |
| _elementsFromPoint: function (x, y) { |
| if (_Global.document.msElementsFromPoint) { |
| return _Global.document.msElementsFromPoint(x, y); |
| } else { |
| var element = _Global.document.elementFromPoint(x, y); |
| return element ? [element] : null; |
| } |
| }, |
| |
| _matchesSelector: function _matchesSelector(element, selectorString) { |
| var matchesSelector = element.matches |
| || element.msMatchesSelector |
| || element.mozMatchesSelector |
| || element.webkitMatchesSelector; |
| return matchesSelector.call(element, selectorString); |
| }, |
| |
| _selectionPartsSelector: _selectionPartsSelector, |
| |
| _isSelectionRendered: function _isSelectionRendered(itemBox) { |
| // The tree is changed at pointerDown but _selectedClass is added only when the user drags an item below the selection threshold so checking for _selectedClass is not reliable. |
| return itemBox.querySelectorAll(_selectionPartsSelector).length > 0; |
| }, |
| |
| _addEventListener: function _addEventListener(element, type, listener, useCapture) { |
| var eventNameLower = type && type.toLowerCase(); |
| var entry = customEvents[eventNameLower]; |
| var equivalentEvent = _BaseUtils._browserEventEquivalents[type]; |
| if (entry) { |
| entry.register(element, type, listener, useCapture); |
| } else if (equivalentEvent) { |
| element.addEventListener(equivalentEvent, listener, useCapture); |
| } else { |
| element.addEventListener(type, listener, useCapture); |
| } |
| }, |
| |
| _removeEventListener: function _removeEventListener(element, type, listener, useCapture) { |
| var eventNameLower = type && type.toLowerCase(); |
| var entry = customEvents[eventNameLower]; |
| var equivalentEvent = _BaseUtils._browserEventEquivalents[type]; |
| if (entry) { |
| entry.unregister(element, type, listener, useCapture); |
| } else if (equivalentEvent) { |
| element.removeEventListener(equivalentEvent, listener, useCapture); |
| } else { |
| element.removeEventListener(type, listener, useCapture); |
| } |
| }, |
| |
| _initEventImpl: function (initType, event, eventType) { |
| eventType = eventType.toLowerCase(); |
| var mapping = eventTranslations[eventType]; |
| if (mapping) { |
| switch (initType.toLowerCase()) { |
| case "pointer": |
| if (!_Global.PointerEvent) { |
| arguments[2] = mapping.mspointer; |
| } |
| break; |
| |
| default: |
| arguments[2] = mapping[initType.toLowerCase()]; |
| break; |
| } |
| } |
| event["init" + initType + "Event"].apply(event, Array.prototype.slice.call(arguments, 2)); |
| }, |
| |
| _initMouseEvent: function (event) { |
| this._initEventImpl.apply(this, ["Mouse", event].concat(Array.prototype.slice.call(arguments, 1))); |
| }, |
| |
| _initPointerEvent: function (event) { |
| this._initEventImpl.apply(this, ["Pointer", event].concat(Array.prototype.slice.call(arguments, 1))); |
| }, |
| |
| _PointerEventProxy: PointerEventProxy, |
| |
| _bubbleEvent: bubbleEvent, |
| |
| _setPointerCapture: function (element, pointerId) { |
| if (element.setPointerCapture) { |
| element.setPointerCapture(pointerId); |
| } |
| }, |
| |
| _releasePointerCapture: function (element, pointerId) { |
| if (element.releasePointerCapture) { |
| element.releasePointerCapture(pointerId); |
| } |
| }, |
| |
| _MSPointerEvent: _MSPointerEvent, |
| |
| _getComputedStyle: _getComputedStyle, |
| |
| _zoomToDuration: _zoomToDuration, |
| |
| _zoomTo: function _zoomTo(element, args) { |
| if (this._supportsSnapPoints && element.msZoomTo) { |
| element.msZoomTo(args); |
| } else { |
| // Schedule to ensure that we're not running from within an event handler. For example, if running |
| // within a focus handler triggered by WinJS.Utilities._setActive, scroll position will not yet be |
| // restored. |
| Scheduler.schedule(function () { |
| var initialPos = getAdjustedScrollPosition(element); |
| var effectiveScrollLeft = (typeof element._zoomToDestX === "number" ? element._zoomToDestX : initialPos.scrollLeft); |
| var effectiveScrollTop = (typeof element._zoomToDestY === "number" ? element._zoomToDestY : initialPos.scrollTop); |
| var cs = _getComputedStyle(element); |
| var scrollLimitX = element.scrollWidth - parseInt(cs.width, 10) - parseInt(cs.paddingLeft, 10) - parseInt(cs.paddingRight, 10); |
| var scrollLimitY = element.scrollHeight - parseInt(cs.height, 10) - parseInt(cs.paddingTop, 10) - parseInt(cs.paddingBottom, 10); |
| |
| if (typeof args.contentX !== "number") { |
| args.contentX = effectiveScrollLeft; |
| } |
| if (typeof args.contentY !== "number") { |
| args.contentY = effectiveScrollTop; |
| } |
| |
| var zoomToDestX = _clamp(args.contentX, 0, scrollLimitX); |
| var zoomToDestY = _clamp(args.contentY, 0, scrollLimitY); |
| if (zoomToDestX === effectiveScrollLeft && zoomToDestY === effectiveScrollTop) { |
| // Scroll position is already in the proper state. This zoomTo is a no-op. |
| return; |
| } |
| |
| element._zoomToId = element._zoomToId || 0; |
| element._zoomToId++; |
| element._zoomToDestX = zoomToDestX; |
| element._zoomToDestY = zoomToDestY; |
| |
| var thisZoomToId = element._zoomToId; |
| var start = _BaseUtils._now(); |
| var xFactor = (element._zoomToDestX - initialPos.scrollLeft) / _zoomToDuration; |
| var yFactor = (element._zoomToDestY - initialPos.scrollTop) / _zoomToDuration; |
| |
| var update = function () { |
| var t = _BaseUtils._now() - start; |
| if (element._zoomToId !== thisZoomToId) { |
| return; |
| } else if (t > _zoomToDuration) { |
| setAdjustedScrollPosition(element, element._zoomToDestX, element._zoomToDestY); |
| element._zoomToDestX = null; |
| element._zoomToDestY = null; |
| } else { |
| setAdjustedScrollPosition(element, initialPos.scrollLeft + t * xFactor, initialPos.scrollTop + t * yFactor); |
| _BaseUtils._requestAnimationFrame(update); |
| } |
| }; |
| |
| _BaseUtils._requestAnimationFrame(update); |
| }, Scheduler.Priority.high, null, "WinJS.Utilities._zoomTo"); |
| } |
| }, |
| |
| _setActive: function _setActive(element, scroller) { |
| var success = true; |
| try { |
| if (_Global.HTMLElement && _Global.HTMLElement.prototype.setActive) { |
| element.setActive(); |
| } else { |
| // We are aware that, unlike setActive(), focus() will scroll to the element that gets focus. However, this is |
| // our current cross-browser solution until there is an equivalent for setActive() in other browsers. |
| // |
| // This _setActive polyfill does have limited support for preventing scrolling: via the scroller parameter, it |
| // can prevent one scroller from scrolling. This functionality is necessary in some scenarios. For example, when using |
| // _zoomTo and _setActive together. |
| |
| var scrollLeft, |
| scrollTop; |
| |
| if (scroller) { |
| scrollLeft = scroller.scrollLeft; |
| scrollTop = scroller.scrollTop; |
| } |
| element.focus(); |
| if (scroller) { |
| scroller.scrollLeft = scrollLeft; |
| scroller.scrollTop = scrollTop; |
| } |
| } |
| } catch (e) { |
| // setActive() raises an exception when trying to focus an invisible item. Checking visibility is non-trivial, so it's best |
| // just to catch the exception and ignore it. focus() on the other hand, does not raise exceptions. |
| success = false; |
| } |
| return success; |
| }, |
| |
| _MutationObserver: _MutationObserver, |
| |
| _resizeNotifier: { |
| get: function () { |
| if (!_resizeNotifier) { |
| _resizeNotifier = new ResizeNotifier(); |
| } |
| return _resizeNotifier; |
| } |
| }, |
| |
| _GenericListener: GenericListener, |
| _globalListener: new GenericListener("Global", _Global, { registerThruWinJSCustomEvents: true }), |
| _documentElementListener: new GenericListener("DocumentElement", _Global.document.documentElement, { registerThruWinJSCustomEvents: true }), |
| _inputPaneListener: _WinRT.Windows.UI.ViewManagement.InputPane ? |
| new GenericListener("InputPane", _WinRT.Windows.UI.ViewManagement.InputPane.getForCurrentView()) : |
| { addEventListener: function () { }, removeEventListener: function () { } }, |
| |
| // Appends a hidden child to the given element that will listen for being added |
| // to the DOM. When the hidden element is added to the DOM, it will dispatch a |
| // "WinJSNodeInserted" event on the provided element. |
| _addInsertedNotifier: function (element) { |
| var hiddenElement = _Global.document.createElement("div"); |
| hiddenElement.style[_BaseUtils._browserStyleEquivalents["animation-name"].scriptName] = "WinJS-node-inserted"; |
| hiddenElement.style[_BaseUtils._browserStyleEquivalents["animation-duration"].scriptName] = "0.01s"; |
| hiddenElement.style["position"] = "absolute"; |
| element.appendChild(hiddenElement); |
| |
| exports._addEventListener(hiddenElement, "animationStart", function (e) { |
| if (e.animationName === "WinJS-node-inserted") { |
| var e = _Global.document.createEvent("Event"); |
| e.initEvent("WinJSNodeInserted", false, true); |
| element.dispatchEvent(e); |
| } |
| }, false); |
| |
| return hiddenElement; |
| }, |
| |
| // Returns a promise which completes when *element* is in the DOM. |
| _inDom: function Utilities_inDom(element) { |
| return new Promise(function (c) { |
| if (_Global.document.body.contains(element)) { |
| c(); |
| } else { |
| var nodeInsertedHandler = function () { |
| element.removeEventListener("WinJSNodeInserted", nodeInsertedHandler, false); |
| c(); |
| }; |
| exports._addInsertedNotifier(element); |
| element.addEventListener("WinJSNodeInserted", nodeInsertedHandler, false); |
| } |
| }); |
| }, |
| |
| // Browser agnostic method to set element flex style |
| // Param is an object in the form {grow: flex-grow, shrink: flex-shrink, basis: flex-basis} |
| // All fields optional |
| _setFlexStyle: function (element, flexParams) { |
| var styleObject = element.style; |
| if (typeof flexParams.grow !== "undefined") { |
| styleObject.msFlexPositive = flexParams.grow; |
| styleObject.webkitFlexGrow = flexParams.grow; |
| styleObject.flexGrow = flexParams.grow; |
| } |
| if (typeof flexParams.shrink !== "undefined") { |
| styleObject.msFlexNegative = flexParams.shrink; |
| styleObject.webkitFlexShrink = flexParams.shrink; |
| styleObject.flexShrink = flexParams.shrink; |
| } |
| if (typeof flexParams.basis !== "undefined") { |
| styleObject.msFlexPreferredSize = flexParams.basis; |
| styleObject.webkitFlexBasis = flexParams.basis; |
| styleObject.flexBasis = flexParams.basis; |
| } |
| }, |
| |
| /// <field locid="WinJS.Utilities.Key" helpKeyword="WinJS.Utilities.Key"> |
| /// Defines a set of keyboard values. |
| /// </field> |
| Key: { |
| /// <field locid="WinJS.Utilities.Key.backspace" helpKeyword="WinJS.Utilities.Key.backspace"> |
| /// BACKSPACE key. |
| /// </field> |
| backspace: 8, |
| |
| /// <field locid="WinJS.Utilities.Key.tab" helpKeyword="WinJS.Utilities.Key.tab"> |
| /// TAB key. |
| /// </field> |
| tab: 9, |
| |
| /// <field locid="WinJS.Utilities.Key.enter" helpKeyword="WinJS.Utilities.Key.enter"> |
| /// ENTER key. |
| /// </field> |
| enter: 13, |
| |
| /// <field locid="WinJS.Utilities.Key.shift" helpKeyword="WinJS.Utilities.Key.shift"> |
| /// Shift key. |
| /// </field> |
| shift: 16, |
| |
| /// <field locid="WinJS.Utilities.Key.ctrl" helpKeyword="WinJS.Utilities.Key.ctrl"> |
| /// CTRL key. |
| /// </field> |
| ctrl: 17, |
| |
| /// <field locid="WinJS.Utilities.Key.alt" helpKeyword="WinJS.Utilities.Key.alt"> |
| /// ALT key |
| /// </field> |
| alt: 18, |
| |
| /// <field locid="WinJS.Utilities.Key.pause" helpKeyword="WinJS.Utilities.Key.pause"> |
| /// Pause key. |
| /// </field> |
| pause: 19, |
| |
| /// <field locid="WinJS.Utilities.Key.capsLock" helpKeyword="WinJS.Utilities.Key.capsLock"> |
| /// CAPS LOCK key. |
| /// </field> |
| capsLock: 20, |
| |
| /// <field locid="WinJS.Utilities.Key.escape" helpKeyword="WinJS.Utilities.Key.escape"> |
| /// ESCAPE key. |
| /// </field> |
| escape: 27, |
| |
| /// <field locid="WinJS.Utilities.Key.space" helpKeyword="WinJS.Utilities.Key.space"> |
| /// SPACE key. |
| /// </field> |
| space: 32, |
| |
| /// <field locid="WinJS.Utilities.Key.pageUp" helpKeyword="WinJS.Utilities.Key.pageUp"> |
| /// PAGE UP key. |
| /// </field> |
| pageUp: 33, |
| |
| /// <field locid="WinJS.Utilities.Key.pageDown" helpKeyword="WinJS.Utilities.Key.pageDown"> |
| /// PAGE DOWN key. |
| /// </field> |
| pageDown: 34, |
| |
| /// <field locid="WinJS.Utilities.Key.end" helpKeyword="WinJS.Utilities.Key.end"> |
| /// END key. |
| /// </field> |
| end: 35, |
| |
| /// <field locid="WinJS.Utilities.Key.home" helpKeyword="WinJS.Utilities.Key.home"> |
| /// HOME key. |
| /// </field> |
| home: 36, |
| |
| /// <field locid="WinJS.Utilities.Key.leftArrow" helpKeyword="WinJS.Utilities.Key.leftArrow"> |
| /// Left arrow key. |
| /// </field> |
| leftArrow: 37, |
| |
| /// <field locid="WinJS.Utilities.Key.upArrow" helpKeyword="WinJS.Utilities.Key.upArrow"> |
| /// Up arrow key. |
| /// </field> |
| upArrow: 38, |
| |
| /// <field locid="WinJS.Utilities.Key.rightArrow" helpKeyword="WinJS.Utilities.Key.rightArrow"> |
| /// Right arrow key. |
| /// </field> |
| rightArrow: 39, |
| |
| /// <field locid="WinJS.Utilities.Key.downArrow" helpKeyword="WinJS.Utilities.Key.downArrow"> |
| /// Down arrow key. |
| /// </field> |
| downArrow: 40, |
| |
| /// <field locid="WinJS.Utilities.Key.insert" helpKeyword="WinJS.Utilities.Key.insert"> |
| /// INSERT key. |
| /// </field> |
| insert: 45, |
| |
| /// <field locid="WinJS.Utilities.Key.deleteKey" helpKeyword="WinJS.Utilities.Key.deleteKey"> |
| /// DELETE key. |
| /// </field> |
| deleteKey: 46, |
| |
| /// <field locid="WinJS.Utilities.Key.num0" helpKeyword="WinJS.Utilities.Key.num0"> |
| /// Number 0 key. |
| /// </field> |
| num0: 48, |
| |
| /// <field locid="WinJS.Utilities.Key.num1" helpKeyword="WinJS.Utilities.Key.num1"> |
| /// Number 1 key. |
| /// </field> |
| num1: 49, |
| |
| /// <field locid="WinJS.Utilities.Key.num2" helpKeyword="WinJS.Utilities.Key.num2"> |
| /// Number 2 key. |
| /// </field> |
| num2: 50, |
| |
| /// <field locid="WinJS.Utilities.Key.num3" helpKeyword="WinJS.Utilities.Key.num3"> |
| /// Number 3 key. |
| /// </field> |
| num3: 51, |
| |
| /// <field locid="WinJS.Utilities.Key.num4" helpKeyword="WinJS.Utilities.Key.num4"> |
| /// Number 4 key. |
| /// </field> |
| num4: 52, |
| |
| /// <field locid="WinJS.Utilities.Key.num5" helpKeyword="WinJS.Utilities.Key.num5"> |
| /// Number 5 key. |
| /// </field> |
| num5: 53, |
| |
| /// <field locid="WinJS.Utilities.Key.num6" helpKeyword="WinJS.Utilities.Key.num6"> |
| /// Number 6 key. |
| /// </field> |
| num6: 54, |
| |
| /// <field locid="WinJS.Utilities.Key.num7" helpKeyword="WinJS.Utilities.Key.num7"> |
| /// Number 7 key. |
| /// </field> |
| num7: 55, |
| |
| /// <field locid="WinJS.Utilities.Key.num8" helpKeyword="WinJS.Utilities.Key.num8"> |
| /// Number 8 key. |
| /// </field> |
| num8: 56, |
| |
| /// <field locid="WinJS.Utilities.Key.num9" helpKeyword="WinJS.Utilities.Key.num9"> |
| /// Number 9 key. |
| /// </field> |
| num9: 57, |
| |
| /// <field locid="WinJS.Utilities.Key.a" helpKeyword="WinJS.Utilities.Key.a"> |
| /// A key. |
| /// </field> |
| a: 65, |
| |
| /// <field locid="WinJS.Utilities.Key.b" helpKeyword="WinJS.Utilities.Key.b"> |
| /// B key. |
| /// </field> |
| b: 66, |
| |
| /// <field locid="WinJS.Utilities.Key.c" helpKeyword="WinJS.Utilities.Key.c"> |
| /// C key. |
| /// </field> |
| c: 67, |
| |
| /// <field locid="WinJS.Utilities.Key.d" helpKeyword="WinJS.Utilities.Key.d"> |
| /// D key. |
| /// </field> |
| d: 68, |
| |
| /// <field locid="WinJS.Utilities.Key.e" helpKeyword="WinJS.Utilities.Key.e"> |
| /// E key. |
| /// </field> |
| e: 69, |
| |
| /// <field locid="WinJS.Utilities.Key.f" helpKeyword="WinJS.Utilities.Key.f"> |
| /// F key. |
| /// </field> |
| f: 70, |
| |
| /// <field locid="WinJS.Utilities.Key.g" helpKeyword="WinJS.Utilities.Key.g"> |
| /// G key. |
| /// </field> |
| g: 71, |
| |
| /// <field locid="WinJS.Utilities.Key.h" helpKeyword="WinJS.Utilities.Key.h"> |
| /// H key. |
| /// </field> |
| h: 72, |
| |
| /// <field locid="WinJS.Utilities.Key.i" helpKeyword="WinJS.Utilities.Key.i"> |
| /// I key. |
| /// </field> |
| i: 73, |
| |
| /// <field locid="WinJS.Utilities.Key.j" helpKeyword="WinJS.Utilities.Key.j"> |
| /// J key. |
| /// </field> |
| j: 74, |
| |
| /// <field locid="WinJS.Utilities.Key.k" helpKeyword="WinJS.Utilities.Key.k"> |
| /// K key. |
| /// </field> |
| k: 75, |
| |
| /// <field locid="WinJS.Utilities.Key.l" helpKeyword="WinJS.Utilities.Key.l"> |
| /// L key. |
| /// </field> |
| l: 76, |
| |
| /// <field locid="WinJS.Utilities.Key.m" helpKeyword="WinJS.Utilities.Key.m"> |
| /// M key. |
| /// </field> |
| m: 77, |
| |
| /// <field locid="WinJS.Utilities.Key.n" helpKeyword="WinJS.Utilities.Key.n"> |
| /// N key. |
| /// </field> |
| n: 78, |
| |
| /// <field locid="WinJS.Utilities.Key.o" helpKeyword="WinJS.Utilities.Key.o"> |
| /// O key. |
| /// </field> |
| o: 79, |
| |
| /// <field locid="WinJS.Utilities.Key.p" helpKeyword="WinJS.Utilities.Key.p"> |
| /// P key. |
| /// </field> |
| p: 80, |
| |
| /// <field locid="WinJS.Utilities.Key.q" helpKeyword="WinJS.Utilities.Key.q"> |
| /// Q key. |
| /// </field> |
| q: 81, |
| |
| /// <field locid="WinJS.Utilities.Key.r" helpKeyword="WinJS.Utilities.Key.r"> |
| /// R key. |
| /// </field> |
| r: 82, |
| |
| /// <field locid="WinJS.Utilities.Key.s" helpKeyword="WinJS.Utilities.Key.s"> |
| /// S key. |
| /// </field> |
| s: 83, |
| |
| /// <field locid="WinJS.Utilities.Key.t" helpKeyword="WinJS.Utilities.Key.t"> |
| /// T key. |
| /// </field> |
| t: 84, |
| |
| /// <field locid="WinJS.Utilities.Key.u" helpKeyword="WinJS.Utilities.Key.u"> |
| /// U key. |
| /// </field> |
| u: 85, |
| |
| /// <field locid="WinJS.Utilities.Key.v" helpKeyword="WinJS.Utilities.Key.v"> |
| /// V key. |
| /// </field> |
| v: 86, |
| |
| /// <field locid="WinJS.Utilities.Key.w" helpKeyword="WinJS.Utilities.Key.w"> |
| /// W key. |
| /// </field> |
| w: 87, |
| |
| /// <field locid="WinJS.Utilities.Key.x" helpKeyword="WinJS.Utilities.Key.x"> |
| /// X key. |
| /// </field> |
| x: 88, |
| |
| /// <field locid="WinJS.Utilities.Key.y" helpKeyword="WinJS.Utilities.Key.y"> |
| /// Y key. |
| /// </field> |
| y: 89, |
| |
| /// <field locid="WinJS.Utilities.Key.z" helpKeyword="WinJS.Utilities.Key.z"> |
| /// Z key. |
| /// </field> |
| z: 90, |
| |
| /// <field locid="WinJS.Utilities.Key.leftWindows" helpKeyword="WinJS.Utilities.Key.leftWindows"> |
| /// Left Windows key. |
| /// </field> |
| leftWindows: 91, |
| |
| /// <field locid="WinJS.Utilities.Key.rightWindows" helpKeyword="WinJS.Utilities.Key.rightWindows"> |
| /// Right Windows key. |
| /// </field> |
| rightWindows: 92, |
| |
| /// <field locid="WinJS.Utilities.Key.menu" helpKeyword="WinJS.Utilities.Key.menu"> |
| /// Menu key. |
| /// </field> |
| menu: 93, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad0" helpKeyword="WinJS.Utilities.Key.numPad0"> |
| /// Number pad 0 key. |
| /// </field> |
| numPad0: 96, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad1" helpKeyword="WinJS.Utilities.Key.numPad1"> |
| /// Number pad 1 key. |
| /// </field> |
| numPad1: 97, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad2" helpKeyword="WinJS.Utilities.Key.numPad2"> |
| /// Number pad 2 key. |
| /// </field> |
| numPad2: 98, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad3" helpKeyword="WinJS.Utilities.Key.numPad3"> |
| /// Number pad 3 key. |
| /// </field> |
| numPad3: 99, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad4" helpKeyword="WinJS.Utilities.Key.numPad4"> |
| /// Number pad 4 key. |
| /// </field> |
| numPad4: 100, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad5" helpKeyword="WinJS.Utilities.Key.numPad5"> |
| /// Number pad 5 key. |
| /// </field> |
| numPad5: 101, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad6" helpKeyword="WinJS.Utilities.Key.numPad6"> |
| /// Number pad 6 key. |
| /// </field> |
| numPad6: 102, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad7" helpKeyword="WinJS.Utilities.Key.numPad7"> |
| /// Number pad 7 key. |
| /// </field> |
| numPad7: 103, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad8" helpKeyword="WinJS.Utilities.Key.numPad8"> |
| /// Number pad 8 key. |
| /// </field> |
| numPad8: 104, |
| |
| /// <field locid="WinJS.Utilities.Key.numPad9" helpKeyword="WinJS.Utilities.Key.numPad9"> |
| /// Number pad 9 key. |
| /// </field> |
| numPad9: 105, |
| |
| /// <field locid="WinJS.Utilities.Key.multiply" helpKeyword="WinJS.Utilities.Key.multiply"> |
| /// Multiplication key. |
| /// </field> |
| multiply: 106, |
| |
| /// <field locid="WinJS.Utilities.Key.add" helpKeyword="WinJS.Utilities.Key.add"> |
| /// Addition key. |
| /// </field> |
| add: 107, |
| |
| /// <field locid="WinJS.Utilities.Key.subtract" helpKeyword="WinJS.Utilities.Key.subtract"> |
| /// Subtraction key. |
| /// </field> |
| subtract: 109, |
| |
| /// <field locid="WinJS.Utilities.Key.decimalPoint" helpKeyword="WinJS.Utilities.Key.decimalPoint"> |
| /// Decimal point key. |
| /// </field> |
| decimalPoint: 110, |
| |
| /// <field locid="WinJS.Utilities.Key.divide" helpKeyword="WinJS.Utilities.Key.divide"> |
| /// Division key. |
| /// </field> |
| divide: 111, |
| |
| /// <field locid="WinJS.Utilities.Key.F1" helpKeyword="WinJS.Utilities.Key.F1"> |
| /// F1 key. |
| /// </field> |
| F1: 112, |
| |
| /// <field locid="WinJS.Utilities.Key.F2" helpKeyword="WinJS.Utilities.Key.F2"> |
| /// F2 key. |
| /// </field> |
| F2: 113, |
| |
| /// <field locid="WinJS.Utilities.Key.F3" helpKeyword="WinJS.Utilities.Key.F3"> |
| /// F3 key. |
| /// </field> |
| F3: 114, |
| |
| /// <field locid="WinJS.Utilities.Key.F4" helpKeyword="WinJS.Utilities.Key.F4"> |
| /// F4 key. |
| /// </field> |
| F4: 115, |
| |
| /// <field locid="WinJS.Utilities.Key.F5" helpKeyword="WinJS.Utilities.Key.F5"> |
| /// F5 key. |
| /// </field> |
| F5: 116, |
| |
| /// <field locid="WinJS.Utilities.Key.F6" helpKeyword="WinJS.Utilities.Key.F6"> |
| /// F6 key. |
| /// </field> |
| F6: 117, |
| |
| /// <field locid="WinJS.Utilities.Key.F7" helpKeyword="WinJS.Utilities.Key.F7"> |
| /// F7 key. |
| /// </field> |
| F7: 118, |
| |
| /// <field locid="WinJS.Utilities.Key.F8" helpKeyword="WinJS.Utilities.Key.F8"> |
| /// F8 key. |
| /// </field> |
| F8: 119, |
| |
| /// <field locid="WinJS.Utilities.Key.F9" helpKeyword="WinJS.Utilities.Key.F9"> |
| /// F9 key. |
| /// </field> |
| F9: 120, |
| |
| /// <field locid="WinJS.Utilities.Key.F10" helpKeyword="WinJS.Utilities.Key.F10"> |
| /// F10 key. |
| /// </field> |
| F10: 121, |
| |
| /// <field locid="WinJS.Utilities.Key.F11" helpKeyword="WinJS.Utilities.Key.F11"> |
| /// F11 key. |
| /// </field> |
| F11: 122, |
| |
| /// <field locid="WinJS.Utilities.Key.F12" helpKeyword="WinJS.Utilities.Key.F12"> |
| /// F12 key. |
| /// </field> |
| F12: 123, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationView" helpKeyword="WinJS.Utilities.Key.NavigationView"> |
| /// XBox One Remote NavigationView key. |
| /// </field> |
| NavigationView: 136, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationMenu" helpKeyword="WinJS.Utilities.Key.NavigationMenu"> |
| /// XBox One Remote NavigationMenu key. |
| /// </field> |
| NavigationMenu: 137, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationUp" helpKeyword="WinJS.Utilities.Key.NavigationUp"> |
| /// XBox One Remote NavigationUp key. |
| /// </field> |
| NavigationUp: 138, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationDown" helpKeyword="WinJS.Utilities.Key.NavigationDown"> |
| /// XBox One Remote NavigationDown key. |
| /// </field> |
| NavigationDown: 139, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationLeft" helpKeyword="WinJS.Utilities.Key.NavigationLeft"> |
| /// XBox One Remote NavigationLeft key. |
| /// </field> |
| NavigationLeft: 140, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationRight" helpKeyword="WinJS.Utilities.Key.NavigationRight"> |
| /// XBox One Remote NavigationRight key. |
| /// </field> |
| NavigationRight: 141, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationAccept" helpKeyword="WinJS.Utilities.Key.NavigationAccept"> |
| /// XBox One Remote NavigationAccept key. |
| /// </field> |
| NavigationAccept: 142, |
| |
| /// <field locid="WinJS.Utilities.Key.NavigationCancel" helpKeyword="WinJS.Utilities.Key.NavigationCancel"> |
| /// XBox One Remote NavigationCancel key. |
| /// </field> |
| NavigationCancel: 143, |
| |
| /// <field locid="WinJS.Utilities.Key.numLock" helpKeyword="WinJS.Utilities.Key.numLock"> |
| /// NUMBER LOCK key. |
| /// </field> |
| numLock: 144, |
| |
| /// <field locid="WinJS.Utilities.Key.scrollLock" helpKeyword="WinJS.Utilities.Key.scrollLock"> |
| /// SCROLL LOCK key. |
| /// </field> |
| scrollLock: 145, |
| |
| /// <field locid="WinJS.Utilities.Key.browserBack" helpKeyword="WinJS.Utilities.Key.browserBack"> |
| /// Browser back key. |
| /// </field> |
| browserBack: 166, |
| |
| /// <field locid="WinJS.Utilities.Key.browserForward" helpKeyword="WinJS.Utilities.Key.browserForward"> |
| /// Browser forward key. |
| /// </field> |
| browserForward: 167, |
| |
| /// <field locid="WinJS.Utilities.Key.semicolon" helpKeyword="WinJS.Utilities.Key.semicolon"> |
| /// SEMICOLON key. |
| /// </field> |
| semicolon: 186, |
| |
| /// <field locid="WinJS.Utilities.Key.equal" helpKeyword="WinJS.Utilities.Key.equal"> |
| /// EQUAL key. |
| /// </field> |
| equal: 187, |
| |
| /// <field locid="WinJS.Utilities.Key.comma" helpKeyword="WinJS.Utilities.Key.comma"> |
| /// COMMA key. |
| /// </field> |
| comma: 188, |
| |
| /// <field locid="WinJS.Utilities.Key.dash" helpKeyword="WinJS.Utilities.Key.dash"> |
| /// DASH key. |
| /// </field> |
| dash: 189, |
| |
| /// <field locid="WinJS.Utilities.Key.period" helpKeyword="WinJS.Utilities.Key.period"> |
| /// PERIOD key. |
| /// </field> |
| period: 190, |
| |
| /// <field locid="WinJS.Utilities.Key.forwardSlash" helpKeyword="WinJS.Utilities.Key.forwardSlash"> |
| /// FORWARD SLASH key. |
| /// </field> |
| forwardSlash: 191, |
| |
| /// <field locid="WinJS.Utilities.Key.graveAccent" helpKeyword="WinJS.Utilities.Key.graveAccent"> |
| /// Accent grave key. |
| /// </field> |
| graveAccent: 192, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadA" helpKeyword="WinJS.Utilities.Key.GamepadA"> |
| /// XBox One GamepadA key. |
| /// </field> |
| GamepadA: 195, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadB" helpKeyword="WinJS.Utilities.Key.GamepadB"> |
| /// XBox One GamepadB key. |
| /// </field> |
| GamepadB: 196, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadX" helpKeyword="WinJS.Utilities.Key.GamepadX"> |
| /// XBox One GamepadX key. |
| /// </field> |
| GamepadX: 197, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadY" helpKeyword="WinJS.Utilities.Key.GamepadY"> |
| /// XBox One GamepadY key. |
| /// </field> |
| GamepadY: 198, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightShoulder" helpKeyword="WinJS.Utilities.Key.GamepadRightShoulder"> |
| /// XBox One GamepadRightShoulder key. |
| /// </field> |
| GamepadRightShoulder: 199, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftShoulder" helpKeyword="WinJS.Utilities.Key.GamepadLeftShoulder"> |
| /// XBox One GamepadLeftShoulder key. |
| /// </field> |
| GamepadLeftShoulder: 200, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftTrigger" helpKeyword="WinJS.Utilities.Key.GamepadLeftTrigger"> |
| /// XBox One GamepadLeftTrigger key. |
| /// </field> |
| GamepadLeftTrigger: 201, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightTrigger" helpKeyword="WinJS.Utilities.Key.GamepadRightTrigger"> |
| /// XBox One GamepadRightTrigger key. |
| /// </field> |
| GamepadRightTrigger: 202, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadDPadUp" helpKeyword="WinJS.Utilities.Key.GamepadDPadUp"> |
| /// XBox One GamepadDPadUp key. |
| /// </field> |
| GamepadDPadUp: 203, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadDPadDown" helpKeyword="WinJS.Utilities.Key.GamepadDPadDown"> |
| /// XBox One GamepadDPadDown key. |
| /// </field> |
| GamepadDPadDown: 204, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadDPadLeft" helpKeyword="WinJS.Utilities.Key.GamepadDPadLeft"> |
| /// XBox One GamepadDPadLeft key. |
| /// </field> |
| GamepadDPadLeft: 205, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadDPadRight" helpKeyword="WinJS.Utilities.Key.GamepadDPadRight"> |
| /// XBox One GamepadDPadRight key. |
| /// </field> |
| GamepadDPadRight: 206, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadMenu" helpKeyword="WinJS.Utilities.Key.GamepadMenu"> |
| /// XBox One GamepadMenu key. |
| /// </field> |
| GamepadMenu: 207, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadView" helpKeyword="WinJS.Utilities.Key.GamepadView"> |
| /// XBox One GamepadView key. |
| /// </field> |
| GamepadView: 208, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftThumbstick" helpKeyword="WinJS.Utilities.Key.GamepadLeftThumbstick"> |
| /// XBox One GamepadLeftThumbstick key. |
| /// </field> |
| GamepadLeftThumbstick: 209, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightThumbstick" helpKeyword="WinJS.Utilities.Key.GamepadRightThumbstick"> |
| /// XBox One GamepadRightThumbstick key. |
| /// </field> |
| GamepadRightThumbstick: 210, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftThumbstickUp" helpKeyword="WinJS.Utilities.Key.GamepadLeftThumbstickUp"> |
| /// XBox One GamepadLeftThumbstickUp key. |
| /// </field> |
| GamepadLeftThumbstickUp: 211, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftThumbstickDown" helpKeyword="WinJS.Utilities.Key.GamepadLeftThumbstickDown"> |
| /// XBox One GamepadLeftThumbstickDown key. |
| /// </field> |
| GamepadLeftThumbstickDown: 212, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftThumbstickRight" helpKeyword="WinJS.Utilities.Key.GamepadLeftThumbstickRight"> |
| /// XBox One GamepadLeftThumbstickRight key. |
| /// </field> |
| GamepadLeftThumbstickRight: 213, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadLeftThumbstickLeft" helpKeyword="WinJS.Utilities.Key.GamepadLeftThumbstickLeft"> |
| /// XBox One GamepadLeftThumbstickLeft key. |
| /// </field> |
| GamepadLeftThumbstickLeft: 214, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightThumbstickUp" helpKeyword="WinJS.Utilities.Key.GamepadRightThumbstickUp"> |
| /// XBox One GamepadRightThumbstickUp key. |
| /// </field> |
| GamepadRightThumbstickUp: 215, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightThumbstickDown" helpKeyword="WinJS.Utilities.Key.GamepadRightThumbstickDown"> |
| /// XBox One GamepadRightThumbstickDown key. |
| /// </field> |
| GamepadRightThumbstickDown: 216, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightThumbstickRight" helpKeyword="WinJS.Utilities.Key.GamepadRightThumbstickRight"> |
| /// XBox One GamepadRightThumbstickRight key. |
| /// </field> |
| GamepadRightThumbstickRight: 217, |
| |
| /// <field locid="WinJS.Utilities.Key.GamepadRightThumbstickLeft" helpKeyword="WinJS.Utilities.Key.GamepadRightThumbstickLeft"> |
| /// XBox One GamepadRightThumbstickLeft key. |
| /// </field> |
| GamepadRightThumbstickLeft: 218, |
| |
| /// <field locid="WinJS.Utilities.Key.openBracket" helpKeyword="WinJS.Utilities.Key.openBracket"> |
| /// OPEN BRACKET key. |
| /// </field> |
| openBracket: 219, |
| |
| /// <field locid="WinJS.Utilities.Key.backSlash" helpKeyword="WinJS.Utilities.Key.backSlash"> |
| /// BACKSLASH key. |
| /// </field> |
| backSlash: 220, |
| |
| /// <field locid="WinJS.Utilities.Key.closeBracket" helpKeyword="WinJS.Utilities.Key.closeBracket"> |
| /// CLOSE BRACKET key. |
| /// </field> |
| closeBracket: 221, |
| |
| /// <field locid="WinJS.Utilities.Key.singleQuote" helpKeyword="WinJS.Utilities.Key.singleQuote"> |
| /// SINGLE QUOTE key. |
| /// </field> |
| singleQuote: 222, |
| |
| /// <field locid="WinJS.Utilities.Key.IME" helpKeyword="WinJS.Utilities.Key.IME"> |
| /// Any IME input. |
| /// </field> |
| IME: 229 |
| }, |
| |
| data: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.data"> |
| /// <summary locid="WinJS.Utilities.data"> |
| /// Gets the data value associated with the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.data_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.data_returnValue"> |
| /// The value associated with the element. |
| /// </returns> |
| /// </signature> |
| if (!element[_dataKey]) { |
| element[_dataKey] = {}; |
| } |
| return element[_dataKey]; |
| }, |
| |
| hasClass: function (e, name) { |
| /// <signature helpKeyword="WinJS.Utilities.hasClass"> |
| /// <summary locid="WinJS.Utilities.hasClass"> |
| /// Determines whether the specified element has the specified class. |
| /// </summary> |
| /// <param name="e" type="HTMLElement" locid="WinJS.Utilities.hasClass_p:e"> |
| /// The element. |
| /// </param> |
| /// <param name="name" type="String" locid="WinJS.Utilities.hasClass_p:name"> |
| /// The name of the class. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Utilities.hasClass_returnValue"> |
| /// true if the specified element contains the specified class; otherwise, false. |
| /// </returns> |
| /// </signature> |
| |
| if (e.classList) { |
| return e.classList.contains(name); |
| } else { |
| var className = getClassName(e); |
| var names = className.trim().split(" "); |
| var l = names.length; |
| for (var i = 0; i < l; i++) { |
| if (names[i] === name) { |
| return true; |
| } |
| } |
| return false; |
| } |
| }, |
| |
| addClass: addClass, |
| |
| removeClass: removeClass, |
| |
| toggleClass: toggleClass, |
| |
| _setAttribute: setAttribute, |
| |
| getRelativeLeft: function (element, parent) { |
| /// <signature helpKeyword="WinJS.Utilities.getRelativeLeft"> |
| /// <summary locid="WinJS.Utilities.getRelativeLeft"> |
| /// Gets the left coordinate of the specified element relative to the specified parent. |
| /// </summary> |
| /// <param name="element" domElement="true" locid="WinJS.Utilities.getRelativeLeft_p:element"> |
| /// The element. |
| /// </param> |
| /// <param name="parent" domElement="true" locid="WinJS.Utilities.getRelativeLeft_p:parent"> |
| /// The parent element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getRelativeLeft_returnValue"> |
| /// The relative left coordinate. |
| /// </returns> |
| /// </signature> |
| if (!element) { |
| return 0; |
| } |
| |
| var left = element.offsetLeft; |
| var e = element.parentNode; |
| while (e) { |
| left -= e.offsetLeft; |
| |
| if (e === parent) { |
| break; |
| } |
| e = e.parentNode; |
| } |
| |
| return left; |
| }, |
| |
| getRelativeTop: function (element, parent) { |
| /// <signature helpKeyword="WinJS.Utilities.getRelativeTop"> |
| /// <summary locid="WinJS.Utilities.getRelativeTop"> |
| /// Gets the top coordinate of the element relative to the specified parent. |
| /// </summary> |
| /// <param name="element" domElement="true" locid="WinJS.Utilities.getRelativeTop_p:element"> |
| /// The element. |
| /// </param> |
| /// <param name="parent" domElement="true" locid="WinJS.Utilities.getRelativeTop_p:parent"> |
| /// The parent element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getRelativeTop_returnValue"> |
| /// The relative top coordinate. |
| /// </returns> |
| /// </signature> |
| if (!element) { |
| return 0; |
| } |
| |
| var top = element.offsetTop; |
| var e = element.parentNode; |
| while (e) { |
| top -= e.offsetTop; |
| |
| if (e === parent) { |
| break; |
| } |
| e = e.parentNode; |
| } |
| |
| return top; |
| }, |
| |
| getScrollPosition: getScrollPosition, |
| |
| setScrollPosition: setScrollPosition, |
| |
| empty: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.empty"> |
| /// <summary locid="WinJS.Utilities.empty"> |
| /// Removes all the child nodes from the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" domElement="true" locid="WinJS.Utilities.empty_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="HTMLElement" locid="WinJS.Utilities.empty_returnValue"> |
| /// The element. |
| /// </returns> |
| /// </signature> |
| if (element.childNodes && element.childNodes.length > 0) { |
| for (var i = element.childNodes.length - 1; i >= 0; i--) { |
| element.removeChild(element.childNodes.item(i)); |
| } |
| } |
| return element; |
| }, |
| |
| _isDOMElement: function (element) { |
| return element && |
| typeof element === "object" && |
| typeof element.tagName === "string"; |
| }, |
| |
| getContentWidth: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getContentWidth"> |
| /// <summary locid="WinJS.Utilities.getContentWidth"> |
| /// Gets the width of the content of the specified element. The content width does not include borders or padding. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getContentWidth_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getContentWidth_returnValue"> |
| /// The content width of the element. |
| /// </returns> |
| /// </signature> |
| var border = getDimension(element, "borderLeftWidth") + getDimension(element, "borderRightWidth"), |
| padding = getDimension(element, "paddingLeft") + getDimension(element, "paddingRight"); |
| return element.offsetWidth - border - padding; |
| }, |
| _getPreciseContentWidth: function (element) { |
| var border = _getPreciseDimension(element, "borderLeftWidth") + _getPreciseDimension(element, "borderRightWidth"), |
| padding = _getPreciseDimension(element, "paddingLeft") + _getPreciseDimension(element, "paddingRight"); |
| return element.offsetWidth - border - padding; |
| }, |
| |
| getTotalWidth: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getTotalWidth"> |
| /// <summary locid="WinJS.Utilities.getTotalWidth"> |
| /// Gets the width of the element, including margins. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getTotalWidth_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getTotalWidth_returnValue"> |
| /// The width of the element including margins. |
| /// </returns> |
| /// </signature> |
| var margin = getDimension(element, "marginLeft") + getDimension(element, "marginRight"); |
| return element.offsetWidth + margin; |
| }, |
| _getPreciseTotalWidth: function (element) { |
| var margin = _getPreciseDimension(element, "marginLeft") + _getPreciseDimension(element, "marginRight"); |
| return element.offsetWidth + margin; |
| }, |
| |
| getContentHeight: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getContentHeight"> |
| /// <summary locid="WinJS.Utilities.getContentHeight"> |
| /// Gets the height of the content of the specified element. The content height does not include borders or padding. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getContentHeight_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Number" integer="true" locid="WinJS.Utilities.getContentHeight_returnValue"> |
| /// The content height of the element. |
| /// </returns> |
| /// </signature> |
| var border = getDimension(element, "borderTopWidth") + getDimension(element, "borderBottomWidth"), |
| padding = getDimension(element, "paddingTop") + getDimension(element, "paddingBottom"); |
| return element.offsetHeight - border - padding; |
| }, |
| _getPreciseContentHeight: function (element) { |
| var border = _getPreciseDimension(element, "borderTopWidth") + _getPreciseDimension(element, "borderBottomWidth"), |
| padding = _getPreciseDimension(element, "paddingTop") + _getPreciseDimension(element, "paddingBottom"); |
| return element.offsetHeight - border - padding; |
| }, |
| |
| getTotalHeight: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getTotalHeight"> |
| /// <summary locid="WinJS.Utilities.getTotalHeight"> |
| /// Gets the height of the element, including its margins. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getTotalHeight_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getTotalHeight_returnValue"> |
| /// The height of the element including margins. |
| /// </returns> |
| /// </signature> |
| var margin = getDimension(element, "marginTop") + getDimension(element, "marginBottom"); |
| return element.offsetHeight + margin; |
| }, |
| _getPreciseTotalHeight: function (element) { |
| var margin = _getPreciseDimension(element, "marginTop") + _getPreciseDimension(element, "marginBottom"); |
| return element.offsetHeight + margin; |
| }, |
| |
| getPosition: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getPosition"> |
| /// <summary locid="WinJS.Utilities.getPosition"> |
| /// Gets the position of the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getPosition_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.getPosition_returnValue"> |
| /// An object that contains the left, top, width and height properties of the element. |
| /// </returns> |
| /// </signature> |
| return exports._getPositionRelativeTo(element, null); |
| }, |
| |
| getTabIndex: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.getTabIndex"> |
| /// <summary locid="WinJS.Utilities.getTabIndex"> |
| /// Gets the tabIndex of the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.getTabIndex_p:element"> |
| /// The element. |
| /// </param> |
| /// <returns type="Number" locid="WinJS.Utilities.getTabIndex_returnValue"> |
| /// The tabIndex of the element. Returns -1 if the element cannot be tabbed to |
| /// </returns> |
| /// </signature> |
| // For reference: http://www.w3.org/html/wg/drafts/html/master/single-page.html#specially-focusable |
| var tabbableElementsRE = /BUTTON|COMMAND|MENUITEM|OBJECT|SELECT|TEXTAREA/; |
| if (element.disabled) { |
| return -1; |
| } |
| var tabIndex = element.getAttribute("tabindex"); |
| if (tabIndex === null || tabIndex === undefined) { |
| var name = element.tagName; |
| if (tabbableElementsRE.test(name) || |
| (element.href && (name === "A" || name === "AREA" || name === "LINK")) || |
| (name === "INPUT" && element.type !== "hidden") || |
| (name === "TH" && element.sorted)) { |
| return 0; |
| } |
| return -1; |
| } |
| return parseInt(tabIndex, 10); |
| }, |
| |
| convertToPixels: convertToPixels, |
| _convertToPrecisePixels: _convertToPrecisePixels, |
| _getPreciseMargins: _getPreciseMargins, |
| |
| |
| eventWithinElement: function (element, event) { |
| /// <signature helpKeyword="WinJS.Utilities.eventWithinElement"> |
| /// <summary locid="WinJS.Utilities.eventWithinElement"> |
| /// Determines whether the specified event occurred within the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.eventWithinElement_p:element"> |
| /// The element. |
| /// </param> |
| /// <param name="event" type="Event" locid="WinJS.Utilities.eventWithinElement_p:event"> |
| /// The event. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Utilities.eventWithinElement_returnValue"> |
| /// true if the event occurred within the element; otherwise, false. |
| /// </returns> |
| /// </signature> |
| var related = event.relatedTarget; |
| if (related && related !== element) { |
| return element.contains(related); |
| } |
| |
| return false; |
| }, |
| |
| //UI Utilities |
| _deprecated: function (message) { |
| _Global.console && _Global.console.warn(message); |
| }, |
| |
| // Take a renderer which may be a function (signature: (data) => element) or a WinJS.Binding.Template |
| // and return a function with a unified synchronous contract which is: |
| // |
| // (data, container) => element |
| // |
| // Where: |
| // |
| // 1) if you pass container the content will be rendered into the container and the |
| // container will be returned. |
| // |
| // 2) if you don't pass a container the content will be rendered and returned. |
| // |
| _syncRenderer: function (renderer, tagName) { |
| tagName = tagName || "div"; |
| if (typeof renderer === "function") { |
| return function (data, container) { |
| if (container) { |
| container.appendChild(renderer(data)); |
| return container; |
| } else { |
| return renderer(data); |
| } |
| }; |
| } |
| |
| var template; |
| if (typeof renderer.render === "function") { |
| template = renderer; |
| } else if (renderer.winControl && typeof renderer.winControl.render === "function") { |
| template = renderer.winControl; |
| } |
| |
| return function (data, container) { |
| var host = container || _Global.document.createElement(tagName); |
| template.render(data, host); |
| if (container) { |
| return container; |
| } else { |
| // The expectation is that the creation of the DOM elements happens synchronously |
| // and as such we steal the first child and make it the root element. |
| // |
| var element = host.firstElementChild; |
| |
| // Because we have changed the "root" we may need to move the dispose method |
| // created by the template to the child and do a little switcheroo on dispose. |
| // |
| if (element && host.dispose) { |
| var prev = element.dispose; |
| element.dispose = function () { |
| element.dispose = prev; |
| host.appendChild(element); |
| host.dispose(); |
| }; |
| } |
| return element; |
| } |
| }; |
| }, |
| |
| _getPositionRelativeTo: function Utilities_getPositionRelativeTo(element, ancestor) { |
| var fromElement = element, |
| offsetParent = element.offsetParent, |
| top = element.offsetTop, |
| left = element.offsetLeft; |
| |
| while ((element = element.parentNode) && |
| element !== ancestor && |
| element !== _Global.document.body && |
| element !== _Global.document.documentElement) { |
| top -= element.scrollTop; |
| var dir = _getComputedStyle(element, null).direction; |
| left -= dir !== "rtl" ? element.scrollLeft : -getAdjustedScrollPosition(element).scrollLeft; |
| |
| if (element === offsetParent) { |
| top += element.offsetTop; |
| left += element.offsetLeft; |
| offsetParent = element.offsetParent; |
| } |
| } |
| |
| return { |
| left: left, |
| top: top, |
| width: fromElement.offsetWidth, |
| height: fromElement.offsetHeight |
| }; |
| }, |
| |
| // *element* is not included in the tabIndex search |
| _getHighAndLowTabIndices: function Utilities_getHighAndLowTabIndices(element) { |
| var descendants = element.getElementsByTagName("*"); |
| var lowestTabIndex = 0; |
| var highestTabIndex = 0; |
| // tabIndex=0 is the highest (considered higher than positive tab indices) so |
| // we can stop searching for a higher tab index once we find tabIndex=0. |
| var foundTabIndex0 = false; |
| for (var i = 0, len = descendants.length; i < len; i++) { |
| var tabIndexStr = descendants[i].getAttribute("tabIndex"); |
| if (tabIndexStr !== null && tabIndexStr !== undefined) { |
| var tabIndex = parseInt(tabIndexStr, 10); |
| // Update lowest |
| if (tabIndex > 0 && (tabIndex < lowestTabIndex || lowestTabIndex === 0)) { |
| lowestTabIndex = tabIndex; |
| } |
| // Update highest |
| if (!foundTabIndex0) { |
| if (tabIndex === 0) { |
| foundTabIndex0 = true; |
| highestTabIndex = 0; |
| } else if (tabIndex > highestTabIndex) { |
| highestTabIndex = tabIndex; |
| } |
| } |
| } |
| } |
| |
| return { |
| highest: highestTabIndex, |
| lowest: lowestTabIndex |
| }; |
| }, |
| |
| _getLowestTabIndexInList: function Utilities_getLowestTabIndexInList(elements) { |
| // Returns the lowest positive tabIndex in a list of elements. |
| // Returns 0 if there are no positive tabIndices. |
| var lowestTabIndex = 0; |
| var elmTabIndex; |
| for (var i = 0; i < elements.length; i++) { |
| elmTabIndex = parseInt(elements[i].getAttribute("tabIndex"), 10); |
| if ((0 < elmTabIndex) |
| && ((elmTabIndex < lowestTabIndex) || !lowestTabIndex)) { |
| lowestTabIndex = elmTabIndex; |
| } |
| } |
| |
| return lowestTabIndex; |
| }, |
| |
| _getHighestTabIndexInList: function Utilities_getHighestTabIndexInList(elements) { |
| // Returns 0 if any element is explicitly set to 0. (0 is the highest tabIndex) |
| // Returns the highest tabIndex in the list of elements. |
| // Returns 0 if there are no positive tabIndices. |
| var highestTabIndex = 0; |
| var elmTabIndex; |
| for (var i = 0; i < elements.length; i++) { |
| elmTabIndex = parseInt(elements[i].getAttribute("tabIndex"), 10); |
| if (elmTabIndex === 0) { |
| return elmTabIndex; |
| } else if (highestTabIndex < elmTabIndex) { |
| highestTabIndex = elmTabIndex; |
| } |
| } |
| |
| return highestTabIndex; |
| }, |
| |
| _hasCursorKeysBehaviors: function Utilities_hasCursorKeysBehaviors(element) { |
| if (element.tagName === "SELECT" || |
| element.tagName === "TEXTAREA") { |
| return true; |
| } |
| if (element.tagName === "INPUT") { |
| return element.type === "" || |
| element.type === "date" || |
| element.type === "datetime" || |
| element.type === "datetime-local" || |
| element.type === "email" || |
| element.type === "month" || |
| element.type === "number" || |
| element.type === "password" || |
| element.type === "range" || |
| element.type === "search" || |
| element.type === "tel" || |
| element.type === "text" || |
| element.type === "time" || |
| element.type === "url" || |
| element.type === "week"; |
| } |
| return false; |
| }, |
| |
| _reparentChildren: function (originalParent, destinationParent) { |
| var child = originalParent.firstChild; |
| while (child) { |
| var sibling = child.nextSibling; |
| destinationParent.appendChild(child); |
| child = sibling; |
| } |
| }, |
| |
| // Ensures that the same element has focus before and after *callback* is |
| // called. Useful if moving focus is an unintentional side effect of *callback*. |
| // For example, this could happen if *callback* removes and reinserts elements |
| // to the DOM. |
| _maintainFocus: function ElementUtilities_maintainFocus(callback) { |
| var focusedElement = _Global.document.activeElement; |
| callback(); |
| exports._trySetActiveOnAnyElement(focusedElement); |
| }, |
| |
| // Tries to give focus to an element (even if its tabIndex is -1) via setActive. |
| _trySetActiveOnAnyElement: function Utilities_trySetActiveOnAnyElement(element, scroller) { |
| return exports._tryFocusOnAnyElement(element, true, scroller); |
| }, |
| |
| // Tries to give focus to an element (even if its tabIndex is -1). |
| _tryFocusOnAnyElement: function Utilities_tryFocusOnAnyElement(element, useSetActive, scroller) { |
| var previousActiveElement = _Global.document.activeElement; |
| |
| if (element === previousActiveElement) { |
| return true; |
| } |
| |
| if (useSetActive) { |
| exports._setActive(element, scroller); |
| } else { |
| element.focus(); |
| } |
| |
| return previousActiveElement !== _Global.document.activeElement; |
| }, |
| |
| // Tries to give focus to an element which is a tabstop (i.e. tabIndex >= 0) |
| // via setActive. |
| _trySetActive: function Utilities_trySetActive(elem, scroller) { |
| return this._tryFocus(elem, true, scroller); |
| }, |
| |
| // Tries to give focus to an element which is a tabstop (i.e. tabIndex >= 0). |
| _tryFocus: function Utilities_tryFocus(elem, useSetActive, scroller) { |
| var previousActiveElement = _Global.document.activeElement; |
| |
| if (elem === previousActiveElement) { |
| return true; |
| } |
| |
| var simpleLogicForValidTabStop = (exports.getTabIndex(elem) >= 0); |
| if (!simpleLogicForValidTabStop) { |
| return false; |
| } |
| |
| if (useSetActive) { |
| exports._setActive(elem, scroller); |
| } else { |
| elem.focus(); |
| } |
| |
| if (previousActiveElement !== _Global.document.activeElement) { |
| return true; |
| } |
| return false; |
| }, |
| |
| _setActiveFirstFocusableElement: function Utilities_setActiveFirstFocusableElement(rootEl, scroller) { |
| return this._focusFirstFocusableElement(rootEl, true, scroller); |
| }, |
| |
| _focusFirstFocusableElement: function Utilities_focusFirstFocusableElement(rootEl, useSetActive, scroller) { |
| var _elms = rootEl.getElementsByTagName("*"); |
| |
| // Get the tabIndex set to the firstDiv (which is the lowest) |
| var _lowestTabIndex = this._getLowestTabIndexInList(_elms); |
| var _nextLowestTabIndex = 0; |
| |
| // If there are positive tabIndices, set focus to the element with the lowest tabIndex. |
| // Keep trying with the next lowest tabIndex until all tabIndices have been exhausted. |
| // Otherwise set focus to the first focusable element in DOM order. |
| var i; |
| while (_lowestTabIndex) { |
| for (i = 0; i < _elms.length; i++) { |
| if (_elms[i].tabIndex === _lowestTabIndex) { |
| if (this._tryFocus(_elms[i], useSetActive, scroller)) { |
| return true; |
| } |
| } else if ((_lowestTabIndex < _elms[i].tabIndex) |
| && ((_elms[i].tabIndex < _nextLowestTabIndex) || (_nextLowestTabIndex === 0))) { |
| // Here if _lowestTabIndex < _elms[i].tabIndex < _nextLowestTabIndex |
| _nextLowestTabIndex = _elms[i].tabIndex; |
| } |
| } |
| |
| // We weren't able to set focus to anything at that tabIndex |
| // If we found a higher valid tabIndex, try that now |
| _lowestTabIndex = _nextLowestTabIndex; |
| _nextLowestTabIndex = 0; |
| } |
| |
| // Wasn't able to set focus to anything with a positive tabIndex, try everything now. |
| // This is where things with tabIndex of 0 will be tried. |
| for (i = 0; i < _elms.length; i++) { |
| if (this._tryFocus(_elms[i], useSetActive, scroller)) { |
| return true; |
| } |
| } |
| |
| return false; |
| }, |
| |
| _setActiveLastFocusableElement: function Utilities_setActiveLastFocusableElement(rootEl, scroller) { |
| return this._focusLastFocusableElement(rootEl, true, scroller); |
| }, |
| |
| _focusLastFocusableElement: function Utilities_focusLastFocusableElement(rootEl, useSetActive, scroller) { |
| var _elms = rootEl.getElementsByTagName("*"); |
| // Get the tabIndex set to the finalDiv (which is the highest) |
| var _highestTabIndex = this._getHighestTabIndexInList(_elms); |
| var _nextHighestTabIndex = 0; |
| |
| // Try all tabIndex 0 first. After this conditional the _highestTabIndex |
| // should be equal to the highest positive tabIndex. |
| var i; |
| if (_highestTabIndex === 0) { |
| for (i = _elms.length - 1; i >= 0; i--) { |
| if (_elms[i].tabIndex === _highestTabIndex) { |
| if (this._tryFocus(_elms[i], useSetActive, scroller)) { |
| return true; |
| } |
| } else if (_nextHighestTabIndex < _elms[i].tabIndex) { |
| _nextHighestTabIndex = _elms[i].tabIndex; |
| } |
| } |
| |
| _highestTabIndex = _nextHighestTabIndex; |
| _nextHighestTabIndex = 0; |
| } |
| |
| // If there are positive tabIndices, set focus to the element with the highest tabIndex. |
| // Keep trying with the next highest tabIndex until all tabIndices have been exhausted. |
| // Otherwise set focus to the last focusable element in DOM order. |
| while (_highestTabIndex) { |
| for (i = _elms.length - 1; i >= 0; i--) { |
| if (_elms[i].tabIndex === _highestTabIndex) { |
| if (this._tryFocus(_elms[i], useSetActive, scroller)) { |
| return true; |
| } |
| } else if ((_nextHighestTabIndex < _elms[i].tabIndex) && (_elms[i].tabIndex < _highestTabIndex)) { |
| // Here if _nextHighestTabIndex < _elms[i].tabIndex < _highestTabIndex |
| _nextHighestTabIndex = _elms[i].tabIndex; |
| } |
| } |
| |
| // We weren't able to set focus to anything at that tabIndex |
| // If we found a lower valid tabIndex, try that now |
| _highestTabIndex = _nextHighestTabIndex; |
| _nextHighestTabIndex = 0; |
| } |
| |
| // Wasn't able to set focus to anything with a tabIndex, try everything now |
| for (i = _elms.length - 2; i > 0; i--) { |
| if (this._tryFocus(_elms[i], useSetActive, scroller)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Dispose',[ |
| 'exports', |
| '../Core/_Base', |
| '../Core/_WriteProfilerMark', |
| './_ElementUtilities' |
| ], function (exports, _Base, _WriteProfilerMark, _ElementUtilities) { |
| "use strict"; |
| |
| function markDisposable(element, disposeImpl) { |
| /// <signature helpKeyword="WinJS.Utilities.markDisposable"> |
| /// <summary locid="WinJS.Utilities.markDisposable"> |
| /// Adds the specified dispose implementation to the specified element and marks it as disposable. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.markDisposable_p:element"> |
| /// The element to mark as disposable. |
| /// </param> |
| /// <param name="disposeImpl" type="Function" locid="WinJS.Utilities.markDisposable_p:disposeImpl"> |
| /// The function containing the element-specific dispose logic that will be called by the dispose function. |
| /// </param> |
| /// </signature> |
| var disposed = false; |
| _ElementUtilities.addClass(element, "win-disposable"); |
| |
| var disposable = element.winControl || element; |
| disposable.dispose = function () { |
| if (disposed) { |
| return; |
| } |
| |
| disposed = true; |
| disposeSubTree(element); |
| if (disposeImpl) { |
| disposeImpl(); |
| } |
| }; |
| } |
| |
| function disposeSubTree(element) { |
| /// <signature helpKeyword="WinJS.Utilities.disposeSubTree"> |
| /// <summary locid="WinJS.Utilities.disposeSubTree"> |
| /// Disposes all first-generation disposable elements that are descendents of the specified element. |
| /// The specified element itself is not disposed. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.disposeSubTree_p:element"> |
| /// The root element whose sub-tree is to be disposed. |
| /// </param> |
| /// </signature> |
| if (!element) { |
| return; |
| } |
| |
| _WriteProfilerMark("WinJS.Utilities.disposeSubTree,StartTM"); |
| var query = element.querySelectorAll(".win-disposable"); |
| |
| var index = 0; |
| var length = query.length; |
| while (index < length) { |
| var disposable = query[index]; |
| if (disposable.winControl && disposable.winControl.dispose) { |
| disposable.winControl.dispose(); |
| } |
| if (disposable.dispose) { |
| disposable.dispose(); |
| } |
| |
| // Skip over disposable's descendants since they are this disposable's responsibility to clean up. |
| index += disposable.querySelectorAll(".win-disposable").length + 1; |
| } |
| _WriteProfilerMark("WinJS.Utilities.disposeSubTree,StopTM"); |
| } |
| |
| function _disposeElement(element) { |
| // This helper should only be used for supporting dispose scenarios predating the dispose pattern. |
| // The specified element should be well enough defined so we don't have to check whether it |
| // a) has a disposable winControl, |
| // b) is disposable itself, |
| // or has disposable descendants in which case either a) or b) must have been true when designed correctly. |
| if (!element) { |
| return; |
| } |
| |
| var disposed = false; |
| if (element.winControl && element.winControl.dispose) { |
| element.winControl.dispose(); |
| disposed = true; |
| } |
| if (element.dispose) { |
| element.dispose(); |
| disposed = true; |
| } |
| |
| if (!disposed) { |
| disposeSubTree(element); |
| } |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| |
| markDisposable: markDisposable, |
| |
| disposeSubTree: disposeSubTree, |
| |
| _disposeElement: _disposeElement |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/ControlProcessor/_OptionsLexer',[ |
| 'exports', |
| '../Core/_Base' |
| ], function optionsLexerInit(exports, _Base) { |
| "use strict"; |
| |
| /* |
| |
| Lexical grammar is defined in ECMA-262-5, section 7. |
| |
| Lexical productions used in this grammar defined in ECMA-262-5: |
| |
| Production Section |
| -------------------------------- |
| Identifier 7.6 |
| NullLiteral 7.8.1 |
| BooleanLiteral 7.8.2 |
| NumberLiteral 7.8.3 |
| StringLiteral 7.8.4 |
| |
| */ |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _optionsLexer: _Base.Namespace._lazy(function () { |
| |
| var tokenType = { |
| leftBrace: 1, // { |
| rightBrace: 2, // } |
| leftBracket: 3, // [ |
| rightBracket: 4, // ] |
| separator: 5, // ECMA-262-5, 7.2 |
| colon: 6, // : |
| semicolon: 7, // ; |
| comma: 8, // , |
| dot: 9, // . |
| nullLiteral: 10, // ECMA-262-5, 7.8.1 (null) |
| trueLiteral: 11, // ECMA-262-5, 7.8.2 (true) |
| falseLiteral: 12, // ECMA-262-5, 7.8.2 (false) |
| numberLiteral: 13, // ECMA-262-5, 7.8.3 |
| stringLiteral: 14, // ECMA-262-5, 7.8.4 |
| identifier: 15, // ECMA-262-5, 7.6 |
| reservedWord: 16, |
| thisKeyword: 17, |
| leftParentheses: 18, // ( |
| rightParentheses: 19, // ) |
| eof: 20, |
| error: 21 |
| }; |
| // debugging - this costs something like 20% |
| // |
| //Object.keys(tokenType).forEach(function (key) { |
| // tokenType[key] = key.toString(); |
| //}); |
| var tokens = { |
| leftBrace: { type: tokenType.leftBrace, length: 1 }, |
| rightBrace: { type: tokenType.rightBrace, length: 1 }, |
| leftBracket: { type: tokenType.leftBracket, length: 1 }, |
| rightBracket: { type: tokenType.rightBracket, length: 1 }, |
| colon: { type: tokenType.colon, length: 1 }, |
| semicolon: { type: tokenType.semicolon, length: 1 }, |
| comma: { type: tokenType.comma, length: 1 }, |
| dot: { type: tokenType.dot, length: 1 }, |
| nullLiteral: { type: tokenType.nullLiteral, length: 4, value: null, keyword: true }, |
| trueLiteral: { type: tokenType.trueLiteral, length: 4, value: true, keyword: true }, |
| falseLiteral: { type: tokenType.falseLiteral, length: 5, value: false, keyword: true }, |
| thisKeyword: { type: tokenType.thisKeyword, length: 4, value: "this", keyword: true }, |
| leftParentheses: { type: tokenType.leftParentheses, length: 1 }, |
| rightParentheses: { type: tokenType.rightParentheses, length: 1 }, |
| eof: { type: tokenType.eof, length: 0 } |
| }; |
| |
| function reservedWord(word) { |
| return { type: tokenType.reservedWord, value: word, length: word.length, keyword: true }; |
| } |
| function reservedWordLookup(identifier) { |
| // Moving from a simple object literal lookup for reserved words to this |
| // switch was worth a non-trivial performance increase (5-7%) as this path |
| // gets taken for any identifier. |
| // |
| switch (identifier.charCodeAt(0)) { |
| case /*b*/98: |
| switch (identifier) { |
| case 'break': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*c*/99: |
| switch (identifier) { |
| case 'case': |
| case 'catch': |
| case 'class': |
| case 'const': |
| case 'continue': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*d*/100: |
| switch (identifier) { |
| case 'debugger': |
| case 'default': |
| case 'delete': |
| case 'do': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*e*/101: |
| switch (identifier) { |
| case 'else': |
| case 'enum': |
| case 'export': |
| case 'extends': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*f*/102: |
| switch (identifier) { |
| case 'false': |
| return tokens.falseLiteral; |
| |
| case 'finally': |
| case 'for': |
| case 'function': |
| return reservedWord(identifier); |
| } |
| |
| break; |
| case /*i*/105: |
| switch (identifier) { |
| case 'if': |
| case 'import': |
| case 'in': |
| case 'instanceof': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*n*/110: |
| switch (identifier) { |
| case 'null': |
| return tokens.nullLiteral; |
| |
| case 'new': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*r*/114: |
| switch (identifier) { |
| case 'return': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*s*/115: |
| switch (identifier) { |
| case 'super': |
| case 'switch': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*t*/116: |
| switch (identifier) { |
| case 'true': |
| return tokens.trueLiteral; |
| |
| case 'this': |
| return tokens.thisKeyword; |
| |
| case 'throw': |
| case 'try': |
| case 'typeof': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*v*/118: |
| switch (identifier) { |
| case 'var': |
| case 'void': |
| return reservedWord(identifier); |
| } |
| break; |
| |
| case /*w*/119: |
| switch (identifier) { |
| case 'while': |
| case 'with': |
| return reservedWord(identifier); |
| } |
| break; |
| } |
| return; |
| } |
| |
| var lexer = (function () { |
| function isIdentifierStartCharacter(code, text, offset, limit) { |
| // The ES5 spec decalares that identifiers consist of a bunch of unicode classes, without |
| // WinRT support for determining unicode class membership we are looking at 2500+ lines of |
| // javascript code to encode the relevant class tables. Instead we look for everything |
| // which is legal and < 0x7f, we exclude whitespace and line terminators, and then accept |
| // everything > 0x7f. |
| // |
| // Here's the ES5 production: |
| // |
| // Lu | Ll | Lt | Lm | Lo | Nl |
| // $ |
| // _ |
| // \ UnicodeEscapeSequence |
| // |
| switch (code) { |
| case (code >= /*a*/97 && code <= /*z*/122) && code: |
| case (code >= /*A*/65 && code <= /*Z*/90) && code: |
| case /*$*/36: |
| case /*_*/95: |
| return true; |
| |
| case isWhitespace(code) && code: |
| case isLineTerminator(code) && code: |
| return false; |
| |
| case (code > 0x7f) && code: |
| return true; |
| |
| case /*\*/92: |
| if (offset + 4 < limit) { |
| if (text.charCodeAt(offset) === /*u*/117 && |
| isHexDigit(text.charCodeAt(offset + 1)) && |
| isHexDigit(text.charCodeAt(offset + 2)) && |
| isHexDigit(text.charCodeAt(offset + 3)) && |
| isHexDigit(text.charCodeAt(offset + 4))) { |
| return true; |
| } |
| } |
| return false; |
| |
| default: |
| return false; |
| } |
| } |
| /* |
| // Hand-inlined into readIdentifierPart |
| function isIdentifierPartCharacter(code) { |
| // See comment in isIdentifierStartCharacter. |
| // |
| // Mn | Mc | Nd | Pc |
| // <ZWNJ> | <ZWJ> |
| // |
| switch (code) { |
| case isIdentifierStartCharacter(code) && code: |
| case isDecimalDigit(code) && code: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| */ |
| function readIdentifierPart(text, offset, limit) { |
| var hasEscape = false; |
| while (offset < limit) { |
| var code = text.charCodeAt(offset); |
| switch (code) { |
| //case isIdentifierStartCharacter(code) && code: |
| case (code >= /*a*/97 && code <= /*z*/122) && code: |
| case (code >= /*A*/65 && code <= /*Z*/90) && code: |
| case /*$*/36: |
| case /*_*/95: |
| break; |
| |
| case isWhitespace(code) && code: |
| case isLineTerminator(code) && code: |
| return hasEscape ? -offset : offset; |
| |
| case (code > 0x7f) && code: |
| break; |
| |
| //case isDecimalDigit(code) && code: |
| case (code >= /*0*/48 && code <= /*9*/57) && code: |
| break; |
| |
| case /*\*/92: |
| if (offset + 5 < limit) { |
| if (text.charCodeAt(offset + 1) === /*u*/117 && |
| isHexDigit(text.charCodeAt(offset + 2)) && |
| isHexDigit(text.charCodeAt(offset + 3)) && |
| isHexDigit(text.charCodeAt(offset + 4)) && |
| isHexDigit(text.charCodeAt(offset + 5))) { |
| offset += 5; |
| hasEscape = true; |
| break; |
| } |
| } |
| return hasEscape ? -offset : offset; |
| |
| default: |
| return hasEscape ? -offset : offset; |
| } |
| offset++; |
| } |
| return hasEscape ? -offset : offset; |
| } |
| function readIdentifierToken(text, offset, limit) { |
| var startOffset = offset; |
| offset = readIdentifierPart(text, offset, limit); |
| var hasEscape = false; |
| if (offset < 0) { |
| offset = -offset; |
| hasEscape = true; |
| } |
| var identifier = text.substr(startOffset, offset - startOffset); |
| if (hasEscape) { |
| identifier = "" + JSON.parse('"' + identifier + '"'); |
| } |
| var wordToken = reservedWordLookup(identifier); |
| if (wordToken) { |
| return wordToken; |
| } |
| return { |
| type: tokenType.identifier, |
| length: offset - startOffset, |
| value: identifier |
| }; |
| } |
| function isHexDigit(code) { |
| switch (code) { |
| case (code >= /*0*/48 && code <= /*9*/57) && code: |
| case (code >= /*a*/97 && code <= /*f*/102) && code: |
| case (code >= /*A*/65 && code <= /*F*/70) && code: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| function readHexIntegerLiteral(text, offset, limit) { |
| while (offset < limit && isHexDigit(text.charCodeAt(offset))) { |
| offset++; |
| } |
| return offset; |
| } |
| function isDecimalDigit(code) { |
| switch (code) { |
| case (code >= /*0*/48 && code <= /*9*/57) && code: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| function readDecimalDigits(text, offset, limit) { |
| while (offset < limit && isDecimalDigit(text.charCodeAt(offset))) { |
| offset++; |
| } |
| return offset; |
| } |
| function readDecimalLiteral(text, offset, limit) { |
| offset = readDecimalDigits(text, offset, limit); |
| if (offset < limit && text.charCodeAt(offset) === /*.*/46 && offset + 1 < limit && isDecimalDigit(text.charCodeAt(offset + 1))) { |
| offset = readDecimalDigits(text, offset + 2, limit); |
| } |
| if (offset < limit) { |
| var code = text.charCodeAt(offset); |
| if (code === /*e*/101 || code === /*E*/69) { |
| var tempOffset = offset + 1; |
| if (tempOffset < limit) { |
| code = text.charCodeAt(tempOffset); |
| if (code === /*+*/43 || code === /*-*/45) { |
| tempOffset++; |
| } |
| offset = readDecimalDigits(text, tempOffset, limit); |
| } |
| } |
| } |
| return offset; |
| } |
| function readDecimalLiteralToken(text, start, offset, limit) { |
| var offset = readDecimalLiteral(text, offset, limit); |
| var length = offset - start; |
| return { |
| type: tokenType.numberLiteral, |
| length: length, |
| value: +text.substr(start, length) |
| }; |
| } |
| function isLineTerminator(code) { |
| switch (code) { |
| case 0x000A: // line feed |
| case 0x000D: // carriage return |
| case 0x2028: // line separator |
| case 0x2029: // paragraph separator |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| function readStringLiteralToken(text, offset, limit) { |
| var startOffset = offset; |
| var quoteCharCode = text.charCodeAt(offset); |
| var hasEscape = false; |
| offset++; |
| while (offset < limit && !isLineTerminator(text.charCodeAt(offset))) { |
| if (offset + 1 < limit && text.charCodeAt(offset) === /*\*/92) { |
| hasEscape = true; |
| |
| switch (text.charCodeAt(offset + 1)) { |
| case quoteCharCode: |
| case 0x005C: // \ |
| case 0x000A: // line feed |
| case 0x2028: // line separator |
| case 0x2029: // paragraph separator |
| offset += 2; |
| continue; |
| |
| case 0x000D: // carriage return |
| if (offset + 2 < limit && text.charCodeAt(offset + 2) === 0x000A) { |
| // Skip \r\n |
| offset += 3; |
| } else { |
| offset += 2; |
| } |
| continue; |
| } |
| } |
| offset++; |
| if (text.charCodeAt(offset - 1) === quoteCharCode) { |
| break; |
| } |
| } |
| var length = offset - startOffset; |
| // If we don't have a terminating quote go through the escape path. |
| hasEscape = hasEscape || length === 1 || text.charCodeAt(offset - 1) !== quoteCharCode; |
| var stringValue; |
| if (hasEscape) { |
| stringValue = eval(text.substr(startOffset, length)); // jshint ignore:line |
| } else { |
| stringValue = text.substr(startOffset + 1, length - 2); |
| } |
| return { |
| type: tokenType.stringLiteral, |
| length: length, |
| value: stringValue |
| }; |
| } |
| function isWhitespace(code) { |
| switch (code) { |
| case 0x0009: // tab |
| case 0x000B: // vertical tab |
| case 0x000C: // form feed |
| case 0x0020: // space |
| case 0x00A0: // no-breaking space |
| case 0xFEFF: // BOM |
| return true; |
| |
| // There are no category Zs between 0x00A0 and 0x1680. |
| // |
| case (code < 0x1680) && code: |
| return false; |
| |
| // Unicode category Zs |
| // |
| case 0x1680: |
| case 0x180e: |
| case (code >= 0x2000 && code <= 0x200a) && code: |
| case 0x202f: |
| case 0x205f: |
| case 0x3000: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| // Hand-inlined isWhitespace. |
| function readWhitespace(text, offset, limit) { |
| while (offset < limit) { |
| var code = text.charCodeAt(offset); |
| switch (code) { |
| case 0x0009: // tab |
| case 0x000B: // vertical tab |
| case 0x000C: // form feed |
| case 0x0020: // space |
| case 0x00A0: // no-breaking space |
| case 0xFEFF: // BOM |
| break; |
| |
| // There are no category Zs between 0x00A0 and 0x1680. |
| // |
| case (code < 0x1680) && code: |
| return offset; |
| |
| // Unicode category Zs |
| // |
| case 0x1680: |
| case 0x180e: |
| case (code >= 0x2000 && code <= 0x200a) && code: |
| case 0x202f: |
| case 0x205f: |
| case 0x3000: |
| break; |
| |
| default: |
| return offset; |
| } |
| offset++; |
| } |
| return offset; |
| } |
| function lex(result, text, offset, limit) { |
| while (offset < limit) { |
| var startOffset = offset; |
| var code = text.charCodeAt(offset++); |
| var token; |
| switch (code) { |
| case isWhitespace(code) && code: |
| case isLineTerminator(code) && code: |
| offset = readWhitespace(text, offset, limit); |
| token = { type: tokenType.separator, length: offset - startOffset }; |
| // don't include whitespace in the token stream. |
| continue; |
| |
| case /*"*/34: |
| case /*'*/39: |
| token = readStringLiteralToken(text, offset - 1, limit); |
| break; |
| |
| case /*(*/40: |
| token = tokens.leftParentheses; |
| break; |
| |
| case /*)*/41: |
| token = tokens.rightParentheses; |
| break; |
| |
| case /*+*/43: |
| case /*-*/45: |
| if (offset < limit) { |
| var afterSign = text.charCodeAt(offset); |
| if (afterSign === /*.*/46) { |
| var signOffset = offset + 1; |
| if (signOffset < limit && isDecimalDigit(text.charCodeAt(signOffset))) { |
| token = readDecimalLiteralToken(text, startOffset, signOffset, limit); |
| break; |
| } |
| } else if (isDecimalDigit(afterSign)) { |
| token = readDecimalLiteralToken(text, startOffset, offset, limit); |
| break; |
| } |
| } |
| token = { type: tokenType.error, length: offset - startOffset, value: text.substring(startOffset, offset) }; |
| break; |
| |
| case /*,*/44: |
| token = tokens.comma; |
| break; |
| |
| case /*.*/46: |
| token = tokens.dot; |
| if (offset < limit && isDecimalDigit(text.charCodeAt(offset))) { |
| token = readDecimalLiteralToken(text, startOffset, offset, limit); |
| } |
| break; |
| |
| case /*0*/48: |
| var ch2 = (offset < limit ? text.charCodeAt(offset) : 0); |
| if (ch2 === /*x*/120 || ch2 === /*X*/88) { |
| var hexOffset = readHexIntegerLiteral(text, offset + 1, limit); |
| token = { |
| type: tokenType.numberLiteral, |
| length: hexOffset - startOffset, |
| value: +text.substr(startOffset, hexOffset - startOffset) |
| }; |
| } else { |
| token = readDecimalLiteralToken(text, startOffset, offset, limit); |
| } |
| break; |
| |
| case (code >= /*1*/49 && code <= /*9*/57) && code: |
| token = readDecimalLiteralToken(text, startOffset, offset, limit); |
| break; |
| |
| case /*:*/58: |
| token = tokens.colon; |
| break; |
| |
| case /*;*/59: |
| token = tokens.semicolon; |
| break; |
| |
| case /*[*/91: |
| token = tokens.leftBracket; |
| break; |
| |
| case /*]*/93: |
| token = tokens.rightBracket; |
| break; |
| |
| case /*{*/123: |
| token = tokens.leftBrace; |
| break; |
| |
| case /*}*/125: |
| token = tokens.rightBrace; |
| break; |
| |
| default: |
| if (isIdentifierStartCharacter(code, text, offset, limit)) { |
| token = readIdentifierToken(text, offset - 1, limit); |
| break; |
| } |
| token = { type: tokenType.error, length: offset - startOffset, value: text.substring(startOffset, offset) }; |
| break; |
| } |
| |
| offset += (token.length - 1); |
| result.push(token); |
| } |
| } |
| return function (text) { |
| var result = []; |
| lex(result, text, 0, text.length); |
| result.push(tokens.eof); |
| return result; |
| }; |
| })(); |
| lexer.tokenType = tokenType; |
| return lexer; |
| }) |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/ControlProcessor/_OptionsParser',[ |
| 'exports', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Resources', |
| './_OptionsLexer' |
| ], function optionsParserInit(exports, _Base, _BaseUtils, _ErrorFromName, _Resources, _OptionsLexer) { |
| "use strict"; |
| |
| var strings = { |
| get invalidOptionsRecord() { return "Invalid options record: '{0}', expected to be in the format of an object literal. {1}"; }, |
| get unexpectedTokenExpectedToken() { return "Unexpected token: {0}, expected token: {1}, at offset {2}"; }, |
| get unexpectedTokenExpectedTokens() { return "Unexpected token: {0}, expected one of: {1}, at offset {2}"; }, |
| get unexpectedTokenGeneric() { return "Unexpected token: {0}, at offset {1}"; }, |
| }; |
| |
| /* |
| Notation is described in ECMA-262-5 (ECMAScript Language Specification, 5th edition) section 5. |
| |
| Lexical grammar is defined in ECMA-262-5, section 7. |
| |
| Lexical productions used in this grammar defined in ECMA-262-5: |
| |
| Production Section |
| -------------------------------- |
| Identifier 7.6 |
| NullLiteral 7.8.1 |
| BooleanLiteral 7.8.2 |
| NumberLiteral 7.8.3 |
| StringLiteral 7.8.4 |
| |
| Syntactic grammar for the value of the data-win-options attribute. |
| |
| OptionsLiteral: |
| ObjectLiteral |
| |
| ObjectLiteral: |
| { } |
| { ObjectProperties } |
| { ObjectProperties , } |
| |
| ObjectProperties: |
| ObjectProperty |
| ObjectProperties, ObjectProperty |
| |
| ObjectProperty: |
| PropertyName : Value |
| |
| PropertyName: (from ECMA-262-6, 11.1.5) |
| StringLiteral |
| NumberLiteral |
| Identifier |
| |
| ArrayLiteral: |
| [ ] |
| [ Elision ] |
| [ ArrayElements ] |
| [ ArrayElements , ] |
| [ ArrayElements , Elision ] |
| |
| ArrayElements: |
| Value |
| Elision Value |
| ArrayElements , Value |
| ArrayElements , Elision Value |
| |
| Elision: |
| , |
| Elision , |
| |
| Value: |
| NullLiteral |
| NumberLiteral |
| BooleanLiteral |
| StringLiteral |
| ArrayLiteral |
| ObjectLiteral |
| IdentifierExpression |
| ObjectQueryExpression |
| |
| AccessExpression: |
| [ Value ] |
| . Identifier |
| |
| AccessExpressions: |
| AccessExpression |
| AccessExpressions AccessExpression |
| |
| IdentifierExpression: |
| Identifier |
| Identifier AccessExpressions |
| |
| ObjectQueryExpression: |
| Identifier ( StringLiteral ) |
| Identifier ( StringLiteral ) AccessExpressions |
| |
| |
| NOTE: We have factored the above grammar to allow the infrastructure to be used |
| by the BindingInterpreter as well. The BaseInterpreter does NOT provide an |
| implementation of _evaluateValue(), this is expected to be provided by the |
| derived class since right now the two have different grammars for Value |
| |
| AccessExpression: |
| [ Value ] |
| . Identifier |
| |
| AccessExpressions: |
| AccessExpression |
| AccessExpressions AccessExpression |
| |
| Identifier: |
| Identifier (from ECMA-262-6, 7.6) |
| |
| IdentifierExpression: |
| Identifier |
| Identifier AccessExpressions |
| |
| Value: |
| *** Provided by concrete interpreter *** |
| |
| */ |
| |
| function illegal() { |
| throw "Illegal"; |
| } |
| |
| var imports = _Base.Namespace.defineWithParent(null, null, { |
| lexer: _Base.Namespace._lazy(function () { |
| return _OptionsLexer._optionsLexer; |
| }), |
| tokenType: _Base.Namespace._lazy(function () { |
| return _OptionsLexer._optionsLexer.tokenType; |
| }), |
| }); |
| |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| |
| function tokenTypeName(type) { |
| var keys = Object.keys(imports.tokenType); |
| for (var i = 0, len = keys.length; i < len; i++) { |
| if (type === imports.tokenType[keys[i]]) { |
| return keys[i]; |
| } |
| } |
| return "<unknown>"; |
| } |
| |
| var local = _Base.Namespace.defineWithParent(null, null, { |
| |
| BaseInterpreter: _Base.Namespace._lazy(function () { |
| return _Base.Class.define(null, { |
| _error: function (message) { |
| throw new _ErrorFromName("WinJS.UI.ParseError", message); |
| }, |
| _currentOffset: function () { |
| var p = this._pos; |
| var offset = 0; |
| for (var i = 0; i < p; i++) { |
| offset += this._tokens[i].length; |
| } |
| return offset; |
| }, |
| _evaluateAccessExpression: function (value) { |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| this._read(); |
| switch (this._current.type) { |
| case imports.tokenType.identifier: |
| case this._current.keyword && this._current.type: |
| var id = this._current.value; |
| this._read(); |
| return value[id]; |
| |
| default: |
| this._unexpectedToken(imports.tokenType.identifier, imports.tokenType.reservedWord); |
| break; |
| } |
| return; |
| |
| case imports.tokenType.leftBracket: |
| this._read(); |
| var index = this._evaluateValue(); |
| this._read(imports.tokenType.rightBracket); |
| return value[index]; |
| |
| // default: is unreachable because all the callers are conditional on |
| // the next token being either a . or { |
| // |
| } |
| }, |
| _evaluateAccessExpressions: function (value) { |
| while (true) { |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| value = this._evaluateAccessExpression(value); |
| break; |
| |
| default: |
| return value; |
| } |
| } |
| }, |
| _evaluateIdentifier: function (nested, value) { |
| var id = this._readIdentifier(); |
| value = nested ? value[id] : this._context[id]; |
| return value; |
| }, |
| _evaluateIdentifierExpression: function () { |
| var value = this._evaluateIdentifier(false); |
| |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| return this._evaluateAccessExpressions(value); |
| default: |
| return value; |
| } |
| }, |
| _initialize: function (tokens, originalSource, context, functionContext) { |
| this._originalSource = originalSource; |
| this._tokens = tokens; |
| this._context = context; |
| this._functionContext = functionContext; |
| this._pos = 0; |
| this._current = this._tokens[0]; |
| }, |
| _read: function (expected) { |
| if (expected && this._current.type !== expected) { |
| this._unexpectedToken(expected); |
| } |
| if (this._current !== imports.tokenType.eof) { |
| this._current = this._tokens[++this._pos]; |
| } |
| }, |
| _peek: function (expected) { |
| if (expected && this._current.type !== expected) { |
| return; |
| } |
| if (this._current !== imports.tokenType.eof) { |
| return this._tokens[this._pos + 1]; |
| } |
| }, |
| _readAccessExpression: function (parts) { |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| this._read(); |
| switch (this._current.type) { |
| case imports.tokenType.identifier: |
| case this._current.keyword && this._current.type: |
| parts.push(this._current.value); |
| this._read(); |
| break; |
| |
| default: |
| this._unexpectedToken(imports.tokenType.identifier, imports.tokenType.reservedWord); |
| break; |
| } |
| return; |
| |
| case imports.tokenType.leftBracket: |
| this._read(); |
| parts.push(this._evaluateValue()); |
| this._read(imports.tokenType.rightBracket); |
| return; |
| |
| // default: is unreachable because all the callers are conditional on |
| // the next token being either a . or { |
| // |
| } |
| }, |
| _readAccessExpressions: function (parts) { |
| while (true) { |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| this._readAccessExpression(parts); |
| break; |
| |
| default: |
| return; |
| } |
| } |
| }, |
| _readIdentifier: function () { |
| var id = this._current.value; |
| this._read(imports.tokenType.identifier); |
| return id; |
| }, |
| _readIdentifierExpression: function () { |
| var parts = []; |
| if (this._peek(imports.tokenType.thisKeyword) && parts.length === 0) { |
| this._read(); |
| } else { |
| parts.push(this._readIdentifier()); |
| } |
| |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| this._readAccessExpressions(parts); |
| break; |
| } |
| |
| return parts; |
| }, |
| _unexpectedToken: function (expected) { |
| var unexpected = (this._current.type === imports.tokenType.error ? "'" + this._current.value + "'" : tokenTypeName(this._current.type)); |
| if (expected) { |
| if (arguments.length === 1) { |
| expected = tokenTypeName(expected); |
| this._error(_Resources._formatString(strings.unexpectedTokenExpectedToken, unexpected, expected, this._currentOffset())); |
| } else { |
| var names = []; |
| for (var i = 0, len = arguments.length; i < len; i++) { |
| names.push(tokenTypeName(arguments[i])); |
| } |
| expected = names.join(", "); |
| this._error(_Resources._formatString(strings.unexpectedTokenExpectedTokens, unexpected, expected, this._currentOffset())); |
| } |
| } else { |
| this._error(_Resources._formatString(strings.unexpectedTokenGeneric, unexpected, this._currentOffset())); |
| } |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| OptionsInterpreter: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(local.BaseInterpreter, function (tokens, originalSource, context, functionContext) { |
| this._initialize(tokens, originalSource, context, functionContext); |
| }, { |
| _error: function (message) { |
| throw new _ErrorFromName("WinJS.UI.ParseError", _Resources._formatString(strings.invalidOptionsRecord, this._originalSource, message)); |
| }, |
| _evaluateArrayLiteral: function () { |
| var a = []; |
| this._read(imports.tokenType.leftBracket); |
| this._readArrayElements(a); |
| this._read(imports.tokenType.rightBracket); |
| return a; |
| }, |
| _evaluateObjectLiteral: function () { |
| var o = {}; |
| this._read(imports.tokenType.leftBrace); |
| this._readObjectProperties(o); |
| this._tryReadComma(); |
| this._read(imports.tokenType.rightBrace); |
| return o; |
| }, |
| _evaluateOptionsLiteral: function () { |
| var value = this._evaluateValue(); |
| if (this._current.type !== imports.tokenType.eof) { |
| this._unexpectedToken(imports.tokenType.eof); |
| } |
| return value; |
| }, |
| _peekValue: function () { |
| switch (this._current.type) { |
| case imports.tokenType.falseLiteral: |
| case imports.tokenType.nullLiteral: |
| case imports.tokenType.stringLiteral: |
| case imports.tokenType.trueLiteral: |
| case imports.tokenType.numberLiteral: |
| case imports.tokenType.leftBrace: |
| case imports.tokenType.leftBracket: |
| case imports.tokenType.identifier: |
| return true; |
| default: |
| return false; |
| } |
| }, |
| _evaluateValue: function () { |
| switch (this._current.type) { |
| case imports.tokenType.falseLiteral: |
| case imports.tokenType.nullLiteral: |
| case imports.tokenType.stringLiteral: |
| case imports.tokenType.trueLiteral: |
| case imports.tokenType.numberLiteral: |
| var value = this._current.value; |
| this._read(); |
| return value; |
| |
| case imports.tokenType.leftBrace: |
| return this._evaluateObjectLiteral(); |
| |
| case imports.tokenType.leftBracket: |
| return this._evaluateArrayLiteral(); |
| |
| case imports.tokenType.identifier: |
| if (this._peek(imports.tokenType.identifier).type === imports.tokenType.leftParentheses) { |
| return requireSupportedForProcessing(this._evaluateObjectQueryExpression()); |
| } |
| return requireSupportedForProcessing(this._evaluateIdentifierExpression()); |
| |
| default: |
| this._unexpectedToken(imports.tokenType.falseLiteral, imports.tokenType.nullLiteral, imports.tokenType.stringLiteral, |
| imports.tokenType.trueLiteral, imports.tokenType.numberLiteral, imports.tokenType.leftBrace, imports.tokenType.leftBracket, |
| imports.tokenType.identifier); |
| break; |
| } |
| }, |
| _tryReadElement: function (a) { |
| if (this._peekValue()) { |
| a.push(this._evaluateValue()); |
| return true; |
| } else { |
| return false; |
| } |
| }, |
| _tryReadComma: function () { |
| if (this._peek(imports.tokenType.comma)) { |
| this._read(); |
| return true; |
| } |
| return false; |
| }, |
| _tryReadElision: function (a) { |
| var found = false; |
| while (this._tryReadComma()) { |
| a.push(undefined); |
| found = true; |
| } |
| return found; |
| }, |
| _readArrayElements: function (a) { |
| while (!this._peek(imports.tokenType.rightBracket)) { |
| var elision = this._tryReadElision(a); |
| var element = this._tryReadElement(a); |
| var comma = this._peek(imports.tokenType.comma); |
| if (element && comma) { |
| // if we had a element followed by a comma, eat the comma and try to read the next element |
| this._read(); |
| } else if (element || elision) { |
| // if we had a element without a trailing comma or if all we had were commas we're done |
| break; |
| } else { |
| // if we didn't have a element or elision then we are done and in error |
| this._unexpectedToken(imports.tokenType.falseLiteral, imports.tokenType.nullLiteral, imports.tokenType.stringLiteral, |
| imports.tokenType.trueLiteral, imports.tokenType.numberLiteral, imports.tokenType.leftBrace, imports.tokenType.leftBracket, |
| imports.tokenType.identifier); |
| break; |
| } |
| } |
| }, |
| _readObjectProperties: function (o) { |
| while (!this._peek(imports.tokenType.rightBrace)) { |
| var property = this._tryReadObjectProperty(o); |
| var comma = this._peek(imports.tokenType.comma); |
| if (property && comma) { |
| // if we had a property followed by a comma, eat the comma and try to read the next property |
| this._read(); |
| } else if (property) { |
| // if we had a property without a trailing comma we're done |
| break; |
| } else { |
| // if we didn't have a property then we are done and in error |
| this._unexpectedToken(imports.tokenType.numberLiteral, imports.tokenType.stringLiteral, imports.tokenType.identifier); |
| break; |
| } |
| } |
| }, |
| _tryReadObjectProperty: function (o) { |
| switch (this._current.type) { |
| case imports.tokenType.numberLiteral: |
| case imports.tokenType.stringLiteral: |
| case imports.tokenType.identifier: |
| case this._current.keyword && this._current.type: |
| var propertyName = this._current.value; |
| this._read(); |
| this._read(imports.tokenType.colon); |
| o[propertyName] = this._evaluateValue(); |
| return true; |
| |
| default: |
| return false; |
| } |
| }, |
| _failReadObjectProperty: function () { |
| this._unexpectedToken(imports.tokenType.numberLiteral, imports.tokenType.stringLiteral, imports.tokenType.identifier, imports.tokenType.reservedWord); |
| }, |
| _evaluateObjectQueryExpression: function () { |
| var functionName = this._current.value; |
| this._read(imports.tokenType.identifier); |
| this._read(imports.tokenType.leftParentheses); |
| var queryExpression = this._current.value; |
| this._read(imports.tokenType.stringLiteral); |
| this._read(imports.tokenType.rightParentheses); |
| |
| var value = requireSupportedForProcessing(this._functionContext[functionName])(queryExpression); |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| return this._evaluateAccessExpressions(value); |
| |
| default: |
| return value; |
| } |
| }, |
| run: function () { |
| return this._evaluateOptionsLiteral(); |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| OptionsParser: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(local.OptionsInterpreter, function (tokens, originalSource) { |
| this._initialize(tokens, originalSource); |
| }, { |
| // When parsing it is illegal to get to any of these "evaluate" RHS productions because |
| // we will always instead go to the "read" version |
| // |
| _evaluateAccessExpression: illegal, |
| _evaluateAccessExpressions: illegal, |
| _evaluateIdentifier: illegal, |
| _evaluateIdentifierExpression: illegal, |
| _evaluateObjectQueryExpression: illegal, |
| |
| _evaluateValue: function () { |
| switch (this._current.type) { |
| case imports.tokenType.falseLiteral: |
| case imports.tokenType.nullLiteral: |
| case imports.tokenType.stringLiteral: |
| case imports.tokenType.trueLiteral: |
| case imports.tokenType.numberLiteral: |
| var value = this._current.value; |
| this._read(); |
| return value; |
| |
| case imports.tokenType.leftBrace: |
| return this._evaluateObjectLiteral(); |
| |
| case imports.tokenType.leftBracket: |
| return this._evaluateArrayLiteral(); |
| |
| case imports.tokenType.identifier: |
| if (this._peek(imports.tokenType.identifier).type === imports.tokenType.leftParentheses) { |
| return this._readObjectQueryExpression(); |
| } |
| return this._readIdentifierExpression(); |
| |
| default: |
| this._unexpectedToken(imports.tokenType.falseLiteral, imports.tokenType.nullLiteral, imports.tokenType.stringLiteral, |
| imports.tokenType.trueLiteral, imports.tokenType.numberLiteral, imports.tokenType.leftBrace, imports.tokenType.leftBracket, |
| imports.tokenType.identifier); |
| break; |
| } |
| }, |
| |
| _readIdentifierExpression: function () { |
| var parts = local.BaseInterpreter.prototype._readIdentifierExpression.call(this); |
| return new IdentifierExpression(parts); |
| }, |
| _readObjectQueryExpression: function () { |
| var functionName = this._current.value; |
| this._read(imports.tokenType.identifier); |
| this._read(imports.tokenType.leftParentheses); |
| var queryExpressionLiteral = this._current.value; |
| this._read(imports.tokenType.stringLiteral); |
| this._read(imports.tokenType.rightParentheses); |
| |
| var call = new CallExpression(functionName, queryExpressionLiteral); |
| switch (this._current.type) { |
| case imports.tokenType.dot: |
| case imports.tokenType.leftBracket: |
| var parts = [call]; |
| this._readAccessExpressions(parts); |
| return new IdentifierExpression(parts); |
| |
| default: |
| return call; |
| } |
| }, |
| }, { |
| supportedForProcessing: false, |
| }); |
| }) |
| |
| }); |
| |
| var parser = function (text, context, functionContext) { |
| var tokens = imports.lexer(text); |
| var interpreter = new local.OptionsInterpreter(tokens, text, context || {}, functionContext || {}); |
| return interpreter.run(); |
| }; |
| Object.defineProperty(parser, "_BaseInterpreter", { get: function () { return local.BaseInterpreter; } }); |
| |
| var parser2 = function (text) { |
| var tokens = imports.lexer(text); |
| var parser = new local.OptionsParser(tokens, text); |
| return parser.run(); |
| }; |
| |
| // Consumers of parser2 need to be able to see the AST for RHS expression in order to emit |
| // code representing these portions of the options record |
| // |
| var CallExpression = _Base.Class.define(function (target, arg0Value) { |
| this.target = target; |
| this.arg0Value = arg0Value; |
| }); |
| CallExpression.supportedForProcessing = false; |
| |
| var IdentifierExpression = _Base.Class.define(function (parts) { |
| this.parts = parts; |
| }); |
| IdentifierExpression.supportedForProcessing = false; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| |
| // This is the mis-named interpreter version of the options record processor. |
| // |
| optionsParser: parser, |
| |
| // This is the actual parser version of the options record processor. |
| // |
| _optionsParser: parser2, |
| _CallExpression: CallExpression, |
| _IdentifierExpression: IdentifierExpression, |
| |
| }); |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/ControlProcessor',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_Log', |
| './Core/_Resources', |
| './Core/_WriteProfilerMark', |
| './ControlProcessor/_OptionsParser', |
| './Promise', |
| './Utilities/_ElementUtilities' |
| ], function declarativeControlsInit(exports, _Global, _Base, _BaseUtils, _Log, _Resources, _WriteProfilerMark, _OptionsParser, Promise, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var strings = { |
| get errorActivatingControl() { return "Error activating control: {0}"; }, |
| }; |
| |
| var markSupportedForProcessing = _BaseUtils.markSupportedForProcessing; |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| var processedAllCalled = false; |
| |
| function createSelect(element) { |
| var result = function select(selector) { |
| /// <signature helpKeyword="WinJS.UI.select.createSelect"> |
| /// <summary locid="WinJS.UI.select.createSelect"> |
| /// Walks the DOM tree from the given element to the root of the document, whenever |
| /// a selector scope is encountered select performs a lookup within that scope for |
| /// the given selector string. The first matching element is returned. |
| /// </summary> |
| /// <param name="selector" type="String" locid="WinJS.UI.select.createSelect_p:selector">The selector string.</param> |
| /// <returns type="HTMLElement" domElement="true" locid="WinJS.UI.select.createSelect_returnValue">The target element, if found.</returns> |
| /// </signature> |
| var current = element; |
| var selected; |
| while (current) { |
| if (current.msParentSelectorScope) { |
| var scope = current.parentNode; |
| if (scope) { |
| selected = _ElementUtilities._matchesSelector(scope, selector) ? scope : scope.querySelector(selector); |
| if (selected) { |
| break; |
| } |
| } |
| } |
| current = current.parentNode; |
| } |
| |
| return selected || _Global.document.querySelector(selector); |
| }; |
| return markSupportedForProcessing(result); |
| } |
| |
| function activate(element, Handler) { |
| return new Promise(function activate2(complete, error) { |
| try { |
| var options; |
| var optionsAttribute = element.getAttribute("data-win-options"); |
| if (optionsAttribute) { |
| options = _OptionsParser.optionsParser(optionsAttribute, _Global, { |
| select: createSelect(element) |
| }); |
| } |
| |
| var ctl; |
| var count = 1; |
| |
| // handler is required to call complete if it takes that parameter |
| // |
| if (Handler.length > 2) { |
| count++; |
| } |
| var checkComplete = function checkComplete() { |
| count--; |
| if (count === 0) { |
| element.winControl = element.winControl || ctl; |
| complete(ctl); |
| } |
| }; |
| |
| // async exceptions from the handler get dropped on the floor... |
| // |
| ctl = new Handler(element, options, checkComplete); |
| checkComplete(); |
| } |
| catch (err) { |
| _Log.log && _Log.log(_Resources._formatString(strings.errorActivatingControl, err && err.message), "winjs controls", "error"); |
| error(err); |
| } |
| }); |
| } |
| |
| function processAllImpl(rootElement, skipRootElement) { |
| return new Promise(function processAllImpl2(complete, error) { |
| _WriteProfilerMark("WinJS.UI:processAll,StartTM"); |
| rootElement = rootElement || _Global.document.body; |
| var pending = 0; |
| var selector = "[data-win-control]"; |
| var allElements = rootElement.querySelectorAll(selector); |
| var elements = []; |
| if (!skipRootElement && getControlHandler(rootElement)) { |
| elements.push(rootElement); |
| } |
| for (var i = 0, len = allElements.length; i < len; i++) { |
| elements.push(allElements[i]); |
| } |
| |
| // bail early if there is nothing to process |
| // |
| if (elements.length === 0) { |
| _WriteProfilerMark("WinJS.UI:processAll,StopTM"); |
| complete(rootElement); |
| return; |
| } |
| |
| var checkAllComplete = function () { |
| pending = pending - 1; |
| if (pending < 0) { |
| _WriteProfilerMark("WinJS.UI:processAll,StopTM"); |
| complete(rootElement); |
| } |
| }; |
| |
| // First go through and determine which elements to activate |
| // |
| var controls = new Array(elements.length); |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var element = elements[i]; |
| var control; |
| var instance = element.winControl; |
| if (instance) { |
| control = instance.constructor; |
| // already activated, don't need to add to controls array |
| } else { |
| controls[i] = control = getControlHandler(element); |
| } |
| if (control && control.isDeclarativeControlContainer) { |
| i += element.querySelectorAll(selector).length; |
| } |
| } |
| |
| // Now go through and activate those |
| // |
| _WriteProfilerMark("WinJS.UI:processAllActivateControls,StartTM"); |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var ctl = controls[i]; |
| var element = elements[i]; |
| if (ctl && !element.winControl) { |
| pending++; |
| activate(element, ctl).then(checkAllComplete, function (e) { |
| _WriteProfilerMark("WinJS.UI:processAll,StopTM"); |
| error(e); |
| }); |
| |
| if (ctl.isDeclarativeControlContainer && typeof ctl.isDeclarativeControlContainer === "function") { |
| var idcc = requireSupportedForProcessing(ctl.isDeclarativeControlContainer); |
| idcc(element.winControl, processAll); |
| } |
| } |
| } |
| _WriteProfilerMark("WinJS.UI:processAllActivateControls,StopTM"); |
| |
| checkAllComplete(); |
| }); |
| } |
| |
| function getControlHandler(element) { |
| if (element.getAttribute) { |
| var evaluator = element.getAttribute("data-win-control"); |
| if (evaluator) { |
| return _BaseUtils._getMemberFiltered(evaluator.trim(), _Global, requireSupportedForProcessing); |
| } |
| } |
| } |
| |
| function scopedSelect(selector, element) { |
| /// <signature helpKeyword="WinJS.UI.scopedSelect"> |
| /// <summary locid="WinJS.UI.scopedSelect"> |
| /// Walks the DOM tree from the given element to the root of the document, whenever |
| /// a selector scope is encountered select performs a lookup within that scope for |
| /// the given selector string. The first matching element is returned. |
| /// </summary> |
| /// <param name="selector" type="String" locid="WinJS.UI.scopedSelect_p:selector">The selector string.</param> |
| /// <returns type="HTMLElement" domElement="true" locid="WinJS.UI.scopedSelect_returnValue">The target element, if found.</returns> |
| /// </signature> |
| return createSelect(element)(selector); |
| } |
| |
| function processAll(rootElement, skipRoot) { |
| /// <signature helpKeyword="WinJS.UI.processAll"> |
| /// <summary locid="WinJS.UI.processAll"> |
| /// Applies declarative control binding to all elements, starting at the specified root element. |
| /// </summary> |
| /// <param name="rootElement" type="Object" domElement="true" locid="WinJS.UI.processAll_p:rootElement"> |
| /// The element at which to start applying the binding. If this parameter is not specified, the binding is applied to the entire document. |
| /// </param> |
| /// <param name="skipRoot" type="Boolean" optional="true" locid="WinJS.UI.processAll_p:skipRoot"> |
| /// If true, the elements to be bound skip the specified root element and include only the children. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.processAll_returnValue"> |
| /// A promise that is fulfilled when binding has been applied to all the controls. |
| /// </returns> |
| /// </signature> |
| if (!processedAllCalled) { |
| return _BaseUtils.ready().then(function () { |
| processedAllCalled = true; |
| return processAllImpl(rootElement, skipRoot); |
| }); |
| } else { |
| return processAllImpl(rootElement, skipRoot); |
| } |
| } |
| |
| function process(element) { |
| /// <signature helpKeyword="WinJS.UI.process"> |
| /// <summary locid="WinJS.UI.process"> |
| /// Applies declarative control binding to the specified element. |
| /// </summary> |
| /// <param name="element" type="Object" domElement="true" locid="WinJS.UI.process_p:element"> |
| /// The element to bind. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.process_returnValue"> |
| /// A promise that is fulfilled after the control is activated. The value of the |
| /// promise is the control that is attached to element. |
| /// </returns> |
| /// </signature> |
| |
| if (element && element.winControl) { |
| return Promise.as(element.winControl); |
| } |
| var handler = getControlHandler(element); |
| if (!handler) { |
| return Promise.as(); // undefined, no handler |
| } else { |
| return activate(element, handler); |
| } |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| scopedSelect: scopedSelect, |
| processAll: processAll, |
| process: process |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_ElementListUtilities',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../ControlProcessor', |
| '../Promise', |
| '../Utilities/_Control', |
| '../Utilities/_ElementUtilities' |
| ], function elementListUtilities(exports, _Global, _Base, ControlProcessor, Promise, _Control, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| QueryCollection: _Base.Class.derive(Array, function (items) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection"> |
| /// <summary locid="WinJS.Utilities.QueryCollection"> |
| /// Represents the result of a query selector, and provides |
| /// various operations that perform actions over the elements of |
| /// the collection. |
| /// </summary> |
| /// <param name="items" locid="WinJS.Utilities.QueryCollection_p:items"> |
| /// The items resulting from the query. |
| /// </param> |
| /// </signature> |
| if (items) { |
| this.include(items); |
| } |
| }, { |
| forEach: function (callbackFn, thisArg) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.forEach"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.forEach"> |
| /// Performs an action on each item in the QueryCollection |
| /// </summary> |
| /// <param name="callbackFn" type="function(value, Number index, traversedObject)" locid="WinJS.Utilities.QueryCollection.forEach_p:callbackFn"> |
| /// Action to perform on each item. |
| /// </param> |
| /// <param name="thisArg" isOptional="true" type="function(value, Number index, traversedObject)" locid="WinJS.Utilities.QueryCollection.forEach_p:thisArg"> |
| /// Argument to bind to callbackFn |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.forEach_returnValue"> |
| /// Returns the QueryCollection |
| /// </returns> |
| /// </signature> |
| Array.prototype.forEach.apply(this, [callbackFn, thisArg]); |
| return this; |
| }, |
| get: function (index) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.get"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.get"> |
| /// Gets an item from the QueryCollection. |
| /// </summary> |
| /// <param name="index" type="Number" locid="WinJS.Utilities.QueryCollection.get_p:index"> |
| /// The index of the item to return. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Utilities.QueryCollection.get_returnValue"> |
| /// A single item from the collection. |
| /// </returns> |
| /// </signature> |
| return this[index]; |
| }, |
| setAttribute: function (name, value) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.setAttribute"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.setAttribute"> |
| /// Sets an attribute value on all the items in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.setAttribute_p:name"> |
| /// The name of the attribute to be set. |
| /// </param> |
| /// <param name="value" type="String" locid="WinJS.Utilities.QueryCollection.setAttribute_p:value"> |
| /// The value of the attribute to be set. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.setAttribute_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| item.setAttribute(name, value); |
| }); |
| return this; |
| }, |
| getAttribute: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.getAttribute"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.getAttribute"> |
| /// Gets an attribute value from the first element in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.getAttribute_p:name"> |
| /// The name of the attribute. |
| /// </param> |
| /// <returns type="String" locid="WinJS.Utilities.QueryCollection.getAttribute_returnValue"> |
| /// The value of the attribute. |
| /// </returns> |
| /// </signature> |
| if (this.length > 0) { |
| return this[0].getAttribute(name); |
| } |
| }, |
| addClass: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.addClass"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.addClass"> |
| /// Adds the specified class to all the elements in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.addClass_p:name"> |
| /// The name of the class to add. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.addClass_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| _ElementUtilities.addClass(item, name); |
| }); |
| return this; |
| }, |
| hasClass: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.hasClass"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.hasClass"> |
| /// Determines whether the specified class exists on the first element of the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.hasClass_p:name"> |
| /// The name of the class. |
| /// </param> |
| /// <returns type="Boolean" locid="WinJS.Utilities.QueryCollection.hasClass_returnValue"> |
| /// true if the element has the specified class; otherwise, false. |
| /// </returns> |
| /// </signature> |
| if (this.length > 0) { |
| return _ElementUtilities.hasClass(this[0], name); |
| } |
| return false; |
| }, |
| removeClass: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.removeClass"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.removeClass"> |
| /// Removes the specified class from all the elements in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.removeClass_p:name"> |
| /// The name of the class to be removed. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.removeClass_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| _ElementUtilities.removeClass(item, name); |
| }); |
| return this; |
| }, |
| toggleClass: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.toggleClass"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.toggleClass"> |
| /// Toggles (adds or removes) the specified class on all the elements in the collection. |
| /// If the class is present, it is removed; if it is absent, it is added. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.toggleClass_p:name"> |
| /// The name of the class to be toggled. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.toggleClass_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| _ElementUtilities.toggleClass(item, name); |
| }); |
| return this; |
| }, |
| listen: function (eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.listen"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.listen"> |
| /// Registers the listener for the specified event on all the elements in the collection. |
| /// </summary> |
| /// <param name="eventType" type="String" locid="WinJS.Utilities.QueryCollection.listen_p:eventType"> |
| /// The name of the event. |
| /// </param> |
| /// <param name="listener" type="Function" locid="WinJS.Utilities.QueryCollection.listen_p:listener"> |
| /// The event handler function to be called when the event occurs. |
| /// </param> |
| /// <param name="capture" type="Boolean" locid="WinJS.Utilities.QueryCollection.listen_p:capture"> |
| /// true if capture == true is to be passed to addEventListener; otherwise, false. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.listen_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| item.addEventListener(eventType, listener, capture); |
| }); |
| return this; |
| }, |
| removeEventListener: function (eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.removeEventListener"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.removeEventListener"> |
| /// Unregisters the listener for the specified event on all the elements in the collection. |
| /// </summary> |
| /// <param name="eventType" type="String" locid="WinJS.Utilities.QueryCollection.removeEventListener_p:eventType"> |
| /// The name of the event. |
| /// </param> |
| /// <param name="listener" type="Function" locid="WinJS.Utilities.QueryCollection.removeEventListener_p:listener"> |
| /// The event handler function. |
| /// </param> |
| /// <param name="capture" type="Boolean" locid="WinJS.Utilities.QueryCollection.removeEventListener_p:capture"> |
| /// true if capture == true; otherwise, false. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.removeEventListener_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| item.removeEventListener(eventType, listener, capture); |
| }); |
| return this; |
| }, |
| setStyle: function (name, value) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.setStyle"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.setStyle"> |
| /// Sets the specified style property for all the elements in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.setStyle_p:name"> |
| /// The name of the style property. |
| /// </param> |
| /// <param name="value" type="String" locid="WinJS.Utilities.QueryCollection.setStyle_p:value"> |
| /// The value for the property. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.setStyle_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| item.style[name] = value; |
| }); |
| return this; |
| }, |
| clearStyle: function (name) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.clearStyle"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.clearStyle"> |
| /// Clears the specified style property for all the elements in the collection. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Utilities.QueryCollection.clearStyle_p:name"> |
| /// The name of the style property to be cleared. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.clearStyle_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| this.forEach(function (item) { |
| item.style[name] = ""; |
| }); |
| return this; |
| }, |
| query: function (query) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.query"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.query"> |
| /// Executes a query selector on all the elements in the collection |
| /// and aggregates the result into a QueryCollection. |
| /// </summary> |
| /// <param name="query" type="String" locid="WinJS.Utilities.QueryCollection.query_p:query"> |
| /// The query selector string. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.query_returnValue"> |
| /// A QueryCollection object containing the aggregate results of |
| /// executing the query on all the elements in the collection. |
| /// </returns> |
| /// </signature> |
| var newCollection = new exports.QueryCollection(); |
| this.forEach(function (item) { |
| newCollection.include(item.querySelectorAll(query)); |
| }); |
| return newCollection; |
| }, |
| include: function (items) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.include"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.include"> |
| /// Adds a set of items to this QueryCollection. |
| /// </summary> |
| /// <param name="items" locid="WinJS.Utilities.QueryCollection.include_p:items"> |
| /// The items to add to the QueryCollection. This may be an |
| /// array-like object, a document fragment, or a single item. |
| /// </param> |
| /// </signature> |
| if (typeof items.length === "number") { |
| for (var i = 0; i < items.length; i++) { |
| this.push(items[i]); |
| } |
| } else if (items.DOCUMENT_FRAGMENT_NODE && items.nodeType === items.DOCUMENT_FRAGMENT_NODE) { |
| this.include(items.childNodes); |
| } else { |
| this.push(items); |
| } |
| }, |
| control: function (Ctor, options) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.control"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.control"> |
| /// Creates controls that are attached to the elements in this QueryCollection. |
| /// </summary> |
| /// <param name='Ctor' locid="WinJS.Utilities.QueryCollection.control_p:ctor"> |
| /// A constructor function that is used to create controls to attach to the elements. |
| /// </param> |
| /// <param name='options' locid="WinJS.Utilities.QueryCollection.control_p:options"> |
| /// The options passed to the newly-created controls. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.control_returnValue"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| /// <signature> |
| /// <summary locid="WinJS.Utilities.QueryCollection.control2"> |
| /// Configures the controls that are attached to the elements in this QueryCollection. |
| /// </summary> |
| /// <param name='ctor' locid="WinJS.Utilities.QueryCollection.control_p:ctor2"> |
| /// The options passed to the controls. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.control_returnValue2"> |
| /// This QueryCollection object. |
| /// </returns> |
| /// </signature> |
| |
| if (Ctor && typeof (Ctor) === "function") { |
| this.forEach(function (element) { |
| element.winControl = new Ctor(element, options); |
| }); |
| } else { |
| options = Ctor; |
| this.forEach(function (element) { |
| ControlProcessor.process(element).done(function (control) { |
| control && _Control.setOptions(control, options); |
| }); |
| }); |
| } |
| return this; |
| }, |
| template: function (templateElement, data, renderDonePromiseCallback) { |
| /// <signature helpKeyword="WinJS.Utilities.QueryCollection.template"> |
| /// <summary locid="WinJS.Utilities.QueryCollection.template"> |
| /// Renders a template that is bound to the given data |
| /// and parented to the elements included in the QueryCollection. |
| /// If the QueryCollection contains multiple elements, the template |
| /// is rendered multiple times, once at each element in the QueryCollection |
| /// per item of data passed. |
| /// </summary> |
| /// <param name="templateElement" type="DOMElement" locid="WinJS.Utilities.QueryCollection.template_p:templateElement"> |
| /// The DOM element to which the template control is attached to. |
| /// </param> |
| /// <param name="data" type="Object" locid="WinJS.Utilities.QueryCollection.template_p:data"> |
| /// The data to render. If the data is an array (or any other object |
| /// that has a forEach method) then the template is rendered |
| /// multiple times, once for each item in the collection. |
| /// </param> |
| /// <param name="renderDonePromiseCallback" type="Function" locid="WinJS.Utilities.QueryCollection.template_p:renderDonePromiseCallback"> |
| /// If supplied, this function is called |
| /// each time the template gets rendered, and is passed a promise |
| /// that is fulfilled when the template rendering is complete. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.QueryCollection.template_returnValue"> |
| /// The QueryCollection. |
| /// </returns> |
| /// </signature> |
| if (templateElement instanceof exports.QueryCollection) { |
| templateElement = templateElement[0]; |
| } |
| var template = templateElement.winControl; |
| |
| if (data === null || data === undefined || !data.forEach) { |
| data = [data]; |
| } |
| |
| renderDonePromiseCallback = renderDonePromiseCallback || function () { }; |
| |
| var that = this; |
| var donePromises = []; |
| data.forEach(function (datum) { |
| that.forEach(function (element) { |
| donePromises.push(template.render(datum, element)); |
| }); |
| }); |
| renderDonePromiseCallback(Promise.join(donePromises)); |
| |
| return this; |
| } |
| }, { |
| supportedForProcessing: false, |
| }), |
| |
| query: function (query, element) { |
| /// <signature helpKeyword="WinJS.Utilities.query"> |
| /// <summary locid="WinJS.Utilities.query"> |
| /// Executes a query selector on the specified element or the entire document. |
| /// </summary> |
| /// <param name="query" type="String" locid="WinJS.Utilities.query_p:query"> |
| /// The query selector to be executed. |
| /// </param> |
| /// <param name="element" optional="true" type="HTMLElement" locid="WinJS.Utilities.query_p:element"> |
| /// The element on which to execute the query. If this parameter is not specified, the |
| /// query is executed on the entire document. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.query_returnValue"> |
| /// The QueryCollection that contains the results of the query. |
| /// </returns> |
| /// </signature> |
| return new exports.QueryCollection((element || _Global.document).querySelectorAll(query)); |
| }, |
| |
| id: function (id) { |
| /// <signature helpKeyword="WinJS.Utilities.id"> |
| /// <summary locid="WinJS.Utilities.id"> |
| /// Looks up an element by ID and wraps the result in a QueryCollection. |
| /// </summary> |
| /// <param name="id" type="String" locid="WinJS.Utilities.id_p:id"> |
| /// The ID of the element. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.id_returnValue"> |
| /// A QueryCollection that contains the element, if it is found. |
| /// </returns> |
| /// </signature> |
| var e = _Global.document.getElementById(id); |
| return new exports.QueryCollection(e ? [e] : []); |
| }, |
| |
| children: function (element) { |
| /// <signature helpKeyword="WinJS.Utilities.children"> |
| /// <summary locid="WinJS.Utilities.children"> |
| /// Creates a QueryCollection that contains the children of the specified parent element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.children_p:element"> |
| /// The parent element. |
| /// </param> |
| /// <returns type="WinJS.Utilities.QueryCollection" locid="WinJS.Utilities.children_returnValue"> |
| /// The QueryCollection that contains the children of the element. |
| /// </returns> |
| /// </signature> |
| return new exports.QueryCollection(element.children); |
| } |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Hoverable',[ |
| 'exports', |
| '../Core/_Global' |
| ], function hoverable(exports, _Global) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| _Global.document.documentElement.classList.add("win-hoverable"); |
| exports.isHoverable = true; |
| |
| if (!_Global.MSPointerEvent) { |
| var touchStartHandler = function () { |
| _Global.document.removeEventListener("touchstart", touchStartHandler); |
| // Remove win-hoverable CSS class fromstartt . <html> to avoid :hover styles in webkit when there is |
| // touch support. |
| _Global.document.documentElement.classList.remove("win-hoverable"); |
| exports.isHoverable = false; |
| }; |
| |
| _Global.document.addEventListener("touchstart", touchStartHandler); |
| } |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_ParallelWorkQueue',[ |
| 'exports', |
| '../Core/_Base', |
| '../Promise', |
| '../Scheduler' |
| ], function parallelWorkQueueInit(exports, _Base, Promise, Scheduler) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _ParallelWorkQueue : _Base.Namespace._lazy(function () { |
| return _Base.Class.define(function ParallelWorkQueue_ctor(maxRunning) { |
| var workIndex = 0; |
| var workItems = {}; |
| var workQueue = []; |
| |
| maxRunning = maxRunning || 3; |
| var running = 0; |
| var processing = 0; |
| function runNext() { |
| running--; |
| // if we have fallen out of this loop, then we know we are already |
| // async, so "post" is OK. If we are still in the loop, then the |
| // loop will continue to run, so we don't need to "post" or |
| // recurse. This avoids stack overflow in the sync case. |
| // |
| if (!processing) { |
| Scheduler.schedule(run, Scheduler.Priority.normal, |
| null, "WinJS._ParallelWorkQueue.runNext"); |
| } |
| } |
| function run() { |
| processing++; |
| for (; running < maxRunning; running++) { |
| var next; |
| var nextWork; |
| do { |
| next = workQueue.shift(); |
| nextWork = next && workItems[next]; |
| } while (next && !nextWork); |
| |
| if (nextWork) { |
| delete workItems[next]; |
| try { |
| nextWork().then(runNext, runNext); |
| } |
| catch (err) { |
| // this will only get hit if there is a queued item that |
| // fails to return something that conforms to the Promise |
| // contract |
| // |
| runNext(); |
| } |
| } else { |
| break; |
| } |
| } |
| processing--; |
| } |
| function queue(f, data, first) { |
| var id = "w" + (workIndex++); |
| var workPromise; |
| return new Promise( |
| function (c, e, p) { |
| var w = function () { |
| workPromise = f().then(c, e, p); |
| return workPromise; |
| }; |
| w.data = data; |
| workItems[id] = w; |
| if (first) { |
| workQueue.unshift(id); |
| } else { |
| workQueue.push(id); |
| } |
| run(); |
| }, |
| function () { |
| delete workItems[id]; |
| if (workPromise) { |
| workPromise.cancel(); |
| } |
| } |
| ); |
| } |
| |
| this.sort = function (f) { |
| workQueue.sort(function (a, b) { |
| a = workItems[a]; |
| b = workItems[b]; |
| return a === undefined && b === undefined ? 0 : a === undefined ? 1 : b === undefined ? -1 : f(a.data, b.data); |
| }); |
| }; |
| this.queue = queue; |
| }, { |
| /* empty */ |
| }, { |
| supportedForProcessing: false, |
| }); |
| }) |
| }); |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_VersionManager',[ |
| 'exports', |
| '../Core/_Base', |
| '../_Signal' |
| ], function versionManagerInit(exports, _Base, _Signal) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _VersionManager: _Base.Namespace._lazy(function () { |
| return _Base.Class.define(function _VersionManager_ctor() { |
| this._unlocked = new _Signal(); |
| this._unlocked.complete(); |
| }, { |
| _cancelCount: 0, |
| _notificationCount: 0, |
| _updateCount: 0, |
| _version: 0, |
| |
| // This should be used generally for all logic that should be suspended while data changes are happening |
| // |
| locked: { get: function () { return this._notificationCount !== 0 || this._updateCount !== 0; } }, |
| |
| // this should only be accessed by the update logic in ListViewImpl.js |
| // |
| noOutstandingNotifications: { get: function () { return this._notificationCount === 0; } }, |
| version: { get: function () { return this._version; } }, |
| |
| unlocked: { get: function () { return this._unlocked.promise; } }, |
| |
| _dispose: function () { |
| if (this._unlocked) { |
| this._unlocked.cancel(); |
| this._unlocked = null; |
| } |
| }, |
| |
| beginUpdating: function () { |
| this._checkLocked(); |
| this._updateCount++; |
| }, |
| endUpdating: function () { |
| this._updateCount--; |
| this._checkUnlocked(); |
| }, |
| beginNotifications: function () { |
| this._checkLocked(); |
| this._notificationCount++; |
| }, |
| endNotifications: function () { |
| this._notificationCount--; |
| this._checkUnlocked(); |
| }, |
| _checkLocked: function () { |
| if (!this.locked) { |
| this._dispose(); |
| this._unlocked = new _Signal(); |
| } |
| }, |
| _checkUnlocked: function () { |
| if (!this.locked) { |
| this._unlocked.complete(); |
| } |
| }, |
| receivedNotification: function () { |
| this._version++; |
| if (this._cancel) { |
| var cancel = this._cancel; |
| this._cancel = null; |
| cancel.forEach(function (p) { p && p.cancel(); }); |
| } |
| }, |
| cancelOnNotification: function (promise) { |
| if (!this._cancel) { |
| this._cancel = []; |
| this._cancelCount = 0; |
| } |
| this._cancel[this._cancelCount++] = promise; |
| return this._cancelCount - 1; |
| }, |
| clearCancelOnNotification: function (token) { |
| if (this._cancel) { |
| delete this._cancel[token]; |
| } |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }) |
| }); |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| // Items Manager |
| |
| define('WinJS/Utilities/_ItemsManager',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Resources', |
| '../Core/_WriteProfilerMark', |
| '../Promise', |
| '../_Signal', |
| '../Scheduler', |
| '../Utilities/_ElementUtilities', |
| './_ParallelWorkQueue', |
| './_VersionManager' |
| ], function itemsManagerInit(exports, _Global, _Base, _BaseUtils, _ErrorFromName, _Resources, _WriteProfilerMark, Promise, _Signal, Scheduler, _ElementUtilities, _ParallelWorkQueue, _VersionManager) { |
| "use strict"; |
| |
| var markSupportedForProcessing = _BaseUtils.markSupportedForProcessing; |
| var uniqueID = _ElementUtilities._uniqueID; |
| |
| function simpleItemRenderer(f) { |
| return markSupportedForProcessing(function (itemPromise, element) { |
| return itemPromise.then(function (item) { |
| return (item ? f(item, element) : null); |
| }); |
| }); |
| } |
| |
| var trivialHtmlRenderer = simpleItemRenderer(function (item) { |
| if (_ElementUtilities._isDOMElement(item.data)) { |
| return item.data; |
| } |
| |
| var data = item.data; |
| if (data === undefined) { |
| data = "undefined"; |
| } else if (data === null) { |
| data = "null"; |
| } else if (typeof data === "object") { |
| data = JSON.stringify(data); |
| } |
| |
| var element = _Global.document.createElement("span"); |
| element.textContent = data.toString(); |
| return element; |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _normalizeRendererReturn: function (v) { |
| if (v) { |
| if (typeof v === "object" && v.element) { |
| var elementPromise = Promise.as(v.element); |
| return elementPromise.then(function (e) { return { element: e, renderComplete: Promise.as(v.renderComplete) }; }); |
| } else { |
| var elementPromise = Promise.as(v); |
| return elementPromise.then(function (e) { return { element: e, renderComplete: Promise.as() }; }); |
| } |
| } else { |
| return { element: null, renderComplete: Promise.as() }; |
| } |
| }, |
| simpleItemRenderer: simpleItemRenderer, |
| _trivialHtmlRenderer: trivialHtmlRenderer |
| }); |
| |
| // Private statics |
| |
| var strings = { |
| get listDataSourceIsInvalid() { return "Invalid argument: dataSource must be an object."; }, |
| get itemRendererIsInvalid() { return "Invalid argument: itemRenderer must be a function."; }, |
| get itemIsInvalid() { return "Invalid argument: item must be a DOM element that was returned by the Items Manager, and has not been replaced or released."; }, |
| }; |
| |
| var imageLoader; |
| var lastSort = new Date(); |
| var minDurationBetweenImageSort = 64; |
| |
| // This optimization is good for a couple of reasons: |
| // - It is a global optimizer, which means that all on screen images take precedence over all off screen images. |
| // - It avoids resorting too frequently by only resorting when a new image loads and it has been at least 64 ms since |
| // the last sort. |
| // Also, it is worth noting that "sort" on an empty queue does no work (besides the function call). |
| function compareImageLoadPriority(a, b) { |
| var aon = false; |
| var bon = false; |
| |
| // Currently isOnScreen is synchronous and fast for list view |
| a.isOnScreen().then(function (v) { aon = v; }); |
| b.isOnScreen().then(function (v) { bon = v; }); |
| |
| return (aon ? 0 : 1) - (bon ? 0 : 1); |
| } |
| |
| var nextImageLoaderId = 0; |
| var seenUrls = {}; |
| var seenUrlsMRU = []; |
| var SEEN_URLS_MAXSIZE = 250; |
| var SEEN_URLS_MRU_MAXSIZE = 1000; |
| |
| function seenUrl(srcUrl) { |
| if ((/^blob:/i).test(srcUrl)) { |
| return; |
| } |
| |
| seenUrls[srcUrl] = true; |
| seenUrlsMRU.push(srcUrl); |
| |
| if (seenUrlsMRU.length > SEEN_URLS_MRU_MAXSIZE) { |
| var mru = seenUrlsMRU; |
| seenUrls = {}; |
| seenUrlsMRU = []; |
| |
| for (var count = 0, i = mru.length - 1; i >= 0 && count < SEEN_URLS_MAXSIZE; i--) { |
| var url = mru[i]; |
| if (!seenUrls[url]) { |
| seenUrls[url] = true; |
| count++; |
| } |
| } |
| } |
| } |
| |
| // Exposing the seenUrl related members to use them in unit tests |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _seenUrl: seenUrl, |
| _getSeenUrls: function () { |
| return seenUrls; |
| }, |
| _getSeenUrlsMRU: function () { |
| return seenUrlsMRU; |
| }, |
| _seenUrlsMaxSize: SEEN_URLS_MAXSIZE, |
| _seenUrlsMRUMaxSize: SEEN_URLS_MRU_MAXSIZE |
| }); |
| |
| function loadImage(srcUrl, image, data) { |
| var imageId = nextImageLoaderId++; |
| imageLoader = imageLoader || new _ParallelWorkQueue._ParallelWorkQueue(6); |
| return imageLoader.queue(function () { |
| return new Promise(function (c, e) { |
| Scheduler.schedule(function ImageLoader_async_loadImage(jobInfo) { |
| if (!image) { |
| image = _Global.document.createElement("img"); |
| } |
| |
| var seen = seenUrls[srcUrl]; |
| |
| if (!seen) { |
| jobInfo.setPromise(new Promise(function (imageLoadComplete) { |
| var tempImage = _Global.document.createElement("img"); |
| |
| var cleanup = function () { |
| tempImage.removeEventListener("load", loadComplete, false); |
| tempImage.removeEventListener("error", loadError, false); |
| |
| // One time use blob images are cleaned up as soon as they are not referenced by images any longer. |
| // We set the image src before clearing the tempImage src to make sure the blob image is always |
| // referenced. |
| image.src = srcUrl; |
| |
| var currentDate = new Date(); |
| if (currentDate - lastSort > minDurationBetweenImageSort) { |
| lastSort = currentDate; |
| imageLoader.sort(compareImageLoadPriority); |
| } |
| }; |
| |
| var loadComplete = function () { |
| imageLoadComplete(jobComplete); |
| }; |
| var loadError = function () { |
| imageLoadComplete(jobError); |
| }; |
| |
| var jobComplete = function () { |
| seenUrl(srcUrl); |
| cleanup(); |
| c(image); |
| }; |
| var jobError = function () { |
| cleanup(); |
| e(image); |
| }; |
| |
| tempImage.addEventListener("load", loadComplete, false); |
| tempImage.addEventListener("error", loadError, false); |
| tempImage.src = srcUrl; |
| })); |
| } else { |
| seenUrl(srcUrl); |
| image.src = srcUrl; |
| c(image); |
| } |
| }, Scheduler.Priority.normal, null, "WinJS.UI._ImageLoader._image" + imageId); |
| }); |
| }, data); |
| } |
| |
| function isImageCached(srcUrl) { |
| return seenUrls[srcUrl]; |
| } |
| |
| function defaultRenderer() { |
| return _Global.document.createElement("div"); |
| } |
| |
| // Public definitions |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _createItemsManager: _Base.Namespace._lazy(function () { |
| var ListNotificationHandler = _Base.Class.define(function ListNotificationHandler_ctor(itemsManager) { |
| // Constructor |
| |
| this._itemsManager = itemsManager; |
| }, { |
| // Public methods |
| |
| beginNotifications: function () { |
| this._itemsManager._versionManager.beginNotifications(); |
| this._itemsManager._beginNotifications(); |
| }, |
| |
| // itemAvailable: not implemented |
| |
| inserted: function (itemPromise, previousHandle, nextHandle) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._inserted(itemPromise, previousHandle, nextHandle); |
| }, |
| |
| changed: function (newItem, oldItem) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._changed(newItem, oldItem); |
| }, |
| |
| moved: function (itemPromise, previousHandle, nextHandle) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._moved(itemPromise, previousHandle, nextHandle); |
| }, |
| |
| removed: function (handle, mirage) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._removed(handle, mirage); |
| }, |
| |
| countChanged: function (newCount, oldCount) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._countChanged(newCount, oldCount); |
| }, |
| |
| indexChanged: function (handle, newIndex, oldIndex) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._indexChanged(handle, newIndex, oldIndex); |
| }, |
| |
| affectedRange: function (range) { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._affectedRange(range); |
| }, |
| |
| endNotifications: function () { |
| this._itemsManager._versionManager.endNotifications(); |
| this._itemsManager._endNotifications(); |
| }, |
| |
| reload: function () { |
| this._itemsManager._versionManager.receivedNotification(); |
| this._itemsManager._reload(); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var ItemsManager = _Base.Class.define(function ItemsManager_ctor(listDataSource, itemRenderer, elementNotificationHandler, options) { |
| // Constructor |
| |
| if (!listDataSource) { |
| throw new _ErrorFromName("WinJS.UI.ItemsManager.ListDataSourceIsInvalid", strings.listDataSourceIsInvalid); |
| } |
| if (!itemRenderer) { |
| throw new _ErrorFromName("WinJS.UI.ItemsManager.ItemRendererIsInvalid", strings.itemRendererIsInvalid); |
| } |
| |
| this.$pipeline_callbacksMap = {}; |
| |
| this._listDataSource = listDataSource; |
| |
| this.dataSource = this._listDataSource; |
| |
| this._elementNotificationHandler = elementNotificationHandler; |
| |
| this._listBinding = this._listDataSource.createListBinding(new ListNotificationHandler(this)); |
| |
| if (options) { |
| if (options.ownerElement) { |
| this._ownerElement = options.ownerElement; |
| } |
| this._profilerId = options.profilerId; |
| this._versionManager = options.versionManager || new _VersionManager._VersionManager(); |
| } |
| |
| this._indexInView = options && options.indexInView; |
| this._itemRenderer = itemRenderer; |
| this._viewCallsReady = options && options.viewCallsReady; |
| |
| // Map of (the uniqueIDs of) elements to records for items |
| this._elementMap = {}; |
| |
| // Map of handles to records for items |
| this._handleMap = {}; |
| |
| // Owner for use with jobs on the scheduler. Allows for easy cancellation of jobs during clean up. |
| this._jobOwner = Scheduler.createOwnerToken(); |
| |
| // Boolean to track whether endNotifications needs to be called on the ElementNotificationHandler |
| this._notificationsSent = false; |
| |
| // Only enable the lastItem method if the data source implements the itemsFromEnd method |
| if (this._listBinding.last) { |
| this.lastItem = function () { |
| return this._elementForItem(this._listBinding.last()); |
| }; |
| } |
| }, { |
| _itemFromItemPromise: function (itemPromise) { |
| return this._waitForElement(this._elementForItem(itemPromise)); |
| }, |
| // If stage 0 is not yet complete, caller is responsible for transitioning the item from stage 0 to stage 1 |
| _itemFromItemPromiseThrottled: function (itemPromise) { |
| return this._waitForElement(this._elementForItem(itemPromise, true)); |
| }, |
| _itemAtIndex: function (index) { |
| var itemPromise = this._itemPromiseAtIndex(index); |
| this._itemFromItemPromise(itemPromise).then(null, function (e) { |
| itemPromise.cancel(); |
| return Promise.wrapError(e); |
| }); |
| }, |
| _itemPromiseAtIndex: function (index) { |
| return this._listBinding.fromIndex(index); |
| }, |
| _waitForElement: function (possiblePlaceholder) { |
| var that = this; |
| return new Promise(function (c) { |
| if (possiblePlaceholder) { |
| if (!that.isPlaceholder(possiblePlaceholder)) { |
| c(possiblePlaceholder); |
| } else { |
| var placeholderID = uniqueID(possiblePlaceholder); |
| var callbacks = that.$pipeline_callbacksMap[placeholderID]; |
| if (!callbacks) { |
| that.$pipeline_callbacksMap[placeholderID] = [c]; |
| } else { |
| callbacks.push(c); |
| } |
| } |
| } else { |
| c(possiblePlaceholder); |
| } |
| }); |
| }, |
| _updateElement: function (newElement, oldElement) { |
| var placeholderID = uniqueID(oldElement); |
| var callbacks = this.$pipeline_callbacksMap[placeholderID]; |
| if (callbacks) { |
| delete this.$pipeline_callbacksMap[placeholderID]; |
| callbacks.forEach(function (c) { c(newElement); }); |
| } |
| }, |
| _firstItem: function () { |
| return this._waitForElement(this._elementForItem(this._listBinding.first())); |
| }, |
| _lastItem: function () { |
| return this._waitForElement(this._elementForItem(this._listBinding.last())); |
| }, |
| _previousItem: function (element) { |
| this._listBinding.jumpToItem(this._itemFromElement(element)); |
| return this._waitForElement(this._elementForItem(this._listBinding.previous())); |
| }, |
| _nextItem: function (element) { |
| this._listBinding.jumpToItem(this._itemFromElement(element)); |
| return this._waitForElement(this._elementForItem(this._listBinding.next())); |
| }, |
| _itemFromPromise: function (itemPromise) { |
| return this._waitForElement(this._elementForItem(itemPromise)); |
| }, |
| isPlaceholder: function (item) { |
| return !!this._recordFromElement(item).elementIsPlaceholder; |
| }, |
| |
| itemObject: function (element) { |
| return this._itemFromElement(element); |
| }, |
| |
| release: function () { |
| this._listBinding.release(); |
| this._elementNotificationHandler = null; |
| this._listBinding = null; |
| this._jobOwner.cancelAll(); |
| this._released = true; |
| }, |
| |
| releaseItemPromise: function (itemPromise) { |
| var handle = itemPromise.handle; |
| var record = this._handleMap[handle]; |
| if (!record) { |
| // The item promise is not in our handle map so we didn't even try to render it yet. |
| itemPromise.cancel(); |
| } else { |
| this._releaseRecord(record); |
| } |
| }, |
| |
| releaseItem: function (element) { |
| var record = this._elementMap[uniqueID(element)]; |
| this._releaseRecord(record); |
| }, |
| |
| _releaseRecord: function (record) { |
| if (!record) { return; } |
| |
| if (record.renderPromise) { |
| record.renderPromise.cancel(); |
| } |
| if (record.itemPromise) { |
| record.itemPromise.cancel(); |
| } |
| if (record.imagePromises) { |
| record.imagePromises.forEach(function (promise) { |
| promise.cancel(); |
| }); |
| } |
| if (record.itemReadyPromise) { |
| record.itemReadyPromise.cancel(); |
| } |
| if (record.renderComplete) { |
| record.renderComplete.cancel(); |
| } |
| |
| this._removeEntryFromElementMap(record.element); |
| this._removeEntryFromHandleMap(record.itemPromise.handle, record); |
| |
| if (record.item) { |
| this._listBinding.releaseItem(record.item); |
| } |
| |
| }, |
| |
| refresh: function () { |
| return this._listDataSource.invalidateAll(); |
| }, |
| |
| // Private members |
| |
| _handlerToNotifyCaresAboutItemAvailable: function () { |
| return !!(this._elementNotificationHandler && this._elementNotificationHandler.itemAvailable); |
| }, |
| |
| _handlerToNotify: function () { |
| if (!this._notificationsSent) { |
| this._notificationsSent = true; |
| |
| if (this._elementNotificationHandler && this._elementNotificationHandler.beginNotifications) { |
| this._elementNotificationHandler.beginNotifications(); |
| } |
| } |
| return this._elementNotificationHandler; |
| }, |
| |
| _defineIndexProperty: function (itemForRenderer, item, record) { |
| record.indexObserved = false; |
| Object.defineProperty(itemForRenderer, "index", { |
| get: function () { |
| record.indexObserved = true; |
| return item.index; |
| } |
| }); |
| }, |
| |
| _renderPlaceholder: function (record) { |
| var itemForRenderer = {}; |
| var elementPlaceholder = defaultRenderer(itemForRenderer); |
| record.elementIsPlaceholder = true; |
| return elementPlaceholder; |
| }, |
| |
| _renderItem: function (itemPromise, record, callerThrottlesStage1) { |
| var that = this; |
| var indexInView = that._indexInView || function () { return true; }; |
| var stage1Signal = new _Signal(); |
| var readySignal = new _Signal(); |
| var perfItemPromiseId = "_renderItem(" + record.item.index + "):itemPromise"; |
| |
| var stage0RunningSync = true; |
| var stage0Ran = false; |
| itemPromise.then(function (item) { |
| stage0Ran = true; |
| if (stage0RunningSync) { |
| stage1Signal.complete(item); |
| } |
| }); |
| stage0RunningSync = false; |
| |
| var itemForRendererPromise = stage1Signal.promise.then(function (item) { |
| if (item) { |
| var itemForRenderer = Object.create(item); |
| // Derive a new item and override its index property, to track whether it is read |
| that._defineIndexProperty(itemForRenderer, item, record); |
| itemForRenderer.ready = readySignal.promise; |
| itemForRenderer.isOnScreen = function () { |
| return Promise.wrap(indexInView(item.index)); |
| }; |
| itemForRenderer.loadImage = function (srcUrl, image) { |
| var loadImagePromise = loadImage(srcUrl, image, itemForRenderer); |
| if (record.imagePromises) { |
| record.imagePromises.push(loadImagePromise); |
| } else { |
| record.imagePromises = [loadImagePromise]; |
| } |
| return loadImagePromise; |
| }; |
| itemForRenderer.isImageCached = isImageCached; |
| return itemForRenderer; |
| } else { |
| return Promise.cancel; |
| } |
| }); |
| |
| function queueAsyncStage1() { |
| itemPromise.then(function (item) { |
| that._writeProfilerMark(perfItemPromiseId + ",StartTM"); |
| stage1Signal.complete(item); |
| that._writeProfilerMark(perfItemPromiseId + ",StopTM"); |
| }); |
| } |
| if (!stage0Ran) { |
| if (callerThrottlesStage1) { |
| record.stage0 = itemPromise; |
| record.startStage1 = function () { |
| record.startStage1 = null; |
| queueAsyncStage1(); |
| }; |
| } else { |
| queueAsyncStage1(); |
| } |
| } |
| |
| itemForRendererPromise.handle = itemPromise.handle; |
| record.itemPromise = itemForRendererPromise; |
| record.itemReadyPromise = readySignal.promise; |
| record.readyComplete = false; |
| |
| // perfRendererWorkId = stage 1 rendering (if itemPromise is async) or stage 1+2 (if itemPromise is sync and ran inline) |
| // perfItemPromiseId = stage 2 rendering only (should only be emitted if itemPromise was async) |
| // perfItemReadyId = stage 3 rendering |
| var perfRendererWorkId = "_renderItem(" + record.item.index + (stage0Ran ? "):syncItemPromise" : "):placeholder"); |
| var perfItemReadyId = "_renderItem(" + record.item.index + "):itemReady"; |
| |
| this._writeProfilerMark(perfRendererWorkId + ",StartTM"); |
| var rendererPromise = Promise.as(that._itemRenderer(itemForRendererPromise, record.element)). |
| then(exports._normalizeRendererReturn). |
| then(function (v) { |
| if (that._released) { |
| return Promise.cancel; |
| } |
| |
| itemForRendererPromise.then(function (item) { |
| // Store pending ready callback off record so ScrollView can call it during realizePage. Otherwise |
| // call it ourselves. |
| record.pendingReady = function () { |
| if (record.pendingReady) { |
| record.pendingReady = null; |
| record.readyComplete = true; |
| that._writeProfilerMark(perfItemReadyId + ",StartTM"); |
| readySignal.complete(item); |
| that._writeProfilerMark(perfItemReadyId + ",StopTM"); |
| } |
| }; |
| if (!that._viewCallsReady) { |
| var job = Scheduler.schedule(record.pendingReady, Scheduler.Priority.normal, |
| record, "WinJS.UI._ItemsManager._pendingReady"); |
| job.owner = that._jobOwner; |
| } |
| }); |
| return v; |
| }); |
| |
| this._writeProfilerMark(perfRendererWorkId + ",StopTM"); |
| return rendererPromise; |
| }, |
| |
| _replaceElement: function (record, elementNew) { |
| this._removeEntryFromElementMap(record.element); |
| record.element = elementNew; |
| this._addEntryToElementMap(elementNew, record); |
| }, |
| |
| _changeElement: function (record, elementNew, elementNewIsPlaceholder) { |
| record.renderPromise = null; |
| var elementOld = record.element, |
| itemOld = record.item; |
| |
| if (record.newItem) { |
| record.item = record.newItem; |
| record.newItem = null; |
| } |
| |
| this._replaceElement(record, elementNew); |
| |
| if (record.item && record.elementIsPlaceholder && !elementNewIsPlaceholder) { |
| record.elementDelayed = null; |
| record.elementIsPlaceholder = false; |
| this._updateElement(record.element, elementOld); |
| if (this._handlerToNotifyCaresAboutItemAvailable()) { |
| this._handlerToNotify().itemAvailable(record.element, elementOld); |
| } |
| } else { |
| this._handlerToNotify().changed(elementNew, elementOld, itemOld); |
| } |
| }, |
| |
| _elementForItem: function (itemPromise, callerThrottlesStage1) { |
| var handle = itemPromise.handle, |
| record = this._recordFromHandle(handle, true), |
| element; |
| |
| if (!handle) { |
| return null; |
| } |
| |
| if (record) { |
| element = record.element; |
| } else { |
| // Create a new record for this item |
| record = { |
| item: itemPromise, |
| itemPromise: itemPromise |
| }; |
| this._addEntryToHandleMap(handle, record); |
| |
| var that = this; |
| var mirage = false; |
| var synchronous = false; |
| |
| var renderPromise = |
| that._renderItem(itemPromise, record, callerThrottlesStage1). |
| then(function (v) { |
| var elementNew = v.element; |
| record.renderComplete = v.renderComplete; |
| |
| itemPromise.then(function (item) { |
| record.item = item; |
| if (!item) { |
| mirage = true; |
| element = null; |
| } |
| }); |
| |
| synchronous = true; |
| record.renderPromise = null; |
| |
| if (elementNew) { |
| if (element) { |
| that._presentElements(record, elementNew); |
| } else { |
| element = elementNew; |
| } |
| } |
| }); |
| |
| if (!mirage) { |
| if (!synchronous) { |
| record.renderPromise = renderPromise; |
| } |
| |
| if (!element) { |
| element = this._renderPlaceholder(record); |
| } |
| |
| record.element = element; |
| this._addEntryToElementMap(element, record); |
| |
| itemPromise.retain(); |
| } |
| } |
| |
| return element; |
| }, |
| |
| _addEntryToElementMap: function (element, record) { |
| this._elementMap[uniqueID(element)] = record; |
| }, |
| |
| _removeEntryFromElementMap: function (element) { |
| delete this._elementMap[uniqueID(element)]; |
| }, |
| |
| _recordFromElement: function (element) { |
| var record = this._elementMap[uniqueID(element)]; |
| if (!record) { |
| this._writeProfilerMark("_recordFromElement:ItemIsInvalidError,info"); |
| throw new _ErrorFromName("WinJS.UI.ItemsManager.ItemIsInvalid", strings.itemIsInvalid); |
| } |
| |
| return record; |
| }, |
| |
| _addEntryToHandleMap: function (handle, record) { |
| this._handleMap[handle] = record; |
| }, |
| |
| _removeEntryFromHandleMap: function (handle) { |
| delete this._handleMap[handle]; |
| }, |
| |
| _handleInHandleMap: function (handle) { |
| return !!this._handleMap[handle]; |
| }, |
| |
| _recordFromHandle: function (handle, ignoreFailure) { |
| var record = this._handleMap[handle]; |
| if (!record && !ignoreFailure) { |
| throw new _ErrorFromName("WinJS.UI.ItemsManager.ItemIsInvalid", strings.itemIsInvalid); |
| } |
| return record; |
| }, |
| |
| _foreachRecord: function (callback) { |
| var records = this._handleMap; |
| for (var property in records) { |
| var record = records[property]; |
| callback(record); |
| } |
| }, |
| |
| _itemFromElement: function (element) { |
| return this._recordFromElement(element).item; |
| }, |
| |
| _elementFromHandle: function (handle) { |
| if (handle) { |
| var record = this._recordFromHandle(handle, true); |
| |
| if (record && record.element) { |
| return record.element; |
| } |
| } |
| |
| return null; |
| }, |
| |
| _inserted: function (itemPromise, previousHandle, nextHandle) { |
| this._handlerToNotify().inserted(itemPromise, previousHandle, nextHandle); |
| }, |
| |
| _changed: function (newItem, oldItem) { |
| if (!this._handleInHandleMap(oldItem.handle)) { return; } |
| |
| var record = this._recordFromHandle(oldItem.handle); |
| |
| if (record.renderPromise) { |
| record.renderPromise.cancel(); |
| } |
| if (record.itemPromise) { |
| record.itemPromise.cancel(); |
| } |
| if (record.imagePromises) { |
| record.imagePromises.forEach(function (promise) { |
| promise.cancel(); |
| }); |
| } |
| if (record.itemReadyPromise) { |
| record.itemReadyPromise.cancel(); |
| } |
| if (record.renderComplete) { |
| record.renderComplete.cancel(); |
| } |
| |
| record.newItem = newItem; |
| |
| var that = this; |
| var newItemPromise = Promise.as(newItem); |
| newItemPromise.handle = record.itemPromise.handle; |
| record.renderPromise = this._renderItem(newItemPromise, record). |
| then(function (v) { |
| record.renderComplete = v.renderComplete; |
| that._changeElement(record, v.element, false); |
| that._presentElements(record); |
| }); |
| }, |
| |
| _moved: function (itemPromise, previousHandle, nextHandle) { |
| // no check for haveHandle, as we get move notification for items we |
| // are "next" to, so we handle the "null element" cases below |
| // |
| var element = this._elementFromHandle(itemPromise.handle); |
| var previous = this._elementFromHandle(previousHandle); |
| var next = this._elementFromHandle(nextHandle); |
| |
| this._handlerToNotify().moved(element, previous, next, itemPromise); |
| this._presentAllElements(); |
| }, |
| |
| _removed: function (handle, mirage) { |
| if (this._handleInHandleMap(handle)) { |
| var element = this._elementFromHandle(handle); |
| |
| this._handlerToNotify().removed(element, mirage, handle); |
| this.releaseItem(element); |
| this._presentAllElements(); |
| } else { |
| this._handlerToNotify().removed(null, mirage, handle); |
| } |
| }, |
| |
| _countChanged: function (newCount, oldCount) { |
| if (this._elementNotificationHandler && this._elementNotificationHandler.countChanged) { |
| this._handlerToNotify().countChanged(newCount, oldCount); |
| } |
| }, |
| |
| _indexChanged: function (handle, newIndex, oldIndex) { |
| var element; |
| if (this._handleInHandleMap(handle)) { |
| var record = this._recordFromHandle(handle); |
| if (record.indexObserved) { |
| if (!record.elementIsPlaceholder) { |
| if (record.item.index !== newIndex) { |
| if (record.renderPromise) { |
| record.renderPromise.cancel(); |
| } |
| if (record.renderComplete) { |
| record.renderComplete.cancel(); |
| } |
| |
| var itemToRender = record.newItem || record.item; |
| itemToRender.index = newIndex; |
| |
| var newItemPromise = Promise.as(itemToRender); |
| newItemPromise.handle = record.itemPromise.handle; |
| |
| var that = this; |
| record.renderPromise = this._renderItem(newItemPromise, record). |
| then(function (v) { |
| record.renderComplete = v.renderComplete; |
| that._changeElement(record, v.element, false); |
| that._presentElements(record); |
| }); |
| } |
| } else { |
| this._changeElement(record, this._renderPlaceholder(record), true); |
| } |
| } |
| element = record.element; |
| } |
| if (this._elementNotificationHandler && this._elementNotificationHandler.indexChanged) { |
| this._handlerToNotify().indexChanged(element, newIndex, oldIndex); |
| } |
| }, |
| |
| _affectedRange: function (range) { |
| if (this._elementNotificationHandler && this._elementNotificationHandler.updateAffectedRange) { |
| this._handlerToNotify().updateAffectedRange(range); |
| } |
| }, |
| |
| _beginNotifications: function () { |
| // accessing _handlerToNotify will force the call to beginNotifications on the client |
| // |
| this._externalBegin = true; |
| this._handlerToNotify(); |
| }, |
| _endNotifications: function () { |
| if (this._notificationsSent) { |
| this._notificationsSent = false; |
| this._externalBegin = false; |
| |
| if (this._elementNotificationHandler && this._elementNotificationHandler.endNotifications) { |
| this._elementNotificationHandler.endNotifications(); |
| } |
| } |
| }, |
| |
| _reload: function () { |
| if (this._elementNotificationHandler && this._elementNotificationHandler.reload) { |
| this._elementNotificationHandler.reload(); |
| } |
| }, |
| |
| // Some functions may be called synchronously or asynchronously, so it's best to post _endNotifications to avoid |
| // calling it prematurely. |
| _postEndNotifications: function () { |
| if (this._notificationsSent && !this._externalBegin && !this._endNotificationsPosted) { |
| this._endNotificationsPosted = true; |
| var that = this; |
| Scheduler.schedule(function ItemsManager_async_endNotifications() { |
| that._endNotificationsPosted = false; |
| that._endNotifications(); |
| }, Scheduler.Priority.high, null, "WinJS.UI._ItemsManager._postEndNotifications"); |
| } |
| }, |
| |
| _presentElement: function (record) { |
| var elementOld = record.element; |
| // Finish modifying the slot before calling back into user code, in case there is a reentrant call |
| this._replaceElement(record, record.elementDelayed); |
| record.elementDelayed = null; |
| |
| record.elementIsPlaceholder = false; |
| this._updateElement(record.element, elementOld); |
| if (this._handlerToNotifyCaresAboutItemAvailable()) { |
| this._handlerToNotify().itemAvailable(record.element, elementOld); |
| } |
| }, |
| |
| _presentElements: function (record, elementDelayed) { |
| if (elementDelayed) { |
| record.elementDelayed = elementDelayed; |
| } |
| |
| this._listBinding.jumpToItem(record.item); |
| if (record.elementDelayed) { |
| this._presentElement(record); |
| } |
| |
| this._postEndNotifications(); |
| }, |
| |
| // Presents all delayed elements |
| _presentAllElements: function () { |
| var that = this; |
| this._foreachRecord(function (record) { |
| if (record.elementDelayed) { |
| that._presentElement(record); |
| } |
| }); |
| }, |
| |
| _writeProfilerMark: function (text) { |
| var message = "WinJS.UI._ItemsManager:" + (this._profilerId ? (this._profilerId + ":") : ":") + text; |
| _WriteProfilerMark(message); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| return function (dataSource, itemRenderer, elementNotificationHandler, options) { |
| return new ItemsManager(dataSource, itemRenderer, elementNotificationHandler, options); |
| }; |
| }) |
| }); |
| |
| }); |
| |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_TabContainer',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| './_ElementUtilities' |
| ], function tabManagerInit(exports, _Global, _Base, _BaseUtils, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| function fireEvent(element, name, forward, cancelable) { |
| var event = _Global.document.createEvent('UIEvent'); |
| event.initUIEvent(name, false, !!cancelable, _Global, forward ? 1 : 0); |
| return !element.dispatchEvent(event); |
| } |
| |
| var getTabIndex = _ElementUtilities.getTabIndex; |
| |
| // tabbableElementsNodeFilter works with the TreeWalker to create a view of the DOM tree that is built up of what we want the focusable tree to look like. |
| // When it runs into a tab contained area, it rejects anything except the childFocus element so that any potentially tabbable things that the TabContainer |
| // doesn't want tabbed to get ignored. |
| function tabbableElementsNodeFilter(node) { |
| var nodeStyle = _ElementUtilities._getComputedStyle(node); |
| if (nodeStyle.display === "none" || nodeStyle.visibility === "hidden") { |
| return _Global.NodeFilter.FILTER_REJECT; |
| } |
| if (node._tabContainer) { |
| return _Global.NodeFilter.FILTER_ACCEPT; |
| } |
| if (node.parentNode && node.parentNode._tabContainer) { |
| var managedTarget = node.parentNode._tabContainer.childFocus; |
| // Ignore subtrees that are under a tab manager but not the child focus. If a node is contained in the child focus, either accept it (if it's tabbable itself), or skip it and find tabbable content inside of it. |
| if (managedTarget && node.contains(managedTarget)) { |
| return (getTabIndex(node) >= 0 ? _Global.NodeFilter.FILTER_ACCEPT : _Global.NodeFilter.FILTER_SKIP); |
| } |
| return _Global.NodeFilter.FILTER_REJECT; |
| } |
| var tabIndex = getTabIndex(node); |
| if (tabIndex >= 0) { |
| return _Global.NodeFilter.FILTER_ACCEPT; |
| } |
| return _Global.NodeFilter.FILTER_SKIP; |
| } |
| |
| // We've got to manually scrape the results the walker generated, since the walker will have generated a fairly good representation of the tabbable tree, but |
| // won't have a perfect image. Trees like this cause a problem for the walker: |
| // [ tabContainer element ] |
| // [ element containing childFocus ] |
| // [ childFocus ] [ sibling of child focus that has tabIndex >= 0 ] |
| // We can't tell the tree walker to jump right to the childFocus, so it'll collect the childFocus but also that sibling element. We don't want that sibling element |
| // to appear in our version of the tabOrder, so scrapeTabManagedSubtree will take the pretty accurate representation we get from the TreeWalker, and do a little |
| // more pruning to give us only the nodes we're interested in. |
| function scrapeTabManagedSubtree(walker) { |
| var tabManagedElement = walker.currentNode, |
| childFocus = tabManagedElement._tabContainer.childFocus, |
| elementsFound = []; |
| |
| if (!childFocus) { |
| return []; |
| } |
| |
| walker.currentNode = childFocus; |
| function scrapeSubtree() { |
| if (walker.currentNode._tabContainer) { |
| elementsFound = elementsFound.concat(scrapeTabManagedSubtree(walker)); |
| } else { |
| // A child focus can have tabIndex = -1, so check the tabIndex before marking it as valid |
| if (getTabIndex(walker.currentNode) >= 0) { |
| elementsFound.push(walker.currentNode); |
| } |
| if (walker.firstChild()) { |
| do { |
| scrapeSubtree(); |
| } while (walker.nextSibling()); |
| walker.parentNode(); |
| } |
| } |
| } |
| scrapeSubtree(); |
| walker.currentNode = tabManagedElement; |
| |
| return elementsFound; |
| } |
| |
| function TabHelperObject(element, tabIndex) { |
| function createCatcher() { |
| var fragment = _Global.document.createElement("DIV"); |
| fragment.tabIndex = (tabIndex ? tabIndex : 0); |
| fragment.setAttribute("aria-hidden", true); |
| return fragment; |
| } |
| |
| var parent = element.parentNode; |
| |
| // Insert prefix focus catcher |
| var catcherBegin = createCatcher(); |
| parent.insertBefore(catcherBegin, element); |
| |
| // Insert postfix focus catcher |
| var catcherEnd = createCatcher(); |
| parent.insertBefore(catcherEnd, element.nextSibling); |
| |
| catcherBegin.addEventListener("focus", function () { |
| fireEvent(element, "onTabEnter", true); |
| }, true); |
| catcherEnd.addEventListener("focus", function () { |
| fireEvent(element, "onTabEnter", false); |
| }, true); |
| |
| this._catcherBegin = catcherBegin; |
| this._catcherEnd = catcherEnd; |
| var refCount = 1; |
| this.addRef = function () { |
| refCount++; |
| }; |
| this.release = function () { |
| if (--refCount === 0) { |
| if (catcherBegin.parentElement) { |
| parent.removeChild(catcherBegin); |
| } |
| if (catcherEnd.parentElement) { |
| parent.removeChild(catcherEnd); |
| } |
| } |
| return refCount; |
| }; |
| this.updateTabIndex = function (tabIndex) { |
| catcherBegin.tabIndex = tabIndex; |
| catcherEnd.tabIndex = tabIndex; |
| }; |
| } |
| |
| var TrackTabBehavior = { |
| attach: function (element, tabIndex) { |
| /// |
| if (!element["win-trackTabHelperObject"]) { |
| element["win-trackTabHelperObject"] = new TabHelperObject(element, tabIndex); |
| } else { |
| element["win-trackTabHelperObject"].addRef(); |
| } |
| |
| return element["win-trackTabHelperObject"]; |
| }, |
| |
| detach: function (element) { |
| /// |
| if (!element["win-trackTabHelperObject"].release()) { |
| delete element["win-trackTabHelperObject"]; |
| } |
| } |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| TrackTabBehavior: TrackTabBehavior, |
| TabContainer: _Base.Class.define(function TabContainer_ctor(element) { |
| /// <signature helpKeyword="WinJS.UI.TabContainer.TabContainer"> |
| /// <summary locid="WinJS.UI.TabContainer.constructor"> |
| /// Constructs the TabContainer. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" domElement="true" locid="WinJS.UI.TabContainer.constructor_p:element"> |
| /// The DOM element to be associated with the TabContainer. |
| /// </param> |
| /// <param name="options" type="Object" locid="WinJS.UI.TabContainer.constructor_p:options"> |
| /// The set of options to be applied initially to the TabContainer. |
| /// </param> |
| /// <returns type="WinJS.UI.TabContainer" locid="WinJS.UI.TabContainer.constructor_returnValue"> |
| /// A constructed TabContainer. |
| /// </returns> |
| /// </signature> |
| this._element = element; |
| this._tabIndex = 0; |
| element._tabContainer = this; |
| if (element.getAttribute("tabindex") === null) { |
| element.tabIndex = -1; |
| } |
| var that = this; |
| |
| element.addEventListener("onTabEnter", function (e) { |
| var skipDefaultBehavior = fireEvent(that._element, "onTabEntered", e.detail, true); |
| if (skipDefaultBehavior) { |
| return; |
| } |
| |
| if (that.childFocus) { |
| that.childFocus.focus(); |
| } else { |
| element.focus(); |
| } |
| }); |
| element.addEventListener("keydown", function (e) { |
| var targetElement = e.target; |
| if (e.keyCode === _ElementUtilities.Key.tab) { |
| var forwardTab = !e.shiftKey; |
| var canKeepTabbing = that._hasMoreElementsInTabOrder(targetElement, forwardTab); |
| if (!canKeepTabbing) { |
| var skipTabExitHandling = fireEvent(that._element, "onTabExiting", forwardTab, true); |
| if (skipTabExitHandling) { |
| e.stopPropagation(); |
| e.preventDefault(); |
| return; |
| } |
| var allTabbableElements = that._element.querySelectorAll("a[href],area[href],button,command,input,link,menuitem,object,select,textarea,th[sorted],[tabindex]"), |
| len = allTabbableElements.length, |
| originalTabIndices = []; |
| |
| for (var i = 0; i < len; i++) { |
| var element = allTabbableElements[i]; |
| originalTabIndices.push(element.tabIndex); |
| element.tabIndex = -1; |
| } |
| // If there's nothing else that can be tabbed to on the page, tab should wrap around back to the tab contained area. |
| // We'll disable the sentinel node that's directly in the path of the tab order (catcherEnd for forward tabs, and |
| // catcherBegin for shift+tabs), but leave the other sentinel node untouched so tab can wrap around back into the region. |
| that._elementTabHelper[forwardTab ? "_catcherEnd" : "_catcherBegin"].tabIndex = -1; |
| |
| var restoreTabIndicesOnBlur = function () { |
| targetElement.removeEventListener("blur", restoreTabIndicesOnBlur, false); |
| for (var i = 0; i < len; i++) { |
| if (originalTabIndices[i] !== -1) { |
| // When the original tabIndex was -1, don't try restoring to -1 again. A nested TabContainer might also be in the middle of handling this same code, |
| // and so would have set tabIndex = -1 on this element. The nested tab container will restore the element's tabIndex properly. |
| allTabbableElements[i].tabIndex = originalTabIndices[i]; |
| } |
| } |
| that._elementTabHelper._catcherBegin.tabIndex = that._tabIndex; |
| that._elementTabHelper._catcherEnd.tabIndex = that._tabIndex; |
| }; |
| targetElement.addEventListener("blur", restoreTabIndicesOnBlur, false); |
| _BaseUtils._yieldForEvents(function () { |
| fireEvent(that._element, "onTabExit", forwardTab); |
| }); |
| } |
| } |
| }); |
| |
| this._elementTabHelper = TrackTabBehavior.attach(element, this._tabIndex); |
| this._elementTabHelper._catcherBegin.tabIndex = 0; |
| this._elementTabHelper._catcherEnd.tabIndex = 0; |
| }, { |
| |
| // Public members |
| |
| /// <signature helpKeyword="WinJS.UI.TabContainer.dispose"> |
| /// <summary locid="WinJS.UI.TabContainer.dispose"> |
| /// Disposes the Tab Container. |
| /// </summary> |
| /// </signature> |
| dispose: function () { |
| TrackTabBehavior.detach(this._element, this._tabIndex); |
| }, |
| |
| /// <field type="HTMLElement" domElement="true" locid="WinJS.UI.TabContainer.childFocus" helpKeyword="WinJS.UI.TabContainer.childFocus"> |
| /// Gets or sets the child element that has focus. |
| /// </field> |
| childFocus: { |
| set: function (e) { |
| if (e !== this._focusElement) { |
| if (e && e.parentNode) { |
| this._focusElement = e; |
| } else { |
| this._focusElement = null; |
| } |
| } |
| }, |
| get: function () { |
| return this._focusElement; |
| } |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.UI.TabContainer.tabIndex" helpKeyword="WinJS.UI.TabContainer.tabIndex"> |
| /// Gets or sets the tab order of the control within its container. |
| /// </field> |
| tabIndex: { |
| set: function (tabIndex) { |
| this._tabIndex = tabIndex; |
| this._elementTabHelper.updateTabIndex(tabIndex); |
| }, |
| |
| get: function () { |
| return this._tabIndex; |
| } |
| }, |
| |
| // Private members |
| |
| _element: null, |
| _skipper: function (e) { |
| e.stopPropagation(); |
| e.preventDefault(); |
| }, |
| _hasMoreElementsInTabOrder: function (currentFocus, movingForwards) { |
| if (!this.childFocus) { |
| return false; |
| } |
| var walker = _Global.document.createTreeWalker(this._element, _Global.NodeFilter.SHOW_ELEMENT, tabbableElementsNodeFilter, false); |
| var tabStops = scrapeTabManagedSubtree(walker); |
| for (var i = 0; i < tabStops.length; i++) { |
| if (tabStops[i] === currentFocus) { |
| return (movingForwards ? (i < tabStops.length - 1) : (i > 0)); |
| } |
| } |
| return false; |
| }, |
| _focusElement: null |
| |
| }, { // Static Members |
| supportedForProcessing: false, |
| }) |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_KeyboardBehavior',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| './_Control', |
| './_ElementUtilities', |
| './_TabContainer' |
| ], function KeyboardBehaviorInit(exports, _Global, _Base, _Control, _ElementUtilities, _TabContainer) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var InputTypes = { |
| touch: "touch", |
| pen: "pen", |
| mouse: "mouse", |
| keyboard: "keyboard" |
| }; |
| var _lastInputType = InputTypes.mouse; |
| |
| // Keys should be the same as the values for a PointerEvent's pointerType. |
| var pointerTypeToInputType = { |
| // IE 10 uses numbers for its pointerType |
| 2: InputTypes.touch, |
| 3: InputTypes.pen, |
| 4: InputTypes.mouse, |
| |
| // Others use strings for their pointerTypes |
| touch: InputTypes.touch, |
| pen: InputTypes.pen, |
| mouse: InputTypes.mouse |
| }; |
| |
| _ElementUtilities._addEventListener(_Global, "pointerdown", function (eventObject) { |
| _lastInputType = pointerTypeToInputType[eventObject.pointerType] || InputTypes.mouse; |
| }, true); |
| |
| _Global.addEventListener("keydown", function () { |
| _lastInputType = InputTypes.keyboard; |
| }, true); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _keyboardSeenLast: { |
| get: function _keyboardSeenLast_get() { |
| return _lastInputType === InputTypes.keyboard; |
| }, |
| set: function _keyboardSeenLast_set(value) { |
| _lastInputType = (value ? InputTypes.keyboard : InputTypes.mouse); |
| } |
| }, |
| _lastInputType: { |
| get: function _lastInputType_get() { |
| return _lastInputType; |
| }, |
| set: function _lastInputType_set(value) { |
| if (InputTypes[value]) { |
| _lastInputType = value; |
| } |
| } |
| }, |
| _InputTypes: InputTypes, |
| _WinKeyboard: function (element) { |
| // Win Keyboard behavior is a solution that would be similar to -ms-keyboard-focus. |
| // It monitors the last input (keyboard/mouse) and adds/removes a win-keyboard class |
| // so that you can style .foo.win-keyboard:focus vs .foo:focus to add a keyboard rect |
| // on an item only when the last input method was keyboard. |
| // Reminder: Touch edgy does not count as an input method. |
| _ElementUtilities._addEventListener(element, "pointerdown", function (ev) { |
| // In case pointer down came on the active element. |
| _ElementUtilities.removeClass(ev.target, "win-keyboard"); |
| }, true); |
| element.addEventListener("keydown", function (ev) { |
| _ElementUtilities.addClass(ev.target, "win-keyboard"); |
| }, true); |
| _ElementUtilities._addEventListener(element, "focusin", function (ev) { |
| exports._keyboardSeenLast && _ElementUtilities.addClass(ev.target, "win-keyboard"); |
| }, false); |
| _ElementUtilities._addEventListener(element, "focusout", function (ev) { |
| _ElementUtilities.removeClass(ev.target, "win-keyboard"); |
| }, false); |
| }, |
| _KeyboardBehavior: _Base.Namespace._lazy(function () { |
| var Key = _ElementUtilities.Key; |
| |
| var _KeyboardBehavior = _Base.Class.define(function KeyboardBehavior_ctor(element, options) { |
| // KeyboardBehavior allows you to easily convert a bunch of tabable elements into a single tab stop with |
| // navigation replaced by keyboard arrow (Up/Down/Left/Right) + Home + End + Custom keys. |
| // |
| // Example use cases: |
| // |
| // 1 Dimensional list: FixedDirection = height and FixedSize = 1; |
| // [1] [ 2 ] [ 3 ] [4] [ 5 ]... |
| // |
| // 2 Dimensional list: FixedDirection = height and FixedSize = 2; |
| // [1] [3] [5] [7] ... |
| // [2] [4] [6] [8] |
| // |
| // 1 Dimensional list: FixedDirection = width and FixedSize = 1; |
| // [ 1 ] |
| // - - |
| // | | |
| // | 2 | |
| // | | |
| // - - |
| // [ 3 ] |
| // [ 4 ] |
| // ... |
| // |
| // 2 Dimensional list: FixedDirection = width and FixedSize = 2; |
| // [1][2] |
| // [3][4] |
| // [5][6] |
| // ... |
| // |
| // Currently it is a "behavior" instead of a "control" so it can be attached to the same element as a |
| // winControl. The main scenario for this would be to attach it to the same element as a repeater. |
| // |
| // It also blocks "Portaling" where you go off the end of one column and wrap around to the other |
| // column. It also blocks "Carousel" where you go from the end of the list to the beginning. |
| // |
| // Keyboarding behavior supports nesting. It supports your tab stops having sub tab stops. If you want |
| // an interactive element within the tab stop you need to use the win-interactive classname or during the |
| // keydown event stop propogation so that the event is skipped. |
| // |
| // If you have custom keyboarding the getAdjacent API is provided. This can be used to enable keyboarding |
| // in multisize 2d lists or custom keyboard commands. PageDown and PageUp are the most common since this |
| // behavior does not detect scrollers. |
| // |
| // It also allows developers to show/hide keyboard focus rectangles themselves. |
| // |
| // It has an API called currentIndex so that Tab (or Shift+Tab) or a developer imitating Tab will result in |
| // the correct item having focus. |
| // |
| // It also allows an element to be represented as 2 arrow stops (commonly used for a split button) by calling |
| // the _getFocusInto API on the child element's winControl if it exists. |
| |
| element = element || _Global.document.createElement("DIV"); |
| options = options || {}; |
| |
| element._keyboardBehavior = this; |
| this._element = element; |
| |
| this._fixedDirection = _KeyboardBehavior.FixedDirection.width; |
| this._fixedSize = 1; |
| this._currentIndex = 0; |
| |
| _Control.setOptions(this, options); |
| |
| // If there's a scroller, the TabContainer can't be inside of the scroller. Otherwise, tabbing into the |
| // TabContainer will cause the scroller to scroll. |
| this._tabContainer = new _TabContainer.TabContainer(this.scroller || this._element); |
| this._tabContainer.tabIndex = 0; |
| if (this._element.children.length > 0) { |
| this._tabContainer.childFocus = this._getFocusInto(this._element.children[0]); |
| } |
| |
| this._element.addEventListener('keydown', this._keyDownHandler.bind(this)); |
| _ElementUtilities._addEventListener(this._element, 'pointerdown', this._MSPointerDownHandler.bind(this)); |
| }, { |
| element: { |
| get: function () { |
| return this._element; |
| } |
| }, |
| |
| fixedDirection: { |
| get: function () { |
| return this._fixedDirection; |
| }, |
| set: function (value) { |
| this._fixedDirection = value; |
| } |
| }, |
| |
| fixedSize: { |
| get: function () { |
| return this._fixedSize; |
| }, |
| set: function (value) { |
| if (+value === value) { |
| value = Math.max(1, value); |
| this._fixedSize = value; |
| } |
| } |
| }, |
| |
| currentIndex: { |
| get: function () { |
| if (this._element.children.length > 0) { |
| return this._currentIndex; |
| } |
| return -1; |
| }, |
| set: function (value) { |
| if (+value === value) { |
| var length = this._element.children.length; |
| value = Math.max(0, Math.min(length - 1, value)); |
| this._currentIndex = value; |
| this._tabContainer.childFocus = this._getFocusInto(this._element.children[value]); |
| } |
| } |
| }, |
| |
| getAdjacent: { |
| get: function () { |
| return this._getAdjacent; |
| }, |
| set: function (value) { |
| this._getAdjacent = value; |
| } |
| }, |
| |
| // If set, KeyboardBehavior will prevent *scroller* from scrolling when moving focus |
| scroller: { |
| get: function () { |
| return this._scroller; |
| }, |
| set: function (value) { |
| this._scroller = value; |
| } |
| }, |
| |
| _keyDownHandler: function _KeyboardBehavior_keyDownHandler(ev) { |
| if (!ev.altKey) { |
| if (_ElementUtilities._matchesSelector(ev.target, ".win-interactive, .win-interactive *")) { |
| return; |
| } |
| var newIndex = this.currentIndex; |
| var maxIndex = this._element.children.length - 1; |
| |
| var rtl = _ElementUtilities._getComputedStyle(this._element).direction === "rtl"; |
| var leftStr = rtl ? Key.rightArrow : Key.leftArrow; |
| var rightStr = rtl ? Key.leftArrow : Key.rightArrow; |
| |
| var targetIndex = this.getAdjacent && this.getAdjacent(newIndex, ev.keyCode); |
| if (+targetIndex === targetIndex) { |
| newIndex = targetIndex; |
| } else { |
| var modFixedSize = newIndex % this.fixedSize; |
| |
| if (ev.keyCode === leftStr) { |
| if (this.fixedDirection === _KeyboardBehavior.FixedDirection.width) { |
| if (modFixedSize !== 0) { |
| newIndex--; |
| } |
| } else { |
| if (newIndex >= this.fixedSize) { |
| newIndex -= this.fixedSize; |
| } |
| } |
| } else if (ev.keyCode === rightStr) { |
| if (this.fixedDirection === _KeyboardBehavior.FixedDirection.width) { |
| if (modFixedSize !== this.fixedSize - 1) { |
| newIndex++; |
| } |
| } else { |
| if (newIndex + this.fixedSize - modFixedSize <= maxIndex) { |
| newIndex += this.fixedSize; |
| } |
| } |
| } else if (ev.keyCode === Key.upArrow) { |
| if (this.fixedDirection === _KeyboardBehavior.FixedDirection.height) { |
| if (modFixedSize !== 0) { |
| newIndex--; |
| } |
| } else { |
| if (newIndex >= this.fixedSize) { |
| newIndex -= this.fixedSize; |
| } |
| } |
| } else if (ev.keyCode === Key.downArrow) { |
| if (this.fixedDirection === _KeyboardBehavior.FixedDirection.height) { |
| if (modFixedSize !== this.fixedSize - 1) { |
| newIndex++; |
| } |
| } else { |
| if (newIndex + this.fixedSize - modFixedSize <= maxIndex) { |
| newIndex += this.fixedSize; |
| } |
| } |
| } else if (ev.keyCode === Key.home) { |
| newIndex = 0; |
| } else if (ev.keyCode === Key.end) { |
| newIndex = this._element.children.length - 1; |
| } |
| } |
| |
| newIndex = Math.max(0, Math.min(this._element.children.length - 1, newIndex)); |
| |
| if (newIndex !== this.currentIndex) { |
| this._focus(newIndex, ev.keyCode); |
| |
| // Allow KeyboardBehavior to be nested |
| if (ev.keyCode === leftStr || ev.keyCode === rightStr || ev.keyCode === Key.upArrow || ev.keyCode === Key.downArrow) { |
| ev.stopPropagation(); |
| } |
| |
| ev.preventDefault(); |
| } |
| } |
| }, |
| |
| _getFocusInto: function _KeyboardBehavior_getFocusInto(elementToFocus, keyCode) { |
| return elementToFocus && elementToFocus.winControl && elementToFocus.winControl._getFocusInto ? |
| elementToFocus.winControl._getFocusInto(keyCode) : |
| elementToFocus; |
| }, |
| |
| _focus: function _KeyboardBehavior_focus(index, keyCode) { |
| index = (+index === index) ? index : this.currentIndex; |
| |
| var elementToFocus = this._element.children[index]; |
| if (elementToFocus) { |
| elementToFocus = this._getFocusInto(elementToFocus, keyCode); |
| |
| this.currentIndex = index; |
| |
| _ElementUtilities._setActive(elementToFocus, this.scroller); |
| } |
| }, |
| |
| _MSPointerDownHandler: function _KeyboardBehavior_MSPointerDownHandler(ev) { |
| var srcElement = ev.target; |
| if (srcElement === this.element) { |
| return; |
| } |
| |
| while (srcElement.parentNode !== this.element) { |
| srcElement = srcElement.parentNode; |
| } |
| |
| var index = -1; |
| while (srcElement) { |
| index++; |
| srcElement = srcElement.previousElementSibling; |
| } |
| |
| this.currentIndex = index; |
| } |
| }, { |
| FixedDirection: { |
| height: "height", |
| width: "width" |
| } |
| }); |
| |
| return _KeyboardBehavior; |
| }) |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_SafeHtml',[ |
| 'exports', |
| '../Core/_WinJS', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_ErrorFromName', |
| '../Core/_Resources' |
| ], function safeHTMLInit(exports, _WinJS, _Global, _Base, _ErrorFromName, _Resources) { |
| "use strict"; |
| |
| |
| var setInnerHTML, |
| setInnerHTMLUnsafe, |
| setOuterHTML, |
| setOuterHTMLUnsafe, |
| insertAdjacentHTML, |
| insertAdjacentHTMLUnsafe; |
| |
| var strings = { |
| get nonStaticHTML() { return "Unable to add dynamic content. A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property or the document.write method to add a script element will generate this exception. If the content is safe and from a trusted source, use a method to explicitly manipulate elements and attributes, such as createElement, or use setInnerHTMLUnsafe (or other unsafe method)."; }, |
| }; |
| |
| setInnerHTML = setInnerHTMLUnsafe = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setInnerHTML"> |
| /// <summary locid="WinJS.Utilities.setInnerHTML"> |
| /// Sets the innerHTML property of the specified element to the specified text. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.setInnerHTML_p:element"> |
| /// The element on which the innerHTML property is to be set. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.setInnerHTML_p:text"> |
| /// The value to be set to the innerHTML property. |
| /// </param> |
| /// </signature> |
| element.innerHTML = text; |
| }; |
| setOuterHTML = setOuterHTMLUnsafe = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setOuterHTML"> |
| /// <summary locid="WinJS.Utilities.setOuterHTML"> |
| /// Sets the outerHTML property of the specified element to the specified text. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.setOuterHTML_p:element"> |
| /// The element on which the outerHTML property is to be set. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.setOuterHTML_p:text"> |
| /// The value to be set to the outerHTML property. |
| /// </param> |
| /// </signature> |
| element.outerHTML = text; |
| }; |
| insertAdjacentHTML = insertAdjacentHTMLUnsafe = function (element, position, text) { |
| /// <signature helpKeyword="WinJS.Utilities.insertAdjacentHTML"> |
| /// <summary locid="WinJS.Utilities.insertAdjacentHTML"> |
| /// Calls insertAdjacentHTML on the specified element. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.insertAdjacentHTML_p:element"> |
| /// The element on which insertAdjacentHTML is to be called. |
| /// </param> |
| /// <param name="position" type="String" locid="WinJS.Utilities.insertAdjacentHTML_p:position"> |
| /// The position relative to the element at which to insert the HTML. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.insertAdjacentHTML_p:text"> |
| /// The value to be provided to insertAdjacentHTML. |
| /// </param> |
| /// </signature> |
| element.insertAdjacentHTML(position, text); |
| }; |
| |
| var msApp = _Global.MSApp; |
| if (msApp && msApp.execUnsafeLocalFunction) { |
| setInnerHTMLUnsafe = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setInnerHTMLUnsafe"> |
| /// <summary locid="WinJS.Utilities.setInnerHTMLUnsafe"> |
| /// Sets the innerHTML property of the specified element to the specified text. |
| /// </summary> |
| /// <param name='element' type='HTMLElement' locid="WinJS.Utilities.setInnerHTMLUnsafe_p:element"> |
| /// The element on which the innerHTML property is to be set. |
| /// </param> |
| /// <param name='text' type="String" locid="WinJS.Utilities.setInnerHTMLUnsafe_p:text"> |
| /// The value to be set to the innerHTML property. |
| /// </param> |
| /// </signature> |
| msApp.execUnsafeLocalFunction(function () { |
| try { |
| _WinJS._execUnsafe = true; |
| element.innerHTML = text; |
| } finally { |
| _WinJS._execUnsafe = false; |
| } |
| }); |
| }; |
| setOuterHTMLUnsafe = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setOuterHTMLUnsafe"> |
| /// <summary locid="WinJS.Utilities.setOuterHTMLUnsafe"> |
| /// Sets the outerHTML property of the specified element to the specified text |
| /// in the context of msWWA.execUnsafeLocalFunction. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.setOuterHTMLUnsafe_p:element"> |
| /// The element on which the outerHTML property is to be set. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.setOuterHTMLUnsafe_p:text"> |
| /// The value to be set to the outerHTML property. |
| /// </param> |
| /// </signature> |
| msApp.execUnsafeLocalFunction(function () { |
| try { |
| _WinJS._execUnsafe = true; |
| element.outerHTML = text; |
| } finally { |
| _WinJS._execUnsafe = false; |
| } |
| }); |
| }; |
| insertAdjacentHTMLUnsafe = function (element, position, text) { |
| /// <signature helpKeyword="WinJS.Utilities.insertAdjacentHTMLUnsafe"> |
| /// <summary locid="WinJS.Utilities.insertAdjacentHTMLUnsafe"> |
| /// Calls insertAdjacentHTML on the specified element in the context |
| /// of msWWA.execUnsafeLocalFunction. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.insertAdjacentHTMLUnsafe_p:element"> |
| /// The element on which insertAdjacentHTML is to be called. |
| /// </param> |
| /// <param name="position" type="String" locid="WinJS.Utilities.insertAdjacentHTMLUnsafe_p:position"> |
| /// The position relative to the element at which to insert the HTML. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.insertAdjacentHTMLUnsafe_p:text"> |
| /// Value to be provided to insertAdjacentHTML. |
| /// </param> |
| /// </signature> |
| msApp.execUnsafeLocalFunction(function () { |
| try { |
| _WinJS._execUnsafe = true; |
| element.insertAdjacentHTML(position, text); |
| } finally { |
| _WinJS._execUnsafe = false; |
| } |
| }); |
| }; |
| } else if (_Global.msIsStaticHTML) { |
| var check = function (str) { |
| if (!_Global.msIsStaticHTML(str)) { |
| throw new _ErrorFromName("WinJS.Utitilies.NonStaticHTML", strings.nonStaticHTML); |
| } |
| }; |
| // If we ever get isStaticHTML we can attempt to recreate the behavior we have in the local |
| // compartment, in the mean-time all we can do is sanitize the input. |
| // |
| setInnerHTML = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setInnerHTML"> |
| /// <summary locid="WinJS.Utilities.msIsStaticHTML.setInnerHTML"> |
| /// Sets the innerHTML property of a element to the specified text |
| /// if it passes a msIsStaticHTML check. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.msIsStaticHTML.setInnerHTML_p:element"> |
| /// The element on which the innerHTML property is to be set. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.msIsStaticHTML.setInnerHTML_p:text"> |
| /// The value to be set to the innerHTML property. |
| /// </param> |
| /// </signature> |
| check(text); |
| element.innerHTML = text; |
| }; |
| setOuterHTML = function (element, text) { |
| /// <signature helpKeyword="WinJS.Utilities.setOuterHTML"> |
| /// <summary locid="WinJS.Utilities.msIsStaticHTML.setOuterHTML"> |
| /// Sets the outerHTML property of a element to the specified text |
| /// if it passes a msIsStaticHTML check. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.msIsStaticHTML.setOuterHTML_p:element"> |
| /// The element on which the outerHTML property is to be set. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.msIsStaticHTML.setOuterHTML_p:text"> |
| /// The value to be set to the outerHTML property. |
| /// </param> |
| /// </signature> |
| check(text); |
| element.outerHTML = text; |
| }; |
| insertAdjacentHTML = function (element, position, text) { |
| /// <signature helpKeyword="WinJS.Utilities.insertAdjacentHTML"> |
| /// <summary locid="WinJS.Utilities.msIsStaticHTML.insertAdjacentHTML"> |
| /// Calls insertAdjacentHTML on the element if it passes |
| /// a msIsStaticHTML check. |
| /// </summary> |
| /// <param name="element" type="HTMLElement" locid="WinJS.Utilities.msIsStaticHTML.insertAdjacentHTML_p:element"> |
| /// The element on which insertAdjacentHTML is to be called. |
| /// </param> |
| /// <param name="position" type="String" locid="WinJS.Utilities.msIsStaticHTML.insertAdjacentHTML_p:position"> |
| /// The position relative to the element at which to insert the HTML. |
| /// </param> |
| /// <param name="text" type="String" locid="WinJS.Utilities.msIsStaticHTML.insertAdjacentHTML_p:text"> |
| /// The value to be provided to insertAdjacentHTML. |
| /// </param> |
| /// </signature> |
| check(text); |
| element.insertAdjacentHTML(position, text); |
| }; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| setInnerHTML: setInnerHTML, |
| setInnerHTMLUnsafe: setInnerHTMLUnsafe, |
| setOuterHTML: setOuterHTML, |
| setOuterHTMLUnsafe: setOuterHTMLUnsafe, |
| insertAdjacentHTML: insertAdjacentHTML, |
| insertAdjacentHTMLUnsafe: insertAdjacentHTMLUnsafe |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Select',[ |
| 'exports', |
| '../Core/_Base', |
| './_SafeHtml' |
| ], function selectInit(exports, _Base, _SafeHtml) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| _Select: _Base.Namespace._lazy(function () { |
| var encodeHtmlRegEx = /[&<>'"]/g; |
| var encodeHtmlEscapeMap = { |
| "&": "&", |
| "<": "<", |
| ">": ">", |
| "'": "'", |
| '"': """ |
| }; |
| var stringDirectionRegEx = /[\u200e\u200f]/g; |
| function encodeHtml(str) { |
| return str.replace(encodeHtmlRegEx, function (m) { |
| return encodeHtmlEscapeMap[m] || ""; |
| }); |
| } |
| function stripDirectionMarker(str) { |
| return str.replace(stringDirectionRegEx, ""); |
| } |
| function stockGetValue(index) { |
| /*jshint validthis: true */ |
| return this[index]; |
| } |
| function stockGetLength() { |
| /*jshint validthis: true */ |
| return this.length; |
| } |
| function fixDataSource(dataSource) { |
| if (!dataSource.getValue) { |
| dataSource.getValue = stockGetValue; |
| } |
| |
| if (!dataSource.getLength) { |
| dataSource.getLength = stockGetLength; |
| } |
| return dataSource; |
| } |
| |
| return _Base.Class.define(function _Select_ctor(element, options) { |
| // This is an implementation detail of the TimePicker and DatePicker, designed |
| // to provide a primitive "data bound" select control. This is not designed to |
| // be used outside of the TimePicker and DatePicker controls. |
| // |
| |
| this._dataSource = fixDataSource(options.dataSource); |
| this._index = options.index || 0; |
| |
| this._domElement = element; |
| // Mark this as a tab stop |
| this._domElement.tabIndex = 0; |
| |
| if (options.disabled) { |
| this.setDisabled(options.disabled); |
| } |
| |
| var that = this; |
| this._domElement.addEventListener("change", function () { |
| //Should be set to _index to prevent events from firing twice |
| that._index = that._domElement.selectedIndex; |
| }, false); |
| |
| //update runtime accessibility value after initialization |
| this._createSelectElement(); |
| }, { |
| _index: 0, |
| _dataSource: null, |
| |
| dataSource: { |
| get: function () { return this._dataSource; }, |
| set: function (value) { |
| this._dataSource = fixDataSource(value); |
| |
| //Update layout as data source change |
| if (this._domElement) { |
| this._createSelectElement(); |
| } |
| } |
| }, |
| |
| setDisabled: function (disabled) { |
| if (disabled) { |
| this._domElement.setAttribute("disabled", "disabled"); |
| } else { |
| this._domElement.removeAttribute("disabled"); |
| } |
| }, |
| |
| _createSelectElement: function () { |
| var dataSourceLength = this._dataSource.getLength(); |
| var text = ""; |
| for (var i = 0; i < dataSourceLength; i++) { |
| var value = "" + this._dataSource.getValue(i); |
| var escaped = encodeHtml(value); |
| // WinRT localization often tags the strings with reading direction. We want this |
| // for display text (escaped), but don't want this in the value space, as it |
| // only present for display. |
| // |
| var stripped = stripDirectionMarker(escaped); |
| text += "<option value='" + stripped + "'>" + escaped + "</option>"; |
| } |
| _SafeHtml.setInnerHTMLUnsafe(this._domElement, text); |
| this._domElement.selectedIndex = this._index; |
| }, |
| |
| index: { |
| get: function () { |
| return Math.max(0, Math.min(this._index, this._dataSource.getLength() - 1)); |
| }, |
| set: function (value) { |
| if (this._index !== value) { |
| this._index = value; |
| |
| var d = this._domElement; |
| if (d && d.selectedIndex !== value) { |
| d.selectedIndex = value; |
| } |
| } |
| } |
| }, |
| |
| value: { |
| get: function () { |
| return this._dataSource.getValue(this.index); |
| } |
| } |
| }); |
| }) |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Telemetry',[ |
| 'exports' |
| ], function telemetryInit(exports) { |
| "use strict"; |
| |
| /// NOTE: This file should be included when NOT building |
| /// Microsoft WinJS Framework Package which will be available in Windows Store. |
| |
| exports.send = function (name, params) { |
| /// <signature helpKeyword="WinJS._Telemetry.send"> |
| /// <summary locid="WinJS._Telemetry.send"> |
| /// Formatter to upload the name/value pair to Asimov in the correct format. |
| /// This will result in no-op when built outside of Microsoft Framework Package. |
| /// </summary> |
| /// <param name="params" type="Object" locid="WinJS._Telemetry.send_p:params"> |
| /// Object of name/value pair items that need to be logged. They can be of type, |
| /// bool, int32, string. Any other type will be ignored. |
| /// </param> |
| /// </signature> |
| /* empty */ |
| }; |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_UI',[ |
| 'exports', |
| '../Core/_BaseCoreUtils', |
| '../Core/_Base' |
| ], function uiInit(exports, _BaseCoreUtils, _Base) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| eventHandler: function (handler) { |
| /// <signature helpKeyword="WinJS.UI.eventHandler"> |
| /// <summary locid="WinJS.UI.eventHandler"> |
| /// Marks a event handler function as being compatible with declarative processing. |
| /// </summary> |
| /// <param name="handler" type="Object" locid="WinJS.UI.eventHandler_p:handler"> |
| /// The handler to be marked as compatible with declarative processing. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.UI.eventHandler_returnValue"> |
| /// The input handler. |
| /// </returns> |
| /// </signature> |
| return _BaseCoreUtils.markSupportedForProcessing(handler); |
| }, |
| /// <field locid="WinJS.UI.Orientation" helpKeyword="WinJS.UI.Orientation"> |
| /// Orientation options for a control's property |
| /// </field> |
| Orientation: { |
| /// <field locid="WinJS.UI.Orientation.horizontal" helpKeyword="WinJS.UI.Orientation.horizontal"> |
| /// Horizontal |
| /// </field> |
| horizontal: "horizontal", |
| /// <field locid="WinJS.UI.Orientation.vertical" helpKeyword="WinJS.UI.Orientation.vertical"> |
| /// Vertical |
| /// </field> |
| vertical: "vertical" |
| }, |
| |
| CountResult: { |
| unknown: "unknown" |
| }, |
| |
| CountError: { |
| noResponse: "noResponse" |
| }, |
| |
| DataSourceStatus: { |
| ready: "ready", |
| waiting: "waiting", |
| failure: "failure" |
| }, |
| |
| FetchError: { |
| noResponse: "noResponse", |
| doesNotExist: "doesNotExist" |
| }, |
| |
| EditError: { |
| noResponse: "noResponse", |
| canceled: "canceled", |
| notPermitted: "notPermitted", |
| noLongerMeaningful: "noLongerMeaningful" |
| }, |
| |
| /// <field locid="WinJS.UI.ListView.ObjectType" helpKeyword="WinJS.UI.ObjectType"> |
| /// Specifies the type of an IListViewEntity. |
| /// </field> |
| ObjectType: { |
| /// <field locid="WinJS.UI.ListView.ObjectType.item" helpKeyword="WinJS.UI.ObjectType.item"> |
| /// This value represents a ListView item. |
| /// </field> |
| item: "item", |
| /// <field locid="WinJS.UI.ListView.ObjectType.groupHeader" helpKeyword="WinJS.UI.ObjectType.groupHeader"> |
| /// This value represents a ListView group header. |
| /// </field> |
| groupHeader: "groupHeader", |
| /// <field locid="WinJS.UI.ListView.ObjectType.header" helpKeyword="WinJS.UI.ObjectType.header"> |
| /// This value represents the ListView's header. |
| /// </field> |
| header: "header", |
| /// <field locid="WinJS.UI.ListView.ObjectType.footer" helpKeyword="WinJS.UI.ObjectType.footer"> |
| /// This value represents the ListView's footer. |
| /// </field> |
| footer: "footer", |
| }, |
| |
| /// <field locid="WinJS.UI.ListView.SelectionMode" helpKeyword="WinJS.UI.SelectionMode"> |
| /// Specifies the selection mode for a ListView. |
| /// </field> |
| SelectionMode: { |
| /// <field locid="WinJS.UI.ListView.SelectionMode.none" helpKeyword="WinJS.UI.SelectionMode.none"> |
| /// Items cannot be selected. |
| /// </field> |
| none: "none", |
| /// <field locid="WinJS.UI.ListView.SelectionMode.single" helpKeyword="WinJS.UI.SelectionMode.single"> |
| /// A single item may be selected. |
| /// <compatibleWith platform="Windows" minVersion="8.0"/> |
| /// </field> |
| single: "single", |
| /// <field locid="WinJS.UI.ListView.SelectionMode.multi" helpKeyword="WinJS.UI.SelectionMode.multi"> |
| /// Multiple items may be selected. |
| /// </field> |
| multi: "multi" |
| }, |
| |
| /// <field locid="WinJS.UI.TapBehavior" helpKeyword="WinJS.UI.TapBehavior"> |
| /// Specifies how an ItemContainer or items in a ListView respond to the tap interaction. |
| /// </field> |
| TapBehavior: { |
| /// <field locid="WinJS.UI.TapBehavior.directSelect" helpKeyword="WinJS.UI.TapBehavior.directSelect"> |
| /// Tapping the item invokes it and selects it. Navigating to the item with the keyboard changes the |
| /// the selection so that the focused item is the only item that is selected. |
| /// <compatibleWith platform="Windows" minVersion="8.0"/> |
| /// </field> |
| directSelect: "directSelect", |
| /// <field locid="WinJS.UI.TapBehavior.toggleSelect" helpKeyword="WinJS.UI.TapBehavior.toggleSelect"> |
| /// Tapping the item invokes it. If the item was selected, tapping it clears the selection. If the item wasn't |
| /// selected, tapping the item selects it. |
| /// Navigating to the item with the keyboard does not select or invoke it. |
| /// </field> |
| toggleSelect: "toggleSelect", |
| /// <field locid="WinJS.UI.TapBehavior.invokeOnly" helpKeyword="WinJS.UI.TapBehavior.invokeOnly"> |
| /// Tapping the item invokes it. Navigating to the item with keyboard does not select it or invoke it. |
| /// </field> |
| invokeOnly: "invokeOnly", |
| /// <field locid="WinJS.UI.TapBehavior.none" helpKeyword="WinJS.UI.TapBehavior.none"> |
| /// Nothing happens. |
| /// </field> |
| none: "none" |
| }, |
| |
| /// <field locid="WinJS.UI.SwipeBehavior" helpKeyword="WinJS.UI.SwipeBehavior"> |
| /// Specifies whether items are selected when the user performs a swipe interaction. |
| /// <compatibleWith platform="Windows" minVersion="8.0"/> |
| /// </field> |
| SwipeBehavior: { |
| /// <field locid="WinJS.UI.SwipeBehavior.select" helpKeyword="WinJS.UI.SwipeBehavior.select"> |
| /// The swipe interaction selects the items touched by the swipe. |
| /// </field> |
| select: "select", |
| /// <field locid="WinJS.UI.SwipeBehavior.none" helpKeyword="WinJS.UI.SwipeBehavior.none"> |
| /// The swipe interaction does not change which items are selected. |
| /// </field> |
| none: "none" |
| }, |
| |
| /// <field locid="WinJS.UI.GroupHeaderTapBehavior" helpKeyword="WinJS.UI.GroupHeaderTapBehavior"> |
| /// Specifies how group headers in a ListView respond to the tap interaction. |
| /// </field> |
| GroupHeaderTapBehavior: { |
| /// <field locid="WinJS.UI.GroupHeaderTapBehavior.invoke" helpKeyword="WinJS.UI.GroupHeaderTapBehavior.invoke"> |
| /// Tapping the group header invokes it. |
| /// </field> |
| invoke: "invoke", |
| /// <field locid="WinJS.UI.GroupHeaderTapBehavior.none" helpKeyword="WinJS.UI.GroupHeaderTapBehavior.none"> |
| /// Nothing happens. |
| /// </field> |
| none: "none" |
| } |
| |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities/_Xhr',[ |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Promise', |
| '../Scheduler' |
| ], function xhrInit(_Global, _Base, Promise, Scheduler) { |
| "use strict"; |
| |
| function schedule(f, arg, priority) { |
| Scheduler.schedule(function xhr_callback() { |
| f(arg); |
| }, priority, null, "WinJS.xhr"); |
| } |
| |
| function noop() { |
| } |
| |
| var schemeRegex = /^(\w+)\:\/\//; |
| |
| function xhr(options) { |
| /// <signature helpKeyword="WinJS.xhr"> |
| /// <summary locid="WinJS.xhr"> |
| /// Wraps calls to XMLHttpRequest in a promise. |
| /// </summary> |
| /// <param name="options" type="Object" locid="WinJS.xhr_p:options"> |
| /// The options that are applied to the XMLHttpRequest object. They are: type, |
| /// url, user, password, headers, responseType, data, and customRequestInitializer. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.xhr_returnValue"> |
| /// A promise that returns the XMLHttpRequest object when it completes. |
| /// </returns> |
| /// </signature> |
| var req; |
| return new Promise( |
| function (c, e, p) { |
| /// <returns value="c(new XMLHttpRequest())" locid="WinJS.xhr.constructor._returnValue" /> |
| var priority = Scheduler.currentPriority; |
| req = new _Global.XMLHttpRequest(); |
| |
| var isLocalRequest = false; |
| var schemeMatch = schemeRegex.exec(options.url.toLowerCase()); |
| if (schemeMatch) { |
| if (schemeMatch[1] === 'file') { |
| isLocalRequest = true; |
| } |
| } else if (_Global.location.protocol === 'file:'){ |
| isLocalRequest = true; |
| } |
| |
| |
| req.onreadystatechange = function () { |
| if (req._canceled) { |
| req.onreadystatechange = noop; |
| return; |
| } |
| |
| if (req.readyState === 4) { |
| if ((req.status >= 200 && req.status < 300) || (isLocalRequest && req.status === 0)) { |
| schedule(c, req, priority); |
| } else { |
| schedule(e, req, priority); |
| } |
| req.onreadystatechange = noop; |
| } else { |
| schedule(p, req, priority); |
| } |
| }; |
| |
| req.open( |
| options.type || "GET", |
| options.url, |
| // Promise based XHR does not support sync. |
| // |
| true, |
| options.user, |
| options.password |
| ); |
| req.responseType = options.responseType || ""; |
| |
| Object.keys(options.headers || {}).forEach(function (k) { |
| req.setRequestHeader(k, options.headers[k]); |
| }); |
| |
| if (options.customRequestInitializer) { |
| options.customRequestInitializer(req); |
| } |
| |
| if (options.data === undefined) { |
| req.send(); |
| } else { |
| req.send(options.data); |
| } |
| }, |
| function () { |
| req.onreadystatechange = noop; |
| req._canceled = true; |
| req.abort(); |
| } |
| ); |
| } |
| |
| _Base.Namespace.define("WinJS", { |
| xhr: xhr |
| }); |
| |
| return xhr; |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Utilities',[ |
| './Utilities/_Control', |
| './Utilities/_Dispose', |
| './Utilities/_ElementListUtilities', |
| './Utilities/_ElementUtilities', |
| './Utilities/_Hoverable', |
| './Utilities/_ItemsManager', |
| './Utilities/_KeyboardBehavior', |
| './Utilities/_ParallelWorkQueue', |
| './Utilities/_SafeHtml', |
| './Utilities/_Select', |
| './Utilities/_TabContainer', |
| './Utilities/_Telemetry', |
| './Utilities/_UI', |
| './Utilities/_VersionManager', |
| './Utilities/_Xhr' ], function () { |
| |
| //wrapper module |
| }); |
| define('WinJS/XYFocus',["require", "exports", "./Core/_Global", "./Core/_Base", "./Core/_BaseUtils", "./Utilities/_ElementUtilities", "./Core/_Events", "./ControlProcessor/_OptionsParser"], function (require, exports, _Global, _Base, _BaseUtils, _ElementUtilities, _Events, _OptionsParser) { |
| "use strict"; |
| var Keys = _ElementUtilities.Key; |
| var AttributeNames = { |
| focusOverride: "data-win-xyfocus", |
| focusOverrideLegacy: "data-win-focus" |
| }; |
| var ClassNames = { |
| focusable: "win-focusable", |
| suspended: "win-xyfocus-suspended", |
| toggleMode: "win-xyfocus-togglemode", |
| toggleModeActive: "win-xyfocus-togglemode-active", |
| xboxPlatform: "win-xbox", |
| }; |
| var CrossDomainMessageConstants = { |
| messageDataProperty: "msWinJSXYFocusControlMessage", |
| register: "register", |
| unregister: "unregister", |
| dFocusEnter: "dFocusEnter", |
| dFocusExit: "dFocusExit" |
| }; |
| var DirectionNames = { |
| left: "left", |
| right: "right", |
| up: "up", |
| down: "down" |
| }; |
| var EventNames = { |
| focusChanging: "focuschanging", |
| focusChanged: "focuschanged" |
| }; |
| var FocusableTagNames = [ |
| "A", |
| "BUTTON", |
| "IFRAME", |
| "INPUT", |
| "SELECT", |
| "TEXTAREA" |
| ]; |
| // These factors can be tweaked to adjust which elements are favored by the focus algorithm |
| var ScoringConstants = { |
| primaryAxisDistanceWeight: 30, |
| secondaryAxisDistanceWeight: 20, |
| percentInHistoryShadowWeight: 100000 |
| }; |
| /** |
| * Gets the mapping object that maps keycodes to XYFocus actions. |
| **/ |
| exports.keyCodeMap = { |
| left: [], |
| right: [], |
| up: [], |
| down: [], |
| accept: [], |
| cancel: [], |
| }; |
| /** |
| * Gets or sets the focus root when invoking XYFocus APIs. |
| **/ |
| exports.focusRoot; |
| function findNextFocusElement(direction, options) { |
| var result = _findNextFocusElementInternal(direction, options); |
| return result ? result.target : null; |
| } |
| exports.findNextFocusElement = findNextFocusElement; |
| function moveFocus(direction, options) { |
| var result = findNextFocusElement(direction, options); |
| if (result) { |
| var previousFocusElement = _Global.document.activeElement; |
| if (_trySetFocus(result, -1)) { |
| eventSrc.dispatchEvent(EventNames.focusChanged, { previousFocusElement: previousFocusElement, keyCode: -1 }); |
| return result; |
| } |
| } |
| return null; |
| } |
| exports.moveFocus = moveFocus; |
| // Privates |
| var _lastTarget; |
| var _cachedLastTargetRect; |
| var _historyRect; |
| /** |
| * Executes XYFocus algorithm with the given parameters. Returns true if focus was moved, false otherwise. |
| * @param direction The direction to move focus. |
| * @param keyCode The key code of the pressed key. |
| * @param (optional) A rectangle to use as the source coordinates for finding the next focusable element. |
| * @param (optional) Indicates whether this focus request is allowed to propagate to its parent if we are in iframe. |
| **/ |
| function _xyFocus(direction, keyCode, referenceRect, dontExit) { |
| // If focus has moved since the last XYFocus movement, scrolling occured, or an explicit |
| // reference rectangle was given to us, then we invalidate the history rectangle. |
| if (referenceRect || _Global.document.activeElement !== _lastTarget) { |
| _historyRect = null; |
| _lastTarget = null; |
| _cachedLastTargetRect = null; |
| } |
| else if (_lastTarget && _cachedLastTargetRect) { |
| var lastTargetRect = _toIRect(_lastTarget.getBoundingClientRect()); |
| if (lastTargetRect.left !== _cachedLastTargetRect.left || lastTargetRect.top !== _cachedLastTargetRect.top) { |
| _historyRect = null; |
| _lastTarget = null; |
| _cachedLastTargetRect = null; |
| } |
| } |
| var activeElement = _Global.document.activeElement; |
| var lastTarget = _lastTarget; |
| var result = _findNextFocusElementInternal(direction, { |
| focusRoot: exports.focusRoot, |
| historyRect: _historyRect, |
| referenceElement: _lastTarget, |
| referenceRect: referenceRect |
| }); |
| if (result && _trySetFocus(result.target, keyCode)) { |
| // A focus target was found |
| updateHistoryRect(direction, result); |
| _lastTarget = result.target; |
| _cachedLastTargetRect = result.targetRect; |
| if (_ElementUtilities.hasClass(result.target, ClassNames.toggleMode)) { |
| _ElementUtilities.removeClass(result.target, ClassNames.toggleModeActive); |
| } |
| if (result.target.tagName === "IFRAME") { |
| var targetIframe = result.target; |
| if (IFrameHelper.isXYFocusEnabled(targetIframe)) { |
| // If we successfully moved focus and the new focused item is an IFRAME, then we need to notify it |
| // Note on coordinates: When signaling enter, DO transform the coordinates into the child frame's coordinate system. |
| var refRect = _toIRect({ |
| left: result.referenceRect.left - result.targetRect.left, |
| top: result.referenceRect.top - result.targetRect.top, |
| width: result.referenceRect.width, |
| height: result.referenceRect.height |
| }); |
| var message = {}; |
| message[CrossDomainMessageConstants.messageDataProperty] = { |
| type: CrossDomainMessageConstants.dFocusEnter, |
| direction: direction, |
| referenceRect: refRect |
| }; |
| // postMessage API is safe even in cross-domain scenarios. |
| targetIframe.contentWindow.postMessage(message, "*"); |
| } |
| } |
| eventSrc.dispatchEvent(EventNames.focusChanged, { previousFocusElement: activeElement, keyCode: keyCode }); |
| return true; |
| } |
| else { |
| // No focus target was found; if we are inside an IFRAME and focus is allowed to propagate out, notify the parent that focus is exiting this IFRAME |
| // Note on coordinates: When signaling exit, do NOT transform the coordinates into the parent's coordinate system. |
| if (!dontExit && top !== window) { |
| var refRect = referenceRect; |
| if (!refRect) { |
| refRect = _Global.document.activeElement ? _toIRect(_Global.document.activeElement.getBoundingClientRect()) : _defaultRect(); |
| } |
| var message = {}; |
| message[CrossDomainMessageConstants.messageDataProperty] = { |
| type: CrossDomainMessageConstants.dFocusExit, |
| direction: direction, |
| referenceRect: refRect |
| }; |
| // postMessage API is safe even in cross-domain scenarios. |
| _Global.parent.postMessage(message, "*"); |
| return true; |
| } |
| } |
| return false; |
| // Nested Helpers |
| function updateHistoryRect(direction, result) { |
| var newHistoryRect = _defaultRect(); |
| // It's possible to get into a situation where the target element has no overlap with the reference edge. |
| // |
| //..╔══════════════╗.......................... |
| //..║ reference ║.......................... |
| //..╚══════════════╝.......................... |
| //.....................╔═══════════════════╗.. |
| //.....................║ ║.. |
| //.....................║ target ║.. |
| //.....................║ ║.. |
| //.....................╚═══════════════════╝.. |
| // |
| // If that is the case, we need to reset the coordinates to the edge of the target element. |
| if (direction === DirectionNames.left || direction === DirectionNames.right) { |
| newHistoryRect.top = Math.max(result.targetRect.top, result.referenceRect.top, _historyRect ? _historyRect.top : Number.MIN_VALUE); |
| newHistoryRect.bottom = Math.min(result.targetRect.bottom, result.referenceRect.bottom, _historyRect ? _historyRect.bottom : Number.MAX_VALUE); |
| if (newHistoryRect.bottom <= newHistoryRect.top) { |
| newHistoryRect.top = result.targetRect.top; |
| newHistoryRect.bottom = result.targetRect.bottom; |
| } |
| newHistoryRect.height = newHistoryRect.bottom - newHistoryRect.top; |
| newHistoryRect.width = Number.MAX_VALUE; |
| newHistoryRect.left = Number.MIN_VALUE; |
| newHistoryRect.right = Number.MAX_VALUE; |
| } |
| else { |
| newHistoryRect.left = Math.max(result.targetRect.left, result.referenceRect.left, _historyRect ? _historyRect.left : Number.MIN_VALUE); |
| newHistoryRect.right = Math.min(result.targetRect.right, result.referenceRect.right, _historyRect ? _historyRect.right : Number.MAX_VALUE); |
| if (newHistoryRect.right <= newHistoryRect.left) { |
| newHistoryRect.left = result.targetRect.left; |
| newHistoryRect.right = result.targetRect.right; |
| } |
| newHistoryRect.width = newHistoryRect.right - newHistoryRect.left; |
| newHistoryRect.height = Number.MAX_VALUE; |
| newHistoryRect.top = Number.MIN_VALUE; |
| newHistoryRect.bottom = Number.MAX_VALUE; |
| } |
| _historyRect = newHistoryRect; |
| } |
| } |
| function _findNextFocusElementInternal(direction, options) { |
| options = options || {}; |
| options.focusRoot = options.focusRoot || exports.focusRoot || _Global.document.body; |
| options.historyRect = options.historyRect || _defaultRect(); |
| var maxDistance = Math.max(_Global.screen.availHeight, _Global.screen.availWidth); |
| var refObj = getReferenceObject(options.referenceElement, options.referenceRect); |
| // Handle override |
| if (refObj.element) { |
| var manualOverrideOptions = refObj.element.getAttribute(AttributeNames.focusOverride) || refObj.element.getAttribute(AttributeNames.focusOverrideLegacy); |
| if (manualOverrideOptions) { |
| var parsedOptions = _OptionsParser.optionsParser(manualOverrideOptions); |
| // The left-hand side can be cased as either "left" or "Left". |
| var selector = parsedOptions[direction] || parsedOptions[direction[0].toUpperCase() + direction.substr(1)]; |
| if (selector) { |
| var target; |
| var element = refObj.element; |
| while (!target && element) { |
| target = element.querySelector(selector); |
| element = element.parentElement; |
| } |
| if (target) { |
| if (target === _Global.document.activeElement) { |
| return null; |
| } |
| return { target: target, targetRect: _toIRect(target.getBoundingClientRect()), referenceRect: refObj.rect, usedOverride: true }; |
| } |
| } |
| } |
| } |
| // Calculate scores for each element in the root |
| var bestPotential = { |
| element: null, |
| rect: null, |
| score: 0 |
| }; |
| var allElements = options.focusRoot.querySelectorAll("*"); |
| for (var i = 0, length = allElements.length; i < length; i++) { |
| var potentialElement = allElements[i]; |
| if (refObj.element === potentialElement || !_isFocusable(potentialElement) || _isInInactiveToggleModeContainer(potentialElement)) { |
| continue; |
| } |
| var potentialRect = _toIRect(potentialElement.getBoundingClientRect()); |
| // Skip elements that have either a width of zero or a height of zero |
| if (potentialRect.width === 0 || potentialRect.height === 0) { |
| continue; |
| } |
| var score = calculateScore(direction, maxDistance, options.historyRect, refObj.rect, potentialRect); |
| if (score > bestPotential.score) { |
| bestPotential.element = potentialElement; |
| bestPotential.rect = potentialRect; |
| bestPotential.score = score; |
| } |
| } |
| return bestPotential.element ? { target: bestPotential.element, targetRect: bestPotential.rect, referenceRect: refObj.rect, usedOverride: false } : null; |
| // Nested Helpers |
| function calculatePercentInShadow(minReferenceCoord, maxReferenceCoord, minPotentialCoord, maxPotentialCoord) { |
| /// Calculates the percentage of the potential element that is in the shadow of the reference element. |
| if ((minReferenceCoord >= maxPotentialCoord) || (maxReferenceCoord <= minPotentialCoord)) { |
| // Potential is not in the reference's shadow. |
| return 0; |
| } |
| var pixelOverlap = Math.min(maxReferenceCoord, maxPotentialCoord) - Math.max(minReferenceCoord, minPotentialCoord); |
| var shortEdge = Math.min(maxPotentialCoord - minPotentialCoord, maxReferenceCoord - minReferenceCoord); |
| return shortEdge === 0 ? 0 : (pixelOverlap / shortEdge); |
| } |
| function calculateScore(direction, maxDistance, historyRect, referenceRect, potentialRect) { |
| var score = 0; |
| var percentInShadow; |
| var primaryAxisDistance; |
| var secondaryAxisDistance = 0; |
| var percentInHistoryShadow = 0; |
| switch (direction) { |
| case DirectionNames.left: |
| // Make sure we don't evaluate any potential elements to the right of the reference element |
| if (potentialRect.left >= referenceRect.left) { |
| break; |
| } |
| percentInShadow = calculatePercentInShadow(referenceRect.top, referenceRect.bottom, potentialRect.top, potentialRect.bottom); |
| primaryAxisDistance = referenceRect.left - potentialRect.right; |
| if (percentInShadow > 0) { |
| percentInHistoryShadow = calculatePercentInShadow(historyRect.top, historyRect.bottom, potentialRect.top, potentialRect.bottom); |
| } |
| else { |
| // If the potential element is not in the shadow, then we calculate secondary axis distance |
| secondaryAxisDistance = (referenceRect.bottom <= potentialRect.top) ? (potentialRect.top - referenceRect.bottom) : referenceRect.top - potentialRect.bottom; |
| } |
| break; |
| case DirectionNames.right: |
| // Make sure we don't evaluate any potential elements to the left of the reference element |
| if (potentialRect.right <= referenceRect.right) { |
| break; |
| } |
| percentInShadow = calculatePercentInShadow(referenceRect.top, referenceRect.bottom, potentialRect.top, potentialRect.bottom); |
| primaryAxisDistance = potentialRect.left - referenceRect.right; |
| if (percentInShadow > 0) { |
| percentInHistoryShadow = calculatePercentInShadow(historyRect.top, historyRect.bottom, potentialRect.top, potentialRect.bottom); |
| } |
| else { |
| // If the potential element is not in the shadow, then we calculate secondary axis distance |
| secondaryAxisDistance = (referenceRect.bottom <= potentialRect.top) ? (potentialRect.top - referenceRect.bottom) : referenceRect.top - potentialRect.bottom; |
| } |
| break; |
| case DirectionNames.up: |
| // Make sure we don't evaluate any potential elements below the reference element |
| if (potentialRect.top >= referenceRect.top) { |
| break; |
| } |
| percentInShadow = calculatePercentInShadow(referenceRect.left, referenceRect.right, potentialRect.left, potentialRect.right); |
| primaryAxisDistance = referenceRect.top - potentialRect.bottom; |
| if (percentInShadow > 0) { |
| percentInHistoryShadow = calculatePercentInShadow(historyRect.left, historyRect.right, potentialRect.left, potentialRect.right); |
| } |
| else { |
| // If the potential element is not in the shadow, then we calculate secondary axis distance |
| secondaryAxisDistance = (referenceRect.right <= potentialRect.left) ? (potentialRect.left - referenceRect.right) : referenceRect.left - potentialRect.right; |
| } |
| break; |
| case DirectionNames.down: |
| // Make sure we don't evaluate any potential elements above the reference element |
| if (potentialRect.bottom <= referenceRect.bottom) { |
| break; |
| } |
| percentInShadow = calculatePercentInShadow(referenceRect.left, referenceRect.right, potentialRect.left, potentialRect.right); |
| primaryAxisDistance = potentialRect.top - referenceRect.bottom; |
| if (percentInShadow > 0) { |
| percentInHistoryShadow = calculatePercentInShadow(historyRect.left, historyRect.right, potentialRect.left, potentialRect.right); |
| } |
| else { |
| // If the potential element is not in the shadow, then we calculate secondary axis distance |
| secondaryAxisDistance = (referenceRect.right <= potentialRect.left) ? (potentialRect.left - referenceRect.right) : referenceRect.left - potentialRect.right; |
| } |
| break; |
| } |
| if (primaryAxisDistance >= 0) { |
| // The score needs to be a positive number so we make these distances positive numbers |
| primaryAxisDistance = maxDistance - primaryAxisDistance; |
| secondaryAxisDistance = maxDistance - secondaryAxisDistance; |
| if (primaryAxisDistance >= 0 && secondaryAxisDistance >= 0) { |
| // Potential elements in the shadow get a multiplier to their final score |
| primaryAxisDistance += primaryAxisDistance * percentInShadow; |
| score = primaryAxisDistance * ScoringConstants.primaryAxisDistanceWeight + secondaryAxisDistance * ScoringConstants.secondaryAxisDistanceWeight + percentInHistoryShadow * ScoringConstants.percentInHistoryShadowWeight; |
| } |
| } |
| return score; |
| } |
| function getReferenceObject(referenceElement, referenceRect) { |
| var refElement; |
| var refRect; |
| if ((!referenceElement && !referenceRect) || (referenceElement && !referenceElement.parentNode)) { |
| // Note: We need to check to make sure 'parentNode' is not null otherwise there is a case |
| // where _lastTarget is defined, but calling getBoundingClientRect will throw a native exception. |
| // This case happens if the innerHTML of the parent of the _lastTarget is set to "". |
| // If no valid reference is supplied, we'll use _Global.document.activeElement unless it's the body |
| if (_Global.document.activeElement !== _Global.document.body) { |
| referenceElement = _Global.document.activeElement; |
| } |
| } |
| if (referenceElement) { |
| refElement = referenceElement; |
| refRect = _toIRect(refElement.getBoundingClientRect()); |
| } |
| else if (referenceRect) { |
| refRect = _toIRect(referenceRect); |
| } |
| else { |
| refRect = _defaultRect(); |
| } |
| return { |
| element: refElement, |
| rect: refRect |
| }; |
| } |
| } |
| function _defaultRect() { |
| // We set the top, left, bottom and right properties of the referenceBoundingRectangle to '-1' |
| // (as opposed to '0') because we want to make sure that even elements that are up to the edge |
| // of the screen can receive focus. |
| return { |
| top: -1, |
| bottom: -1, |
| right: -1, |
| left: -1, |
| height: 0, |
| width: 0 |
| }; |
| } |
| function _toIRect(rect) { |
| return { |
| top: Math.floor(rect.top), |
| bottom: Math.floor(rect.top + rect.height), |
| right: Math.floor(rect.left + rect.width), |
| left: Math.floor(rect.left), |
| height: Math.floor(rect.height), |
| width: Math.floor(rect.width), |
| }; |
| } |
| function _trySetFocus(element, keyCode) { |
| // We raise an event on the focusRoot before focus changes to give listeners |
| // a chance to prevent the next focus target from receiving focus if they want. |
| var canceled = eventSrc.dispatchEvent(EventNames.focusChanging, { nextFocusElement: element, keyCode: keyCode }); |
| if (!canceled) { |
| element.focus(); |
| } |
| return _Global.document.activeElement === element; |
| } |
| function _isFocusable(element) { |
| var elementTagName = element.tagName; |
| if (!element.hasAttribute("tabindex") && FocusableTagNames.indexOf(elementTagName) === -1 && !_ElementUtilities.hasClass(element, ClassNames.focusable)) { |
| // If the current potential element is not one of the tags we consider to be focusable, then exit |
| return false; |
| } |
| if (elementTagName === "IFRAME" && !IFrameHelper.isXYFocusEnabled(element)) { |
| // Skip IFRAMEs without compatible XYFocus implementation |
| return false; |
| } |
| if (elementTagName === "DIV" && element["winControl"] && element["winControl"].disabled) { |
| // Skip disabled WinJS controls |
| return false; |
| } |
| var style = _ElementUtilities._getComputedStyle(element); |
| if (element.getAttribute("tabIndex") === "-1" || style.display === "none" || style.visibility === "hidden" || element.disabled) { |
| // Skip elements that are hidden |
| // Note: We don't check for opacity === 0, because the browser cannot tell us this value accurately. |
| return false; |
| } |
| return true; |
| } |
| function _findParentToggleModeContainer(element) { |
| var toggleModeRoot = element.parentElement; |
| while (toggleModeRoot && !_isToggleMode(toggleModeRoot)) { |
| toggleModeRoot = toggleModeRoot.parentElement; |
| } |
| return toggleModeRoot; |
| } |
| function _isInInactiveToggleModeContainer(element) { |
| var container = _findParentToggleModeContainer(element); |
| return container && !_ElementUtilities.hasClass(container, ClassNames.toggleModeActive); |
| } |
| function _isToggleMode(element) { |
| if (_ElementUtilities.hasClass(element, ClassNames.toggleMode)) { |
| return true; |
| } |
| if (element.tagName === "INPUT") { |
| var inputType = element.type.toLowerCase(); |
| if (inputType === "date" || inputType === "datetime" || inputType === "datetime-local" || inputType === "email" || inputType === "month" || inputType === "number" || inputType === "password" || inputType === "range" || inputType === "search" || inputType === "tel" || inputType === "text" || inputType === "time" || inputType === "url" || inputType === "week") { |
| return true; |
| } |
| } |
| else if (element.tagName === "TEXTAREA") { |
| return true; |
| } |
| return false; |
| } |
| function _getStateHandler(element) { |
| var suspended = false; |
| var toggleMode = false; |
| var toggleModeActive = false; |
| if (element) { |
| suspended = _ElementUtilities._matchesSelector(element, "." + ClassNames.suspended + ", ." + ClassNames.suspended + " *"); |
| toggleMode = _isToggleMode(element); |
| toggleModeActive = _ElementUtilities.hasClass(element, ClassNames.toggleModeActive); |
| } |
| var stateHandler = KeyHandlerStates.RestState; |
| if (suspended) { |
| stateHandler = KeyHandlerStates.SuspendedState; |
| } |
| else { |
| if (toggleMode) { |
| if (toggleModeActive) { |
| stateHandler = KeyHandlerStates.ToggleModeActiveState; |
| } |
| else { |
| stateHandler = KeyHandlerStates.ToggleModeRestState; |
| } |
| } |
| } |
| return stateHandler; |
| } |
| function _handleKeyEvent(e) { |
| if (e.defaultPrevented) { |
| return; |
| } |
| var stateHandler = _getStateHandler(document.activeElement); |
| var direction = ""; |
| if (exports.keyCodeMap.up.indexOf(e.keyCode) !== -1) { |
| direction = "up"; |
| } |
| else if (exports.keyCodeMap.down.indexOf(e.keyCode) !== -1) { |
| direction = "down"; |
| } |
| else if (exports.keyCodeMap.left.indexOf(e.keyCode) !== -1) { |
| direction = "left"; |
| } |
| else if (exports.keyCodeMap.right.indexOf(e.keyCode) !== -1) { |
| direction = "right"; |
| } |
| if (direction) { |
| var shouldPreventDefault = stateHandler.xyFocus(direction, e.keyCode); |
| if (shouldPreventDefault) { |
| e.preventDefault(); |
| } |
| } |
| } |
| function _handleCaptureKeyEvent(e) { |
| if (e.defaultPrevented) { |
| return; |
| } |
| var activeElement = document.activeElement; |
| var shouldPreventDefault = false; |
| var stateHandler = _getStateHandler(document.activeElement); |
| if (exports.keyCodeMap.accept.indexOf(e.keyCode) !== -1) { |
| shouldPreventDefault = stateHandler.accept(activeElement); |
| } |
| else if (exports.keyCodeMap.cancel.indexOf(e.keyCode) !== -1) { |
| shouldPreventDefault = stateHandler.cancel(activeElement); |
| } |
| if (shouldPreventDefault) { |
| e.preventDefault(); |
| } |
| } |
| var KeyHandlerStates; |
| (function (KeyHandlerStates) { |
| // Element is not suspended and does not use toggle mode. |
| var RestState = (function () { |
| function RestState() { |
| } |
| RestState.accept = _clickElement; |
| RestState.cancel = _nop; |
| RestState.xyFocus = _xyFocus; // Prevent default when XYFocus moves focus |
| return RestState; |
| })(); |
| KeyHandlerStates.RestState = RestState; |
| // Element has opted out of XYFocus. |
| var SuspendedState = (function () { |
| function SuspendedState() { |
| } |
| SuspendedState.accept = _nop; |
| SuspendedState.cancel = _nop; |
| SuspendedState.xyFocus = _nop; |
| return SuspendedState; |
| })(); |
| KeyHandlerStates.SuspendedState = SuspendedState; |
| // Element uses toggle mode but is not toggled nor opted out of XYFocus. |
| var ToggleModeRestState = (function () { |
| function ToggleModeRestState() { |
| } |
| ToggleModeRestState.accept = function (element) { |
| _ElementUtilities.addClass(element, ClassNames.toggleModeActive); |
| return true; |
| }; |
| ToggleModeRestState.cancel = _nop; |
| ToggleModeRestState.xyFocus = _xyFocus; // Prevent default when XYFocus moves focus |
| return ToggleModeRestState; |
| })(); |
| KeyHandlerStates.ToggleModeRestState = ToggleModeRestState; |
| // Element uses toggle mode and is toggled and did not opt out of XYFocus. |
| var ToggleModeActiveState = (function () { |
| function ToggleModeActiveState() { |
| } |
| ToggleModeActiveState.cancel = function (element) { |
| element && _ElementUtilities.removeClass(element, ClassNames.toggleModeActive); |
| return true; |
| }; |
| ToggleModeActiveState.accept = _clickElement; |
| ToggleModeActiveState.xyFocus = _nop; |
| return ToggleModeActiveState; |
| })(); |
| KeyHandlerStates.ToggleModeActiveState = ToggleModeActiveState; |
| function _clickElement(element) { |
| element && element.click && element.click(); |
| return false; |
| } |
| function _nop() { |
| var args = []; |
| for (var _i = 0; _i < arguments.length; _i++) { |
| args[_i - 0] = arguments[_i]; |
| } |
| return false; |
| } |
| })(KeyHandlerStates || (KeyHandlerStates = {})); |
| var IFrameHelper; |
| (function (IFrameHelper) { |
| // XYFocus caches registered iframes and iterates over the cache for its focus navigation implementation. |
| // However, since there is no reliable way for an iframe to unregister with its parent as it can be |
| // spontaneously taken out of the DOM, the cache can go stale. This helper module makes sure that on |
| // every query to the iframe cache, stale iframes are removed. |
| // Furthermore, merely accessing an iframe that has been garbage collected by the platform will cause an |
| // exception so each iteration during a query must be in a try/catch block. |
| var iframes = []; |
| function count() { |
| // Iterating over it causes stale iframes to be cleared from the cache. |
| _safeForEach(function () { return false; }); |
| return iframes.length; |
| } |
| IFrameHelper.count = count; |
| function getIFrameFromWindow(win) { |
| var iframes = _Global.document.querySelectorAll("IFRAME"); |
| var found = Array.prototype.filter.call(iframes, function (x) { return x.contentWindow === win; }); |
| return found.length ? found[0] : null; |
| } |
| IFrameHelper.getIFrameFromWindow = getIFrameFromWindow; |
| function isXYFocusEnabled(iframe) { |
| var found = false; |
| _safeForEach(function (ifr) { |
| if (ifr === iframe) { |
| found = true; |
| } |
| }); |
| return found; |
| } |
| IFrameHelper.isXYFocusEnabled = isXYFocusEnabled; |
| function registerIFrame(iframe) { |
| iframes.push(iframe); |
| } |
| IFrameHelper.registerIFrame = registerIFrame; |
| function unregisterIFrame(iframe) { |
| var index = -1; |
| _safeForEach(function (ifr, i) { |
| if (ifr === iframe) { |
| index = i; |
| } |
| }); |
| if (index !== -1) { |
| iframes.splice(index, 1); |
| } |
| } |
| IFrameHelper.unregisterIFrame = unregisterIFrame; |
| function _safeForEach(callback) { |
| for (var i = iframes.length - 1; i >= 0; i--) { |
| try { |
| var iframe = iframes[i]; |
| if (!iframe.contentWindow) { |
| iframes.splice(i, 1); |
| } |
| else { |
| callback(iframe, i); |
| } |
| } |
| catch (e) { |
| // Iframe has been GC'd |
| iframes.splice(i, 1); |
| } |
| } |
| } |
| })(IFrameHelper || (IFrameHelper = {})); |
| if (_Global.document) { |
| // Note: This module is not supported in WebWorker |
| // Default mappings |
| exports.keyCodeMap.left.push(Keys.GamepadLeftThumbstickLeft, Keys.GamepadDPadLeft, Keys.NavigationLeft); |
| exports.keyCodeMap.right.push(Keys.GamepadLeftThumbstickRight, Keys.GamepadDPadRight, Keys.NavigationRight); |
| exports.keyCodeMap.up.push(Keys.GamepadLeftThumbstickUp, Keys.GamepadDPadUp, Keys.NavigationUp); |
| exports.keyCodeMap.down.push(Keys.GamepadLeftThumbstickDown, Keys.GamepadDPadDown, Keys.NavigationDown); |
| exports.keyCodeMap.accept.push(Keys.GamepadA, Keys.NavigationAccept); |
| exports.keyCodeMap.cancel.push(Keys.GamepadB, Keys.NavigationCancel); |
| _Global.addEventListener("message", function (e) { |
| // Note: e.source is the Window object of an iframe which could be hosting content |
| // from a different domain. No properties on e.source should be accessed or we may |
| // run into a cross-domain access violation exception. |
| var sourceWindow = null; |
| try { |
| // Since messages are async, by the time we get this message, the iframe could've |
| // been removed from the DOM and e.source is null or throws an exception on access. |
| sourceWindow = e.source; |
| if (!sourceWindow) { |
| return; |
| } |
| } |
| catch (e) { |
| return; |
| } |
| if (!e.data || !e.data[CrossDomainMessageConstants.messageDataProperty]) { |
| return; |
| } |
| var data = e.data[CrossDomainMessageConstants.messageDataProperty]; |
| switch (data.type) { |
| case CrossDomainMessageConstants.register: |
| var iframe = IFrameHelper.getIFrameFromWindow(sourceWindow); |
| iframe && IFrameHelper.registerIFrame(iframe); |
| break; |
| case CrossDomainMessageConstants.unregister: |
| var iframe = IFrameHelper.getIFrameFromWindow(sourceWindow); |
| iframe && IFrameHelper.unregisterIFrame(iframe); |
| break; |
| case CrossDomainMessageConstants.dFocusEnter: |
| // The coordinates stored in data.refRect are already in this frame's coordinate system. |
| // First try to focus anything within this iframe without leaving the current frame. |
| var focused = _xyFocus(data.direction, -1, data.referenceRect, true); |
| if (!focused) { |
| // No focusable element was found, we'll focus document.body if it is focusable. |
| if (_isFocusable(_Global.document.body)) { |
| _Global.document.body.focus(); |
| } |
| else { |
| // Nothing within this iframe is focusable, we call _xyFocus again without a refRect |
| // and allow the request to propagate to the parent. |
| _xyFocus(data.direction, -1); |
| } |
| } |
| break; |
| case CrossDomainMessageConstants.dFocusExit: |
| var iframe = IFrameHelper.getIFrameFromWindow(sourceWindow); |
| if (_Global.document.activeElement !== iframe) { |
| break; |
| } |
| // The coordinates stored in data.refRect are in the IFRAME's coordinate system, |
| // so we must first transform them into this frame's coordinate system. |
| var refRect = data.referenceRect; |
| var iframeRect = iframe.getBoundingClientRect(); |
| refRect.left += iframeRect.left; |
| refRect.top += iframeRect.top; |
| if (typeof refRect.right === "number") { |
| refRect.right += iframeRect.left; |
| } |
| if (typeof refRect.bottom === "number") { |
| refRect.bottom += iframeRect.top; |
| } |
| _xyFocus(data.direction, -1, refRect); |
| break; |
| } |
| }); |
| _BaseUtils.ready().then(function () { |
| if (_ElementUtilities.hasWinRT && _Global["Windows"] && _Global["Windows"]["Xbox"]) { |
| _ElementUtilities.addClass(_Global.document.body, ClassNames.xboxPlatform); |
| } |
| // Subscribe on capture phase to prevent this key event from interacting with |
| // the element/control if XYFocus handled it for accept/cancel keys. |
| _Global.document.addEventListener("keydown", _handleCaptureKeyEvent, true); |
| // Subscribe on bubble phase to allow developers to override XYFocus behaviors for directional keys. |
| _Global.document.addEventListener("keydown", _handleKeyEvent); |
| // If we are running within an iframe, we send a registration message to the parent window |
| if (_Global.top !== _Global.window) { |
| var message = {}; |
| message[CrossDomainMessageConstants.messageDataProperty] = { |
| type: CrossDomainMessageConstants.register, |
| version: 1.0 |
| }; |
| _Global.parent.postMessage(message, "*"); |
| } |
| }); |
| // Publish to WinJS namespace |
| var toPublish = { |
| focusRoot: { |
| get: function () { |
| return exports.focusRoot; |
| }, |
| set: function (value) { |
| exports.focusRoot = value; |
| } |
| }, |
| findNextFocusElement: findNextFocusElement, |
| keyCodeMap: exports.keyCodeMap, |
| moveFocus: moveFocus, |
| onfocuschanged: _Events._createEventProperty(EventNames.focusChanged), |
| onfocuschanging: _Events._createEventProperty(EventNames.focusChanging), |
| _xyFocus: _xyFocus, |
| _iframeHelper: IFrameHelper |
| }; |
| toPublish = _BaseUtils._merge(toPublish, _Events.eventMixin); |
| toPublish["_listeners"] = {}; |
| var eventSrc = toPublish; |
| _Base.Namespace.define("WinJS.UI.XYFocus", toPublish); |
| } |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Fragments',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_WinRT', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_ErrorFromName', |
| './Core/_Resources', |
| './Core/_WriteProfilerMark', |
| './Promise', |
| './Utilities/_ElementUtilities', |
| './Utilities/_SafeHtml', |
| './Utilities/_Xhr' |
| ], function fragmentLoaderInit(exports, _Global, _WinRT, _Base, _BaseUtils, _ErrorFromName, _Resources, _WriteProfilerMark, Promise, _ElementUtilities, _SafeHtml, _Xhr) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var forEach = function (arrayLikeValue, action) { |
| for (var i = 0, l = arrayLikeValue.length; i < l; i++) { |
| action(arrayLikeValue[i], i); |
| } |
| }; |
| var head = _Global.document.head || _Global.document.getElementsByTagName("head")[0]; |
| var scripts = {}; |
| var styles = {}; |
| var links = {}; |
| var initialized = false; |
| var cacheStore = {}; |
| var uniqueId = 1; |
| |
| function addScript(scriptTag, fragmentHref, position, lastNonInlineScriptPromise) { |
| // We synthesize a name for inline scripts because today we put the |
| // inline scripts in the same processing pipeline as src scripts. If |
| // we seperated inline scripts into their own logic, we could simplify |
| // this somewhat. |
| // |
| var src = scriptTag.src; |
| var inline = !src; |
| if (inline) { |
| src = fragmentHref + "script[" + position + "]"; |
| } |
| src = src.toLowerCase(); |
| |
| if (!(src in scripts)) { |
| var promise = null; |
| |
| scripts[src] = true; |
| var n = _Global.document.createElement("script"); |
| if (scriptTag.language) { |
| n.setAttribute("language", "javascript"); |
| } |
| n.setAttribute("type", scriptTag.type); |
| n.setAttribute("async", "false"); |
| if (scriptTag.id) { |
| n.setAttribute("id", scriptTag.id); |
| } |
| if (inline) { |
| var text = scriptTag.text; |
| promise = lastNonInlineScriptPromise.then(function () { |
| n.text = text; |
| }).then(null, function () { |
| // eat error |
| }); |
| } else { |
| promise = new Promise(function (c) { |
| n.onload = n.onerror = function () { |
| c(); |
| }; |
| |
| // Using scriptTag.src to maintain the original casing |
| n.setAttribute("src", scriptTag.src); |
| }); |
| } |
| head.appendChild(n); |
| |
| return { |
| promise: promise, |
| inline: inline, |
| }; |
| } |
| } |
| |
| function addStyle(styleTag, fragmentHref, position) { |
| var src = (fragmentHref + "script[" + position + "]").toLowerCase(); |
| if (!(src in styles)) { |
| styles[src] = true; |
| head.appendChild(styleTag.cloneNode(true)); |
| } |
| } |
| |
| function addLink(styleTag) { |
| var src = styleTag.href.toLowerCase(); |
| if (!(src in links)) { |
| links[src] = true; |
| var n = styleTag.cloneNode(false); |
| |
| // Using scriptTag.href to maintain the original casing |
| n.href = styleTag.href; |
| head.appendChild(n); |
| } |
| } |
| |
| function getStateRecord(href, removeFromCache) { |
| if (typeof href === "string") { |
| return loadFromCache(href, removeFromCache); |
| } else { |
| var state = { |
| docfrag: _ElementUtilities.data(href).docFragment |
| }; |
| if (!state.docfrag) { |
| var fragment = _Global.document.createDocumentFragment(); |
| while (href.childNodes.length > 0) { |
| fragment.appendChild(href.childNodes[0]); |
| } |
| state.docfrag = _ElementUtilities.data(href).docFragment = fragment; |
| href.setAttribute("data-win-hasfragment", ""); |
| } |
| if (removeFromCache) { |
| clearCache(href); |
| } |
| return Promise.as(state); |
| } |
| } |
| function createEntry(state, href) { |
| return populateDocument(state, href). |
| then(function () { |
| if (state.document) { |
| return processDocument(href, state); |
| } else { |
| return state; |
| } |
| }). |
| then(function () { |
| if (state.document) { |
| delete state.document; |
| } |
| return state; |
| }); |
| } |
| |
| function loadFromCache(href, removeFromCache) { |
| var fragmentId = href.toLowerCase(); |
| var state = cacheStore[fragmentId]; |
| |
| if (state) { |
| if (removeFromCache) { |
| delete cacheStore[fragmentId]; |
| } |
| if (state.promise) { |
| return state.promise; |
| } else { |
| return Promise.as(state); |
| } |
| } else { |
| state = {}; |
| if (!removeFromCache) { |
| cacheStore[fragmentId] = state; |
| } |
| var result = state.promise = createEntry(state, href); |
| state.promise.then(function () { delete state.promise; }); |
| return result; |
| } |
| } |
| |
| function processDocument(href, state) { |
| // Once the control's static state has been loaded in the temporary iframe, |
| // this method spelunks the iframe's document to retrieve all relevant information. Also, |
| // this performs any needed fixups on the DOM (like adjusting relative URLs). |
| |
| var cd = state.document; |
| var b = cd.body; |
| var sp = []; |
| |
| forEach(cd.querySelectorAll('link[rel="stylesheet"], link[type="text/css"]'), addLink); |
| forEach(cd.getElementsByTagName('style'), function (e, i) { addStyle(e, href, i); }); |
| |
| // In DOCMODE 11 IE moved to the standards based script loading behavior of |
| // having out-of-line script elements which are dynamically added to the DOM |
| // asynchronously load. This raises two problems for our fragment loader, |
| // |
| // 1) out-of-line scripts need to execute in order |
| // |
| // 2) so do in-line scripts. |
| // |
| // In order to mitigate this behavior we do two things: |
| // |
| // A) We mark all scripts with the attribute async='false' which makes |
| // out-of-line scripts respect DOM append order for execution when they |
| // are eventually retrieved |
| // |
| // B) We chain the setting of in-line script element's 'text' property |
| // on the completion of the previous out-of-line script's execution. |
| // This relies on the fact that the out-of-line script elements will |
| // synchronously run their onload handler immediately after executing |
| // thus assuring that the in-line script will run before the next |
| // trailing out-of-line script. |
| // |
| var lastNonInlineScriptPromise = Promise.as(); |
| forEach(cd.getElementsByTagName('script'), function (e, i) { |
| var result = addScript(e, href, i, lastNonInlineScriptPromise); |
| if (result) { |
| if (!result.inline) { |
| lastNonInlineScriptPromise = result.promise; |
| } |
| sp.push(result.promise); |
| } |
| }); |
| |
| forEach(b.getElementsByTagName('img'), function (e) { e.src = e.src; }); |
| forEach(b.getElementsByTagName('a'), function (e) { |
| // for # only anchor tags, we don't update the href |
| // |
| if (e.href !== "") { |
| var href = e.getAttribute("href"); |
| if (href && href[0] !== "#") { |
| e.href = e.href; |
| } |
| } |
| }); |
| |
| // strip inline scripts from the body, they got copied to the |
| // host document with the rest of the scripts above... |
| // |
| var localScripts = b.getElementsByTagName("script"); |
| while (localScripts.length > 0) { |
| var s = localScripts[0]; |
| s.parentNode.removeChild(s); |
| } |
| |
| return Promise.join(sp).then(function () { |
| // Create the docfrag which is just the body children |
| // |
| var fragment = _Global.document.createDocumentFragment(); |
| var imported = _Global.document.importNode(cd.body, true); |
| while (imported.childNodes.length > 0) { |
| fragment.appendChild(imported.childNodes[0]); |
| } |
| state.docfrag = fragment; |
| |
| return state; |
| }); |
| } |
| |
| function initialize() { |
| if (initialized) { return; } |
| |
| initialized = true; |
| |
| forEach(head.querySelectorAll("script"), function (e) { |
| scripts[e.src.toLowerCase()] = true; |
| }); |
| |
| |
| forEach(head.querySelectorAll('link[rel="stylesheet"], link[type="text/css"]'), function (e) { |
| links[e.href.toLowerCase()] = true; |
| }); |
| } |
| |
| function renderCopy(href, target) { |
| /// <signature helpKeyword="WinJS.UI.Fragments.renderCopy"> |
| /// <summary locid="WinJS.UI.Fragments.renderCopy"> |
| /// Copies the contents of the specified URI into the specified element. |
| /// </summary> |
| /// <param name="href" type="String" locid="WinJS.UI.Fragments.renderCopy_p:href"> |
| /// The URI that contains the fragment to copy. |
| /// </param> |
| /// <param name="target" type="HTMLElement" optional="true" locid="WinJS.UI.Fragments.renderCopy_p:target"> |
| /// The element to which the fragment is appended. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Fragments.renderCopy_returnValue"> |
| /// A promise that is fulfilled when the fragment has been loaded. |
| /// If a target element is not specified, the copied fragment is the |
| /// completed value. |
| /// </returns> |
| /// </signature> |
| |
| return renderImpl(href, target, true); |
| } |
| |
| function renderImpl(href, target, copy) { |
| var profilerMarkIdentifier = (href instanceof _Global.HTMLElement ? _BaseUtils._getProfilerMarkIdentifier(href) : " href='" + href + "'") + "[" + (++uniqueId) + "]"; |
| writeProfilerMark("WinJS.UI.Fragments:render" + profilerMarkIdentifier + ",StartTM"); |
| |
| initialize(); |
| return getStateRecord(href, !copy).then(function (state) { |
| var frag = state.docfrag; |
| if (copy) { |
| frag = frag.cloneNode(true); |
| } |
| |
| var child = frag.firstChild; |
| while (child) { |
| if (child.nodeType === 1 /*Element node*/) { |
| child.msParentSelectorScope = true; |
| } |
| child = child.nextSibling; |
| } |
| |
| var retVal; |
| if (target) { |
| target.appendChild(frag); |
| retVal = target; |
| } else { |
| retVal = frag; |
| } |
| writeProfilerMark("WinJS.UI.Fragments:render" + profilerMarkIdentifier + ",StopTM"); |
| return retVal; |
| }); |
| } |
| |
| function render(href, target) { |
| /// <signature helpKeyword="WinJS.UI.Fragments.render"> |
| /// <summary locid="WinJS.UI.Fragments.render"> |
| /// Copies the contents of the specified URI into the specified element. |
| /// </summary> |
| /// <param name='href' type='String' locid="WinJS.UI.Fragments.render_p:href"> |
| /// The URI that contains the fragment to copy. |
| /// </param> |
| /// <param name='target' type='HTMLElement' optional='true' locid="WinJS.UI.Fragments.render_p:target"> |
| /// The element to which the fragment is appended. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Fragments.render_returnValue"> |
| /// A promise that is fulfilled when the fragment has been loaded. |
| /// If a target element is not specified, the copied fragment is the |
| /// completed value. |
| /// </returns> |
| /// </signature> |
| |
| return renderImpl(href, target, false); |
| } |
| |
| function cache(href) { |
| /// <signature helpKeyword="WinJS.UI.Fragments.cache"> |
| /// <summary locid="WinJS.UI.Fragments.cache"> |
| /// Starts loading the fragment at the specified location. The returned promise completes |
| /// when the fragment is ready to be copied. |
| /// </summary> |
| /// <param name="href" type="String or DOMElement" locid="WinJS.UI.Fragments.cache_p:href"> |
| /// The URI that contains the fragment to be copied. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Fragments.cache_returnValue"> |
| /// A promise that is fulfilled when the fragment has been prepared for copying. |
| /// </returns> |
| /// </signature> |
| initialize(); |
| return getStateRecord(href).then(function (state) { return state.docfrag; }); |
| } |
| |
| function clearCache(href) { |
| /// <signature helpKeyword="WinJS.UI.Fragments.clearCache"> |
| /// <summary locid="WinJS.UI.Fragments.clearCache"> |
| /// Removes any cached information about the specified fragment. This method does not unload any scripts |
| /// or styles that are referenced by the fragment. |
| /// </summary> |
| /// <param name="href" type="String or DOMElement" locid="WinJS.UI.Fragments.clearCache_p:href"> |
| /// The URI that contains the fragment to be cleared. If no URI is provided, the entire contents of the cache are cleared. |
| /// </param> |
| /// </signature> |
| |
| if (!href) { |
| cacheStore = {}; |
| } else if (typeof (href) === "string") { |
| delete cacheStore[href.toLowerCase()]; |
| } else { |
| delete _ElementUtilities.data(href).docFragment; |
| href.removeAttribute("data-win-hasfragment"); |
| } |
| } |
| |
| function populateDocument(state, href) { |
| |
| var htmlDoc = _Global.document.implementation.createHTMLDocument("frag"); |
| var base = htmlDoc.createElement("base"); |
| htmlDoc.head.appendChild(base); |
| var anchor = htmlDoc.createElement("a"); |
| htmlDoc.body.appendChild(anchor); |
| base.href = _Global.document.location.href; // Initialize base URL to primary document URL |
| anchor.setAttribute("href", href); // Resolve the relative path to an absolute path |
| base.href = anchor.href; // Update the base URL to be the resolved absolute path |
| // 'anchor' is no longer needed at this point and will be removed by the innerHTML call |
| state.document = htmlDoc; |
| return getFragmentContents(href).then(function (text) { |
| _SafeHtml.setInnerHTMLUnsafe(htmlDoc.documentElement, text); |
| htmlDoc.head.appendChild(base); |
| }); |
| } |
| |
| var writeProfilerMark = _WriteProfilerMark; |
| |
| var getFragmentContents = getFragmentContentsXHR; |
| function getFragmentContentsXHR(href) { |
| return _Xhr({ url: href }).then(function (req) { |
| return req.responseText; |
| }); |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI.Fragments", { |
| renderCopy: renderCopy, |
| render: render, |
| cache: cache, |
| clearCache: clearCache, |
| _cacheStore: { get: function () { return cacheStore; } }, |
| _getFragmentContents: { |
| get: function () { |
| return getFragmentContents; |
| }, |
| set: function (value) { |
| getFragmentContents = value; |
| } |
| }, |
| _writeProfilerMark: { |
| get: function () { |
| return writeProfilerMark; |
| }, |
| set: function (value) { |
| writeProfilerMark = value; |
| } |
| } |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Application/_State',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Promise' |
| ], function stateInit(exports, _Global, _WinRT, _Base, _BaseUtils, Promise) { |
| "use strict"; |
| |
| function initWithWinRT() { |
| var local, temp, roaming; |
| |
| var IOHelper = _Base.Class.define( |
| function IOHelper_ctor(folder) { |
| this.folder = folder; |
| this._path = folder.path; |
| if (folder.tryGetItemAsync) { |
| this._tryGetItemAsync = folder.tryGetItemAsync.bind(folder); |
| } |
| }, { |
| _tryGetItemAsync: function (fileName) { |
| return this.folder.getFileAsync(fileName).then(null, function () { return false; }); |
| }, |
| |
| exists: function (fileName) { |
| /// <signature helpKeyword="WinJS.Application.IOHelper.exists"> |
| /// <summary locid="WinJS.Application.IOHelper.exists"> |
| /// Determines if the specified file exists in the container |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.IOHelper.exists_p:fileName"> |
| /// The file which may exist within this folder |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.IOHelper.exists_returnValue"> |
| /// Promise with either true (file exists) or false. |
| /// </returns> |
| /// </signature> |
| return this._tryGetItemAsync(fileName).then(function (fileItem) { |
| return fileItem ? true : false; |
| }); |
| }, |
| remove: function (fileName) { |
| /// <signature helpKeyword="WinJS.Application.IOHelper.remove"> |
| /// <summary locid="WinJS.Application.IOHelper.remove"> |
| /// Delets a file in the container |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.IOHelper.remove_p:fileName"> |
| /// The file to be deleted |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.IOHelper.remove_returnValue"> |
| /// Promise which is fulfilled when the file has been deleted |
| /// </returns> |
| /// </signature> |
| return this._tryGetItemAsync(fileName).then(function (fileItem) { |
| return fileItem ? fileItem.deleteAsync() : false; |
| }).then(null, function () { return false; }); |
| }, |
| writeText: function (fileName, str) { |
| /// <signature helpKeyword="WinJS.Application.IOHelper.writeText"> |
| /// <summary locid="WinJS.Application.IOHelper.writeText"> |
| /// Writes a file to the container with the specified text |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.IOHelper.writeText_p:fileName"> |
| /// The file to write to |
| /// </param> |
| /// <param name="str" type="String" locid="WinJS.Application.IOHelper.writeText_p:str"> |
| /// Content to be written to the file |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.IOHelper.writeText_returnValue"> |
| /// Promise which is fulfilled when the file has been written |
| /// </returns> |
| /// </signature> |
| var sto = _WinRT.Windows.Storage; |
| var that = this; |
| return that.folder.createFileAsync(fileName, sto.CreationCollisionOption.openIfExists). |
| then(function (fileItem) { |
| return sto.FileIO.writeTextAsync(fileItem, str); |
| }); |
| }, |
| |
| readText: function (fileName, def) { |
| /// <signature helpKeyword="WinJS.Application.IOHelper.readText"> |
| /// <summary locid="WinJS.Application.IOHelper.readText"> |
| /// Reads the contents of a file from the container, if the file |
| /// doesn't exist, def is returned. |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.IOHelper.readText_p:fileName"> |
| /// The file to read from |
| /// </param> |
| /// <param name="def" type="String" locid="WinJS.Application.IOHelper.readText_p:def"> |
| /// Default value to be returned if the file failed to open |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.IOHelper.readText_returnValue"> |
| /// Promise containing the contents of the file, or def. |
| /// </returns> |
| /// </signature> |
| var sto = _WinRT.Windows.Storage; |
| return this._tryGetItemAsync(fileName).then(function (fileItem) { |
| return fileItem ? sto.FileIO.readTextAsync(fileItem) : def; |
| }).then(null, function () { return def; }); |
| } |
| |
| }, { |
| supportedForProcessing: false, |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Application", { |
| /// <field type="Object" helpKeyword="WinJS.Application.local" locid="WinJS.Application.local"> |
| /// Allows access to create files in the application local storage, which is preserved across runs |
| /// of an application and does not roam. |
| /// </field> |
| local: { |
| get: function () { |
| if (!local) { |
| local = new IOHelper(_WinRT.Windows.Storage.ApplicationData.current.localFolder); |
| } |
| return local; |
| } |
| }, |
| /// <field type="Object" helpKeyword="WinJS.Application.temp" locid="WinJS.Application.temp"> |
| /// Allows access to create files in the application temp storage, which may be reclaimed |
| /// by the system between application runs. |
| /// </field> |
| temp: { |
| get: function () { |
| if (!temp) { |
| temp = new IOHelper(_WinRT.Windows.Storage.ApplicationData.current.temporaryFolder); |
| } |
| return temp; |
| } |
| }, |
| /// <field type="Object" helpKeyword="WinJS.Application.roaming" locid="WinJS.Application.roaming"> |
| /// Allows access to create files in the application roaming storage, which is preserved across runs |
| /// of an application and roams with the user across multiple machines. |
| /// </field> |
| roaming: { |
| get: function () { |
| if (!roaming) { |
| roaming = new IOHelper(_WinRT.Windows.Storage.ApplicationData.current.roamingFolder); |
| } |
| return roaming; |
| } |
| } |
| }); |
| } |
| |
| function initWithStub() { |
| var InMemoryHelper = _Base.Class.define( |
| function InMemoryHelper_ctor() { |
| this.storage = {}; |
| }, { |
| exists: function (fileName) { |
| /// <signature helpKeyword="WinJS.Application.InMemoryHelper.exists"> |
| /// <summary locid="WinJS.Application.InMemoryHelper.exists"> |
| /// Determines if the specified file exists in the container |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.InMemoryHelper.exists_p:fileName"> |
| /// The filename which may exist within this folder |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.InMemoryHelper.exists_returnValue"> |
| /// Promise with either true (file exists) or false. |
| /// </returns> |
| /// </signature> |
| // force conversion to boolean |
| // |
| return Promise.as(this.storage[fileName] !== undefined); |
| }, |
| remove: function (fileName) { |
| /// <signature helpKeyword="WinJS.Application.InMemoryHelper.remove"> |
| /// <summary locid="WinJS.Application.InMemoryHelper.remove"> |
| /// Deletes a file in the container |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.InMemoryHelper.remove_p:fileName"> |
| /// The file to be deleted |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.InMemoryHelper.remove_returnValue"> |
| /// Promise which is fulfilled when the file has been deleted |
| /// </returns> |
| /// </signature> |
| delete this.storage[fileName]; |
| return Promise.as(); |
| }, |
| writeText: function (fileName, str) { |
| /// <signature helpKeyword="WinJS.Application.InMemoryHelper.writeText"> |
| /// <summary locid="WinJS.Application.InMemoryHelper.writeText"> |
| /// Writes a file to the container with the specified text |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.InMemoryHelper.writeText_p:fileName"> |
| /// The filename to write to |
| /// </param> |
| /// <param name="str" type="String" locid="WinJS.Application.InMemoryHelper.writeText_p:str"> |
| /// Content to be written to the file |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.InMemoryHelper.writeText_returnValue"> |
| /// Promise which is fulfilled when the file has been written |
| /// </returns> |
| /// </signature> |
| this.storage[fileName] = str; |
| return Promise.as(str.length); |
| }, |
| readText: function (fileName, def) { |
| /// <signature helpKeyword="WinJS.Application.InMemoryHelper.readText"> |
| /// <summary locid="WinJS.Application.InMemoryHelper.readText"> |
| /// Reads the contents of a file from the container, if the file |
| /// doesn't exist, def is returned. |
| /// </summary> |
| /// <param name="fileName" type="String" locid="WinJS.Application.InMemoryHelper.readText_p:fileName"> |
| /// The filename to read from |
| /// </param> |
| /// <param name="def" type="String" locid="WinJS.Application.InMemoryHelper.readText_p:def"> |
| /// Default value to be returned if the file failed to open |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Application.InMemoryHelper.readText_returnValue"> |
| /// Promise containing the contents of the file, or def. |
| /// </returns> |
| /// </signature> |
| var result = this.storage[fileName]; |
| return Promise.as(typeof result === "string" ? result : def); |
| } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Application", { |
| /// <field type="Object" helpKeyword="WinJS.Application.local" locid="WinJS.Application.local"> |
| /// Allows access to create files in the application local storage, which is preserved across runs |
| /// of an application and does not roam. |
| /// </field> |
| local: new InMemoryHelper(), |
| /// <field type="Object" helpKeyword="WinJS.Application.temp" locid="WinJS.Application.temp"> |
| /// Allows access to create files in the application temp storage, which may be reclaimed |
| /// by the system between application runs. |
| /// </field> |
| temp: new InMemoryHelper(), |
| /// <field type="Object" helpKeyword="WinJS.Application.roaming" locid="WinJS.Application.roaming"> |
| /// Allows access to create files in the application roaming storage, which is preserved across runs |
| /// of an application and roams with the user across multiple machines. |
| /// </field> |
| roaming: new InMemoryHelper() |
| }); |
| } |
| |
| if (_WinRT.Windows.Storage.FileIO && _WinRT.Windows.Storage.ApplicationData && _WinRT.Windows.Storage.CreationCollisionOption) { |
| initWithWinRT(); |
| } else { |
| initWithStub(); |
| } |
| |
| var sessionState = {}; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Application", { |
| sessionState: { |
| get: function () { |
| return sessionState; |
| }, |
| set: function (value) { |
| sessionState = value; |
| } |
| }, |
| _loadState: function (e) { |
| // we only restore state if we are coming back from a clear termination from PLM |
| // |
| if (e.previousExecutionState === 3 /* ApplicationExecutionState.Terminated */) { |
| return exports.local.readText("_sessionState.json", "{}"). |
| then(function (str) { |
| var sessionState = JSON.parse(str); |
| if (sessionState && Object.keys(sessionState).length > 0) { |
| exports._sessionStateLoaded = true; |
| } |
| exports.sessionState = sessionState; |
| }). |
| then(null, function () { |
| exports.sessionState = {}; |
| }); |
| } else { |
| return Promise.as(); |
| } |
| }, |
| _oncheckpoint: function (event, Application) { |
| if (_Global.MSApp && _Global.MSApp.getViewOpener && _Global.MSApp.getViewOpener()) { |
| // don't save state in child windows. |
| return; |
| } |
| var sessionState = exports.sessionState; |
| if ((sessionState && Object.keys(sessionState).length > 0) || exports._sessionStateLoaded) { |
| var stateString; |
| try { |
| stateString = JSON.stringify(sessionState); |
| } catch (e) { |
| stateString = ""; |
| Application.queueEvent({ type: "error", detail: e }); |
| } |
| event.setPromise( |
| exports.local.writeText("_sessionState.json", stateString). |
| then(null, function (err) { |
| Application.queueEvent({ type: "error", detail: err }); |
| }) |
| ); |
| } |
| } |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Navigation',[ |
| 'exports', |
| './Core/_Base', |
| './Core/_Events', |
| './Core/_WriteProfilerMark', |
| './Promise' |
| ], function navigationInit(exports, _Base, _Events, _WriteProfilerMark, Promise) { |
| "use strict"; |
| |
| var navigatedEventName = "navigated"; |
| var navigatingEventName = "navigating"; |
| var beforenavigateEventName = "beforenavigate"; |
| var ListenerType = _Base.Class.mix(_Base.Class.define(null, { /* empty */ }, { supportedForProcessing: false }), _Events.eventMixin); |
| var listeners = new ListenerType(); |
| var history = { |
| backStack: [], |
| current: { location: "", initialPlaceholder: true }, |
| forwardStack: [] |
| }; |
| var createEvent = _Events._createEventProperty; |
| |
| var raiseBeforeNavigate = function (proposed) { |
| _WriteProfilerMark("WinJS.Navigation:navigation,StartTM"); |
| return Promise.as(). |
| then(function () { |
| var waitForPromise = Promise.as(); |
| var defaultPrevented = listeners.dispatchEvent(beforenavigateEventName, { |
| setPromise: function (promise) { |
| /// <signature helpKeyword="WinJS.Navigation.beforenavigate.setPromise"> |
| /// <summary locid="WinJS.Navigation.beforenavigate.setPromise"> |
| /// Used to inform the ListView that asynchronous work is being performed, and that this |
| /// event handler should not be considered complete until the promise completes. |
| /// </summary> |
| /// <param name="promise" type="WinJS.Promise" locid="WinJS.Navigation.beforenavigate.setPromise_p:promise"> |
| /// The promise to wait for. |
| /// </param> |
| /// </signature> |
| |
| waitForPromise = waitForPromise.then(function () { return promise; }); |
| }, |
| location: proposed.location, |
| state: proposed.state |
| }); |
| return waitForPromise.then(function beforeNavComplete(cancel) { |
| return defaultPrevented || cancel; |
| }); |
| }); |
| }; |
| var raiseNavigating = function (delta) { |
| return Promise.as(). |
| then(function () { |
| var waitForPromise = Promise.as(); |
| listeners.dispatchEvent(navigatingEventName, { |
| setPromise: function (promise) { |
| /// <signature helpKeyword="WinJS.Navigation.navigating.setPromise"> |
| /// <summary locid="WinJS.Navigation.navigating.setPromise"> |
| /// Used to inform the ListView that asynchronous work is being performed, and that this |
| /// event handler should not be considered complete until the promise completes. |
| /// </summary> |
| /// <param name="promise" type="WinJS.Promise" locid="WinJS.Navigation.navigating.setPromise_p:promise"> |
| /// The promise to wait for. |
| /// </param> |
| /// </signature> |
| |
| waitForPromise = waitForPromise.then(function () { return promise; }); |
| }, |
| location: history.current.location, |
| state: history.current.state, |
| delta: delta |
| }); |
| return waitForPromise; |
| }); |
| }; |
| var raiseNavigated = function (value, err) { |
| _WriteProfilerMark("WinJS.Navigation:navigation,StopTM"); |
| var waitForPromise = Promise.as(); |
| var detail = { |
| value: value, |
| location: history.current.location, |
| state: history.current.state, |
| setPromise: function (promise) { |
| /// <signature helpKeyword="WinJS.Navigation.navigated.setPromise"> |
| /// <summary locid="WinJS.Navigation.navigated.setPromise"> |
| /// Used to inform the ListView that asynchronous work is being performed, and that this |
| /// event handler should not be considered complete until the promise completes. |
| /// </summary> |
| /// <param name="promise" type="WinJS.Promise" locid="WinJS.Navigation.navigated.setPromise_p:promise"> |
| /// The promise to wait for. |
| /// </param> |
| /// </signature> |
| |
| waitForPromise = waitForPromise.then(function () { return promise; }); |
| } |
| }; |
| if (!value && err) { |
| detail.error = err; |
| } |
| listeners.dispatchEvent(navigatedEventName, detail); |
| return waitForPromise; |
| }; |
| |
| var go = function (distance, fromStack, toStack, delta) { |
| distance = Math.min(distance, fromStack.length); |
| if (distance > 0) { |
| return raiseBeforeNavigate(fromStack[fromStack.length - distance]). |
| then(function goBeforeCompleted(cancel) { |
| if (!cancel) { |
| toStack.push(history.current); |
| while (distance - 1 > 0) { |
| distance--; |
| toStack.push(fromStack.pop()); |
| } |
| history.current = fromStack.pop(); |
| return raiseNavigating(delta).then( |
| raiseNavigated, |
| function (err) { |
| raiseNavigated(undefined, err || true); |
| throw err; |
| }).then(function () { return true; }); |
| } else { |
| return false; |
| } |
| }); |
| } |
| return Promise.wrap(false); |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Navigation", { |
| /// <field name="canGoForward" type="Boolean" locid="WinJS.Navigation.canGoForward" helpKeyword="WinJS.Navigation.canGoForward"> |
| /// Determines whether it is possible to navigate forwards. |
| /// </field> |
| canGoForward: { |
| get: function () { |
| return history.forwardStack.length > 0; |
| } |
| }, |
| /// <field name="canGoBack" type="Boolean" locid="WinJS.Navigation.canGoBack" helpKeyword="WinJS.Navigation.canGoBack"> |
| /// Determines whether it is possible to navigate backwards. |
| /// </field> |
| canGoBack: { |
| get: function () { |
| return history.backStack.length > 0; |
| } |
| }, |
| /// <field name="location" locid="WinJS.Navigation.location" helpKeyword="WinJS.Navigation.location"> |
| /// Gets the current location. |
| /// </field> |
| location: { |
| get: function () { |
| return history.current.location; |
| } |
| }, |
| /// <field name="state" locid="WinJS.Navigation.state" helpKeyword="WinJS.Navigation.state"> |
| /// Gets or sets the navigation state. |
| /// </field> |
| state: { |
| get: function () { |
| return history.current.state; |
| }, |
| set: function (value) { |
| history.current.state = value; |
| } |
| }, |
| /// <field name="history" locid="WinJS.Navigation.history" helpKeyword="WinJS.Navigation.history"> |
| /// Gets or sets the navigation history. |
| /// </field> |
| history: { |
| get: function () { |
| return history; |
| }, |
| set: function (value) { |
| history = value; |
| |
| // ensure the require fields are present |
| // |
| history.backStack = history.backStack || []; |
| history.forwardStack = history.forwardStack || []; |
| history.current = history.current || { location: "", initialPlaceholder: true }; |
| history.current.location = history.current.location || ""; |
| } |
| }, |
| forward: function (distance) { |
| /// <signature helpKeyword="WinJS.Navigation.forward"> |
| /// <summary locid="WinJS.Navigation.forward"> |
| /// Navigates forwards. |
| /// </summary> |
| /// <param name="distance" type="Number" optional="true" locid="WinJS.Navigation.forward_p:distance"> |
| /// The number of entries to go forward. |
| /// </param> |
| /// <returns type="Promise" locid="WinJS.Navigation.forward_returnValue"> |
| /// A promise that is completed with a value that indicates whether or not |
| /// the navigation was successful. |
| /// </returns> |
| /// </signature> |
| distance = distance || 1; |
| return go(distance, history.forwardStack, history.backStack, distance); |
| }, |
| back: function (distance) { |
| /// <signature helpKeyword="WinJS.Navigation.back"> |
| /// <summary locid="WinJS.Navigation.back"> |
| /// Navigates backwards. |
| /// </summary> |
| /// <param name="distance" type="Number" optional="true" locid="WinJS.Navigation.back_p:distance"> |
| /// The number of entries to go back into the history. |
| /// </param> |
| /// <returns type="Promise" locid="WinJS.Navigation.back_returnValue"> |
| /// A promise that is completed with a value that indicates whether or not |
| /// the navigation was successful. |
| /// </returns> |
| /// </signature> |
| distance = distance || 1; |
| return go(distance, history.backStack, history.forwardStack, -distance); |
| }, |
| navigate: function (location, initialState) { |
| /// <signature helpKeyword="WinJS.Navigation.navigate"> |
| /// <summary locid="WinJS.Navigation.navigate"> |
| /// Navigates to a location. |
| /// </summary> |
| /// <param name="location" type="Object" locid="WinJS.Navigation.navigate_p:location"> |
| /// The location to navigate to. Generally the location is a string, but |
| /// it may be anything. |
| /// </param> |
| /// <param name="initialState" type="Object" locid="WinJS.Navigation.navigate_p:initialState"> |
| /// The navigation state that may be accessed through WinJS.Navigation.state. |
| /// </param> |
| /// <returns type="Promise" locid="WinJS.Navigation.navigate_returnValue"> |
| /// A promise that is completed with a value that indicates whether or not |
| /// the navigation was successful. |
| /// </returns> |
| /// </signature> |
| var proposed = { location: location, state: initialState }; |
| return raiseBeforeNavigate(proposed). |
| then(function navBeforeCompleted(cancel) { |
| if (!cancel) { |
| if (!history.current.initialPlaceholder) { |
| history.backStack.push(history.current); |
| } |
| history.forwardStack = []; |
| history.current = proposed; |
| |
| // error or no, we go from navigating -> navigated |
| // cancelation should be handled with "beforenavigate" |
| // |
| return raiseNavigating().then( |
| raiseNavigated, |
| function (err) { |
| raiseNavigated(undefined, err || true); |
| throw err; |
| }).then(function () { return true; }); |
| } else { |
| return false; |
| } |
| }); |
| }, |
| addEventListener: function (eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Navigation.addEventListener"> |
| /// <summary locid="WinJS.Navigation.addEventListener"> |
| /// Adds an event listener to the control. |
| /// </summary> |
| /// <param name="eventType" type="String" locid="WinJS.Navigation.addEventListener_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" type="Function" locid="WinJS.Navigation.addEventListener_p:listener"> |
| /// The listener to invoke when the event gets raised. |
| /// </param> |
| /// <param name="capture" type="Boolean" locid="WinJS.Navigation.addEventListener_p:capture"> |
| /// Specifies whether or not to initiate capture. |
| /// </param> |
| /// </signature> |
| listeners.addEventListener(eventType, listener, capture); |
| }, |
| removeEventListener: function (eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Navigation.removeEventListener"> |
| /// <summary locid="WinJS.Navigation.removeEventListener"> |
| /// Removes an event listener from the control. |
| /// </summary> |
| /// <param name='eventType' type="String" locid="WinJS.Navigation.removeEventListener_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name='listener' type='Function' locid="WinJS.Navigation.removeEventListener_p:listener"> |
| /// The listener to remove. |
| /// </param> |
| /// <param name='capture' type='Boolean' locid="WinJS.Navigation.removeEventListener_p:capture"> |
| /// Specifies whether or not to initiate capture. |
| /// </param> |
| /// </signature> |
| listeners.removeEventListener(eventType, listener, capture); |
| }, |
| /// <field type="Function" locid="WinJS.Navigation.onnavigated" helpKeyword="WinJS.Navigation.onnavigated"> |
| /// A page navigation event that occurs after onbeforenavigate and onnavigating. This event can be used to perform other actions after navigation is complete. |
| /// </field> |
| onnavigated: createEvent(navigatedEventName), |
| /// <field type="Function" locid="WinJS.Navigation.onnavigating" helpKeyword="WinJS.Navigation.onnavigating"> |
| /// A page navigation event that occurs after onbeforenavigate and before onnavigated. This event can be used to perform other actions during navigation. |
| /// </field> |
| onnavigating: createEvent(navigatingEventName), |
| /// <field type="Function" locid="WinJS.Navigation.onbeforenavigate" helpKeyword="WinJS.Navigation.onbeforenavigate"> |
| /// A page navigation event that occurs before onnavigating and onnavigated. This event can be used to cancel navigation or perform other actions prior to navigation. |
| /// </field> |
| onbeforenavigate: createEvent(beforenavigateEventName) |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Application',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_WinRT', |
| './Core/_Base', |
| './Core/_Events', |
| './Core/_Log', |
| './Core/_WriteProfilerMark', |
| './Application/_State', |
| './Navigation', |
| './Promise', |
| './_Signal', |
| './Scheduler', |
| './Utilities/_ElementUtilities' |
| ], function applicationInit(exports, _Global, _WinRT, _Base, _Events, _Log, _WriteProfilerMark, _State, Navigation, Promise, _Signal, Scheduler, _ElementUtilities) { |
| "use strict"; |
| |
| _Global.Debug && (_Global.Debug.setNonUserCodeExceptions = true); |
| |
| var checkpointET = "checkpoint", |
| unloadET = "unload", |
| activatedET = "activated", |
| loadedET = "loaded", |
| readyET = "ready", |
| errorET = "error", |
| settingsET = "settings", |
| backClickET = "backclick", |
| beforeRequestingFocusOnKeyboardInputET = "beforerequestingfocusonkeyboardinput", |
| requestingFocusOnKeyboardInputET = "requestingfocusonkeyboardinput", |
| edgyStartingET = "edgystarting", |
| edgyCompletedET = "edgycompleted", |
| edgyCanceledET = "edgycanceled"; |
| |
| var outstandingPromiseErrors; |
| var eventQueue = []; |
| var eventQueueJob = null; |
| var eventQueuedSignal = null; |
| var running = false; |
| var registered = false; |
| |
| var Symbol = _Global.Symbol; |
| var isModern = !!Symbol && typeof Symbol.iterator === "symbol"; // jshint ignore:line |
| |
| var ListenerType = _Base.Class.mix(_Base.Class.define(null, { /* empty */ }, { supportedForProcessing: false }), _Events.eventMixin); |
| var listeners = new ListenerType(); |
| var createEvent = _Events._createEventProperty; |
| var pendingDeferrals = {}; |
| var pendingDeferralID = 0; |
| var TypeToSearch = { |
| _registered: false, |
| |
| updateRegistration: function Application_TypeToSearch_updateRegistration() { |
| var ls = listeners._listeners && listeners._listeners[requestingFocusOnKeyboardInputET] || []; |
| if (!TypeToSearch._registered && ls.length > 0) { |
| TypeToSearch._updateKeydownCaptureListeners(_Global.top, true /*add*/); |
| TypeToSearch._registered = true; |
| } |
| if (TypeToSearch._registered && ls.length === 0) { |
| TypeToSearch._updateKeydownCaptureListeners(_Global.top, false /*add*/); |
| TypeToSearch._registered = false; |
| } |
| }, |
| |
| _keydownCaptureHandler: function Application_TypeToSearch_keydownCaptureHandler(event) { |
| if (TypeToSearch._registered && TypeToSearch._shouldKeyTriggerTypeToSearch(event)) { |
| requestingFocusOnKeyboardInput(); |
| } |
| }, |
| |
| _frameLoadCaptureHandler: function Application_TypeToSearch_frameLoadCaptureHandler(event) { |
| if (TypeToSearch._registered) { |
| TypeToSearch._updateKeydownCaptureListeners(event.target.contentWindow, true /*add*/); |
| } |
| }, |
| |
| _updateKeydownCaptureListeners: function Application_TypeToSearch_updateKeydownCaptureListeners(win, add) { |
| if (!win) { |
| // This occurs when this handler gets called from an IFrame event that is no longer in the DOM |
| // and therefore does not have a valid contentWindow object. |
| return; |
| } |
| |
| // Register for child frame keydown events in order to support FocusOnKeyboardInput |
| // when focus is in a child frame. Also register for child frame load events so |
| // it still works after frame navigations. |
| // Note: This won't catch iframes added programmatically later, but that can be worked |
| // around by toggling FocusOnKeyboardInput off/on after the new iframe is added. |
| try { |
| if (add) { |
| win.document.addEventListener('keydown', TypeToSearch._keydownCaptureHandler, true); |
| } else { |
| win.document.removeEventListener('keydown', TypeToSearch._keydownCaptureHandler, true); |
| } |
| } catch (e) { // if the IFrame crosses domains, we'll get a permission denied error |
| } |
| |
| if (win.frames) { |
| for (var i = 0, l = win.frames.length; i < l; i++) { |
| var childWin = win.frames[i]; |
| TypeToSearch._updateKeydownCaptureListeners(childWin, add); |
| |
| try { |
| if (add) { |
| if (childWin.frameElement) { |
| childWin.frameElement.addEventListener('load', TypeToSearch._frameLoadCaptureHandler, true); |
| } |
| } else { |
| if (childWin.frameElement) { |
| childWin.frameElement.removeEventListener('load', TypeToSearch._frameLoadCaptureHandler, true); |
| } |
| } |
| } catch (e) { // if the IFrame crosses domains, we'll get a permission denied error |
| } |
| } |
| } |
| }, |
| |
| _shouldKeyTriggerTypeToSearch: function Application_TypeToSearch_shouldKeyTriggerTypeToSearch(event) { |
| var shouldTrigger = false; |
| // First, check if a metaKey is pressed (only applies to MacOS). If so, do nothing here. |
| if (!event.metaKey) { |
| // We also don't handle CTRL/ALT combinations, unless ALTGR is also set. Since there is no shortcut for checking AltGR, |
| // we need to use getModifierState, however, Safari currently doesn't support this. |
| if ((!event.ctrlKey && !event.altKey) || (event.getModifierState && event.getModifierState("AltGraph"))) { |
| // Show on most keys for visible characters like letters, numbers, etc. |
| switch (event.keyCode) { |
| case 0x30: //0x30 0 key |
| case 0x31: //0x31 1 key |
| case 0x32: //0x32 2 key |
| case 0x33: //0x33 3 key |
| case 0x34: //0x34 4 key |
| case 0x35: //0x35 5 key |
| case 0x36: //0x36 6 key |
| case 0x37: //0x37 7 key |
| case 0x38: //0x38 8 key |
| case 0x39: //0x39 9 key |
| |
| case 0x41: //0x41 A key |
| case 0x42: //0x42 B key |
| case 0x43: //0x43 C key |
| case 0x44: //0x44 D key |
| case 0x45: //0x45 E key |
| case 0x46: //0x46 F key |
| case 0x47: //0x47 G key |
| case 0x48: //0x48 H key |
| case 0x49: //0x49 I key |
| case 0x4A: //0x4A J key |
| case 0x4B: //0x4B K key |
| case 0x4C: //0x4C L key |
| case 0x4D: //0x4D M key |
| case 0x4E: //0x4E N key |
| case 0x4F: //0x4F O key |
| case 0x50: //0x50 P key |
| case 0x51: //0x51 Q key |
| case 0x52: //0x52 R key |
| case 0x53: //0x53 S key |
| case 0x54: //0x54 T key |
| case 0x55: //0x55 U key |
| case 0x56: //0x56 V key |
| case 0x57: //0x57 W key |
| case 0x58: //0x58 X key |
| case 0x59: //0x59 Y key |
| case 0x5A: //0x5A Z key |
| |
| case 0x60: // VK_NUMPAD0, //0x60 Numeric keypad 0 key |
| case 0x61: // VK_NUMPAD1, //0x61 Numeric keypad 1 key |
| case 0x62: // VK_NUMPAD2, //0x62 Numeric keypad 2 key |
| case 0x63: // VK_NUMPAD3, //0x63 Numeric keypad 3 key |
| case 0x64: // VK_NUMPAD4, //0x64 Numeric keypad 4 key |
| case 0x65: // VK_NUMPAD5, //0x65 Numeric keypad 5 key |
| case 0x66: // VK_NUMPAD6, //0x66 Numeric keypad 6 key |
| case 0x67: // VK_NUMPAD7, //0x67 Numeric keypad 7 key |
| case 0x68: // VK_NUMPAD8, //0x68 Numeric keypad 8 key |
| case 0x69: // VK_NUMPAD9, //0x69 Numeric keypad 9 key |
| case 0x6A: // VK_MULTIPLY, //0x6A Multiply key |
| case 0x6B: // VK_ADD, //0x6B Add key |
| case 0x6C: // VK_SEPARATOR, //0x6C Separator key |
| case 0x6D: // VK_SUBTRACT, //0x6D Subtract key |
| case 0x6E: // VK_DECIMAL, //0x6E Decimal key |
| case 0x6F: // VK_DIVIDE, //0x6F Divide key |
| |
| case 0xBA: // VK_OEM_1, //0xBA Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key |
| case 0xBB: // VK_OEM_PLUS, //0xBB For any country/region, the '+' key |
| case 0xBC: // VK_OEM_COMMA, //0xBC For any country/region, the ',' key |
| case 0xBD: // VK_OEM_MINUS, //0xBD For any country/region, the '-' key |
| case 0xBE: // VK_OEM_PERIOD, //0xBE For any country/region, the '.' key |
| case 0xBF: // VK_OEM_2, //0xBF Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key |
| case 0xC0: // VK_OEM_3, //0xC0 Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key |
| |
| case 0xDB: // VK_OEM_4, //0xDB Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key |
| case 0xDC: // VK_OEM_5, //0xDC Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key |
| case 0xDD: // VK_OEM_6, //0xDD Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key |
| case 0xDE: // VK_OEM_7, //0xDE Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key |
| case 0xDF: // VK_OEM_8, //0xDF Used for miscellaneous characters; it can vary by keyboard. |
| |
| case 0xE2: // VK_OEM_102, //0xE2 Either the angle bracket key or the backslash key on the RT 102-key keyboard |
| |
| case 0xE5: // VK_PROCESSKEY, //0xE5 IME PROCESS key |
| |
| case 0xE7: // VK_PACKET, //0xE7 Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP |
| shouldTrigger = true; |
| break; |
| } |
| } |
| } |
| return shouldTrigger; |
| } |
| }; |
| |
| function safeSerialize(obj) { |
| var str; |
| try { |
| var seenObjects = []; |
| str = JSON.stringify(obj, function (key, value) { |
| if (value === _Global) { |
| return "[window]"; |
| } else if (value instanceof _Global.HTMLElement) { |
| return "[HTMLElement]"; |
| } else if (typeof value === "function") { |
| return "[function]"; |
| } else if (typeof value === "object") { |
| if (value === null) { |
| return value; |
| } else if (seenObjects.indexOf(value) === -1) { |
| seenObjects.push(value); |
| return value; |
| } else { |
| return "[circular]"; |
| } |
| } else { |
| return value; |
| } |
| |
| }); |
| } |
| catch (err) { |
| // primitives, undefined, null, etc, all get serialized fine. In the |
| // case that stringify fails (typically due to circular graphs) we |
| // just show "[object]". While we may be able to tighten the condition |
| // for the exception, we never way this serialize to fail. |
| // |
| // Note: we make this be a JSON string, so that consumers of the log |
| // can always call JSON.parse. |
| str = JSON.stringify("[object]"); |
| } |
| return str; |
| } |
| |
| function fatalErrorHandler(e) { |
| _Log.log && _Log.log(safeSerialize(e), "winjs", "error"); |
| |
| if (_Global.document && exports._terminateApp) { |
| var data = e.detail; |
| var number = data && (data.number || (data.exception && (data.exception.number || data.exception.code)) || (data.error && data.error.number) || data.errorCode || 0); |
| var terminateData = { |
| description: safeSerialize(data), |
| // note: because of how we listen to events, we rarely get a stack |
| stack: data && (data.stack || (data.exception && (data.exception.stack || data.exception.message)) || (data.error && data.error.stack) || null), |
| errorNumber: number, |
| number: number |
| }; |
| exports._terminateApp(terminateData, e); |
| } |
| } |
| |
| function defaultTerminateAppHandler(data, e) { |
| /*jshint unused: false*/ |
| // This is the unhandled exception handler in WinJS. This handler is invoked whenever a promise |
| // has an exception occur that is not handled (via an error handler passed to then() or a call to done()). |
| // |
| // To see the original exception stack, look at data.stack. |
| // For more information on debugging and exception handling go to http://go.microsoft.com/fwlink/p/?LinkId=253583. |
| |
| debugger; // jshint ignore:line |
| if (_Global.MSApp) { |
| _Global.MSApp.terminateApp(data); |
| } |
| } |
| |
| var terminateAppHandler = defaultTerminateAppHandler; |
| |
| function captureDeferral(obj) { |
| var id = "def" + (pendingDeferralID++); |
| return { deferral: pendingDeferrals[id] = obj.getDeferral(), id: id }; |
| } |
| function completeDeferral(deferral, deferralID) { |
| // If we have a deferralID we our table to find the |
| // deferral. Since we remove it on completion, this |
| // ensures that we never double notify a deferral |
| // in the case of a user call "Application.stop" in |
| // the middle of processing an event |
| // |
| if (deferralID) { |
| deferral = pendingDeferrals[deferralID]; |
| delete pendingDeferrals[deferralID]; |
| } |
| if (deferral) { |
| deferral.complete(); |
| } |
| } |
| function cleanupAllPendingDeferrals() { |
| if (pendingDeferrals) { |
| Object.keys(pendingDeferrals).forEach(function (k) { |
| pendingDeferrals[k].complete(); |
| }); |
| pendingDeferrals = {}; |
| } |
| } |
| |
| function dispatchEvent(eventRecord) { |
| _WriteProfilerMark("WinJS.Application:Event_" + eventRecord.type + ",StartTM"); |
| |
| var waitForPromise = Promise.as(); |
| eventRecord.setPromise = function (promise) { |
| /// <signature helpKeyword="WinJS.Application.eventRecord.setPromise"> |
| /// <summary locid="WinJS.Application.event.setPromise"> |
| /// Used to inform the application object that asynchronous work is being performed, and that this |
| /// event handler should not be considered complete until the promise completes. |
| /// </summary> |
| /// <param name="promise" type="WinJS.Promise" locid="WinJS.Application.eventRecord.setPromise_p:promise"> |
| /// The promise to wait for. |
| /// </param> |
| /// </signature> |
| waitForPromise = waitForPromise.then(function () { return promise; }); |
| }; |
| eventRecord._stoppedImmediatePropagation = false; |
| eventRecord.stopImmediatePropagation = function () { |
| eventRecord._stoppedImmediatePropagation = true; |
| }; |
| eventRecord.detail = eventRecord.detail || {}; |
| if (typeof (eventRecord.detail) === "object") { |
| eventRecord.detail.setPromise = eventRecord.setPromise; |
| } |
| |
| try { |
| if (listeners._listeners) { |
| var handled = false; |
| l = listeners._listeners[eventRecord.type]; |
| if (l) { |
| for (var i = 0, len = l.length; i < len && !eventRecord._stoppedImmediatePropagation; i++) { |
| handled = l[i].listener(eventRecord) || handled; |
| } |
| } |
| } |
| |
| // Fire built in listeners last, for checkpoint this is important |
| // as it lets our built in serialization see any mutations to |
| // app.sessionState |
| // |
| var l = builtInListeners[eventRecord.type]; |
| if (l) { |
| l.forEach(function dispatchOne(e) { e(eventRecord, handled); }); |
| } |
| } |
| catch (err) { |
| if (eventRecord.type === errorET) { |
| fatalErrorHandler(eventRecord); |
| } else { |
| queueEvent({ type: errorET, detail: err }); |
| } |
| } |
| |
| |
| function cleanup(r) { |
| _WriteProfilerMark("WinJS.Application:Event_" + eventRecord.type + ",StopTM"); |
| |
| if (eventRecord._deferral) { |
| completeDeferral(eventRecord._deferral, eventRecord._deferralID); |
| } |
| return r; |
| } |
| |
| return waitForPromise.then(cleanup, function (r) { |
| r = cleanup(r); |
| if (r && r.name === "Canceled") { |
| return; |
| } |
| return Promise.wrapError(r); |
| }); |
| } |
| |
| function createEventQueuedSignal() { |
| if (!eventQueuedSignal) { |
| eventQueuedSignal = new _Signal(); |
| eventQueuedSignal.promise.done(function () { |
| eventQueuedSignal = null; |
| }, function () { |
| eventQueuedSignal = null; |
| }); |
| } |
| return eventQueuedSignal; |
| } |
| |
| function drainOneEvent(queue) { |
| function drainError(err) { |
| queueEvent({ type: errorET, detail: err }); |
| } |
| |
| if (queue.length === 0) { |
| return createEventQueuedSignal().promise; |
| } else { |
| return dispatchEvent(queue.shift()).then(null, drainError); |
| } |
| } |
| |
| // Drains the event queue via the scheduler |
| // |
| function drainQueue(jobInfo) { |
| function drainNext() { |
| return drainQueue; |
| } |
| |
| var queue = jobInfo.job._queue; |
| |
| if (queue.length === 0 && eventQueue.length > 0) { |
| queue = jobInfo.job._queue = copyAndClearQueue(); |
| } |
| |
| jobInfo.setPromise(drainOneEvent(queue).then(drainNext, drainNext)); |
| } |
| |
| function startEventQueue() { |
| function markSync() { |
| sync = true; |
| } |
| |
| var queue = []; |
| var sync = true; |
| var promise; |
| |
| // Drain the queue as long as there are events and they complete synchronously |
| // |
| while (sync) { |
| if (queue.length === 0 && eventQueue.length > 0) { |
| queue = copyAndClearQueue(); |
| } |
| |
| sync = false; |
| promise = drainOneEvent(queue); |
| promise.done(markSync, markSync); |
| } |
| |
| // Schedule a job which will be responsible for draining events for the |
| // lifetime of the application. |
| // |
| eventQueueJob = Scheduler.schedule(function Application_pumpEventQueue(jobInfo) { |
| function drainNext() { |
| return drainQueue; |
| } |
| jobInfo.setPromise(promise.then(drainNext, drainNext)); |
| }, Scheduler.Priority.high, null, "WinJS.Application._pumpEventQueue"); |
| eventQueueJob._queue = queue; |
| } |
| |
| function queueEvent(eventRecord) { |
| /// <signature helpKeyword="WinJS.Application.queueEvent"> |
| /// <summary locid="WinJS.Application.queueEvent"> |
| /// Queues an event to be processed by the WinJS.Application event queue. |
| /// </summary> |
| /// <param name="eventRecord" type="Object" locid="WinJS.Application.queueEvent_p:eventRecord"> |
| /// The event object is expected to have a type property that is |
| /// used as the event name when dispatching on the WinJS.Application |
| /// event queue. The entire object is provided to event listeners |
| /// in the detail property of the event. |
| /// </param> |
| /// </signature> |
| _WriteProfilerMark("WinJS.Application:Event_" + eventRecord.type + " queued,Info"); |
| eventQueue.push(eventRecord); |
| if (running && eventQueuedSignal) { |
| eventQueuedSignal.complete(drainQueue); |
| } |
| } |
| |
| function copyAndClearQueue() { |
| var queue = eventQueue; |
| eventQueue = []; |
| return queue; |
| } |
| |
| var builtInListeners = { |
| activated: [ |
| function Application_activatedHandler() { |
| queueEvent({ type: readyET }); |
| } |
| ], |
| checkpoint: [ |
| function Application_checkpointHandler(e) { |
| _State._oncheckpoint(e, exports); |
| } |
| ], |
| error: [ |
| function Application_errorHandler(e, handled) { |
| if (handled) { |
| return; |
| } |
| fatalErrorHandler(e); |
| } |
| ], |
| backclick: [ |
| function Application_backClickHandler(e, handled) { |
| if (handled) { |
| e._winRTBackPressedEvent.handled = true; |
| } else if (Navigation.canGoBack) { |
| Navigation.back(); |
| e._winRTBackPressedEvent.handled = true; |
| } |
| } |
| ], |
| beforerequestingfocusonkeyboardinput: [ |
| function Application_beforeRequestingFocusOnKeyboardInputHandler(e, handled) { |
| if (!handled) { |
| dispatchEvent({ type: requestingFocusOnKeyboardInputET }); |
| } |
| } |
| ] |
| }; |
| |
| // loaded == DOMContentLoaded |
| // activated == after WinRT Activated |
| // ready == after all of the above |
| // |
| function activatedHandler(e) { |
| var def = captureDeferral(e.activatedOperation); |
| _State._loadState(e).then(function () { |
| queueEvent({ type: activatedET, detail: e, _deferral: def.deferral, _deferralID: def.id }); |
| }); |
| } |
| function suspendingHandler(e) { |
| var def = captureDeferral(e.suspendingOperation); |
| queueEvent({ type: checkpointET, _deferral: def.deferral, _deferralID: def.id }); |
| } |
| function domContentLoadedHandler() { |
| queueEvent({ type: loadedET }); |
| if (!(_Global.document && _WinRT.Windows.UI.WebUI.WebUIApplication)) { |
| var activatedArgs = { |
| arguments: "", |
| kind: "Windows.Launch", |
| previousExecutionState: 0 //_WinRT.Windows.ApplicationModel.Activation.ApplicationExecutionState.NotRunning |
| }; |
| _State._loadState(activatedArgs).then(function () { |
| queueEvent({ type: activatedET, detail: activatedArgs }); |
| }); |
| } |
| } |
| function beforeUnloadHandler() { |
| cleanupAllPendingDeferrals(); |
| queueEvent({ type: unloadET }); |
| } |
| function errorHandler(e) { |
| var flattenedError = {}; |
| for (var key in e) { |
| flattenedError[key] = e[key]; |
| } |
| var data; |
| var handled = true; |
| var prev = exports._terminateApp; |
| try { |
| exports._terminateApp = function (d, e) { |
| handled = false; |
| data = d; |
| if (prev !== defaultTerminateAppHandler) { |
| prev(d, e); |
| } |
| }; |
| dispatchEvent({ |
| type: errorET, |
| detail: { |
| error: flattenedError, |
| errorLine: e.lineno, |
| errorCharacter: e.colno, |
| errorUrl: e.filename, |
| errorMessage: e.message |
| } |
| }); |
| } finally { |
| exports._terminateApp = prev; |
| } |
| return handled; |
| } |
| function promiseErrorHandler(e) { |
| // |
| // e.detail looks like: { exception, error, promise, handler, id, parent } |
| // |
| var details = e.detail; |
| var id = details.id; |
| |
| // If the error has a parent promise then this is not the origination of the |
| // error so we check if it has a handler, and if so we mark that the error |
| // was handled by removing it from outstandingPromiseErrors |
| // |
| if (details.parent) { |
| if (details.handler && outstandingPromiseErrors) { |
| delete outstandingPromiseErrors[id]; |
| } |
| return; |
| } |
| |
| // Work around browsers that don't serialize exceptions |
| if (details.exception instanceof Error) { |
| var error = { |
| stack: details.exception.stack, |
| message: details.exception.message |
| }; |
| details.exception = error; |
| } |
| |
| // If this is the first promise error to occur in this period we need to schedule |
| // a helper to come along after a setImmediate that propagates any remaining |
| // errors to the application's queue. |
| // |
| var shouldScheduleErrors = !outstandingPromiseErrors; |
| |
| // Indicate that this error was orignated and needs to be handled |
| // |
| outstandingPromiseErrors = outstandingPromiseErrors || []; |
| outstandingPromiseErrors[id] = details; |
| |
| if (shouldScheduleErrors) { |
| Scheduler.schedule(function Application_async_promiseErrorHandler() { |
| var errors = outstandingPromiseErrors; |
| outstandingPromiseErrors = null; |
| errors.forEach(function (error) { |
| queueEvent({ type: errorET, detail: error }); |
| }); |
| }, Scheduler.Priority.high, null, "WinJS.Application._queuePromiseErrors"); |
| } |
| } |
| |
| // capture this early |
| // |
| if (_Global.document) { |
| _Global.document.addEventListener("DOMContentLoaded", domContentLoadedHandler, false); |
| } |
| |
| function commandsRequested(e) { |
| var event = { e: e, applicationcommands: undefined }; |
| listeners.dispatchEvent(settingsET, event); |
| } |
| |
| function hardwareButtonBackPressed(winRTBackPressedEvent) { |
| // Fire WinJS.Application 'backclick' event. If the winRTBackPressedEvent is not handled, the app will get suspended. |
| var eventRecord = { type: backClickET }; |
| Object.defineProperty(eventRecord, "_winRTBackPressedEvent", { |
| value: winRTBackPressedEvent, |
| enumerable: false |
| }); |
| dispatchEvent(eventRecord); |
| } |
| |
| function requestingFocusOnKeyboardInput() { |
| // Built in listener for beforeRequestingFocusOnKeyboardInputET will trigger |
| // requestingFocusOnKeyboardInputET if it wasn't handled. |
| dispatchEvent({ type: beforeRequestingFocusOnKeyboardInputET }); |
| } |
| |
| function edgyStarting(eventObject) { |
| dispatchEvent({ type: edgyStartingET, kind: eventObject.kind }); |
| } |
| |
| function edgyCompleted(eventObject) { |
| dispatchEvent({ type: edgyCompletedET, kind: eventObject.kind }); |
| } |
| |
| function edgyCanceled(eventObject) { |
| dispatchEvent({ type: edgyCanceledET, kind: eventObject.kind }); |
| } |
| |
| function getNavManager() { |
| // Use environment inference to avoid a critical error |
| // in `getForCurrentView` when running in Windows 8 compat mode. |
| var manager = _WinRT.Windows.UI.Core.SystemNavigationManager; |
| return (isModern && manager) ? manager.getForCurrentView() : null; |
| } |
| |
| function register() { |
| if (!registered) { |
| registered = true; |
| _Global.addEventListener("beforeunload", beforeUnloadHandler, false); |
| |
| // None of these are enabled in web worker |
| if (_Global.document) { |
| _Global.addEventListener("error", errorHandler, false); |
| if (_WinRT.Windows.UI.WebUI.WebUIApplication) { |
| |
| var wui = _WinRT.Windows.UI.WebUI.WebUIApplication; |
| wui.addEventListener("activated", activatedHandler, false); |
| wui.addEventListener("suspending", suspendingHandler, false); |
| } |
| |
| if (_WinRT.Windows.UI.ApplicationSettings.SettingsPane) { |
| var settingsPane = _WinRT.Windows.UI.ApplicationSettings.SettingsPane.getForCurrentView(); |
| settingsPane.addEventListener("commandsrequested", commandsRequested); |
| } |
| |
| // This integrates WinJS.Application into the hardware or OS-provided back button. |
| var navManager = getNavManager(); |
| if (navManager) { |
| // On Win10 this accomodates hardware buttons (phone), |
| // the taskbar's tablet mode button, and the optional window frame back button. |
| navManager.addEventListener("backrequested", hardwareButtonBackPressed); |
| } else if (_WinRT.Windows.Phone.UI.Input.HardwareButtons) { |
| // For WP 8.1 |
| _WinRT.Windows.Phone.UI.Input.HardwareButtons.addEventListener("backpressed", hardwareButtonBackPressed); |
| } |
| |
| if (_WinRT.Windows.UI.Input.EdgeGesture) { |
| var edgy = _WinRT.Windows.UI.Input.EdgeGesture.getForCurrentView(); |
| edgy.addEventListener("starting", edgyStarting); |
| edgy.addEventListener("completed", edgyCompleted); |
| edgy.addEventListener("canceled", edgyCanceled); |
| } |
| } |
| |
| Promise.addEventListener("error", promiseErrorHandler); |
| } |
| } |
| function unregister() { |
| if (registered) { |
| registered = false; |
| _Global.removeEventListener("beforeunload", beforeUnloadHandler, false); |
| |
| // None of these are enabled in web worker |
| if (_Global.document) { |
| if (_WinRT.Windows.UI.WebUI.WebUIApplication) { |
| _Global.removeEventListener("error", errorHandler, false); |
| |
| var wui = _WinRT.Windows.UI.WebUI.WebUIApplication; |
| wui.removeEventListener("activated", activatedHandler, false); |
| wui.removeEventListener("suspending", suspendingHandler, false); |
| } |
| |
| if (_WinRT.Windows.UI.ApplicationSettings.SettingsPane) { |
| var settingsPane = _WinRT.Windows.UI.ApplicationSettings.SettingsPane.getForCurrentView(); |
| settingsPane.removeEventListener("commandsrequested", commandsRequested); |
| } |
| |
| var navManager = getNavManager(); |
| if (navManager) { |
| navManager.removeEventListener("backrequested", hardwareButtonBackPressed); |
| } else if (_WinRT.Windows.Phone.UI.Input.HardwareButtons) { |
| _WinRT.Windows.Phone.UI.Input.HardwareButtons.removeEventListener("backpressed", hardwareButtonBackPressed); |
| } |
| |
| if (_WinRT.Windows.UI.Input.EdgeGesture) { |
| var edgy = _WinRT.Windows.UI.Input.EdgeGesture.getForCurrentView(); |
| edgy.removeEventListener("starting", edgyStarting); |
| edgy.removeEventListener("completed", edgyCompleted); |
| edgy.removeEventListener("canceled", edgyCanceled); |
| } |
| } |
| |
| Promise.removeEventListener("error", promiseErrorHandler); |
| } |
| } |
| |
| var publicNS = _Base.Namespace._moduleDefine(exports, "WinJS.Application", { |
| stop: function Application_stop() { |
| /// <signature helpKeyword="WinJS.Application.stop"> |
| /// <summary locid="WinJS.Application.stop"> |
| /// Stops application event processing and resets WinJS.Application |
| /// to its initial state. |
| /// </summary> |
| /// </signature> |
| |
| // Need to clear out the event properties explicitly to clear their backing |
| // state. |
| // |
| publicNS.onactivated = null; |
| publicNS.oncheckpoint = null; |
| publicNS.onerror = null; |
| publicNS.onloaded = null; |
| publicNS.onready = null; |
| publicNS.onsettings = null; |
| publicNS.onunload = null; |
| publicNS.onbackclick = null; |
| listeners = new ListenerType(); |
| _State.sessionState = {}; |
| running = false; |
| copyAndClearQueue(); |
| eventQueueJob && eventQueueJob.cancel(); |
| eventQueueJob = null; |
| eventQueuedSignal = null; |
| unregister(); |
| TypeToSearch.updateRegistration(); |
| cleanupAllPendingDeferrals(); |
| }, |
| |
| addEventListener: function Application_addEventListener(eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Application.addEventListener"> |
| /// <summary locid="WinJS.Application.addEventListener"> |
| /// Adds an event listener to the control. |
| /// </summary> |
| /// <param name="eventType" locid="WinJS.Application.addEventListener_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" locid="WinJS.Application.addEventListener_p:listener"> |
| /// The listener to invoke when the event is raised. |
| /// </param> |
| /// <param name="capture" locid="WinJS.Application.addEventListener_p:capture"> |
| /// true to initiate capture; otherwise, false. |
| /// </param> |
| /// </signature> |
| listeners.addEventListener(eventType, listener, capture); |
| if (eventType === requestingFocusOnKeyboardInputET) { |
| TypeToSearch.updateRegistration(); |
| } |
| }, |
| removeEventListener: function Application_removeEventListener(eventType, listener, capture) { |
| /// <signature helpKeyword="WinJS.Application.removeEventListener"> |
| /// <summary locid="WinJS.Application.removeEventListener"> |
| /// Removes an event listener from the control. |
| /// </summary> |
| /// <param name="eventType" locid="WinJS.Application.removeEventListener_p:eventType"> |
| /// The type (name) of the event. |
| /// </param> |
| /// <param name="listener" locid="WinJS.Application.removeEventListener_p:listener"> |
| /// The listener to remove. |
| /// </param> |
| /// <param name="capture" locid="WinJS.Application.removeEventListener_p:capture"> |
| /// Specifies whether or not to initiate capture. |
| /// </param> |
| /// </signature> |
| listeners.removeEventListener(eventType, listener, capture); |
| if (eventType === requestingFocusOnKeyboardInputET) { |
| TypeToSearch.updateRegistration(); |
| } |
| }, |
| |
| checkpoint: function Application_checkpoint() { |
| /// <signature helpKeyword="WinJS.Application.checkpoint"> |
| /// <summary locid="WinJS.Application.checkpoint"> |
| /// Queues a checkpoint event. |
| /// </summary> |
| /// </signature> |
| queueEvent({ type: checkpointET }); |
| }, |
| |
| start: function Application_start() { |
| /// <signature helpKeyword="WinJS.Application.start"> |
| /// <summary locid="WinJS.Application.start"> |
| /// Starts processing events in the WinJS.Application event queue. |
| /// </summary> |
| /// </signature> |
| register(); |
| running = true; |
| startEventQueue(); |
| }, |
| |
| queueEvent: queueEvent, |
| |
| // Like queueEvent but fires the event synchronously. Useful in tests. |
| _dispatchEvent: dispatchEvent, |
| |
| _terminateApp: { |
| get: function Application_terminateApp_get() { |
| return terminateAppHandler; |
| }, |
| set: function Application_terminateApp_set(value) { |
| terminateAppHandler = value; |
| } |
| }, |
| |
| _applicationListener: _Base.Namespace._lazy(function () { |
| // Use _lazy because publicNS can't be referenced in its own definition |
| return new _ElementUtilities._GenericListener("Application", publicNS); |
| }), |
| |
| /// <field type="Function" locid="WinJS.Application.oncheckpoint" helpKeyword="WinJS.Application.oncheckpoint"> |
| /// Occurs when receiving Process Lifetime Management (PLM) notification or when the checkpoint function is called. |
| /// </field> |
| oncheckpoint: createEvent(checkpointET), |
| /// <field type="Function" locid="WinJS.Application.onunload" helpKeyword="WinJS.Application.onunload"> |
| /// Occurs when the application is about to be unloaded. |
| /// </field> |
| onunload: createEvent(unloadET), |
| /// <field type="Function" locid="WinJS.Application.onactivated" helpKeyword="WinJS.Application.onactivated"> |
| /// Occurs when Windows Runtime activation has occurred. |
| /// The name of this event is "activated" (and also "mainwindowactivated".) |
| /// This event occurs after the loaded event and before the ready event. |
| /// </field> |
| onactivated: createEvent(activatedET), |
| /// <field type="Function" locid="WinJS.Application.onloaded" helpKeyword="WinJS.Application.onloaded"> |
| /// Occurs after the DOMContentLoaded event, which fires after the page has been parsed but before all the resources are loaded. |
| /// This event occurs before the activated event and the ready event. |
| /// </field> |
| onloaded: createEvent(loadedET), |
| /// <field type="Function" locid="WinJS.Application.onready" helpKeyword="WinJS.Application.onready"> |
| /// Occurs when the application is ready. This event occurs after the onloaded event and the onactivated event. |
| /// </field> |
| onready: createEvent(readyET), |
| /// <field type="Function" locid="WinJS.Application.onsettings" helpKeyword="WinJS.Application.onsettings"> |
| /// Occurs when the settings charm is invoked. |
| /// </field> |
| onsettings: createEvent(settingsET), |
| /// <field type="Function" locid="WinJS.Application.onerror" helpKeyword="WinJS.Application.onerror"> |
| /// Occurs when an unhandled error has been raised. |
| /// </field> |
| onerror: createEvent(errorET), |
| /// <field type="Function" locid="WinJS.Application.onbackclick" helpKeyword="WinJS.Application.onbackclick"> |
| /// Raised when the users clicks the hardware back button. |
| /// </field> |
| onbackclick: createEvent(backClickET) |
| |
| |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Animations/_Constants',[ |
| 'exports', |
| '../Core/_Base' |
| ], function animationsConstantsInit(exports, _Base) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| /// <field locid="WinJS.UI.PageNavigationAnimation" helpKeyword="WinJS.UI.PageNavigationAnimation"> |
| /// Specifies what animation type should be returned by WinJS.UI.Animation.createPageNavigationAnimations. |
| /// </field> |
| PageNavigationAnimation: { |
| /// <field locid="WinJS.UI.PageNavigationAnimation.turnstile" helpKeyword="WinJS.UI.PageNavigationAnimation.turnstile"> |
| /// The pages will exit and enter using a turnstile animation. |
| /// </field> |
| turnstile: "turnstile", |
| /// <field locid="WinJS.UI.PageNavigationAnimation.slide" helpKeyword="WinJS.UI.PageNavigationAnimation.slide"> |
| /// The pages will exit and enter using an animation that slides up/down. |
| /// </field> |
| slide: "slide", |
| /// <field locid="WinJS.UI.PageNavigationAnimation.enterPage" helpKeyword="WinJS.UI.PageNavigationAnimation.enterPage"> |
| /// The pages will enter using an enterPage animation, and exit with no animation. |
| /// </field> |
| enterPage: "enterPage", |
| /// <field locid="WinJS.UI.PageNavigationAnimation.continuum" helpKeyword="WinJS.UI.PageNavigationAnimation.continuum"> |
| /// The pages will exit and enter using a continuum animation. |
| /// </field> |
| continuum: "continuum" |
| } |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Animations/_TransitionAnimation',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Promise', |
| '../Scheduler', |
| '../Utilities/_ElementUtilities' |
| ], function transitionAnimationInit(exports, _Global, _WinRT, _Base, _BaseUtils, Promise, Scheduler, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var browserStyleEquivalents = _BaseUtils._browserStyleEquivalents; |
| |
| function makeArray(elements) { |
| if (Array.isArray(elements) || elements instanceof _Global.NodeList || elements instanceof _Global.HTMLCollection) { |
| return elements; |
| } else if (elements) { |
| return [elements]; |
| } else { |
| return []; |
| } |
| } |
| |
| var keyframeCounter = 0; |
| function getUniqueKeyframeName() { |
| ++keyframeCounter; |
| return "WinJSUIAnimation" + keyframeCounter; |
| } |
| function isUniqueKeyframeName(s) { |
| return "WinJSUIAnimation" === s.substring(0, 16); |
| } |
| |
| function resolveStyles(elem) { |
| _ElementUtilities._getComputedStyle(elem, null).opacity; |
| } |
| |
| function copyWithEvaluation(iElem, elem) { |
| return function (obj) { |
| var newObj = {}; |
| for (var p in obj) { |
| var v = obj[p]; |
| if (typeof v === "function") { |
| v = v(iElem, elem); |
| } |
| newObj[p] = v; |
| } |
| if (!newObj.exactTiming) { |
| newObj.delay += exports._libraryDelay; |
| } |
| return newObj; |
| }; |
| } |
| |
| var activeActions = []; |
| |
| var reason_interrupted = 1; |
| var reason_canceled = 2; |
| |
| function stopExistingAction(id, prop) { |
| var key = id + "|" + prop; |
| var finish = activeActions[key]; |
| if (finish) { |
| finish(reason_interrupted); |
| } |
| } |
| |
| function registerAction(id, prop, finish) { |
| activeActions[id + "|" + prop] = finish; |
| } |
| |
| function unregisterAction(id, prop) { |
| delete activeActions[id + "|" + prop]; |
| } |
| |
| var StyleCache = _Base.Class.define( |
| // Constructor |
| function StyleCache_ctor(id, desc, style) { |
| this.cref = 0; |
| this.id = id; |
| this.desc = desc; |
| this.removed = {}; |
| this.prevStyles = desc.props.map(function (p) { return style[p[0]]; }); |
| this.prevNames = this.names = style[desc.nameProp]; |
| desc.styleCaches[id] = this; |
| }, { |
| // Members |
| destroy: function StyleCache_destroy(style, skipStylesReset) { |
| var desc = this.desc; |
| delete desc.styleCaches[this.id]; |
| if (!skipStylesReset) { |
| if (this.prevNames === "" && |
| this.prevStyles.every(function (s) { return s === ""; })) { |
| style[desc.shorthandProp] = ""; |
| } else { |
| desc.props.forEach(function (p, i) { |
| style[p[0]] = this.prevStyles[i]; |
| }, this); |
| style[desc.nameProp] = this.prevNames; |
| } |
| } |
| }, |
| removeName: function StyleCache_removeName(style, name, elem, skipStylesReset) { |
| var nameValue = this.names; |
| var names = nameValue.split(", "); |
| var index = names.lastIndexOf(name); |
| if (index >= 0) { |
| names.splice(index, 1); |
| this.names = nameValue = names.join(", "); |
| if (nameValue === "" && this.desc.isTransition) { |
| nameValue = "none"; |
| } |
| } |
| if (--this.cref) { |
| style[this.desc.nameProp] = nameValue; |
| if (!isUniqueKeyframeName(name)) { |
| this.removed[name] = true; |
| } |
| } else { |
| if (elem && nameValue === "none") { |
| style[this.desc.nameProp] = nameValue; |
| resolveStyles(elem); |
| } |
| this.destroy(style, skipStylesReset); |
| } |
| } |
| }); |
| |
| function setTemporaryStyles(elem, id, style, actions, desc) { |
| var styleCache = desc.styleCaches[id] || |
| new StyleCache(id, desc, style); |
| styleCache.cref += actions.length; |
| |
| actions.forEach(function (action) { |
| stopExistingAction(id, action.property); |
| }); |
| |
| if (desc.isTransition || |
| actions.some(function (action) { |
| return styleCache.removed[action[desc.nameField]]; |
| })) { |
| resolveStyles(elem); |
| styleCache.removed = {}; |
| } |
| |
| var newShorthand = actions.map(function (action) { |
| return action[desc.nameField] + " " + |
| desc.props.map(function (p) { |
| return (p[1] ? action[p[1]] : "") + p[2]; |
| }).join(" "); |
| }).join(", "); |
| |
| var newNames = actions.map(function (action) { |
| return action[desc.nameField]; |
| }).join(", "); |
| if (styleCache.names !== "") { |
| newShorthand = styleCache.names + ", " + newShorthand; |
| newNames = styleCache.names + ", " + newNames; |
| } |
| |
| style[desc.shorthandProp] = newShorthand; |
| styleCache.names = newNames; |
| return styleCache; |
| } |
| |
| var elementTransitionProperties = { |
| shorthandProp: browserStyleEquivalents["transition"].scriptName, |
| nameProp: browserStyleEquivalents["transition-property"].scriptName, |
| nameField: "property", |
| props: [ |
| [browserStyleEquivalents["transition-duration"].scriptName, "duration", "ms"], |
| [browserStyleEquivalents["transition-timing-function"].scriptName, "timing", ""], |
| [browserStyleEquivalents["transition-delay"].scriptName, "delay", "ms"] |
| ], |
| isTransition: true, |
| styleCaches: [] |
| }; |
| |
| function completePromise(c, synchronous) { |
| if (synchronous) { |
| c(); |
| } else { |
| Scheduler.schedule(function _Animation_completeAnimationPromise() { |
| c(); |
| }, Scheduler.Priority.normal, null, "WinJS.UI._Animation._completeAnimationPromise"); |
| } |
| } |
| |
| var uniformizeStyle; |
| function executeElementTransition(elem, index, transitions, promises, animate) { |
| if (transitions.length > 0) { |
| var style = elem.style; |
| var id = _ElementUtilities._uniqueID(elem); |
| if (!uniformizeStyle) { |
| uniformizeStyle = _Global.document.createElement("DIV").style; |
| } |
| transitions = transitions.map(copyWithEvaluation(index, elem)); |
| transitions.forEach(function (transition) { |
| var scriptNameOfProperty = _BaseUtils._getCamelCasedName(transition.property); |
| if (transition.hasOwnProperty("from")) { |
| style[scriptNameOfProperty] = transition.from; |
| } |
| uniformizeStyle[scriptNameOfProperty] = transition.to; |
| transition.to = uniformizeStyle[scriptNameOfProperty]; |
| transition.propertyScriptName = scriptNameOfProperty; |
| }); |
| |
| if (animate) { |
| var styleCache = setTemporaryStyles(elem, id, style, transitions, elementTransitionProperties); |
| var listener = elem.disabled ? _Global.document : elem; |
| |
| transitions.forEach(function (transition) { |
| var finish; |
| promises.push(new Promise(function (c) { |
| finish = function (reason) { |
| if (onTransitionEnd) { |
| listener.removeEventListener(_BaseUtils._browserEventEquivalents["transitionEnd"], onTransitionEnd, false); |
| unregisterAction(id, transition.property); |
| styleCache.removeName(style, transition.propertyScriptName, reason ? elem : null, transition.skipStylesReset); |
| _Global.clearTimeout(timeoutId); |
| onTransitionEnd = null; |
| } |
| completePromise(c, reason === reason_canceled); |
| }; |
| |
| var onTransitionEnd = function (event) { |
| if (event.target === elem && event.propertyName === transition.property) { |
| finish(); |
| } |
| }; |
| |
| registerAction(id, transition.property, finish); |
| listener.addEventListener(_BaseUtils._browserEventEquivalents["transitionEnd"], onTransitionEnd, false); |
| |
| var padding = 0; |
| if (style[transition.propertyScriptName] !== transition.to) { |
| style[transition.propertyScriptName] = transition.to; |
| padding = 50; |
| } |
| var timeoutId = _Global.setTimeout(function () { |
| timeoutId = _Global.setTimeout(finish, transition.delay + transition.duration); |
| }, padding); |
| }, function () { finish(reason_canceled); })); |
| }); |
| } else { |
| transitions.forEach(function (transition) { |
| style[transition.propertyScriptName] = transition.to; |
| }); |
| } |
| } |
| } |
| |
| var elementAnimationProperties = { |
| shorthandProp: browserStyleEquivalents["animation"].scriptName, |
| nameProp: browserStyleEquivalents["animation-name"].scriptName, |
| nameField: "keyframe", |
| props: [ |
| [browserStyleEquivalents["animation-duration"].scriptName, "duration", "ms"], |
| [browserStyleEquivalents["animation-timing-function"].scriptName, "timing", ""], |
| [browserStyleEquivalents["animation-delay"].scriptName, "delay", "ms"], |
| [browserStyleEquivalents["animation-iteration-count"].scriptName, "", "1"], |
| [browserStyleEquivalents["animation-direction"].scriptName, "", "normal"], |
| [browserStyleEquivalents["animation-fill-mode"].scriptName, "", "both"] |
| ], |
| isTransition: false, |
| styleCaches: [] |
| }; |
| |
| function executeElementAnimation(elem, index, anims, promises, animate) { |
| if (animate && anims.length > 0) { |
| var style = elem.style; |
| var id = _ElementUtilities._uniqueID(elem); |
| anims = anims.map(copyWithEvaluation(index, elem)); |
| var styleElem; |
| var listener = elem.disabled ? _Global.document : elem; |
| anims.forEach(function (anim) { |
| if (!anim.keyframe) { |
| if (!styleElem) { |
| styleElem = _Global.document.createElement("STYLE"); |
| _Global.document.documentElement.appendChild(styleElem); |
| } |
| anim.keyframe = getUniqueKeyframeName(); |
| var kf = "@" + browserStyleEquivalents["keyframes"] + " " + anim.keyframe + " { from {" + anim.property + ":" + anim.from + ";} to {" + anim.property + ":" + anim.to + ";}}"; |
| styleElem.sheet.insertRule(kf, 0); |
| } else { |
| anim.keyframe = browserStyleEquivalents.animationPrefix + anim.keyframe; |
| } |
| }); |
| var styleCache = setTemporaryStyles(elem, id, style, anims, elementAnimationProperties), |
| animationsToCleanUp = [], |
| animationPromises = []; |
| anims.forEach(function (anim) { |
| var finish; |
| animationPromises.push(new Promise(function (c) { |
| finish = function (reason) { |
| if (onAnimationEnd) { |
| listener.removeEventListener(_BaseUtils._browserEventEquivalents["animationEnd"], onAnimationEnd, false); |
| _Global.clearTimeout(timeoutId); |
| onAnimationEnd = null; |
| } |
| completePromise(c, reason === reason_canceled); |
| }; |
| |
| var onAnimationEnd = function (event) { |
| if (event.target === elem && event.animationName === anim.keyframe) { |
| finish(); |
| } |
| }; |
| |
| registerAction(id, anim.property, finish); |
| // Firefox will stop all animations if we clean up that animation's properties when there're other CSS animations still running |
| // on an element. To work around this, we delay animation style cleanup until all parts of an animation finish. |
| animationsToCleanUp.push({ |
| id: id, |
| property: anim.property, |
| style: style, |
| keyframe: anim.keyframe |
| }); |
| var timeoutId = _Global.setTimeout(function () { |
| timeoutId = _Global.setTimeout(finish, anim.delay + anim.duration); |
| }, 50); |
| listener.addEventListener(_BaseUtils._browserEventEquivalents["animationEnd"], onAnimationEnd, false); |
| }, function () { finish(reason_canceled); })); |
| }); |
| if (styleElem) { |
| _Global.setTimeout(function () { |
| var parentElement = styleElem.parentElement; |
| if (parentElement) { |
| parentElement.removeChild(styleElem); |
| } |
| }, 50); |
| } |
| |
| var cleanupAnimations = function () { |
| for (var i = 0; i < animationsToCleanUp.length; i++) { |
| var anim = animationsToCleanUp[i]; |
| unregisterAction(anim.id, anim.property); |
| styleCache.removeName(anim.style, anim.keyframe); |
| } |
| }; |
| promises.push(Promise.join(animationPromises).then(cleanupAnimations, cleanupAnimations)); |
| } |
| } |
| |
| var enableCount = 0; |
| var animationSettings; |
| function initAnimations() { |
| if (!animationSettings) { |
| if (_WinRT.Windows.UI.ViewManagement.UISettings) { |
| animationSettings = new _WinRT.Windows.UI.ViewManagement.UISettings(); |
| } else { |
| animationSettings = { animationsEnabled: true }; |
| } |
| } |
| } |
| |
| var isAnimationEnabled = function isAnimationEnabledImpl() { |
| /// <signature helpKeyword="WinJS.UI.isAnimationEnabled"> |
| /// <summary locid="WinJS.UI.isAnimationEnabled"> |
| /// Determines whether the WinJS Animation Library will perform animations. |
| /// </summary> |
| /// <returns type="Boolean" locid="WinJS.UI.isAnimationEnabled_returnValue"> |
| /// true if WinJS animations will be performed. |
| /// false if WinJS animations are suppressed. |
| /// </returns> |
| /// </signature> |
| initAnimations(); |
| return enableCount + animationSettings.animationsEnabled > 0; |
| }; |
| |
| function applyAction(element, action, execAction) { |
| try { |
| var animate = exports.isAnimationEnabled(); |
| var elems = makeArray(element); |
| var actions = makeArray(action); |
| |
| var promises = []; |
| |
| for (var i = 0; i < elems.length; i++) { |
| if (Array.isArray(elems[i])) { |
| for (var j = 0; j < elems[i].length; j++) { |
| execAction(elems[i][j], i, actions, promises, animate); |
| } |
| } else { |
| execAction(elems[i], i, actions, promises, animate); |
| } |
| } |
| |
| if (promises.length) { |
| return Promise.join(promises); |
| } else { |
| return Scheduler.schedulePromiseNormal(null, "WinJS.UI._Animation._completeActionPromise").then(null, function () { |
| // Convert a cancelation to the success path |
| }); |
| } |
| } catch (e) { |
| return Promise.wrapError(e); |
| } |
| } |
| |
| function adjustAnimationTime(animation) { |
| if (Array.isArray(animation)) { |
| return animation.map(function (animation) { |
| return adjustAnimationTime(animation); |
| }); |
| } else if (animation) { |
| animation.delay = animationTimeAdjustment(animation.delay); |
| animation.duration = animationTimeAdjustment(animation.duration); |
| return animation; |
| } else { |
| return; |
| } |
| } |
| |
| function animationAdjustment(animation) { |
| if (animationFactor === 1) { |
| return animation; |
| } else { |
| return adjustAnimationTime(animation); |
| } |
| } |
| |
| var animationTimeAdjustment = function _animationTimeAdjustmentImpl(v) { |
| return v * animationFactor; |
| }; |
| |
| var animationFactor = 1; |
| var libraryDelay = 0; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| disableAnimations: function () { |
| /// <signature helpKeyword="WinJS.UI.disableAnimations"> |
| /// <summary locid="WinJS.UI.disableAnimations"> |
| /// Disables animations in the WinJS Animation Library |
| /// by decrementing the animation enable count. |
| /// </summary> |
| /// </signature> |
| enableCount--; |
| }, |
| |
| enableAnimations: function () { |
| /// <signature helpKeyword="WinJS.UI.enableAnimations"> |
| /// <summary locid="WinJS.UI.enableAnimations"> |
| /// Enables animations in the WinJS Animation Library |
| /// by incrementing the animation enable count. |
| /// </summary> |
| /// </signature> |
| enableCount++; |
| }, |
| |
| isAnimationEnabled: { |
| get: function () { |
| return isAnimationEnabled; |
| }, |
| set: function (value) { |
| isAnimationEnabled = value; |
| } |
| }, |
| |
| _libraryDelay: { |
| get: function () { |
| return libraryDelay; |
| }, |
| set: function (value) { |
| libraryDelay = value; |
| } |
| }, |
| |
| executeAnimation: function (element, animation) { |
| /// <signature helpKeyword="WinJS.UI.executeAnimation"> |
| /// <summary locid="WinJS.UI.executeAnimation"> |
| /// Perform a CSS animation that can coexist with other |
| /// Animation Library animations. Applications are not expected |
| /// to call this function directly; they should prefer to use |
| /// the high-level animations in the Animation Library. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.executeAnimation_p:element"> |
| /// Single element or collection of elements on which |
| /// to perform a CSS animation. |
| /// </param> |
| /// <param name="animation" locid="WinJS.UI.executeAnimation_p:animation"> |
| /// Single animation description or array of animation descriptions. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.executeAnimation_returnValue"> |
| /// Promise object that completes when the CSS animation is complete. |
| /// </returns> |
| /// </signature> |
| return applyAction(element, animationAdjustment(animation), executeElementAnimation); |
| }, |
| |
| executeTransition: function (element, transition) { |
| /// <signature helpKeyword="WinJS.UI.executeTransition"> |
| /// <summary locid="WinJS.UI.executeTransition"> |
| /// Perform a CSS transition that can coexist with other |
| /// Animation Library animations. Applications are not expected |
| /// to call this function directly; they should prefer to use |
| /// the high-level animations in the Animation Library. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.executeTransition_p:element"> |
| /// Single element or collection of elements on which |
| /// to perform a CSS transition. |
| /// </param> |
| /// <param name="transition" locid="WinJS.UI.executeTransition_p:transition"> |
| /// Single transition description or array of transition descriptions. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.executeTransition_returnValue"> |
| /// Promise object that completes when the CSS transition is complete. |
| /// </returns> |
| /// </signature> |
| return applyAction(element, animationAdjustment(transition), executeElementTransition); |
| }, |
| |
| _animationTimeAdjustment: { |
| get: function () { |
| return animationTimeAdjustment; |
| }, |
| set: function (value) { |
| animationTimeAdjustment = value; |
| } |
| } |
| |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| _fastAnimations: { |
| get: function () { |
| return animationFactor === 1/20; |
| }, |
| set: function (value) { |
| animationFactor = value ? 1/20 : 1; |
| } |
| }, |
| _slowAnimations: { |
| get: function () { |
| return animationFactor === 3; |
| }, |
| set: function (value) { |
| animationFactor = value ? 3 : 1; |
| } |
| }, |
| _animationFactor: { |
| get: function () { |
| return animationFactor; |
| }, |
| set: function (value) { |
| animationFactor = value; |
| } |
| }, |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Animations',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_WriteProfilerMark', |
| './Utilities/_ElementUtilities', |
| './Animations/_Constants', |
| './Animations/_TransitionAnimation', |
| './Promise' |
| ], function animationsInit(exports, _Global, _Base, _BaseUtils, _WriteProfilerMark, _ElementUtilities, _Constants, _TransitionAnimation, Promise) { |
| "use strict"; |
| |
| var transformNames = _BaseUtils._browserStyleEquivalents["transform"]; |
| |
| // Default to 11 pixel from the left (or right if RTL) |
| var defaultOffset = [{ top: "0px", left: "11px", rtlflip: true }]; |
| |
| var OffsetArray = _Base.Class.define(function OffsetArray_ctor(offset, keyframe, defOffset) { |
| // Constructor |
| defOffset = defOffset || defaultOffset; |
| if (Array.isArray(offset) && offset.length > 0) { |
| this.offsetArray = offset; |
| if (offset.length === 1) { |
| this.keyframe = checkKeyframe(offset[0], defOffset[0], keyframe); |
| } |
| } else if (offset && offset.hasOwnProperty("top") && offset.hasOwnProperty("left")) { |
| this.offsetArray = [offset]; |
| this.keyframe = checkKeyframe(offset, defOffset[0], keyframe); |
| } else { |
| this.offsetArray = defOffset; |
| this.keyframe = chooseKeyframe(defOffset[0], keyframe); |
| } |
| }, { // Public Members |
| getOffset: function (i) { |
| if (i >= this.offsetArray.length) { |
| i = this.offsetArray.length - 1; |
| } |
| return this.offsetArray[i]; |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| function checkKeyframe(offset, defOffset, keyframe) { |
| if (offset.keyframe) { |
| return offset.keyframe; |
| } |
| |
| if (!keyframe || |
| offset.left !== defOffset.left || |
| offset.top !== defOffset.top || |
| (offset.rtlflip && !defOffset.rtlflip)) { |
| return null; |
| } |
| |
| if (!offset.rtlflip) { |
| return keyframe; |
| } |
| |
| return keyframeCallback(keyframe); |
| } |
| |
| function chooseKeyframe(defOffset, keyframe) { |
| if (!keyframe || !defOffset.rtlflip) { |
| return keyframe; |
| } |
| |
| return keyframeCallback(keyframe); |
| } |
| |
| function keyframeCallback(keyframe) { |
| var keyframeRtl = keyframe + "-rtl"; |
| return function (i, elem) { |
| return _ElementUtilities._getComputedStyle(elem).direction === "ltr" ? keyframe : keyframeRtl; |
| }; |
| } |
| |
| function makeArray(elements) { |
| if (Array.isArray(elements) || elements instanceof _Global.NodeList || elements instanceof _Global.HTMLCollection) { |
| return elements; |
| } else if (elements) { |
| return [elements]; |
| } else { |
| return []; |
| } |
| } |
| |
| function collectOffsetArray(elemArray) { |
| var offsetArray = []; |
| for (var i = 0; i < elemArray.length; i++) { |
| var offset = { |
| top: elemArray[i].offsetTop, |
| left: elemArray[i].offsetLeft |
| }; |
| var matrix = _ElementUtilities._getComputedStyle(elemArray[i], null)[transformNames.scriptName].split(","); |
| if (matrix.length === 6) { |
| offset.left += parseFloat(matrix[4]); |
| offset.top += parseFloat(matrix[5]); |
| } |
| offsetArray.push(offset); |
| } |
| return offsetArray; |
| } |
| |
| function staggerDelay(initialDelay, extraDelay, delayFactor, delayCap) { |
| return function (i) { |
| var ret = initialDelay; |
| for (var j = 0; j < i; j++) { |
| extraDelay *= delayFactor; |
| ret += extraDelay; |
| } |
| if (delayCap) { |
| ret = Math.min(ret, delayCap); |
| } |
| return ret; |
| }; |
| } |
| |
| function makeOffsetsRelative(elemArray, offsetArray) { |
| for (var i = 0; i < offsetArray.length; i++) { |
| offsetArray[i].top -= elemArray[i].offsetTop; |
| offsetArray[i].left -= elemArray[i].offsetLeft; |
| } |
| } |
| |
| function animTranslate2DTransform(elemArray, offsetArray, transition) { |
| makeOffsetsRelative(elemArray, offsetArray); |
| for (var i = 0; i < elemArray.length; i++) { |
| if (offsetArray[i].top !== 0 || offsetArray[i].left !== 0) { |
| elemArray[i].style[transformNames.scriptName] = "translate(" + offsetArray[i].left + "px, " + offsetArray[i].top + "px)"; |
| } |
| } |
| return _TransitionAnimation.executeTransition(elemArray, transition); |
| } |
| |
| function animStaggeredSlide(curve, start, end, fadeIn, page, first, second, third) { |
| var elementArray = [], |
| startOffsetArray = [], |
| endOffsetArray = []; |
| function prepareSlide(elements, start, end) { |
| if (!elements) { |
| return; |
| } |
| var startOffset = { |
| left: start + "px", |
| top: "0px" |
| }, |
| endOffset = { |
| left: end + "px", |
| top: "0px" |
| }; |
| if (+elements.length === elements.length) { |
| for (var i = 0, len = elements.length; i < len; i++) { |
| elementArray.push(elements[i]); |
| startOffsetArray.push(startOffset); |
| endOffsetArray.push(endOffset); |
| } |
| } else { |
| elementArray.push(elements); |
| startOffsetArray.push(startOffset); |
| endOffsetArray.push(endOffset); |
| } |
| } |
| var horizontalOffset = 200, |
| startOffset = (start !== 0 ? (start < 0 ? -horizontalOffset : horizontalOffset) : 0), |
| endOffset = (end !== 0 ? (end < 0 ? -horizontalOffset : horizontalOffset) : 0); |
| prepareSlide(page, start, end); |
| prepareSlide(first, startOffset, endOffset); |
| prepareSlide(second, startOffset * 2, endOffset * 2); |
| prepareSlide(third, startOffset * 3, endOffset * 3); |
| startOffsetArray = new OffsetArray(startOffsetArray); |
| endOffsetArray = new OffsetArray(endOffsetArray); |
| return _TransitionAnimation.executeTransition( |
| elementArray, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 350, |
| timing: curve, |
| from: translateCallback(startOffsetArray), |
| to: translateCallback(endOffsetArray) |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 350, |
| timing: fadeIn ? "steps(1, start)" : "steps(1, end)", |
| from: fadeIn ? 0 : 1, |
| to: fadeIn ? 1 : 0 |
| }]); |
| } |
| |
| function animRotationTransform(elemArray, origins, transition) { |
| elemArray = makeArray(elemArray); |
| origins = makeArray(origins); |
| for (var i = 0, len = elemArray.length; i < len; i++) { |
| var rtl = _ElementUtilities._getComputedStyle(elemArray[i]).direction === "rtl"; |
| elemArray[i].style[_BaseUtils._browserStyleEquivalents["transform-origin"].scriptName] = origins[Math.min(origins.length - 1, i)][rtl ? "rtl" : "ltr"]; |
| } |
| function onComplete() { |
| clearAnimRotationTransform(elemArray); |
| } |
| return _TransitionAnimation.executeTransition(elemArray, transition).then(onComplete, onComplete); |
| } |
| |
| function clearAnimRotationTransform(elemArray) { |
| for (var i = 0, len = elemArray.length; i < len; i++) { |
| elemArray[i].style[_BaseUtils._browserStyleEquivalents["transform-origin"].scriptName] = ""; |
| elemArray[i].style[transformNames.scriptName] = ""; |
| elemArray[i].style.opacity = ""; |
| } |
| } |
| |
| function translateCallback(offsetArray, prefix) { |
| prefix = prefix || ""; |
| return function (i, elem) { |
| var offset = offsetArray.getOffset(i); |
| var left = offset.left; |
| if (offset.rtlflip && _ElementUtilities._getComputedStyle(elem).direction === "rtl") { |
| left = left.toString(); |
| if (left.charAt(0) === "-") { |
| left = left.substring(1); |
| } else { |
| left = "-" + left; |
| } |
| } |
| return prefix + "translate(" + left + ", " + offset.top + ")"; |
| }; |
| } |
| |
| function translateCallbackAnimate(offsetArray, suffix) { |
| suffix = suffix || ""; |
| return function (i) { |
| var offset = offsetArray[i]; |
| return "translate(" + offset.left + "px, " + offset.top + "px) " + suffix; |
| }; |
| } |
| |
| function keyframeCallbackAnimate(offsetArray, keyframe) { |
| return function (i) { |
| var offset = offsetArray[i]; |
| return (offset.left === 0 && offset.top === 0) ? keyframe : null; |
| }; |
| } |
| |
| function layoutTransition(LayoutTransition, target, affected, extra) { |
| var targetArray = makeArray(target); |
| var affectedArray = makeArray(affected); |
| var offsetArray = collectOffsetArray(affectedArray); |
| return new LayoutTransition(targetArray, affectedArray, offsetArray, extra); |
| } |
| |
| function collectTurnstileTransformOrigins(elements) { |
| var origins = []; |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var itemBoundingBox = elements[i].getBoundingClientRect(); |
| var offsetLeftLTR = -(40 + itemBoundingBox.left); |
| var offsetLeftRTL = 40 + (_Global.innerWidth - itemBoundingBox.right); |
| var totalOffsetY = ((_Global.innerHeight / 2) - itemBoundingBox.top); |
| origins.push( |
| { |
| ltr: offsetLeftLTR + "px " + totalOffsetY + "px", |
| rtl: offsetLeftRTL + "px " + totalOffsetY + "px" |
| } |
| ); |
| } |
| |
| return origins; |
| } |
| |
| function writeAnimationProfilerMark(text) { |
| _WriteProfilerMark("WinJS.UI.Animation:" + text); |
| } |
| |
| var ExpandAnimation = _Base.Class.define(function ExpandAnimation_ctor(revealedArray, affectedArray, offsetArray) { |
| // Constructor |
| this.revealedArray = revealedArray; |
| this.affectedArray = affectedArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("expandAnimation,StartTM"); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.revealedArray, |
| { |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: this.affectedArray.length > 0 ? 200 : 0, |
| duration: 167, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }); |
| var promise2 = animTranslate2DTransform( |
| this.affectedArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("expandAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var CollapseAnimation = _Base.Class.define(function CollapseAnimation_ctor(hiddenArray, affectedArray, offsetArray) { |
| // Constructor |
| this.hiddenArray = hiddenArray; |
| this.affectedArray = affectedArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("collapseAnimation,StartTM"); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.hiddenArray, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 167, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 1, |
| to: 0 |
| }); |
| var promise2 = animTranslate2DTransform( |
| this.affectedArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: this.hiddenArray.length > 0 ? 167 : 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("collapseAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var RepositionAnimation = _Base.Class.define(function RepositionAnimation_ctor(target, elementArray, offsetArray) { |
| // Constructor |
| this.elementArray = elementArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("repositionAnimation,StartTM"); |
| return animTranslate2DTransform( |
| this.elementArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 33, 1, 250), |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }) |
| .then(function () { writeAnimationProfilerMark("repositionAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var AddToListAnimation = _Base.Class.define(function AddToListAnimation_ctor(addedArray, affectedArray, offsetArray) { |
| // Constructor |
| this.addedArray = addedArray; |
| this.affectedArray = affectedArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("addToListAnimation,StartTM"); |
| var delay = this.affectedArray.length > 0 ? 240 : 0; |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.addedArray, |
| [{ |
| keyframe: "WinJS-scale-up", |
| property: transformNames.cssName, |
| delay: delay, |
| duration: 120, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: "scale(0.85)", |
| to: "none" |
| }, |
| { |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: delay, |
| duration: 120, |
| timing: "linear", |
| from: 0, |
| to: 1 |
| }] |
| ); |
| var promise2 = animTranslate2DTransform( |
| this.affectedArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 400, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("addToListAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var DeleteFromListAnimation = _Base.Class.define(function DeleteFromListAnimation_ctor(deletedArray, remainingArray, offsetArray) { |
| // Constructor |
| this.deletedArray = deletedArray; |
| this.remainingArray = remainingArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("deleteFromListAnimation,StartTM"); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.deletedArray, |
| [{ |
| keyframe: "WinJS-scale-down", |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 120, |
| timing: "cubic-bezier(0.11, 0.5, 0.24, .96)", |
| from: "none", |
| to: "scale(0.85)" |
| }, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 120, |
| timing: "linear", |
| from: 1, |
| to: 0 |
| }]); |
| var promise2 = animTranslate2DTransform( |
| this.remainingArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: this.deletedArray.length > 0 ? 60 : 0, |
| duration: 400, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("deleteFromListAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var _UpdateListAnimation = _Base.Class.define(function _UpdateListAnimation_ctor(addedArray, affectedArray, offsetArray, deleted) { |
| // Constructor |
| this.addedArray = addedArray; |
| this.affectedArray = affectedArray; |
| this.offsetArray = offsetArray; |
| var deletedArray = makeArray(deleted); |
| this.deletedArray = deletedArray; |
| this.deletedOffsetArray = collectOffsetArray(deletedArray); |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("_updateListAnimation,StartTM"); |
| makeOffsetsRelative(this.deletedArray, this.deletedOffsetArray); |
| |
| var delay = 0; |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.deletedArray, |
| [{ |
| keyframe: keyframeCallbackAnimate(this.deletedOffsetArray, "WinJS-scale-down"), |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 120, |
| timing: "cubic-bezier(0.11, 0.5, 0.24, .96)", |
| from: translateCallbackAnimate(this.deletedOffsetArray), |
| to: translateCallbackAnimate(this.deletedOffsetArray, "scale(0.85)") |
| }, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 120, |
| timing: "linear", |
| from: 1, |
| to: 0 |
| }]); |
| |
| if (this.deletedArray.length > 0) { |
| delay += 60; |
| } |
| |
| var promise2 = animTranslate2DTransform( |
| this.affectedArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: delay, |
| duration: 400, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| |
| if (this.affectedArray.length > 0) { |
| delay += 240; |
| } else if (delay) { |
| delay += 60; |
| } |
| |
| var promise3 = _TransitionAnimation.executeAnimation( |
| this.addedArray, |
| [{ |
| keyframe: "WinJS-scale-up", |
| property: transformNames.cssName, |
| delay: delay, |
| duration: 120, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: "scale(0.85)", |
| to: "none" |
| }, |
| { |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: delay, |
| duration: 120, |
| timing: "linear", |
| from: 0, |
| to: 1 |
| }] |
| ); |
| return Promise.join([promise1, promise2, promise3]) |
| .then(function () { writeAnimationProfilerMark("_updateListAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| |
| var AddToSearchListAnimation = _Base.Class.define(function AddToSearchListAnimation_ctor(addedArray, affectedArray, offsetArray) { |
| // Constructor |
| this.addedArray = addedArray; |
| this.affectedArray = affectedArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("addToSearchListAnimation,StartTM"); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.addedArray, |
| { |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: this.affectedArray.length > 0 ? 240 : 0, |
| duration: 117, |
| timing: "linear", |
| from: 0, |
| to: 1 |
| }); |
| var promise2 = animTranslate2DTransform( |
| this.affectedArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 400, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("addToSearchListAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var DeleteFromSearchListAnimation = _Base.Class.define(function DeleteFromSearchListAnimation_ctor(deletedArray, remainingArray, offsetArray) { |
| // Constructor |
| this.deletedArray = deletedArray; |
| this.remainingArray = remainingArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("deleteFromSearchListAnimation,StartTM"); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| this.deletedArray, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 93, |
| timing: "linear", |
| from: 1, |
| to: 0 |
| }); |
| var promise2 = animTranslate2DTransform( |
| this.remainingArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: this.deletedArray.length > 0 ? 60 : 0, |
| duration: 400, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("deleteFromSearchListAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| var PeekAnimation = _Base.Class.define(function PeekAnimation_ctor(target, elementArray, offsetArray) { |
| // Constructor |
| this.elementArray = elementArray; |
| this.offsetArray = offsetArray; |
| }, { // Public Members |
| execute: function () { |
| writeAnimationProfilerMark("peekAnimation,StartTM"); |
| return animTranslate2DTransform( |
| this.elementArray, |
| this.offsetArray, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 2000, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }) |
| .then(function () { writeAnimationProfilerMark("peekAnimation,StopTM"); }); |
| } |
| }, { // Static Members |
| supportedForProcessing: false, |
| }); |
| |
| // |
| // Resize animation |
| // The resize animation requires 2 animations to run simultaneously in sync with each other. It's implemented |
| // without PVL because PVL doesn't provide a way to guarantee that 2 animations will start at the same time. |
| // |
| function transformWithTransition(element, transition) { |
| // transition's properties: |
| // - duration: Number representing the duration of the animation in milliseconds. |
| // - timing: String representing the CSS timing function that controls the progress of the animation. |
| // - to: The value of *element*'s transform property after the animation. |
| var duration = transition.duration * _TransitionAnimation._animationFactor; |
| var transitionProperty = _BaseUtils._browserStyleEquivalents["transition"].scriptName; |
| element.style[transitionProperty] = duration + "ms " + transformNames.cssName + " " + transition.timing; |
| element.style[transformNames.scriptName] = transition.to; |
| |
| var finish; |
| return new Promise(function (c) { |
| var onTransitionEnd = function (eventObject) { |
| if (eventObject.target === element && eventObject.propertyName === transformNames.cssName) { |
| finish(); |
| } |
| }; |
| |
| var didFinish = false; |
| finish = function () { |
| if (!didFinish) { |
| _Global.clearTimeout(timeoutId); |
| element.removeEventListener(_BaseUtils._browserEventEquivalents["transitionEnd"], onTransitionEnd); |
| element.style[transitionProperty] = ""; |
| didFinish = true; |
| } |
| c(); |
| }; |
| |
| // Watch dog timeout |
| var timeoutId = _Global.setTimeout(function () { |
| timeoutId = _Global.setTimeout(finish, duration); |
| }, 50); |
| |
| element.addEventListener(_BaseUtils._browserEventEquivalents["transitionEnd"], onTransitionEnd); |
| }, function () { |
| finish(); // On cancelation, complete the promise successfully to match PVL |
| }); |
| } |
| |
| function getResizeDefaultTransitions() { |
| return { |
| defaultResizeGrowTransition: { |
| duration: 350, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)" |
| }, |
| |
| defaultResizeShrinkTransition: { |
| duration: 120, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)" |
| } |
| }; |
| } |
| |
| // See _resizeTransition's comment for documentation on *args*. |
| function resizeTransition(elementClipper, element, args) { |
| var defaultTransition = getResizeDefaultTransitions()[(args.to > args.from ? "defaultResizeGrowTransition" : "defaultResizeShrinkTransition")]; |
| args = _BaseUtils._merge(args, { |
| duration: args.duration === undefined ? defaultTransition.duration : args.duration, |
| timing: args.timing === undefined ? defaultTransition.timing : args.timing |
| }); |
| |
| var start = args.actualSize - args.from; |
| var end = args.actualSize - args.to; |
| if (!args.anchorTrailingEdge) { |
| start = -start; |
| end = -end; |
| } |
| var translate = args.dimension === "width" ? "translateX" : "translateY"; |
| var transition = { |
| duration: args.duration, |
| timing: args.timing |
| }; |
| |
| // Set up |
| elementClipper.style[transformNames.scriptName] = translate + "(" + start + "px)"; |
| element.style[transformNames.scriptName] = translate + "(" + -start + "px)"; |
| |
| // Resolve styles |
| _ElementUtilities._getComputedStyle(elementClipper).opacity; |
| _ElementUtilities._getComputedStyle(element).opacity; |
| |
| // Merge the transitions, but don't animate yet |
| var clipperTransition = _BaseUtils._merge(transition, { to: translate + "(" + end + "px)" }); |
| var elementTransition = _BaseUtils._merge(transition, { to: translate + "(" + -end + "px)" }); |
| |
| // Return an array so that we can prepare any other animations before beginning everything (used by commanding surface open/close animations) |
| return [ |
| { element: elementClipper, transition: clipperTransition }, |
| { element: element, transition: elementTransition } |
| ]; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI.Animation", { |
| |
| createExpandAnimation: function (revealed, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createExpandAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createExpandAnimation"> |
| /// Creates an expand animation. |
| /// After creating the ExpandAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the ExpandAnimation object. |
| /// </summary> |
| /// <param name="revealed" locid="WinJS.UI.Animation.createExpandAnimation_p:revealed"> |
| /// Single element or collection of elements which were revealed. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.createExpandAnimation_p:affected"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the expand. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createExpandAnimation_returnValue"> |
| /// ExpandAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(ExpandAnimation, revealed, affected); |
| }, |
| |
| createCollapseAnimation: function (hidden, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createCollapseAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createCollapseAnimation"> |
| /// Creates a collapse animation. |
| /// After creating the CollapseAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the CollapseAnimation object. |
| /// </summary> |
| /// <param name="hidden" locid="WinJS.UI.Animation.createCollapseAnimation_p:hidden"> |
| /// Single element or collection of elements being removed from view. |
| /// When the animation completes, the application should hide the elements |
| /// or remove them from the document. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.createCollapseAnimation_p:affected"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the collapse. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createCollapseAnimation_returnValue"> |
| /// CollapseAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(CollapseAnimation, hidden, affected); |
| }, |
| |
| createRepositionAnimation: function (element) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createRepositionAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createRepositionAnimation"> |
| /// Creates a reposition animation. |
| /// After creating the RepositionAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the RepositionAnimation object. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.createRepositionAnimation_p:element"> |
| /// Single element or collection of elements which were repositioned. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createRepositionAnimation_returnValue"> |
| /// RepositionAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(RepositionAnimation, null, element); |
| }, |
| |
| fadeIn: function (shown) { |
| /// <signature helpKeyword="WinJS.UI.Animation.fadeIn"> |
| /// <summary locid="WinJS.UI.Animation.fadeIn"> |
| /// Execute a fade-in animation. |
| /// </summary> |
| /// <param name="shown" locid="WinJS.UI.Animation.fadeIn_p:element"> |
| /// Single element or collection of elements to fade in. |
| /// At the end of the animation, the opacity of the elements is 1. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.fadeIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("fadeIn,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| shown, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 250, |
| timing: "linear", |
| from: 0, |
| to: 1 |
| }) |
| .then(function () { writeAnimationProfilerMark("fadeIn,StopTM"); }); |
| }, |
| |
| fadeOut: function (hidden) { |
| /// <signature helpKeyword="WinJS.UI.Animation.fadeOut"> |
| /// <summary locid="WinJS.UI.Animation.fadeOut"> |
| /// Execute a fade-out animation. |
| /// </summary> |
| /// <param name="hidden" locid="WinJS.UI.Animation.fadeOut_p:element"> |
| /// Single element or collection of elements to fade out. |
| /// At the end of the animation, the opacity of the elements is 0. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.fadeOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("fadeOut,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| hidden, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 167, |
| timing: "linear", |
| to: 0 |
| }) |
| .then(function () { writeAnimationProfilerMark("fadeOut,StopTM"); }); |
| }, |
| |
| createAddToListAnimation: function (added, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createAddToListAnimation" > |
| /// <summary locid="WinJS.UI.Animation.createAddToListAnimation"> |
| /// Creates an animation for adding to a list. |
| /// After creating the AddToListAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the AddToListAnimation object. |
| /// </summary> |
| /// <param name="added" locid="WinJS.UI.Animation.createAddToListAnimation_p:added"> |
| /// Single element or collection of elements which were added. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.createAddToListAnimation_p:affected"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the add. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createAddToListAnimation_returnValue"> |
| /// AddToListAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(AddToListAnimation, added, affected); |
| }, |
| |
| createDeleteFromListAnimation: function (deleted, remaining) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createDeleteFromListAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createDeleteFromListAnimation"> |
| /// Crestes an animation for deleting from a list. |
| /// After creating the DeleteFromListAnimation object, |
| /// modify the document to reflect the deletion, |
| /// then call the execute method on the DeleteFromListAnimation object. |
| /// </summary> |
| /// <param name="deleted" locid="WinJS.UI.Animation.createDeleteFromListAnimation_p:deleted"> |
| /// Single element or collection of elements which will be deleted. |
| /// When the animation completes, the application should hide the elements |
| /// or remove them from the document. |
| /// </param> |
| /// <param name="remaining" locid="WinJS.UI.Animation.createDeleteFromListAnimation_p:remaining"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the deletion. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createDeleteFromListAnimation_returnValue"> |
| /// DeleteFromListAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(DeleteFromListAnimation, deleted, remaining); |
| }, |
| |
| _createUpdateListAnimation: function (added, deleted, affected) { |
| return layoutTransition(_UpdateListAnimation, added, affected, deleted); |
| }, |
| |
| createAddToSearchListAnimation: function (added, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createAddToSearchListAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createAddToSearchListAnimation"> |
| /// Creates an animation for adding to a list of search results. |
| /// This is similar to an AddToListAnimation, but faster. |
| /// After creating the AddToSearchListAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the AddToSearchListAnimation object. |
| /// </summary> |
| /// <param name="added" locid="WinJS.UI.Animation.createAddToSearchListAnimation_p:added"> |
| /// Single element or collection of elements which were added. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.createAddToSearchListAnimation_p:affected"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the add. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createAddToSearchListAnimation_returnValue"> |
| /// AddToSearchListAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(AddToSearchListAnimation, added, affected); |
| }, |
| |
| createDeleteFromSearchListAnimation: function (deleted, remaining) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createDeleteFromSearchListAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createDeleteFromSearchListAnimation"> |
| /// Creates an animation for deleting from a list of search results. |
| /// This is similar to an DeleteFromListAnimation, but faster. |
| /// After creating the DeleteFromSearchListAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the DeleteFromSearchListAnimation object. |
| /// </summary> |
| /// <param name="deleted" locid="WinJS.UI.Animation.createDeleteFromSearchListAnimation_p:deleted"> |
| /// Single element or collection of elements which will be deleted. |
| /// When the animation completes, the application should hide the elements |
| /// or remove them from the document. |
| /// </param> |
| /// <param name="remaining" locid="WinJS.UI.Animation.createDeleteFromSearchListAnimation_p:remaining"> |
| /// Single element or collection of elements whose positions were |
| /// affected by the deletion. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createDeleteFromSearchListAnimation_returnValue"> |
| /// DeleteFromSearchListAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(DeleteFromSearchListAnimation, deleted, remaining); |
| }, |
| |
| |
| showEdgeUI: function (element, offset, options) { |
| /// <signature helpKeyword="WinJS.UI.Animation.showEdgeUI"> |
| /// <summary locid="WinJS.UI.Animation.showEdgeUI"> |
| /// Slides an element or elements into position at the edge of the screen. |
| /// This animation is designed for a small object like an appbar. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.showEdgeUI_p:element"> |
| /// Single element or collection of elements to be slid into position. |
| /// The elements should be at their final positions |
| /// at the time the function is called. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.showEdgeUI_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <param name="options" type="Object" optional="true" locid="WinJS.UI.Animation.showEdgeUI_p:options"> |
| /// Optional object which can specify the mechanism to use to play the animation. By default css |
| /// animations are used but if { mechanism: "transition" } is provided css transitions will be used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.showEdgeUI_p:returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("showEdgeUI,StartTM"); |
| |
| var isTransition = options && options.mechanism === "transition"; |
| var offsetArray = new OffsetArray(offset, "WinJS-showEdgeUI", [{ top: "-70px", left: "0px" }]); |
| return _TransitionAnimation[(isTransition ? "executeTransition" : "executeAnimation")]( |
| element, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: isTransition ? translateCallback(offsetArray) : (offsetArray.keyframe || translateCallback(offsetArray)), |
| to: "none" |
| }) |
| .then(function () { writeAnimationProfilerMark("showEdgeUI,StopTM"); }); |
| }, |
| |
| showPanel: function (element, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.showPanel"> |
| /// <summary locid="WinJS.UI.Animation.showPanel"> |
| /// Slides an element or elements into position at the edge of the screen. |
| /// This animation is designed for a large object like a keyboard. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.showPanel_p:element"> |
| /// Single element or collection of elements to be slid into position. |
| /// The elements should be at their final positions |
| /// at the time the function is called. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.showPanel_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.showPanel_returnValue"> |
| /// promise object |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("showPanel,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-showPanel", [{ top: "0px", left: "364px", rtlflip: true }]); |
| return _TransitionAnimation.executeAnimation( |
| element, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 550, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray), |
| to: "none" |
| }) |
| .then(function () { writeAnimationProfilerMark("showPanel,StopTM"); }); |
| }, |
| |
| hideEdgeUI: function (element, offset, options) { |
| /// <signature helpKeyword="WinJS.UI.Animation.hideEdgeUI"> |
| /// <summary locid="WinJS.UI.Animation.hideEdgeUI"> |
| /// Slides an element or elements at the edge of the screen out of view. |
| /// This animation is designed for a small object like an appbar. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.hideEdgeUI_p:element"> |
| /// Single element or collection of elements to be slid out. |
| /// The elements should be at their onscreen positions |
| /// at the time the function is called. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.hideEdgeUI_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <param name="options" type="Object" optional="true" locid="WinJS.UI.Animation.hideEdgeUI_p:options"> |
| /// Optional object which can specify the mechanism to use to play the animation. By default css |
| /// animations are used but if { mechanism: "transition" } is provided css transitions will be used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.hideEdgeUI_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("hideEdgeUI,StartTM"); |
| |
| var isTransition = options && options.mechanism === "transition"; |
| var offsetArray = new OffsetArray(offset, "WinJS-hideEdgeUI", [{ top: "-70px", left: "0px" }]); |
| return _TransitionAnimation[(isTransition ? "executeTransition" : "executeAnimation")]( |
| element, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: "none", |
| to: isTransition ? translateCallback(offsetArray) : (offsetArray.keyframe || translateCallback(offsetArray)) |
| }) |
| .then(function () { writeAnimationProfilerMark("hideEdgeUI,StopTM"); }); |
| }, |
| |
| hidePanel: function (element, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.hidePanel"> |
| /// <summary locid="WinJS.UI.Animation.hidePanel"> |
| /// Slides an element or elements at the edge of the screen out of view. |
| /// This animation is designed for a large object like a keyboard. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.hidePanel_p:element"> |
| /// Single element or collection of elements to be slid out. |
| /// The elements should be at their onscreen positions |
| /// at the time the function is called. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.hidePanel_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.hidePanel_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("hidePanel,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-hidePanel", [{ top: "0px", left: "364px", rtlflip: true }]); |
| return _TransitionAnimation.executeAnimation( |
| element, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 550, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: "none", |
| to: offsetArray.keyframe || translateCallback(offsetArray) |
| }) |
| .then(function () { writeAnimationProfilerMark("hidePanel,StopTM"); }); |
| }, |
| |
| showPopup: function (element, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.showPopup"> |
| /// <summary locid="WinJS.UI.Animation.showPopup"> |
| /// Displays an element or elements in the style of a popup. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.showPopup_p:element"> |
| /// Single element or collection of elements to be shown like a popup. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.showPopup_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.showPopup_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("showPopup,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-showPopup", [{ top: "50px", left: "0px" }]); |
| return _TransitionAnimation.executeAnimation( |
| element, |
| [{ |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: 83, |
| duration: 83, |
| timing: "linear", |
| from: 0, |
| to: 1 |
| }, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray), |
| to: "none" |
| }]) |
| .then(function () { writeAnimationProfilerMark("showPopup,StopTM"); }); |
| }, |
| |
| hidePopup: function (element) { |
| /// <signature helpKeyword="WinJS.UI.Animation.hidePopup" > |
| /// <summary locid="WinJS.UI.Animation.hidePopup"> |
| /// Removes a popup from the screen. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.hidePopup_p:element"> |
| /// Single element or collection of elements to be hidden like a popup. |
| /// When the animation completes, the application should hide the elements |
| /// or remove them from the document. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.hidePopup_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("hidePopup,StartTM"); |
| |
| return _TransitionAnimation.executeAnimation( |
| element, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 83, |
| timing: "linear", |
| from: 1, |
| to: 0 |
| }) |
| .then(function () { writeAnimationProfilerMark("hidePopup,StopTM"); }); |
| }, |
| |
| pointerDown: function (element) { |
| /// <signature helpKeyword="WinJS.UI.Animation.pointerDown"> |
| /// <summary locid="WinJS.UI.Animation.pointerDown"> |
| /// Execute a pointer-down animation. |
| /// Use the pointerUp animation to reverse the effect of this animation. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.pointerDown_p:element"> |
| /// Single element or collection of elements responding to the |
| /// pointer-down event. |
| /// At the end of the animation, the elements' properties have been |
| /// modified to reflect the pointer-down state. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.pointerDown_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("pointerDown,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| element, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 167, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "scale(0.975, 0.975)" |
| }) |
| .then(function () { writeAnimationProfilerMark("pointerDown,StopTM"); }); |
| }, |
| |
| pointerUp: function (element) { |
| /// <signature helpKeyword="WinJS.UI.Animation.pointerUp"> |
| /// <summary locid="WinJS.UI.Animation.pointerUp"> |
| /// Execute a pointer-up animation. |
| /// This reverses the effect of a pointerDown animation. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.pointerUp_p:element"> |
| /// Single element or collection of elements responding to |
| /// the pointer-up event. |
| /// At the end of the animation, the elements' properties have been |
| /// returned to normal. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.pointerUp_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("pointerUp,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| element, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 167, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }) |
| .then(function () { writeAnimationProfilerMark("pointerUp,StopTM"); }); |
| }, |
| |
| dragSourceStart: function (dragSource, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.dragSourceStart" > |
| /// <summary locid="WinJS.UI.Animation.dragSourceStart"> |
| /// Execute a drag-start animation. |
| /// Use the dragSourceEnd animation to reverse the effects of this animation. |
| /// </summary> |
| /// <param name="dragSource" locid="WinJS.UI.Animation.dragSourceStart_p:dragSource"> |
| /// Single element or collection of elements being dragged. |
| /// At the end of the animation, the elements' properties have been |
| /// modified to reflect the drag state. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.dragSourceStart_p:affected"> |
| /// Single element or collection of elements to highlight as not |
| /// being dragged. |
| /// At the end of the animation, the elements' properties have been |
| /// modified to reflect the drag state. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.dragSourceStart_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("dragSourceStart,StartTM"); |
| |
| var promise1 = _TransitionAnimation.executeTransition( |
| dragSource, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 240, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "scale(1.05)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 240, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: 0.65 |
| }]); |
| var promise2 = _TransitionAnimation.executeTransition( |
| affected, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 240, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "scale(0.95)" |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("dragSourceStart,StopTM"); }); |
| }, |
| |
| dragSourceEnd: function (dragSource, offset, affected) { |
| /// <signature helpKeyword="WinJS.UI.Animation.dragSourceEnd"> |
| /// <summary locid="WinJS.UI.Animation.dragSourceEnd"> |
| /// Execute a drag-end animation. |
| /// This reverses the effect of the dragSourceStart animation. |
| /// </summary> |
| /// <param name="dragSource" locid="WinJS.UI.Animation.dragSourceEnd_p:dragSource"> |
| /// Single element or collection of elements no longer being dragged. |
| /// At the end of the animation, the elements' properties have been |
| /// returned to normal. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.dragSourceEnd_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// dragSource parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <param name="affected" locid="WinJS.UI.Animation.dragSourceEnd_p:affected"> |
| /// Single element or collection of elements which were highlighted as not |
| /// being dragged. |
| /// At the end of the animation, the elements' properties have been |
| /// returned to normal. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.dragSourceEnd_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("dragSourceEnd,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-dragSourceEnd"); |
| var promise1 = _TransitionAnimation.executeTransition( |
| dragSource, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" // this removes the scale |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: 1 |
| }]); |
| |
| var promise2 = _TransitionAnimation.executeAnimation( |
| dragSource, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray, "scale(1.05) "), |
| to: "none" |
| }); |
| |
| var promise3 = _TransitionAnimation.executeTransition( |
| affected, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| return Promise.join([promise1, promise2, promise3]) |
| .then(function () { writeAnimationProfilerMark("dragSourceEnd,StopTM"); }); |
| }, |
| |
| |
| enterContent: function (incoming, offset, options) { |
| /// <signature helpKeyword="WinJS.UI.Animation.enterContent"> |
| /// <summary locid="WinJS.UI.Animation.enterContent"> |
| /// Execute an enter-content animation. |
| /// </summary> |
| /// <param name="incoming" locid="WinJS.UI.Animation.enterContent_p:incoming"> |
| /// Single element or collection of elements which represent |
| /// the incoming content. |
| /// At the end of the animation, the opacity of the elements is 1. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.enterContent_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// incoming parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <param name="options" type="Object" optional="true" locid="WinJS.UI.Animation.enterContent_p:options"> |
| /// Optional object which can specify the mechanism to use to play the animation. By default css |
| /// animations are used but if { mechanism: "transition" } is provided css transitions will be used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.enterContent_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("enterContent,StartTM"); |
| |
| var animationPromise; |
| var offsetArray = new OffsetArray(offset, "WinJS-enterContent", [{ top: "28px", left: "0px", rtlflip: false }]); |
| if (options && options.mechanism === "transition") { |
| animationPromise = _TransitionAnimation.executeTransition( |
| incoming, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 550, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: translateCallback(offsetArray), |
| to: "none" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 170, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }]); |
| } else { |
| var promise1 = _TransitionAnimation.executeAnimation( |
| incoming, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 550, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray), |
| to: "none" |
| }); |
| var promise2 = _TransitionAnimation.executeTransition( |
| incoming, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 170, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }); |
| animationPromise = Promise.join([promise1, promise2]); |
| } |
| return animationPromise.then(function () { writeAnimationProfilerMark("enterContent,StopTM"); }); |
| }, |
| |
| exitContent: function (outgoing, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.exitContent"> |
| /// <summary locid="WinJS.UI.Animation.exitContent"> |
| /// Execute an exit-content animation. |
| /// </summary> |
| /// <param name="outgoing" locid="WinJS.UI.Animation.exitContent_p:outgoing"> |
| /// Single element or collection of elements which represent |
| /// the outgoing content. |
| /// At the end of the animation, the opacity of the elements is 0. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.exitContent_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// outgoing parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.exitContent_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("exitContent,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-exit", [{ top: "0px", left: "0px" }]); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| outgoing, |
| offset && { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 117, |
| timing: "linear", |
| from: "none", |
| to: offsetArray.keyframe || translateCallback(offsetArray) |
| }); |
| |
| var promise2 = _TransitionAnimation.executeTransition( |
| outgoing, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 117, |
| timing: "linear", |
| to: 0 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("exitContent,StopTM"); }); |
| }, |
| |
| dragBetweenEnter: function (target, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.dragBetweenEnter"> |
| /// <summary locid="WinJS.UI.Animation.dragBetweenEnter"> |
| /// Execute an animation which indicates that a dragged object |
| /// can be dropped between other elements. |
| /// Use the dragBetweenLeave animation to reverse the effects of this animation. |
| /// </summary> |
| /// <param name="target" locid="WinJS.UI.Animation.dragBetweenEnter_p:target"> |
| /// Single element or collection of elements (usually two) |
| /// that the dragged object can be dropped between. |
| /// At the end of the animation, the elements' properties have been |
| /// modified to reflect the drag-between state. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.dragBetweenEnter_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.dragBetweenEnter_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("dragBetweenEnter,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, null, [{ top: "-40px", left: "0px" }, { top: "40px", left: "0px" }]); |
| return _TransitionAnimation.executeTransition( |
| target, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 200, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: translateCallback(offsetArray, "scale(0.95) ") |
| }) |
| .then(function () { writeAnimationProfilerMark("dragBetweenEnter,StopTM"); }); |
| }, |
| |
| dragBetweenLeave: function (target) { |
| /// <signature helpKeyword="WinJS.UI.Animation.dragBetweenLeave"> |
| /// <summary locid="WinJS.UI.Animation.dragBetweenLeave"> |
| /// Execute an animation which indicates that a dragged object |
| /// will no longer be dropped between other elements. |
| /// This reverses the effect of the dragBetweenEnter animation. |
| /// </summary> |
| /// <param name="target" locid="WinJS.UI.Animation.dragBetweenLeave_p:target"> |
| /// Single element or collection of elements (usually two) |
| /// that the dragged object no longer will be dropped between. |
| /// At the end of the animation, the elements' properties have been |
| /// set to the dragSourceStart state. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.dragBetweenLeave_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("dragBetweenLeave,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| target, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 200, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "scale(0.95)" |
| }) |
| .then(function () { writeAnimationProfilerMark("dragBetweenLeave,StopTM"); }); |
| }, |
| |
| swipeSelect: function (selected, selection) { |
| /// <signature helpKeyword="WinJS.UI.Animation.swipeSelect"> |
| /// <summary locid="WinJS.UI.Animation.swipeSelect"> |
| /// Slide a swipe-selected object back into position when the |
| /// pointer is released, and show the selection mark. |
| /// </summary> |
| /// <param name="selected" locid="WinJS.UI.Animation.swipeSelect_p:selected"> |
| /// Single element or collection of elements being selected. |
| /// At the end of the animation, the elements' properties have been |
| /// returned to normal. |
| /// </param> |
| /// <param name="selection" locid="WinJS.UI.Animation.swipeSelect_p:selection"> |
| /// Single element or collection of elements that is the selection mark. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.swipeSelect_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("swipeSelect,StartTM"); |
| |
| var promise1 = _TransitionAnimation.executeTransition( |
| selected, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 300, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| |
| var promise2 = _TransitionAnimation.executeAnimation( |
| selection, |
| { |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: 0, |
| duration: 300, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("swipeSelect,StopTM"); }); |
| }, |
| |
| swipeDeselect: function (deselected, selection) { |
| /// <signature helpKeyword="WinJS.UI.Animation.swipeDeselect"> |
| /// <summary locid="WinJS.UI.Animation.swipeDeselect"> |
| /// Slide a swipe-deselected object back into position when the |
| /// pointer is released, and hide the selection mark. |
| /// </summary> |
| /// <param name="deselected" locid="WinJS.UI.Animation.swipeDeselect_p:deselected"> |
| /// Single element or collection of elements being deselected. |
| /// At the end of the animation, the elements' properties have been |
| /// returned to normal. |
| /// </param> |
| /// <param name="selection" locid="WinJS.UI.Animation.swipeDeselect_p:selection"> |
| /// Single element or collection of elements that is the selection mark. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.swipeDeselect_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("swipeDeselect,StartTM"); |
| |
| var promise1 = _TransitionAnimation.executeTransition( |
| deselected, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 300, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: "" |
| }); |
| |
| var promise2 = _TransitionAnimation.executeAnimation( |
| selection, |
| { |
| keyframe: "WinJS-opacity-out", |
| property: "opacity", |
| delay: 0, |
| duration: 300, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 1, |
| to: 0 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("swipeDeselect,StopTM"); }); |
| }, |
| |
| swipeReveal: function (target, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.swipeReveal"> |
| /// <summary locid="WinJS.UI.Animation.swipeReveal"> |
| /// Reveal an object as the result of a swipe, or slide the |
| /// swipe-selected object back into position after the reveal. |
| /// </summary> |
| /// <param name="target" locid="WinJS.UI.Animation.swipeReveal_p:target"> |
| /// Single element or collection of elements being selected. |
| /// At the end of the animation, the elements' properties have been |
| /// modified to reflect the specified offset. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.swipeReveal_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// When moving the object back into position, the offset should be |
| /// { top: "0px", left: "0px" }. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// The default value describes the motion for a reveal. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.swipeReveal_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("swipeReveal,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, null, [{ top: "25px", left: "0px" }]); |
| return _TransitionAnimation.executeTransition( |
| target, |
| { |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 300, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| to: translateCallback(offsetArray) |
| }) |
| .then(function () { writeAnimationProfilerMark("swipeReveal,StopTM"); }); |
| }, |
| |
| enterPage: function (element, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.enterPage"> |
| /// <summary locid="WinJS.UI.Animation.enterPage"> |
| /// Execute an enterPage animation. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.enterPage_p:element"> |
| /// Single element or collection of elements representing the |
| /// incoming page. |
| /// At the end of the animation, the opacity of the elements is 1. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.enterPage_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// element parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.enterPage_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("enterPage,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-enterPage", [{ top: "28px", left: "0px", rtlflip: false }]); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| element, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 83, 1, 333), |
| duration: 1000, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray), |
| to: "none" |
| }); |
| var promise2 = _TransitionAnimation.executeTransition( |
| element, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 83, 1, 333), |
| duration: 170, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("enterPage,StopTM"); }); |
| }, |
| |
| exitPage: function (outgoing, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.exitPage"> |
| /// <summary locid="WinJS.UI.Animation.exitPage"> |
| /// Execute an exitPage animation. |
| /// </summary> |
| /// <param name="outgoing" locid="WinJS.UI.Animation.exitPage_p:outgoing"> |
| /// Single element or collection of elements representing |
| /// the outgoing page. |
| /// At the end of the animation, the opacity of the elements is 0. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.exitPage_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the ending point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// outgoing parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.exitPage_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("exitPage,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-exit", [{ top: "0px", left: "0px" }]); |
| var promise1 = _TransitionAnimation.executeAnimation( |
| outgoing, |
| offset && { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 117, |
| timing: "linear", |
| from: "none", |
| to: offsetArray.keyframe || translateCallback(offsetArray) |
| }); |
| |
| var promise2 = _TransitionAnimation.executeTransition( |
| outgoing, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 117, |
| timing: "linear", |
| to: 0 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("exitPage,StopTM"); }); |
| }, |
| |
| crossFade: function (incoming, outgoing) { |
| /// <signature helpKeyword="WinJS.UI.Animation.crossFade"> |
| /// <summary locid="WinJS.UI.Animation.crossFade"> |
| /// Execute a crossFade animation. |
| /// </summary> |
| /// <param name="incoming" locid="WinJS.UI.Animation.crossFade_p:incoming"> |
| /// Single incoming element or collection of incoming elements. |
| /// At the end of the animation, the opacity of the elements is 1. |
| /// </param> |
| /// <param name="outgoing" locid="WinJS.UI.Animation.crossFade_p:outgoing"> |
| /// Single outgoing element or collection of outgoing elements. |
| /// At the end of the animation, the opacity of the elements is 0. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.crossFade_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("crossFade,StartTM"); |
| |
| var promise1 = _TransitionAnimation.executeTransition( |
| incoming, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 167, |
| timing: "linear", |
| to: 1 |
| }); |
| |
| var promise2 = _TransitionAnimation.executeTransition( |
| outgoing, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 167, |
| timing: "linear", |
| to: 0 |
| }); |
| return Promise.join([promise1, promise2]) |
| .then(function () { writeAnimationProfilerMark("crossFade,StopTM"); }); |
| }, |
| |
| createPeekAnimation: function (element) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createPeekAnimation"> |
| /// <summary locid="WinJS.UI.Animation.createPeekAnimation"> |
| /// Creates a peek animation. |
| /// After creating the PeekAnimation object, |
| /// modify the document to move the elements to their new positions, |
| /// then call the execute method on the PeekAnimation object. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Animation.createPeekAnimation_p:element"> |
| /// Single element or collection of elements to be repositioned for peek. |
| /// </param> |
| /// <returns type="{ execute: Function }" locid="WinJS.UI.Animation.createPeekAnimation_returnValue"> |
| /// PeekAnimation object whose execute method returns |
| /// a Promise that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| return layoutTransition(PeekAnimation, null, element); |
| }, |
| |
| updateBadge: function (incoming, offset) { |
| /// <signature helpKeyword="WinJS.UI.Animation.updateBadge"> |
| /// <summary locid="WinJS.UI.Animation.updateBadge"> |
| /// Execute an updateBadge animation. |
| /// </summary> |
| /// <param name="incoming" locid="WinJS.UI.Animation.updateBadge_p:incoming"> |
| /// Single element or collection of elements representing the |
| /// incoming badge. |
| /// </param> |
| /// <param name="offset" locid="WinJS.UI.Animation.updateBadge_p:offset"> |
| /// Optional offset object or collection of offset objects |
| /// array describing the starting point of the animation. |
| /// If the number of offset objects is less than the length of the |
| /// incoming parameter, then the last value is repeated for all |
| /// remaining elements. |
| /// If this parameter is omitted, then a default value is used. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.updateBadge_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("updateBadge,StartTM"); |
| |
| var offsetArray = new OffsetArray(offset, "WinJS-updateBadge", [{ top: "24px", left: "0px" }]); |
| return _TransitionAnimation.executeAnimation( |
| incoming, |
| [{ |
| keyframe: "WinJS-opacity-in", |
| property: "opacity", |
| delay: 0, |
| duration: 367, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: 0, |
| to: 1 |
| }, |
| { |
| keyframe: offsetArray.keyframe, |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 1333, |
| timing: "cubic-bezier(0.1, 0.9, 0.2, 1)", |
| from: offsetArray.keyframe || translateCallback(offsetArray), |
| to: "none" |
| }]) |
| .then(function () { writeAnimationProfilerMark("updateBadge,StopTM"); }); |
| }, |
| |
| turnstileForwardIn: function (incomingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.turnstileForwardIn"> |
| /// <summary locid="WinJS.UI.Animation.turnstileForwardIn"> |
| /// Execute a turnstile forward in animation. |
| /// </summary> |
| /// <param name="incomingElements" locid="WinJS.UI.Animation.turnstileForwardIn_p:incomingElements"> |
| /// Single element or collection of elements to animate. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.turnstileForwardIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("turnstileForwardIn,StartTM"); |
| |
| incomingElements = makeArray(incomingElements); |
| var origins = collectTurnstileTransformOrigins(incomingElements); |
| return animRotationTransform( |
| incomingElements, |
| origins, |
| [{ |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 300, |
| timing: "cubic-bezier(0.01,0.975,0.4775,0.9775)", |
| from: "perspective(600px) rotateY(80deg)", |
| to: "perspective(600px) rotateY(0deg)" |
| }, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 300, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]) |
| .then(function () { writeAnimationProfilerMark("turnstileForwardIn,StopTM"); }); |
| }, |
| |
| turnstileForwardOut: function (outgoingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.turnstileForwardOut"> |
| /// <summary locid="WinJS.UI.Animation.turnstileForwardOut"> |
| /// Execute a turnstile forward out animation. |
| /// </summary> |
| /// <param name="outgoingElements" locid="WinJS.UI.Animation.turnstileForwardOut_p:outgoingElements"> |
| /// Single element or collection of elements to animate. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.turnstileForwardOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("turnstileForwardOut,StartTM"); |
| |
| outgoingElements = makeArray(outgoingElements); |
| var origins = collectTurnstileTransformOrigins(outgoingElements); |
| return animRotationTransform( |
| outgoingElements, |
| origins, |
| [{ |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 128, |
| timing: "cubic-bezier(0.4925,0.01,0.7675,-0.01)", |
| from: "perspective(600px) rotateY(0deg)", |
| to: "perspective(600px) rotateY(-50deg)", |
| }, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 128, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0, |
| }]) |
| .then(function () { writeAnimationProfilerMark("turnstileForwardOut,StopTM"); }); |
| }, |
| |
| turnstileBackwardIn: function (incomingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.turnstileBackwardIn"> |
| /// <summary locid="WinJS.UI.Animation.turnstileBackwardIn"> |
| /// Execute a turnstile backwards in animation. |
| /// </summary> |
| /// <param name="incomingElements" locid="WinJS.UI.Animation.turnstileBackwardIn_p:incomingElements"> |
| /// Single element or collection of elements to animate. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.turnstileBackwardIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("turnstileBackwardIn,StartTM"); |
| |
| incomingElements = makeArray(incomingElements); |
| var origins = collectTurnstileTransformOrigins(incomingElements); |
| return animRotationTransform( |
| incomingElements, |
| origins, |
| [{ |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 300, |
| timing: "cubic-bezier(0.01,0.975,0.4775,0.9775)", |
| from: "perspective(600px) rotateY(-50deg)", |
| to: "perspective(600px) rotateY(0deg)" |
| }, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 300, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]) |
| .then(function () { writeAnimationProfilerMark("turnstileBackwardIn,StopTM"); }); |
| }, |
| |
| turnstileBackwardOut: function (outgoingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.turnstileBackwardOut"> |
| /// <summary locid="WinJS.UI.Animation.turnstileBackwardOut"> |
| /// Execute a turnstile backward out animation. |
| /// </summary> |
| /// <param name="outgoingElements" locid="WinJS.UI.Animation.turnstileBackwardOut_p:outgoingElements"> |
| /// Single element or collection of elements to animate. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.turnstileBackwardOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("turnstileBackwardOut,StartTM"); |
| |
| outgoingElements = makeArray(outgoingElements); |
| var origins = collectTurnstileTransformOrigins(outgoingElements); |
| return animRotationTransform( |
| outgoingElements, |
| origins, |
| [{ |
| property: transformNames.cssName, |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 128, |
| timing: "cubic-bezier(0.4925,0.01,0.7675,-0.01)", |
| from: "perspective(800px) rotateY(0deg)", |
| to: "perspective(800px) rotateY(80deg)", |
| }, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 50, 1, 1000), |
| duration: 128, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0, |
| }]) |
| .then(function () { writeAnimationProfilerMark("turnstileBackwardOut,StopTM"); }); |
| }, |
| |
| slideDown: function (outgoingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideDown"> |
| /// <summary locid="WinJS.UI.Animation.slideDown"> |
| /// Execute a slide down animation. |
| /// </summary> |
| /// <param name="outgoingElements" locid="WinJS.UI.Animation.slideDown_p:outgoingElements"> |
| /// Single element or collection of elements to animate sliding down. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideDown_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideDown,StartTM"); |
| |
| return animRotationTransform( |
| outgoingElements, |
| { ltr: "", rtl: "" }, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 250, |
| timing: "cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", |
| from: "translate(0px, 0px)", |
| to: "translate(0px, 200px)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 250, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0 |
| }]) |
| .then(function () { writeAnimationProfilerMark("slideDown,StopTM"); }); |
| }, |
| |
| slideUp: function (incomingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideUp"> |
| /// <summary locid="WinJS.UI.Animation.slideUp"> |
| /// Execute a slide up animation. |
| /// </summary> |
| /// <param name="incomingElements" locid="WinJS.UI.Animation.slideUp_p:incomingElements"> |
| /// Single element or collection of elements to animate sliding up. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideUp_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideUp,StartTM"); |
| |
| return animRotationTransform( |
| incomingElements, |
| { ltr: "", rtl: "" }, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0.17,0.79,0.215,1.0025)", |
| from: "translate(0px, 200px)", |
| to: "translate(0px, 0px)" |
| }, |
| { |
| property: "opacity", |
| delay: staggerDelay(0, 34, 1, 1000), |
| duration: 350, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]) |
| .then(function () { writeAnimationProfilerMark("slideUp,StopTM"); }); |
| }, |
| |
| slideRightIn: function (page, firstIncomingElements, secondIncomingElements, thirdIncomingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideRightIn"> |
| /// <summary locid="WinJS.UI.Animation.slideRightIn"> |
| /// Execute a slide in from left to right animation. |
| /// </summary> |
| /// <param name="page" locid="WinJS.UI.Animation.slideRightIn_p:page"> |
| /// The page containing all elements to slide. |
| /// </param> |
| /// <param name="firstIncomingElements" locid="WinJS.UI.Animation.slideRightIn_p:firstIncomingElements"> |
| /// First element or collection of elements to animate sliding in. |
| /// </param> |
| /// <param name="secondIncomingElements" locid="WinJS.UI.Animation.slideRightIn_p:secondIncomingElements"> |
| /// Second element or collection of elements to animate sliding in, which will be offset slightly farther than the first. |
| /// </param> |
| /// <param name="thirdIncomingElements" locid="WinJS.UI.Animation.slideRightIn_p:thirdIncomingElements"> |
| /// Third element or collection of elements to animate sliding in, which will be offset slightly farther than the second. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideRightIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideRightIn,StartTM"); |
| |
| return animStaggeredSlide("cubic-bezier(0.17,0.79,0.215,1.0025)", -_Global.innerWidth, 0, true, page, firstIncomingElements, secondIncomingElements, thirdIncomingElements) |
| .then(function () { writeAnimationProfilerMark("slideRightIn,StopTM"); }); |
| }, |
| |
| slideRightOut: function (page, firstOutgoingElements, secondOutgoingElements, thirdOutgoingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideRightOut"> |
| /// <summary locid="WinJS.UI.Animation.slideRightOut"> |
| /// Execute a slide out from left to right animation. |
| /// </summary> |
| /// <param name="page" locid="WinJS.UI.Animation.slideRightOut_p:page"> |
| /// The page containing all elements to slide. |
| /// </param> |
| /// <param name="firstOutgoingElements" locid="WinJS.UI.Animation.slideRightOut_p:firstOutgoingElements"> |
| /// First element or collection of elements to animate sliding out. |
| /// </param> |
| /// <param name="secondOutgoingElements" locid="WinJS.UI.Animation.slideRightOut_p:secondOutgoingElements"> |
| /// Second element or collection of elements to animate sliding out, which will be offset slightly farther than the first. |
| /// </param> |
| /// <param name="thirdOutgoingElements" locid="WinJS.UI.Animation.slideRightOut_p:thirdOutgoingElements"> |
| /// Third element or collection of elements to animate sliding out, which will be offset slightly farther than the second. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideRightOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideRightOut,StartTM"); |
| |
| return animStaggeredSlide("cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", 0, _Global.innerWidth, false, page, firstOutgoingElements, secondOutgoingElements, thirdOutgoingElements) |
| .then(function () { writeAnimationProfilerMark("slideRightOut,StopTM"); }); |
| }, |
| |
| slideLeftIn: function (page, firstIncomingElements, secondIncomingElements, thirdIncomingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideLeftIn"> |
| /// <summary locid="WinJS.UI.Animation.slideLeftIn"> |
| /// Execute a slide in from right to left animation. |
| /// </summary> |
| /// <param name="page" locid="WinJS.UI.Animation.slideLeftIn_p:page"> |
| /// The page containing all elements to slide. |
| /// </param> |
| /// <param name="firstIncomingElements" locid="WinJS.UI.Animation.slideLeftIn_p:firstIncomingElements"> |
| /// First element or collection of elements to animate sliding in. |
| /// </param> |
| /// <param name="secondIncomingElements" locid="WinJS.UI.Animation.slideLeftIn_p:secondIncomingElements"> |
| /// Second element or collection of elements to animate sliding in, which will be offset slightly farther than the first. |
| /// </param> |
| /// <param name="thirdIncomingElements" locid="WinJS.UI.Animation.slideLeftIn_p:thirdIncomingElements"> |
| /// Third element or collection of elements to animate sliding in, which will be offset slightly farther than the second. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideLeftIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideLeftIn,StartTM"); |
| |
| return animStaggeredSlide("cubic-bezier(0.17,0.79,0.215,1.0025)", _Global.innerWidth, 0, true, page, firstIncomingElements, secondIncomingElements, thirdIncomingElements) |
| .then(function () { writeAnimationProfilerMark("slideLeftIn,StopTM"); }); |
| }, |
| |
| slideLeftOut: function (page, firstOutgoingElements, secondOutgoingElements, thirdOutgoingElements) { |
| /// <signature helpKeyword="WinJS.UI.Animation.slideLeftOut"> |
| /// <summary locid="WinJS.UI.Animation.slideLeftOut"> |
| /// Execute a slide out from right to left animation. |
| /// </summary> |
| /// <param name="page" locid="WinJS.UI.Animation.slideLeftOut_p:page"> |
| /// The page containing all elements to slide. |
| /// </param> |
| /// <param name="firstOutgoingElements" locid="WinJS.UI.Animation.slideLeftOut_p:firstOutgoingElements"> |
| /// First element or collection of elements to animate sliding out. |
| /// </param> |
| /// <param name="secondOutgoingElements" locid="WinJS.UI.Animation.slideLeftOut_p:secondOutgoingElements"> |
| /// Second element or collection of elements to animate sliding out, which will be offset slightly farther than the first. |
| /// </param> |
| /// <param name="thirdOutgoingElements" locid="WinJS.UI.Animation.slideLeftOut_p:thirdOutgoingElements"> |
| /// Third element or collection of elements to animate sliding out, which will be offset slightly farther than the second. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.slideLeftOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("slideLeftOut,StartTM"); |
| |
| return animStaggeredSlide("cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", 0, -_Global.innerWidth, false, page, firstOutgoingElements, secondOutgoingElements, thirdOutgoingElements) |
| .then(function () { writeAnimationProfilerMark("slideLeftOut,StopTM"); }); |
| }, |
| |
| continuumForwardIn: function (incomingPage, incomingItemRoot, incomingItemContent) { |
| /// <signature helpKeyword="WinJS.UI.Animation.continuumForwardIn"> |
| /// <summary locid="WinJS.UI.Animation.continuumForwardIn"> |
| /// Execute a continuum animation, scaling up the incoming page while scaling, rotating, and translating the incoming item. |
| /// </summary> |
| /// <param name="incomingPage" locid="WinJS.UI.Animation.continuumForwardIn_p:incomingPage"> |
| /// Single element to be scaled up that is the page root and does not contain the incoming item. |
| /// </param> |
| /// <param name="incomingItemRoot" locid="WinJS.UI.Animation.continuumForwardIn_p:incomingItemRoot"> |
| /// Root of the item that will be translated as part of the continuum animation. |
| /// </param> |
| /// <param name="incomingItemContent" locid="WinJS.UI.Animation.continuumForwardIn_p:incomingItemContent"> |
| /// Content of the item that will be scaled and rotated as part of the continuum animation. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.continuumForwardIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("continuumForwardIn,StartTM"); |
| |
| return Promise.join([ |
| _TransitionAnimation.executeTransition(incomingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0.33, 0.18, 0.11, 1)", |
| from: "scale(0.5, 0.5)", |
| to: "scale(1.0, 1.0)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]), |
| _TransitionAnimation.executeTransition(incomingItemRoot, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0.24,1.15,0.11,1.1575)", |
| from: "translate(0px, 225px)", |
| to: "translate(0px, 0px)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]), |
| animRotationTransform(incomingItemContent, { ltr: "0px 50%", rtl: "100% 50%" }, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0,0.62,0.8225,0.9625)", |
| from: "rotateX(80deg) scale(1.5, 1.5)", |
| to: "rotateX(0deg) scale(1.0, 1.0)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 350, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]) |
| ]) |
| .then(function () { writeAnimationProfilerMark("continuumForwardIn,StopTM"); }); |
| }, |
| |
| continuumForwardOut: function (outgoingPage, outgoingItem) { |
| /// <signature helpKeyword="WinJS.UI.Animation.continuumForwardOut"> |
| /// <summary locid="WinJS.UI.Animation.continuumForwardOut"> |
| /// Execute a continuum animation, scaling down the outgoing page while scaling, rotating, and translating the outgoing item. |
| /// </summary> |
| /// <param name="outgoingPage" locid="WinJS.UI.Animation.continuumForwardOut_p:outgoingPage"> |
| /// Single element to be scaled down that is the page root and contains the outgoing item. |
| /// </param> |
| /// <param name="outgoingItem" locid="WinJS.UI.Animation.continuumForwardOut_p:outgoingItem"> |
| /// Single element to be scaled, rotated, and translated away from the outgoing page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.continuumForwardOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("continuumForwardOut,StartTM"); |
| |
| return Promise.join([ |
| _TransitionAnimation.executeTransition(outgoingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 120, |
| timing: "cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", |
| from: "scale(1.0, 1.0)", |
| to: "scale(1.1, 1.1)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 120, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0, |
| }]), |
| animRotationTransform(outgoingItem, { ltr: "0px 100%", rtl: "100% 100%" }, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 152, |
| timing: "cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", |
| from: "rotateX(0deg) scale(1.0, 1.0) translate(0px, 0px)", |
| to: "rotateX(80deg) scale(1.5, 1.5) translate(0px, 150px)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 152, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0, |
| }]) |
| ]) |
| .then(function () { writeAnimationProfilerMark("continuumForwardOut,StopTM"); }); |
| }, |
| |
| continuumBackwardIn: function (incomingPage, incomingItem) { |
| /// <signature helpKeyword="WinJS.UI.Animation.continuumBackwardIn"> |
| /// <summary locid="WinJS.UI.Animation.continuumBackwardIn"> |
| /// Execute a continuum animation, scaling down the incoming page while scaling, rotating, and translating the incoming item. |
| /// </summary> |
| /// <param name="incomingPage" locid="WinJS.UI.Animation.continuumBackwardIn_p:incomingPage"> |
| /// Single element to be scaled down that is the page root and contains the incoming item. |
| /// </param> |
| /// <param name="incomingItem" locid="WinJS.UI.Animation.continuumBackwardIn_p:incomingItem"> |
| /// Single element to be scaled, rotated, and translated into its final position on the page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.continuumBackwardIn_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("continuumBackwardIn,StartTM"); |
| |
| return Promise.join([ |
| _TransitionAnimation.executeTransition(incomingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 200, |
| timing: "cubic-bezier(0.33, 0.18, 0.11, 1)", |
| from: "scale(1.25, 1.25)", |
| to: "scale(1.0, 1.0)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 200, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]), |
| animRotationTransform(incomingItem, { ltr: "0px 50%", rtl: "100% 50%" }, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 250, |
| timing: "cubic-bezier(0.2975, 0.7325, 0.4725, 0.99)", |
| from: "rotateX(80deg) translate(0px, -100px)", |
| to: "rotateX(0deg) translate(0px, 0px)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 250, |
| timing: "cubic-bezier(0, 2, 0, 2)", |
| from: 0, |
| to: 1, |
| }]) |
| ]) |
| .then(function () { writeAnimationProfilerMark("continuumBackwardIn,StopTM"); }); |
| }, |
| |
| continuumBackwardOut: function (outgoingPage) { |
| /// <signature helpKeyword="WinJS.UI.Animation.continuumBackwardOut"> |
| /// <summary locid="WinJS.UI.Animation.continuumBackwardOut"> |
| /// Execute a continuum animation, scaling down the outgoing page while fading it out. |
| /// </summary> |
| /// <param name="outgoingPage" locid="WinJS.UI.Animation.continuumBackwardOut_p:outgoingPage"> |
| /// Single element to be scaled down that is the page root. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.continuumBackwardOut_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("continuumBackwardOut,StartTM"); |
| |
| return _TransitionAnimation.executeTransition(outgoingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 167, |
| timing: "cubic-bezier(0.3825,0.0025,0.8775,-0.1075)", |
| from: "scale(1.0, 1.0)", |
| to: "scale(0.5, 0.5)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 167, |
| timing: "cubic-bezier(1,-0.42,0.995,-0.425)", |
| from: 1, |
| to: 0, |
| }]) |
| .then(function () { writeAnimationProfilerMark("continuumBackwardOut,StopTM"); }); |
| }, |
| |
| drillInIncoming: function (incomingPage) { |
| /// <signature helpKeyword="WinJS.UI.Animation.drillInIncoming"> |
| /// <summary locid="WinJS.UI.Animation.drillInIncoming"> |
| /// Execute the incoming phase of the drill in animation, scaling up the incoming page while fading it in. |
| /// </summary> |
| /// <param name="incomingPage" locid="WinJS.UI.Animation.drillInIncoming_p:incomingPage"> |
| /// Element to be scaled up and faded in. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.drillInIncoming_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("drillInIncoming,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| incomingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: "scale(0.84)", |
| to: "scale(1.0)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: 0, |
| to: 1, |
| }]) |
| .then(function () { writeAnimationProfilerMark("drillInIncoming,StopTM"); }); |
| }, |
| |
| drillInOutgoing: function (outgoingPage) { |
| /// <signature helpKeyword="WinJS.UI.Animation.drillInOutgoing"> |
| /// <summary locid="WinJS.UI.Animation.drillInOutgoing"> |
| /// Execute the outgoing phase of the drill in animation, scaling up the outgoing page while fading it out. |
| /// </summary> |
| /// <param name="outgoingPage" locid="WinJS.UI.Animation.drillInOutgoing_p:outgoingPage"> |
| /// Element to be scaled up and faded out. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.drillInOutgoing_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("drillInOutgoing,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| outgoingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 233, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: "scale(1.0)", |
| to: "scale(1.29)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 233, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: 1, |
| to: 0, |
| }]) |
| .then(function () { writeAnimationProfilerMark("drillInOutgoing,StopTM"); }); |
| }, |
| |
| drillOutIncoming: function (incomingPage) { |
| /// <signature helpKeyword="WinJS.UI.Animation.drillOutIncoming"> |
| /// <summary locid="WinJS.UI.Animation.drillOutIncoming"> |
| /// Execute the incoming phase of the drill out animation, scaling down the incoming page while fading it in. |
| /// </summary> |
| /// <param name="incomingPage" locid="WinJS.UI.Animation.drillOutIncoming_p:incomingPage"> |
| /// Element to be scaled up and faded in. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.drillOutIncoming_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("drillOutIncoming,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| incomingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: "scale(1.29)", |
| to: "scale(1.0)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 500, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: 0, |
| to: 1, |
| }]) |
| .then(function () { writeAnimationProfilerMark("drillOutIncoming,StopTM"); }); |
| }, |
| |
| drillOutOutgoing: function (outgoingPage) { |
| /// <signature helpKeyword="WinJS.UI.Animation.drillOutOutgoing"> |
| /// <summary locid="WinJS.UI.Animation.drillOutOutgoing"> |
| /// Execute the outgoing phase of the drill out animation, scaling down the outgoing page while fading it out. |
| /// </summary> |
| /// <param name="outgoingPage" locid="WinJS.UI.Animation.drillOutOutgoing_p:outgoingPage"> |
| /// Element to be scaled down and faded out. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Animation.drillOutOutgoing_returnValue"> |
| /// Promise object that completes when the animation is complete. |
| /// </returns> |
| /// </signature> |
| writeAnimationProfilerMark("drillOutOutgoing,StartTM"); |
| |
| return _TransitionAnimation.executeTransition( |
| outgoingPage, |
| [{ |
| property: transformNames.cssName, |
| delay: 0, |
| duration: 233, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: "scale(1.0)", |
| to: "scale(0.84)" |
| }, |
| { |
| property: "opacity", |
| delay: 0, |
| duration: 233, |
| timing: "cubic-bezier(0.1,0.9,0.2,1)", |
| from: 1, |
| to: 0, |
| }]) |
| .then(function () { writeAnimationProfilerMark("drillOutOutgoing,StopTM"); }); |
| }, |
| |
| createPageNavigationAnimations: function (currentPreferredAnimation, nextPreferredAnimation, movingBackwards) { |
| /// <signature helpKeyword="WinJS.UI.Animation.createPageNavigationAnimations" > |
| /// <summary locid="WinJS.UI.Animation.createPageNavigationAnimations"> |
| /// Creates an exit and entrance animation to play for a page navigation given the current and incoming pages' |
| /// animation preferences and whether the pages are navigating forwards or backwards. |
| /// </summary> |
| /// <param name="currentPreferredAnimation" locid="WinJS.UI.Animation.createPageNavigationAnimations_p:currentPreferredAnimation"> |
| /// A value from WinJS.UI.PageNavigationAnimation describing the animation the current page prefers to use. |
| /// </param> |
| /// <param name="nextPreferredAnimation" locid="WinJS.UI.Animation.createPageNavigationAnimations_p:nextPreferredAnimation"> |
| /// A value from WinJS.UI.PageNavigationAnimation describing the animation the incoming page prefers to use. |
| /// </param> |
| /// <param name="movingBackwards" locid="WinJS.UI.Animation.createPageNavigationAnimations_p:movingBackwards"> |
| /// Boolean value for whether the navigation is moving backwards. |
| /// </param> |
| /// <returns type="{ entrance: Function, exit: Function }" locid="WinJS.UI.Animation.createPageNavigationAnimations_returnValue"> |
| /// Returns an object containing the exit and entrance animations to play based on the parameters given. |
| /// </returns> |
| /// </signature> |
| function emptyAnimationFunction() { |
| return Promise.wrap(); |
| } |
| |
| return { |
| exit: emptyAnimationFunction, |
| entrance: exports.enterPage |
| }; |
| }, |
| |
| // Plays an animation which makes an element look like it is resizing in 1 dimension. Arguments: |
| // - elementClipper: The parent of *element*. It shouldn't have any margin, border, or padding and its |
| // size should match element's size. Its purpose is to clip *element* during the animation to give |
| // it the illusion that it is resizing. |
| // - element: The element that should look like it's resizing. |
| // - args: An object with the following properties (each is required unless noted otherwise): |
| // - from: A number representing the old total width/height of the element. |
| // - to: A number representing the new total width/height of the element. |
| // - actualSize: A number representing the actual total width/height of the element (should be at least |
| // as big as from and to). The element should be at *actualSize* when this function is called. |
| // from/to/actualSize represent the width/height of *element*'s margin box (e.g. getTotalWidth). |
| // - dimension: The dimension on which *element* is resizing. Either "width" or "height". |
| // - anchorTrailingEdge (optional): During the resize animation, one edge will move and the other |
| // edge will remain where it is. This flag specifies which edge is anchored (i.e. won't move). |
| // - duration (optional): Number representing the duration of the animation in milliseconds. |
| // - timing (optional): String representing the CSS timing function that controls the progress of the animation. |
| // |
| _resizeTransition: function Utilities_resizeTransition(elementClipper, element, args) { |
| if (args.to === args.from || !_TransitionAnimation.isAnimationEnabled()) { |
| return Promise.as(); |
| } else { |
| var animationsToPlay = resizeTransition(elementClipper, element, args); |
| var animationPromises = []; |
| for (var i = 0, len = animationsToPlay.length; i < len; i++) { |
| animationPromises.push(transformWithTransition(animationsToPlay[i].element, animationsToPlay[i].transition)); |
| } |
| return Promise.join(animationPromises); |
| } |
| }, |
| |
| _commandingSurfaceOpenAnimation: function Utilities_commandingSurfaceOpenAnimation(args) { |
| if (!_TransitionAnimation.isAnimationEnabled()) { |
| return Promise.as(); |
| } |
| |
| var actionAreaClipper = args.actionAreaClipper, |
| actionArea = args.actionArea, |
| overflowAreaClipper = args.overflowAreaClipper, |
| overflowArea = args.overflowArea, |
| closedHeight = args.oldHeight, |
| openedHeight = args.newHeight, |
| overflowAreaHeight = args.overflowAreaHeight, |
| menuPositionedAbove = args.menuPositionedAbove; |
| var deltaHeight = openedHeight - closedHeight; |
| var actionAreaAnimations = []; |
| var transitionToUse = getResizeDefaultTransitions().defaultResizeGrowTransition; |
| |
| // The commanding surface open animation is a combination of animations. We need to animate the actionArea and overflowArea |
| // elements expanding and appearing. The first animation we prepare is the animation on the actionArea. This animation changes depending |
| // on whether the overflow menu will appear above or below the commanding surface. |
| // When the menu is positioned above, we can do a simple translation to get the animation we want. |
| // When the menu is positioned below, we have to do a resize transition using the actionArea's clipper in order to animate the surface expanding. |
| // In either case, we don't want to play the animation immediately because the overflowArea's animation still needs to be set up, |
| // The animations that need to be played on the actionArea elements will be stored in actionAreaAnimations until after the overflowArea |
| // animations are prepared, so that we can begin every animation at once. We do this to avoid a small 1-2px gap appearing between the overflowArea |
| // and the actionArea that would appear were we to start these animations at separate times |
| if (menuPositionedAbove) { |
| actionArea.style[transformNames.scriptName] = "translateY(" + deltaHeight + "px)"; |
| _ElementUtilities._getComputedStyle(actionArea).opacity; |
| var transition = _BaseUtils._merge(transitionToUse, { to: "translateY(0px)" }); |
| actionAreaAnimations.push({ element: actionArea, transition: transition }); |
| } else { |
| actionAreaAnimations = resizeTransition(actionAreaClipper, actionArea, { |
| from: closedHeight, |
| to: openedHeight, |
| actualSize: openedHeight, |
| dimension: "height", |
| anchorTrailingEdge: false |
| }); |
| } |
| |
| // Now we set up the overflowArea animations. The overflowArea animation has two parts: |
| // The first animation is played on the overflowAreaClipper. This animation is a translation animation that we play that makes it look like the |
| // overflow menu is moving up along with the actionArea as it expands. |
| // The next animation is played on the overflowArea itself, which we animate up/down by the full size of the overflowArea. |
| // When combined, it makes it look like the overflowArea is sliding in its content while it slides up with the actionArea. |
| // Since the overflowArea and its clipper are in their final positions when this animation function is called, we apply an opposite translation |
| // to move them both to where they would have been just before the surface opened, then animate them going to translateY(0). |
| overflowAreaClipper.style[transformNames.scriptName] = "translateY(" + (menuPositionedAbove ? deltaHeight : -deltaHeight) + "px)"; |
| overflowArea.style[transformNames.scriptName] = "translateY(" + (menuPositionedAbove ? overflowAreaHeight : -overflowAreaHeight) + "px)"; |
| |
| // Resolve styles on the overflowArea and overflowAreaClipper to prepare them for animation |
| _ElementUtilities._getComputedStyle(overflowAreaClipper).opacity; |
| _ElementUtilities._getComputedStyle(overflowArea).opacity; |
| |
| var animationPromises = []; |
| for (var i = 0, len = actionAreaAnimations.length; i < len; i++) { |
| animationPromises.push(transformWithTransition(actionAreaAnimations[i].element, actionAreaAnimations[i].transition)); |
| } |
| var overflowAreaTransition = _BaseUtils._merge(transitionToUse, { to: "translateY(0px)" }); |
| animationPromises.push(transformWithTransition(overflowAreaClipper, overflowAreaTransition)); |
| animationPromises.push(transformWithTransition(overflowArea, overflowAreaTransition)); |
| return Promise.join(animationPromises); |
| }, |
| |
| _commandingSurfaceCloseAnimation: function Utilities_commandingSurfaceCloseAnimation(args) { |
| if (!_TransitionAnimation.isAnimationEnabled()) { |
| return Promise.as(); |
| } |
| |
| var actionAreaClipper = args.actionAreaClipper, |
| actionArea = args.actionArea, |
| overflowAreaClipper = args.overflowAreaClipper, |
| overflowArea = args.overflowArea, |
| openedHeight = args.oldHeight, |
| closedHeight = args.newHeight, |
| overflowAreaHeight = args.overflowAreaHeight, |
| menuPositionedAbove = args.menuPositionedAbove; |
| var deltaHeight = closedHeight - openedHeight; |
| var actionAreaAnimations = []; |
| var transitionToUse = getResizeDefaultTransitions().defaultResizeShrinkTransition; |
| if (menuPositionedAbove) { |
| actionArea.style[transformNames.scriptName] = "translateY(0px)"; |
| _ElementUtilities._getComputedStyle(actionArea).opacity; |
| var transition = _BaseUtils._merge(transitionToUse, { to: "translateY(" + -deltaHeight + "px)" }); |
| actionAreaAnimations.push({ element: actionArea, transition: transition }); |
| } else { |
| actionAreaAnimations = resizeTransition(actionAreaClipper, actionArea, { |
| from: openedHeight, |
| to: closedHeight, |
| actualSize: openedHeight, |
| dimension: "height", |
| anchorTrailingEdge: false |
| }); |
| } |
| // Set up |
| overflowAreaClipper.style[transformNames.scriptName] = "translateY(0px)"; |
| overflowArea.style[transformNames.scriptName] = "translateY(0px)"; |
| |
| // Resolve styles on the overflowArea and overflowAreaClipper to prepare them for animation |
| _ElementUtilities._getComputedStyle(overflowAreaClipper).opacity; |
| _ElementUtilities._getComputedStyle(overflowArea).opacity; |
| |
| // Now that everything's set up, we can kick off all the animations in unision |
| var animationPromises = []; |
| for (var i = 0, len = actionAreaAnimations.length; i < len; i++) { |
| animationPromises.push(transformWithTransition(actionAreaAnimations[i].element, actionAreaAnimations[i].transition)); |
| } |
| var overflowAreaClipperTransition = _BaseUtils._merge(transitionToUse, { to: "translateY(" + (menuPositionedAbove ? -deltaHeight : deltaHeight) + "px)" }); |
| var overflowAreaTransition = _BaseUtils._merge(transitionToUse, { to: "translateY(" + (menuPositionedAbove ? overflowAreaHeight : -overflowAreaHeight) + "px)" }); |
| animationPromises.push(transformWithTransition(overflowAreaClipper, overflowAreaClipperTransition)); |
| animationPromises.push(transformWithTransition(overflowArea, overflowAreaTransition)); |
| return Promise.join(animationPromises); |
| } |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Binding/_BindingParser',[ |
| 'exports', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Log', |
| '../Core/_Resources', |
| '../Core/_WriteProfilerMark', |
| '../ControlProcessor/_OptionsLexer', |
| '../ControlProcessor/_OptionsParser' |
| ], function bindingParserInit(exports, _Base, _BaseUtils, _ErrorFromName, _Log, _Resources, _WriteProfilerMark, _OptionsLexer, _OptionsParser) { |
| "use strict"; |
| |
| |
| var strings = { |
| get invalidBinding() { return "Invalid binding:'{0}'. Expected to be '<destProp>:<sourceProp>;'. {1}"; }, |
| get bindingInitializerNotFound() { return "Initializer not found:'{0}'"; }, |
| }; |
| |
| /* |
| See comment for data-win-options attribute grammar for context. |
| |
| Syntactic grammar for the value of the data-win-bind attribute. |
| |
| BindDeclarations: |
| BindDeclaration |
| BindDeclarations ; BindDeclaration |
| |
| BindDeclaration: |
| DestinationPropertyName : SourcePropertyName |
| DestinationPropertyName : SourcePropertyName InitializerName |
| |
| DestinationPropertyName: |
| IdentifierExpression |
| |
| SourcePropertyName: |
| IdentifierExpression |
| |
| InitializerName: |
| IdentifierExpression |
| |
| Value: |
| NumberLiteral |
| StringLiteral |
| |
| AccessExpression: |
| [ Value ] |
| . Identifier |
| |
| AccessExpressions: |
| AccessExpression |
| AccessExpressions AccessExpression |
| |
| IdentifierExpression: |
| Identifier |
| Identifier AccessExpressions |
| |
| */ |
| var imports = _Base.Namespace.defineWithParent(null, null, { |
| lexer: _Base.Namespace._lazy(function () { |
| return _OptionsLexer._optionsLexer; |
| }), |
| tokenType: _Base.Namespace._lazy(function () { |
| return _OptionsLexer._optionsLexer.tokenType; |
| }), |
| }); |
| |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| |
| var local = _Base.Namespace.defineWithParent(null, null, { |
| |
| BindingInterpreter: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(_OptionsParser.optionsParser._BaseInterpreter, function (tokens, originalSource, context) { |
| this._initialize(tokens, originalSource, context); |
| }, { |
| _error: function (message) { |
| throw new _ErrorFromName("WinJS.Binding.ParseError", _Resources._formatString(strings.invalidBinding, this._originalSource, message)); |
| }, |
| _evaluateInitializerName: function () { |
| if (this._current.type === imports.tokenType.identifier) { |
| var initializer = this._evaluateIdentifierExpression(); |
| if (_Log.log && !initializer) { |
| _Log.log(_Resources._formatString(strings.bindingInitializerNotFound, this._originalSource), "winjs binding", "error"); |
| } |
| return requireSupportedForProcessing(initializer); |
| } |
| return; |
| }, |
| _evaluateValue: function () { |
| switch (this._current.type) { |
| case imports.tokenType.stringLiteral: |
| case imports.tokenType.numberLiteral: |
| var value = this._current.value; |
| this._read(); |
| return value; |
| |
| default: |
| this._unexpectedToken(imports.tokenType.stringLiteral, imports.tokenType.numberLiteral); |
| return; |
| } |
| }, |
| _readBindDeclarations: function () { |
| var bindings = []; |
| while (true) { |
| switch (this._current.type) { |
| case imports.tokenType.identifier: |
| case imports.tokenType.thisKeyword: |
| bindings.push(this._readBindDeclaration()); |
| break; |
| |
| case imports.tokenType.semicolon: |
| this._read(); |
| break; |
| |
| case imports.tokenType.eof: |
| return bindings; |
| |
| default: |
| this._unexpectedToken(imports.tokenType.identifier, imports.tokenType.semicolon, imports.tokenType.eof); |
| return; |
| } |
| } |
| }, |
| _readBindDeclaration: function () { |
| var dest = this._readDestinationPropertyName(); |
| this._read(imports.tokenType.colon); |
| var src = this._readSourcePropertyName(); |
| var initializer = this._evaluateInitializerName(); |
| return { |
| destination: dest, |
| source: src, |
| initializer: initializer, |
| }; |
| }, |
| _readDestinationPropertyName: function () { |
| return this._readIdentifierExpression(); |
| }, |
| _readSourcePropertyName: function () { |
| return this._readIdentifierExpression(); |
| }, |
| run: function () { |
| return this._readBindDeclarations(); |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| BindingParser: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(local.BindingInterpreter, function (tokens, originalSource) { |
| this._initialize(tokens, originalSource, {}); |
| }, { |
| _readInitializerName: function () { |
| if (this._current.type === imports.tokenType.identifier) { |
| return this._readIdentifierExpression(); |
| } |
| return; |
| }, |
| _readBindDeclaration: function () { |
| var dest = this._readDestinationPropertyName(); |
| this._read(imports.tokenType.colon); |
| var src = this._readSourcePropertyName(); |
| var initializer = this._readInitializerName(); |
| return { |
| destination: dest, |
| source: src, |
| initializer: initializer, |
| }; |
| }, |
| }, { |
| supportedForProcessing: false, |
| }); |
| }) |
| |
| }); |
| |
| function parser(text, context) { |
| _WriteProfilerMark("WinJS.Binding:bindingParser,StartTM"); |
| var tokens = imports.lexer(text); |
| var interpreter = new local.BindingInterpreter(tokens, text, context || {}); |
| var res = interpreter.run(); |
| _WriteProfilerMark("WinJS.Binding:bindingParser,StopTM"); |
| return res; |
| } |
| |
| function parser2(text) { |
| _WriteProfilerMark("WinJS.Binding:bindingParser,StartTM"); |
| var tokens = imports.lexer(text); |
| var interpreter = new local.BindingParser(tokens, text); |
| var res = interpreter.run(); |
| _WriteProfilerMark("WinJS.Binding:bindingParser,StopTM"); |
| return res; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| _bindingParser: parser, |
| _bindingParser2: parser2, |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Binding/_DomWeakRefTable',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Scheduler' |
| ], function DOMWeakRefTableInit(exports, _Global, _WinRT, _Base, _BaseUtils, Scheduler) { |
| "use strict"; |
| |
| if (_WinRT.Windows.Foundation.Uri && _WinRT.msSetWeakWinRTProperty && _WinRT.msGetWeakWinRTProperty) { |
| |
| var host = new _WinRT.Windows.Foundation.Uri("about://blank"); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| |
| _createWeakRef: function (element, id) { |
| _WinRT.msSetWeakWinRTProperty(host, id, element); |
| return id; |
| }, |
| |
| _getWeakRefElement: function (id) { |
| return _WinRT.msGetWeakWinRTProperty(host, id); |
| } |
| |
| }); |
| |
| return; |
| |
| } |
| |
| // Defaults |
| var SWEEP_PERIOD = 500; |
| var TIMEOUT = 1000; |
| var table = {}; |
| var cleanupToken; |
| var noTimeoutUnderDebugger = true; |
| var fastLoadPath = false; |
| |
| function cleanup() { |
| if (SWEEP_PERIOD === 0) { // If we're using post |
| cleanupToken = 0; // indicate that cleanup has run |
| } |
| var keys = Object.keys(table); |
| var time = Date.now() - TIMEOUT; |
| var i, len; |
| for (i = 0, len = keys.length; i < len; i++) { |
| var id = keys[i]; |
| if (table[id].time < time) { |
| delete table[id]; |
| } |
| } |
| unscheduleCleanupIfNeeded(); |
| } |
| |
| function scheduleCleanupIfNeeded() { |
| if ((_Global.Debug && _Global.Debug.debuggerEnabled && noTimeoutUnderDebugger) || cleanupToken) { |
| return; |
| } |
| if (SWEEP_PERIOD === 0) { |
| Scheduler.schedule(cleanup, Scheduler.Priority.idle, null, "WinJS.Utilities._DOMWeakRefTable.cleanup"); |
| cleanupToken = 1; |
| } else { |
| cleanupToken = _Global.setInterval(cleanup, SWEEP_PERIOD); |
| } |
| } |
| |
| function unscheduleCleanupIfNeeded() { |
| if (_Global.Debug && _Global.Debug.debuggerEnabled && noTimeoutUnderDebugger) { |
| return; |
| } |
| if (SWEEP_PERIOD === 0) { // if we're using post |
| if (!cleanupToken) { // and there isn't already one scheduled |
| if (Object.keys(table).length !== 0) { // and there are items in the table |
| Scheduler.schedule( // schedule another call to cleanup |
| cleanup, |
| Scheduler.Priority.idle, |
| null, "WinJS.Utilities._DOMWeakRefTable.cleanup" |
| ); |
| cleanupToken = 1; // and protect against overscheduling |
| } |
| } |
| } else if (cleanupToken) { |
| if (Object.keys(table).length === 0) { |
| _Global.clearInterval(cleanupToken); |
| cleanupToken = 0; |
| } |
| } |
| } |
| |
| function createWeakRef(element, id) { |
| table[id] = { element: element, time: Date.now() }; |
| scheduleCleanupIfNeeded(); |
| return id; |
| } |
| |
| function getWeakRefElement(id) { |
| if (fastLoadPath) { |
| var entry = table[id]; |
| if (entry) { |
| return entry.element; |
| } else { |
| return _Global.document.getElementById(id); |
| } |
| } else { |
| var element = _Global.document.getElementById(id); |
| if (element) { |
| delete table[id]; |
| unscheduleCleanupIfNeeded(); |
| } else { |
| var entry = table[id]; |
| if (entry) { |
| entry.time = Date.now(); |
| element = entry.element; |
| } |
| } |
| return element; |
| } |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Utilities", { |
| _DOMWeakRefTable_noTimeoutUnderDebugger: { |
| get: function () { |
| return noTimeoutUnderDebugger; |
| }, |
| set: function (value) { |
| noTimeoutUnderDebugger = value; |
| } |
| }, |
| _DOMWeakRefTable_sweepPeriod: { |
| get: function () { |
| return SWEEP_PERIOD; |
| }, |
| set: function (value) { |
| SWEEP_PERIOD = value; |
| } |
| }, |
| _DOMWeakRefTable_timeout: { |
| get: function () { |
| return TIMEOUT; |
| }, |
| set: function (value) { |
| TIMEOUT = value; |
| } |
| }, |
| _DOMWeakRefTable_tableSize: { get: function () { return Object.keys(table).length; } }, |
| _DOMWeakRefTable_fastLoadPath: { |
| get: function () { |
| return fastLoadPath; |
| }, |
| set: function (value) { |
| fastLoadPath = value; |
| } |
| }, |
| _createWeakRef: createWeakRef, |
| _getWeakRefElement: getWeakRefElement |
| |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Binding/_Data',[ |
| 'exports', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Log', |
| '../Core/_Resources', |
| '../Promise', |
| '../Scheduler', |
| './_DomWeakRefTable' |
| ], function dataInit(exports, _WinRT, _Base, _BaseUtils, _ErrorFromName, _Log, _Resources, Promise, Scheduler, _DomWeakRefTable) { |
| "use strict"; |
| |
| |
| var strings = { |
| get exceptionFromBindingInitializer() { return "Exception thrown from binding initializer: {0}"; }, |
| get propertyIsUndefined() { return "{0} is undefined"; }, |
| get unsupportedDataTypeForBinding() { return "Unsupported data type"; }, |
| }; |
| |
| var observableMixin = { |
| _listeners: null, |
| _pendingNotifications: null, |
| _notifyId: 0, |
| |
| _getObservable: function () { |
| return this; |
| }, |
| |
| _cancel: function (name) { |
| var v = this._pendingNotifications; |
| var hit = false; |
| if (v) { |
| var k = Object.keys(v); |
| for (var i = k.length - 1; i >= 0; i--) { |
| var entry = v[k[i]]; |
| if (entry.target === name) { |
| if (entry.promise) { |
| entry.promise.cancel(); |
| entry.promise = null; |
| } |
| delete v[k[i]]; |
| hit = true; |
| } |
| } |
| } |
| return hit; |
| }, |
| |
| notify: function (name, newValue, oldValue) { |
| /// <signature helpKeyword="WinJS.Binding.observableMixin.notify"> |
| /// <summary locid="WinJS.Binding.observableMixin.notify"> |
| /// Notifies listeners that a property value was updated. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.observableMixin.notify_p:name">The name of the property that is being updated.</param> |
| /// <param name="newValue" type="Object" locid="WinJS.Binding.observableMixin.notify_p:newValue">The new value for the property.</param> |
| /// <param name="oldValue" type="Object" locid="WinJS.Binding.observableMixin.notify_p:oldValue">The old value for the property.</param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Binding.observableMixin.notify_returnValue">A promise that is completed when the notifications are complete.</returns> |
| /// </signature> |
| var listeners = this._listeners && this._listeners[name]; |
| if (listeners) { |
| var that = this; |
| |
| // Handle the case where we are updating a value that is currently updating |
| // |
| that._cancel(name); |
| |
| // Starting new work, we cache the work description and queue up to do the notifications |
| // |
| that._pendingNotifications = that._pendingNotifications || {}; |
| var x = that._notifyId++; |
| var cap = that._pendingNotifications[x] = { target: name }; |
| |
| var cleanup = function () { |
| delete that._pendingNotifications[x]; |
| }; |
| |
| // Binding guarantees async notification, so we do timeout() |
| // |
| cap.promise = Scheduler.schedulePromiseNormal(null, "WinJS.Binding.observableMixin.notify"). |
| then(function () { |
| // cap.promise is removed after canceled, so we use this as a signal |
| // to indicate that we should abort early |
| // |
| for (var i = 0, l = listeners.length; i < l && cap.promise; i++) { |
| try { |
| listeners[i](newValue, oldValue); |
| } |
| catch (e) { |
| _Log.log && _Log.log(_Resources._formatString(strings.exceptionFromBindingInitializer, e.toString()), "winjs binding", "error"); |
| } |
| } |
| cleanup(); |
| return newValue; |
| }); |
| |
| return cap.promise; |
| } |
| |
| return Promise.as(); |
| }, |
| |
| bind: function (name, action) { |
| /// <signature helpKeyword="WinJS.Binding.observableMixin.bind"> |
| /// <summary locid="WinJS.Binding.observableMixin.bind"> |
| /// Links the specified action to the property specified in the name parameter. |
| /// This function is invoked when the value of the property may have changed. |
| /// It is not guaranteed that the action will be called only when a value has actually changed, |
| /// nor is it guaranteed that the action will be called for every value change. The implementation |
| /// of this function coalesces change notifications, such that multiple updates to a property |
| /// value may result in only a single call to the specified action. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.observableMixin.bind_p:name"> |
| /// The name of the property to which to bind the action. |
| /// </param> |
| /// <param name="action" type="function" locid="WinJS.Binding.observableMixin.bind_p:action"> |
| /// The function to invoke asynchronously when the property may have changed. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.observableMixin.bind_returnValue"> |
| /// This object is returned. |
| /// </returns> |
| /// </signature> |
| |
| this._listeners = this._listeners || {}; |
| var listeners = this._listeners[name] = this._listeners[name] || []; |
| |
| // duplicate detection, multiple binds with the same action should have no effect |
| // |
| var found = false; |
| for (var i = 0, l = listeners.length; i < l; i++) { |
| if (listeners[i] === action) { |
| found = true; |
| break; |
| } |
| } |
| |
| if (!found) { |
| listeners.push(action); |
| |
| // out of band notification, we want to avoid a broadcast to all listeners |
| // so we can't just call notify. |
| // |
| action(unwrap(this[name])); |
| } |
| return this; |
| }, |
| |
| unbind: function (name, action) { |
| /// <signature helpKeyword="WinJS.Binding.observableMixin.unbind"> |
| /// <summary locid="WinJS.Binding.observableMixin.unbind"> |
| /// Removes one or more listeners from the notification list for a given property. |
| /// </summary> |
| /// <param name="name" type="String" optional="true" locid="WinJS.Binding.observableMixin.unbind_p:name"> |
| /// The name of the property to unbind. If this parameter is omitted, all listeners |
| /// for all events are removed. |
| /// </param> |
| /// <param name="action" type="function" optional="true" locid="WinJS.Binding.observableMixin.unbind_p:action"> |
| /// The function to remove from the listener list for the specified property. If this parameter is omitted, all listeners |
| /// are removed for the specific property. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.observableMixin.unbind_returnValue"> |
| /// This object is returned. |
| /// </returns> |
| /// </signature> |
| |
| this._listeners = this._listeners || {}; |
| |
| if (name && action) { |
| // this assumes we rarely have more than one |
| // listener, so we optimize to not do a lot of |
| // array manipulation, although it means we |
| // may do some extra GC churn in the other cases... |
| // |
| var listeners = this._listeners[name]; |
| if (listeners) { |
| var nl; |
| for (var i = 0, l = listeners.length; i < l; i++) { |
| if (listeners[i] !== action) { |
| (nl = nl || []).push(listeners[i]); |
| } |
| } |
| this._listeners[name] = nl; |
| } |
| |
| // we allow any pending notification sweep to complete, |
| // which means that "unbind" inside of a notification |
| // will not prevent that notification from occuring. |
| // |
| } else if (name) { |
| this._cancel(name); |
| delete this._listeners[name]; |
| } else { |
| var that = this; |
| if (that._pendingNotifications) { |
| var v = that._pendingNotifications; |
| that._pendingNotifications = {}; |
| Object.keys(v).forEach(function (k) { |
| var n = v[k]; |
| if (n.promise) { n.promise.cancel(); } |
| }); |
| } |
| this._listeners = {}; |
| } |
| return this; |
| } |
| }; |
| |
| var dynamicObservableMixin = { |
| _backingData: null, |
| |
| _initObservable: function (data) { |
| this._backingData = data || {}; |
| }, |
| |
| getProperty: function (name) { |
| /// <signature helpKeyword="WinJS.Binding.dynamicObservableMixin.getProperty"> |
| /// <summary locid="WinJS.Binding.dynamicObservableMixin.getProperty"> |
| /// Gets a property value by name. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.dynamicObservableMixin.getProperty_p:name"> |
| /// The name of property to get. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.dynamicObservableMixin.getProperty_returnValue"> |
| /// The value of the property as an observable object. |
| /// </returns> |
| /// </signature> |
| var data = this._backingData[name]; |
| if (_Log.log && data === undefined) { |
| _Log.log(_Resources._formatString(strings.propertyIsUndefined, name), "winjs binding", "warn"); |
| } |
| return as(data); |
| }, |
| |
| setProperty: function (name, value) { |
| /// <signature helpKeyword="WinJS.Binding.dynamicObservableMixin.setProperty"> |
| /// <summary locid="WinJS.Binding.dynamicObservableMixin.setProperty"> |
| /// Updates a property value and notifies any listeners. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.dynamicObservableMixin.setProperty_p:name"> |
| /// The name of the property to update. |
| /// </param> |
| /// <param name="value" locid="WinJS.Binding.dynamicObservableMixin.setProperty_p:value"> |
| /// The new value of the property. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.dynamicObservableMixin.setProperty_returnValue"> |
| /// This object is returned. |
| /// </returns> |
| /// </signature> |
| |
| this.updateProperty(name, value); |
| return this; |
| }, |
| |
| addProperty: function (name, value) { |
| /// <signature helpKeyword="WinJS.Binding.dynamicObservableMixin.addProperty"> |
| /// <summary locid="WinJS.Binding.dynamicObservableMixin.addProperty"> |
| /// Adds a property with change notification to this object, including a ECMAScript5 property definition. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.dynamicObservableMixin.addProperty_p:name"> |
| /// The name of the property to add. |
| /// </param> |
| /// <param name="value" locid="WinJS.Binding.dynamicObservableMixin.addProperty_p:value"> |
| /// The value of the property. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.dynamicObservableMixin.addProperty_returnValue"> |
| /// This object is returned. |
| /// </returns> |
| /// </signature> |
| |
| // we could walk Object.keys to more deterministically determine this, |
| // however in the normal case this avoids a bunch of string compares |
| // |
| if (!this[name]) { |
| Object.defineProperty(this, |
| name, { |
| get: function () { return this.getProperty(name); }, |
| set: function (value) { this.setProperty(name, value); }, |
| enumerable: true, |
| configurable: true |
| } |
| ); |
| } |
| return this.setProperty(name, value); |
| }, |
| |
| updateProperty: function (name, value) { |
| /// <signature helpKeyword="WinJS.Binding.dynamicObservableMixin.updateProperty"> |
| /// <summary locid="WinJS.Binding.dynamicObservableMixin.updateProperty"> |
| /// Updates a property value and notifies any listeners. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.dynamicObservableMixin.updateProperty_p:name"> |
| /// The name of the property to update. |
| /// </param> |
| /// <param name="value" locid="WinJS.Binding.dynamicObservableMixin.updateProperty_p:value"> |
| /// The new value of the property. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Binding.dynamicObservableMixin.updateProperty_returnValue"> |
| /// A promise that completes when the notifications for |
| /// this property change have been processed. If multiple notifications are coalesced, |
| /// the promise may be canceled or the value of the promise may be updated. |
| /// The fulfilled value of the promise is the new value of the property for |
| /// which the notifications have been completed. |
| /// </returns> |
| /// </signature> |
| |
| var oldValue = this._backingData[name]; |
| var newValue = unwrap(value); |
| if (oldValue !== newValue) { |
| this._backingData[name] = newValue; |
| |
| // This will complete when the listeners are notified, even |
| // if a new value is used. The only time this promise will fail |
| // (cancel) will be if we start notifying and then have to |
| // cancel in the middle of processing it. That's a pretty |
| // subtle contract. |
| // |
| // IE has a bug where readonly properties will not throw, |
| // even in strict mode, when set using a string accessor. |
| // To be consistent across browsers, only notify if the |
| // set succeeded. |
| if (this._backingData[name] === newValue) { |
| return this.notify(name, newValue, oldValue); |
| } |
| } |
| return Promise.as(); |
| }, |
| |
| removeProperty: function (name) { |
| /// <signature helpKeyword="WinJS.Binding.dynamicObservableMixin.removeProperty"> |
| /// <summary locid="WinJS.Binding.dynamicObservableMixin.removeProperty"> |
| /// Removes a property value. |
| /// </summary> |
| /// <param name="name" type="String" locid="WinJS.Binding.dynamicObservableMixin.removeProperty_p:name"> |
| /// The name of the property to remove. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.dynamicObservableMixin.removeProperty_returnValue"> |
| /// This object is returned. |
| /// </returns> |
| /// </signature> |
| |
| var oldValue = this._backingData[name]; |
| var value; // capture "undefined" |
| // in strict mode these may throw |
| try { |
| delete this._backingData[name]; |
| } catch (e) { } |
| try { |
| delete this[name]; |
| } catch (e) { } |
| this.notify(name, value, oldValue); |
| return this; |
| } |
| }; |
| |
| // Merge "obsevable" into "dynamicObservable" |
| // |
| Object.keys(observableMixin).forEach(function (k) { |
| dynamicObservableMixin[k] = observableMixin[k]; |
| }); |
| |
| |
| var bind = function (observable, bindingDescriptor) { |
| /// <signature helpKeyword="WinJS.Binding.bind"> |
| /// <summary locid="WinJS.Binding.bind"> |
| /// Binds to one or more properties on the observable object or or on child values |
| /// of that object. |
| /// </summary> |
| /// <param name="observable" type="Object" locid="WinJS.Binding.bind_p:observable"> |
| /// The object to bind to. |
| /// </param> |
| /// <param name="bindingDescriptor" type="Object" locid="WinJS.Binding.bind_p:bindingDescriptor"> |
| /// An object literal containing the binding declarations. Binding declarations take the form: |
| /// { propertyName: (function | bindingDeclaration), ... } |
| /// |
| /// For example, binding to a nested member of an object is declared like this: |
| /// bind(someObject, { address: { street: function(v) { ... } } }); |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.bind_returnValue"> |
| /// An object that contains at least a "cancel" field, which is |
| /// a function that removes all bindings associated with this bind |
| /// request. |
| /// </returns> |
| /// </signature> |
| return bindImpl(observable, bindingDescriptor); |
| }; |
| var bindRefId = 0; |
| var createBindRefId = function () { |
| return "bindHandler" + (bindRefId++); |
| }; |
| var createProxy = function (func, bindStateRef) { |
| if (!_WinRT.msGetWeakWinRTProperty) { |
| return func; |
| } |
| |
| var id = createBindRefId(); |
| _DomWeakRefTable._getWeakRefElement(bindStateRef)[id] = func; |
| return function (n, o) { |
| var bindState = _DomWeakRefTable._getWeakRefElement(bindStateRef); |
| if (bindState) { |
| bindState[id](n, o); |
| } |
| }; |
| }; |
| var bindImpl = function (observable, bindingDescriptor, bindStateRef) { |
| observable = as(observable); |
| if (!observable) { |
| return { cancel: function () { }, empty: true }; |
| } |
| |
| var bindState; |
| if (!bindStateRef) { |
| bindStateRef = createBindRefId(); |
| bindState = {}; |
| _DomWeakRefTable._createWeakRef(bindState, bindStateRef); |
| } |
| |
| var complexLast = {}; |
| var simpleLast = null; |
| |
| function cancelSimple() { |
| if (simpleLast) { |
| simpleLast.forEach(function (e) { |
| e.source.unbind(e.prop, e.listener); |
| }); |
| } |
| simpleLast = null; |
| } |
| |
| function cancelComplex(k) { |
| if (complexLast[k]) { |
| complexLast[k].complexBind.cancel(); |
| delete complexLast[k]; |
| } |
| } |
| |
| Object.keys(bindingDescriptor).forEach(function (k) { |
| var listener = bindingDescriptor[k]; |
| if (listener instanceof Function) { |
| // Create a proxy for the listener which indirects weakly through the bind |
| // state, if this is the root object tack the bind state onto the listener |
| // |
| listener = createProxy(listener, bindStateRef); |
| listener.bindState = bindState; |
| simpleLast = simpleLast || []; |
| simpleLast.push({ source: observable, prop: k, listener: listener }); |
| observable.bind(k, listener); |
| } else { |
| var propChanged = function (v) { |
| cancelComplex(k); |
| var complexBind = bindImpl(as(v), listener, bindStateRef); |
| |
| // In the case that we hit an "undefined" in the chain, we prop the change |
| // notification to all listeners, basically saying that x.y.z where "y" |
| // is undefined resolves to undefined. |
| // |
| if (complexBind.empty) { |
| var recursiveNotify = function (root) { |
| Object.keys(root).forEach(function (key) { |
| var item = root[key]; |
| if (item instanceof Function) { |
| item(undefined, undefined); |
| } else { |
| recursiveNotify(item); |
| } |
| }); |
| }; |
| recursiveNotify(listener); |
| } |
| complexLast[k] = { source: v, complexBind: complexBind }; |
| }; |
| |
| // Create a proxy for the listener which indirects weakly through the bind |
| // state, if this is the root object tack the bind state onto the listener |
| // |
| propChanged = createProxy(propChanged, bindStateRef); |
| propChanged.bindState = bindState; |
| simpleLast = simpleLast || []; |
| simpleLast.push({ source: observable, prop: k, listener: propChanged }); |
| observable.bind(k, propChanged); |
| } |
| }); |
| |
| return { |
| cancel: function () { |
| cancelSimple(); |
| Object.keys(complexLast).forEach(function (k) { cancelComplex(k); }); |
| } |
| }; |
| }; |
| |
| |
| var ObservableProxy = _Base.Class.mix(function (data) { |
| this._initObservable(data); |
| Object.defineProperties(this, expandProperties(data)); |
| }, dynamicObservableMixin); |
| |
| var expandProperties = function (shape) { |
| /// <signature helpKeyword="WinJS.Binding.expandProperties"> |
| /// <summary locid="WinJS.Binding.expandProperties"> |
| /// Wraps the specified object so that all its properties |
| /// are instrumented for binding. This is meant to be used in |
| /// conjunction with the binding mixin. |
| /// </summary> |
| /// <param name="shape" type="Object" locid="WinJS.Binding.expandProperties_p:shape"> |
| /// The specification for the bindable object. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.expandProperties_returnValue"> |
| /// An object with a set of properties all of which are wired for binding. |
| /// </returns> |
| /// </signature> |
| var props = {}; |
| function addToProps(k) { |
| props[k] = { |
| get: function () { return this.getProperty(k); }, |
| set: function (value) { this.setProperty(k, value); }, |
| enumerable: true, |
| configurable: true // enables delete |
| }; |
| } |
| while (shape && shape !== Object.prototype) { |
| Object.keys(shape).forEach(addToProps); |
| shape = Object.getPrototypeOf(shape); |
| } |
| return props; |
| }; |
| |
| var define = function (data) { |
| /// <signature helpKeyword="WinJS.Binding.define"> |
| /// <summary locid="WinJS.Binding.define"> |
| /// Creates a new constructor function that supports observability with |
| /// the specified set of properties. |
| /// </summary> |
| /// <param name="data" type="Object" locid="WinJS.Binding.define_p:data"> |
| /// The object to use as the pattern for defining the set of properties, for example: |
| /// var MyPointClass = define({x:0,y:0}); |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Binding.define_returnValue"> |
| /// A constructor function with 1 optional argument that is the initial state of |
| /// the properties. |
| /// </returns> |
| /// </signature> |
| |
| // Common unsupported types, we just coerce to be an empty record |
| // |
| if (!data || typeof (data) !== "object" || (data instanceof Date) || Array.isArray(data)) { |
| if (_BaseUtils.validation) { |
| throw new _ErrorFromName("WinJS.Binding.UnsupportedDataType", _Resources._formatString(strings.unsupportedDataTypeForBinding)); |
| } else { |
| return; |
| } |
| } |
| |
| return _Base.Class.mix( |
| function (init) { |
| /// <signature helpKeyword="WinJS.Binding.define.return"> |
| /// <summary locid="WinJS.Binding.define.return"> |
| /// Creates a new observable object. |
| /// </summary> |
| /// <param name="init" type="Object" locid="WinJS.Binding.define.return_p:init"> |
| /// The initial values for the properties. |
| /// </param> |
| /// </signature> |
| |
| this._initObservable(init || Object.create(data)); |
| }, |
| dynamicObservableMixin, |
| expandProperties(data) |
| ); |
| }; |
| |
| var as = function (data) { |
| /// <signature helpKeyword="WinJS.Binding.as"> |
| /// <summary locid="WinJS.Binding.as"> |
| /// Returns an observable object. This may be an observable proxy for the specified object, an existing proxy, or |
| /// the specified object itself if it directly supports observability. |
| /// </summary> |
| /// <param name="data" type="Object" locid="WinJS.Binding.as_p:data"> |
| /// Object to provide observability for. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.as_returnValue"> |
| /// The observable object. |
| /// </returns> |
| /// </signature> |
| |
| if (!data) { |
| return data; |
| } |
| |
| var type = typeof data; |
| if (type === "object" |
| && !(data instanceof Date) |
| && !(Array.isArray(data))) { |
| if (data._getObservable) { |
| return data._getObservable(); |
| } |
| |
| var observable = new ObservableProxy(data); |
| observable.backingData = data; |
| Object.defineProperty( |
| data, |
| "_getObservable", |
| { |
| value: function () { return observable; }, |
| enumerable: false, |
| writable: false |
| } |
| ); |
| return observable; |
| } else { |
| return data; |
| } |
| }; |
| |
| var unwrap = function (data) { |
| /// <signature helpKeyword="WinJS.Binding.unwrap"> |
| /// <summary locid="WinJS.Binding.unwrap"> |
| /// Returns the original (non-observable) object is returned if the specified object is an observable proxy, . |
| /// </summary> |
| /// <param name="data" type="Object" locid="WinJS.Binding.unwrap_p:data"> |
| /// The object for which to retrieve the original value. |
| /// </param> |
| /// <returns type="Object" locid="WinJS.Binding.unwrap_returnValue"> |
| /// If the specified object is an observable proxy, the original object is returned, otherwise the same object is returned. |
| /// </returns> |
| /// </signature> |
| if (data && data.backingData) { |
| return data.backingData; |
| } else { |
| return data; |
| } |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| // must use long form because mixin has "get" and "set" as members, so the define |
| // method thinks it's a property |
| mixin: { value: dynamicObservableMixin, enumerable: true, writable: true, configurable: true }, |
| dynamicObservableMixin: { value: dynamicObservableMixin, enumerable: true, writable: true, configurable: true }, |
| observableMixin: { value: observableMixin, enumerable: true, writable: true, configurable: true }, |
| expandProperties: expandProperties, |
| define: define, |
| as: as, |
| unwrap: unwrap, |
| bind: bind |
| }); |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Binding/_Declarative',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Log', |
| '../Core/_Resources', |
| '../Core/_WriteProfilerMark', |
| '../Promise', |
| '../Utilities/_ElementUtilities', |
| './_BindingParser', |
| './_Data', |
| './_DomWeakRefTable' |
| ], function declarativeInit(exports, _Global, _WinRT, _Base, _BaseUtils, _ErrorFromName, _Log, _Resources, _WriteProfilerMark, Promise, _ElementUtilities, _BindingParser, _Data, _DomWeakRefTable) { |
| "use strict"; |
| |
| var uid = (Math.random() * 1000) >> 0; |
| |
| // If we have proper weak references then we can move away from using the element's ID property |
| // |
| var optimizeBindingReferences = _WinRT.msSetWeakWinRTProperty && _WinRT.msGetWeakWinRTProperty; |
| |
| var strings = { |
| get attributeBindingSingleProperty() { return "Attribute binding requires a single destination attribute name, often in the form \"this['aria-label']\" or \"width\"."; }, |
| get cannotBindToThis() { return "Can't bind to 'this'."; }, |
| get creatingNewProperty() { return "Creating new property {0}. Full path:{1}"; }, |
| get duplicateBindingDetected() { return "Binding against element with id {0} failed because a duplicate id was detected."; }, |
| get elementNotFound() { return "Element not found:{0}"; }, |
| get errorInitializingBindings() { return "Error initializing bindings: {0}"; }, |
| get propertyDoesNotExist() { return "{0} doesn't exist. Full path:{1}"; }, |
| get idBindingNotSupported() { return "Declarative binding to ID field is not supported. Initializer: {0}"; }, |
| get nestedDOMElementBindingNotSupported() { return "Binding through a property {0} of type HTMLElement is not supported, Full path:{1}."; } |
| }; |
| |
| var markSupportedForProcessing = _BaseUtils.markSupportedForProcessing; |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| |
| function registerAutoDispose(bindable, callback) { |
| var d = bindable._autoDispose; |
| d && d.push(callback); |
| } |
| function autoDispose(bindable) { |
| bindable._autoDispose = (bindable._autoDispose || []).filter(function (callback) { return callback(); }); |
| } |
| |
| function checkBindingToken(element, bindingId) { |
| if (element) { |
| if (element.winBindingToken === bindingId) { |
| return element; |
| } else { |
| _Log.log && _Log.log(_Resources._formatString(strings.duplicateBindingDetected, element.id), "winjs binding", "error"); |
| } |
| } else { |
| return element; |
| } |
| } |
| |
| function setBindingToken(element) { |
| if (element.winBindingToken) { |
| return element.winBindingToken; |
| } |
| |
| var bindingToken = "_win_bind" + (uid++); |
| Object.defineProperty(element, "winBindingToken", { configurable: false, writable: false, enumerable: false, value: bindingToken }); |
| return bindingToken; |
| } |
| |
| function initializerOneBinding(bind, ref, bindingId, source, e, pend, cacheEntry) { |
| var initializer = bind.initializer; |
| if (initializer) { |
| initializer = initializer.winControl || initializer["data-win-control"] || initializer; |
| } |
| if (initializer instanceof Function) { |
| var result = initializer(source, bind.source, e, bind.destination); |
| |
| if (cacheEntry) { |
| if (result && result.cancel) { |
| cacheEntry.bindings.push(function () { result.cancel(); }); |
| } else { |
| // notify the cache that we encountered an uncancellable thing |
| // |
| cacheEntry.nocache = true; |
| } |
| } |
| return result; |
| } else if (initializer && initializer.render) { |
| pend.count++; |
| |
| // notify the cache that we encountered an uncancellable thing |
| // |
| if (cacheEntry) { |
| cacheEntry.nocache = true; |
| } |
| |
| requireSupportedForProcessing(initializer.render).call(initializer, getValue(source, bind.source), e). |
| then(function () { |
| pend.checkComplete(); |
| }); |
| } |
| } |
| |
| function makeBinding(ref, bindingId, pend, bindable, bind, cacheEntry) { |
| var first = true; |
| var bindResult; |
| var canceled = false; |
| |
| autoDispose(bindable); |
| |
| var resolveWeakRef = function () { |
| if (canceled) { return; } |
| |
| var found = checkBindingToken(_DomWeakRefTable._getWeakRefElement(ref), bindingId); |
| if (!found) { |
| _Log.log && _Log.log(_Resources._formatString(strings.elementNotFound, ref), "winjs binding", "info"); |
| if (bindResult) { |
| bindResult.cancel(); |
| } |
| } |
| return found; |
| }; |
| var bindingAction = function (v) { |
| var found = resolveWeakRef(); |
| if (found) { |
| nestedSet(found, bind.destination, v); |
| } |
| if (first) { |
| pend.checkComplete(); |
| first = false; |
| } |
| }; |
| registerAutoDispose(bindable, resolveWeakRef); |
| |
| bindResult = bindWorker(bindable, bind.source, bindingAction); |
| if (bindResult) { |
| var cancel = bindResult.cancel; |
| bindResult.cancel = function () { |
| canceled = true; |
| return cancel.call(bindResult); |
| }; |
| if (cacheEntry) { |
| cacheEntry.bindings.push(function () { bindResult.cancel(); }); |
| } |
| } |
| |
| return bindResult; |
| } |
| |
| function sourceOneBinding(bind, ref, bindingId, source, e, pend, cacheEntry) { |
| var bindable; |
| if (source !== _Global) { |
| source = _Data.as(source); |
| } |
| if (source._getObservable) { |
| bindable = source._getObservable(); |
| } |
| if (bindable) { |
| pend.count++; |
| // declarative binding must use a weak ref to the target element |
| // |
| return makeBinding(ref, bindingId, pend, bindable, bind, cacheEntry); |
| } else { |
| nestedSet(e, bind.destination, getValue(source, bind.source)); |
| } |
| } |
| |
| function filterIdBinding(declBind, bindingStr) { |
| for (var bindIndex = declBind.length - 1; bindIndex >= 0; bindIndex--) { |
| var bind = declBind[bindIndex]; |
| var dest = bind.destination; |
| if (dest.length === 1 && dest[0] === "id") { |
| if (_BaseUtils.validation) { |
| throw new _ErrorFromName("WinJS.Binding.IdBindingNotSupported", _Resources._formatString(strings.idBindingNotSupported, bindingStr)); |
| } |
| _Log.log && _Log.log(_Resources._formatString(strings.idBindingNotSupported, bindingStr), "winjs binding", "error"); |
| declBind.splice(bindIndex, 1); |
| } |
| } |
| return declBind; |
| } |
| |
| function calcBinding(bindingStr, bindingCache) { |
| if (bindingCache) { |
| var declBindCache = bindingCache.expressions[bindingStr]; |
| var declBind; |
| if (!declBindCache) { |
| declBind = filterIdBinding(_BindingParser._bindingParser(bindingStr, _Global), bindingStr); |
| bindingCache.expressions[bindingStr] = declBind; |
| } |
| if (!declBind) { |
| declBind = declBindCache; |
| } |
| return declBind; |
| } else { |
| return filterIdBinding(_BindingParser._bindingParser(bindingStr, _Global), bindingStr); |
| } |
| } |
| |
| function declarativeBindImpl(rootElement, dataContext, skipRoot, bindingCache, defaultInitializer, c) { |
| _WriteProfilerMark("WinJS.Binding:processAll,StartTM"); |
| |
| var pend = { |
| count: 0, |
| checkComplete: function checkComplete() { |
| this.count--; |
| if (this.count === 0) { |
| _WriteProfilerMark("WinJS.Binding:processAll,StopTM"); |
| c(); |
| } |
| } |
| }; |
| var baseElement = (rootElement || _Global.document.body); |
| var selector = "[data-win-bind],[data-win-control]"; |
| var elements = baseElement.querySelectorAll(selector); |
| var neg; |
| if (!skipRoot && (baseElement.getAttribute("data-win-bind") || baseElement.winControl)) { |
| neg = baseElement; |
| } |
| |
| pend.count++; |
| var source = dataContext || _Global; |
| |
| _DomWeakRefTable._DOMWeakRefTable_fastLoadPath = true; |
| try { |
| var baseElementData = _ElementUtilities.data(baseElement); |
| baseElementData.winBindings = baseElementData.winBindings || []; |
| |
| for (var i = (neg ? -1 : 0), l = elements.length; i < l; i++) { |
| var element = i < 0 ? neg : elements[i]; |
| |
| // If we run into a declarative control container (e.g. Binding.Template) we don't process its |
| // children, but we do give it an opportunity to process them later using this data context. |
| // |
| if (element.winControl && element.winControl.constructor && element.winControl.constructor.isDeclarativeControlContainer) { |
| i += element.querySelectorAll(selector).length; |
| |
| var idcc = element.winControl.constructor.isDeclarativeControlContainer; |
| if (typeof idcc === "function") { |
| idcc = requireSupportedForProcessing(idcc); |
| idcc(element.winControl, function (element) { |
| return declarativeBind(element, dataContext, false, bindingCache, defaultInitializer); |
| }); |
| } |
| } |
| |
| // In order to catch controls above we may have elements which don't have bindings, skip them |
| // |
| if (!element.hasAttribute("data-win-bind")) { |
| continue; |
| } |
| |
| var original = element.getAttribute("data-win-bind"); |
| var declBind = calcBinding(original, bindingCache); |
| |
| if (!declBind.implemented) { |
| for (var bindIndex = 0, bindLen = declBind.length; bindIndex < bindLen; bindIndex++) { |
| var bind = declBind[bindIndex]; |
| bind.initializer = bind.initializer || defaultInitializer; |
| if (bind.initializer) { |
| bind.implementation = initializerOneBinding; |
| } else { |
| bind.implementation = sourceOneBinding; |
| } |
| } |
| declBind.implemented = true; |
| } |
| |
| pend.count++; |
| |
| var bindingId = setBindingToken(element); |
| var ref = optimizeBindingReferences ? bindingId : element.id; |
| |
| if (!ref) { |
| // We use our own counter here, as the IE "uniqueId" is only |
| // global to a document, which means that binding against |
| // unparented DOM elements would get duplicate IDs. |
| // |
| // The elements may not be parented at this point, but they |
| // will be parented by the time the binding action is fired. |
| // |
| element.id = ref = bindingId; |
| } |
| |
| _DomWeakRefTable._createWeakRef(element, ref); |
| var elementData = _ElementUtilities.data(element); |
| elementData.winBindings = null; |
| var cacheEntry; |
| if (bindingCache && bindingCache.elements) { |
| cacheEntry = bindingCache.elements[ref]; |
| if (!cacheEntry) { |
| bindingCache.elements[ref] = cacheEntry = { bindings: [] }; |
| } |
| } |
| |
| for (var bindIndex2 = 0, bindLen2 = declBind.length; bindIndex2 < bindLen2; bindIndex2++) { |
| var bind2 = declBind[bindIndex2]; |
| var cancel2 = bind2.implementation(bind2, ref, bindingId, source, element, pend, cacheEntry); |
| if (cancel2) { |
| elementData.winBindings = elementData.winBindings || []; |
| elementData.winBindings.push(cancel2); |
| baseElementData.winBindings.push(cancel2); |
| } |
| } |
| pend.count--; |
| } |
| } |
| finally { |
| _DomWeakRefTable._DOMWeakRefTable_fastLoadPath = false; |
| } |
| pend.checkComplete(); |
| } |
| |
| function declarativeBind(rootElement, dataContext, skipRoot, bindingCache, defaultInitializer) { |
| /// <signature helpKeyword="WinJS.Binding.declarativeBind"> |
| /// <summary locid="WinJS.Binding.declarativeBind"> |
| /// Binds values from the specified data context to elements that are descendants of the specified root element |
| /// and have declarative binding attributes (data-win-bind). |
| /// </summary> |
| /// <param name="rootElement" type="DOMElement" optional="true" locid="WinJS.Binding.declarativeBind_p:rootElement"> |
| /// The element at which to start traversing to find elements to bind to. If this parameter is omitted, the entire document |
| /// is searched. |
| /// </param> |
| /// <param name="dataContext" type="Object" optional="true" locid="WinJS.Binding.declarativeBind_p:dataContext"> |
| /// The object to use for default data binding. |
| /// </param> |
| /// <param name="skipRoot" type="Boolean" optional="true" locid="WinJS.Binding.declarativeBind_p:skipRoot"> |
| /// If true, the elements to be bound skip the specified root element and include only the children. |
| /// </param> |
| /// <param name="bindingCache" optional="true" locid="WinJS.Binding.declarativeBind_p:bindingCache"> |
| /// The cached binding data. |
| /// </param> |
| /// <param name="defaultInitializer" optional="true" locid="WinJS.Binding.declarativeBind_p:defaultInitializer"> |
| /// The binding initializer to use in the case that one is not specified in a binding expression. If not |
| /// provided the behavior is the same as WinJS.Binding.defaultBind. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Binding.declarativeBind_returnValue"> |
| /// A promise that completes when each item that contains binding declarations has |
| /// been processed and the update has started. |
| /// </returns> |
| /// </signature> |
| |
| return new Promise(function (c, e, p) { |
| declarativeBindImpl(rootElement, dataContext, skipRoot, bindingCache, defaultInitializer, c, e, p); |
| }).then(null, function (e) { |
| _Log.log && _Log.log(_Resources._formatString(strings.errorInitializingBindings, e && e.message), "winjs binding", "error"); |
| return Promise.wrapError(e); |
| }); |
| } |
| |
| function converter(convert) { |
| /// <signature helpKeyword="WinJS.Binding.converter"> |
| /// <summary locid="WinJS.Binding.converter"> |
| /// Creates a default binding initializer for binding between a source |
| /// property and a destination property with a provided converter function |
| /// that is executed on the value of the source property. |
| /// </summary> |
| /// <param name="convert" type="Function" locid="WinJS.Binding.converter_p:convert"> |
| /// The conversion that operates over the result of the source property |
| /// to produce a value that is set to the destination property. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Binding.converter_returnValue"> |
| /// The binding initializer. |
| /// </returns> |
| /// </signature> |
| var userConverter = function (source, sourceProperties, dest, destProperties, initialValue) { |
| var bindingId = setBindingToken(dest); |
| var ref = optimizeBindingReferences ? bindingId : dest.id; |
| |
| if (!ref) { |
| dest.id = ref = bindingId; |
| } |
| |
| _DomWeakRefTable._createWeakRef(dest, ref); |
| |
| var bindable; |
| if (source !== _Global) { |
| source = _Data.as(source); |
| } |
| if (source._getObservable) { |
| bindable = source._getObservable(); |
| } |
| if (bindable) { |
| var workerResult = bindWorker(_Data.as(source), sourceProperties, function (v) { |
| var found = checkBindingToken(_DomWeakRefTable._getWeakRefElement(ref), bindingId); |
| if (found) { |
| nestedSet(found, destProperties, convert(requireSupportedForProcessing(v))); |
| } else if (workerResult) { |
| _Log.log && _Log.log(_Resources._formatString(strings.elementNotFound, ref), "winjs binding", "info"); |
| workerResult.cancel(); |
| } |
| }); |
| return workerResult; |
| } else { |
| var value = getValue(source, sourceProperties); |
| if (value !== initialValue) { |
| nestedSet(dest, destProperties, convert(value)); |
| } |
| } |
| }; |
| return markSupportedForProcessing(userConverter); |
| } |
| |
| function getValue(obj, path) { |
| if (obj !== _Global) { |
| obj = requireSupportedForProcessing(obj); |
| } |
| if (path) { |
| for (var i = 0, len = path.length; i < len && (obj !== null && obj !== undefined) ; i++) { |
| obj = requireSupportedForProcessing(obj[path[i]]); |
| } |
| } |
| return obj; |
| } |
| |
| function nestedSet(dest, destProperties, v) { |
| requireSupportedForProcessing(v); |
| dest = requireSupportedForProcessing(dest); |
| for (var i = 0, len = (destProperties.length - 1) ; i < len; i++) { |
| dest = requireSupportedForProcessing(dest[destProperties[i]]); |
| if (!dest) { |
| _Log.log && _Log.log(_Resources._formatString(strings.propertyDoesNotExist, destProperties[i], destProperties.join(".")), "winjs binding", "error"); |
| return; |
| } else if (dest instanceof _Global.Node) { |
| _Log.log && _Log.log(_Resources._formatString(strings.nestedDOMElementBindingNotSupported, destProperties[i], destProperties.join(".")), "winjs binding", "error"); |
| return; |
| } |
| } |
| if (destProperties.length === 0) { |
| _Log.log && _Log.log(strings.cannotBindToThis, "winjs binding", "error"); |
| return; |
| } |
| var prop = destProperties[destProperties.length - 1]; |
| if (_Log.log) { |
| if (dest[prop] === undefined) { |
| _Log.log(_Resources._formatString(strings.creatingNewProperty, prop, destProperties.join(".")), "winjs binding", "warn"); |
| } |
| } |
| dest[prop] = v; |
| } |
| |
| function attributeSet(dest, destProperties, v) { |
| dest = requireSupportedForProcessing(dest); |
| if (!destProperties || destProperties.length !== 1 || !destProperties[0]) { |
| _Log.log && _Log.log(strings.attributeBindingSingleProperty, "winjs binding", "error"); |
| return; |
| } |
| dest.setAttribute(destProperties[0], v); |
| } |
| |
| function setAttribute(source, sourceProperties, dest, destProperties, initialValue) { |
| /// <signature helpKeyword="WinJS.Binding.setAttribute"> |
| /// <summary locid="WinJS.Binding.setAttribute"> |
| /// Creates a one-way binding between the source object and |
| /// an attribute on the destination element. |
| /// </summary> |
| /// <param name="source" type="Object" locid="WinJS.Binding.setAttribute_p:source"> |
| /// The source object. |
| /// </param> |
| /// <param name="sourceProperties" type="Array" locid="WinJS.Binding.setAttribute_p:sourceProperties"> |
| /// The path on the source object to the source property. |
| /// </param> |
| /// <param name="dest" type="Object" locid="WinJS.Binding.setAttribute_p:dest"> |
| /// The destination object (must be a DOM element). |
| /// </param> |
| /// <param name="destProperties" type="Array" locid="WinJS.Binding.setAttribute_p:destProperties"> |
| /// The path on the destination object to the destination property, this must be a single name. |
| /// </param> |
| /// <param name="initialValue" optional="true" locid="WinJS.Binding.setAttribute_p:initialValue"> |
| /// The known initial value of the target, if the source value is the same as this initial |
| /// value (using ===) then the target is not set the first time. |
| /// </param> |
| /// <returns type="{ cancel: Function }" locid="WinJS.Binding.setAttribute_returnValue"> |
| /// An object with a cancel method that is used to coalesce bindings. |
| /// </returns> |
| /// </signature> |
| |
| var bindingId = setBindingToken(dest); |
| var ref = optimizeBindingReferences ? bindingId : dest.id; |
| |
| if (!ref) { |
| dest.id = ref = bindingId; |
| } |
| |
| _DomWeakRefTable._createWeakRef(dest, ref); |
| |
| var bindable; |
| if (source !== _Global) { |
| source = _Data.as(source); |
| } |
| if (source._getObservable) { |
| bindable = source._getObservable(); |
| } |
| if (bindable) { |
| var counter = 0; |
| var workerResult = bindWorker(bindable, sourceProperties, function (v) { |
| if (++counter === 1) { |
| if (v === initialValue) { |
| return; |
| } |
| } |
| var found = checkBindingToken(_DomWeakRefTable._getWeakRefElement(ref), bindingId); |
| if (found) { |
| attributeSet(found, destProperties, requireSupportedForProcessing(v)); |
| } else if (workerResult) { |
| _Log.log && _Log.log(_Resources._formatString(strings.elementNotFound, ref), "winjs binding", "info"); |
| workerResult.cancel(); |
| } |
| }); |
| return workerResult; |
| } else { |
| var value = getValue(source, sourceProperties); |
| if (value !== initialValue) { |
| attributeSet(dest, destProperties, value); |
| } |
| } |
| } |
| function setAttributeOneTime(source, sourceProperties, dest, destProperties) { |
| /// <signature helpKeyword="WinJS.Binding.setAttributeOneTime"> |
| /// <summary locid="WinJS.Binding.setAttributeOneTime"> |
| /// Sets an attribute on the destination element to the value of the source property |
| /// </summary> |
| /// <param name="source" type="Object" locid="WinJS.Binding.setAttributeOneTime_p:source"> |
| /// The source object. |
| /// </param> |
| /// <param name="sourceProperties" type="Array" locid="WinJS.Binding.setAttributeOneTime_p:sourceProperties"> |
| /// The path on the source object to the source property. |
| /// </param> |
| /// <param name="dest" type="Object" locid="WinJS.Binding.setAttributeOneTime_p:dest"> |
| /// The destination object (must be a DOM element). |
| /// </param> |
| /// <param name="destProperties" type="Array" locid="WinJS.Binding.setAttributeOneTime_p:destProperties"> |
| /// The path on the destination object to the destination property, this must be a single name. |
| /// </param> |
| /// </signature> |
| return attributeSet(dest, destProperties, getValue(source, sourceProperties)); |
| } |
| |
| function addClassOneTime(source, sourceProperties, dest) { |
| /// <signature helpKeyword="WinJS.Binding.addClassOneTime"> |
| /// <summary locid="WinJS.Binding.addClassOneTime"> |
| /// Adds a class or Array list of classes on the destination element to the value of the source property |
| /// </summary> |
| /// <param name="source" type="Object" locid="WinJS.Binding.addClassOneTime:source"> |
| /// The source object. |
| /// </param> |
| /// <param name="sourceProperties" type="Array" locid="WinJS.Binding.addClassOneTime:sourceProperties"> |
| /// The path on the source object to the source property. |
| /// </param> |
| /// <param name="dest" type="Object" locid="WinJS.Binding.addClassOneTime:dest"> |
| /// The destination object (must be a DOM element). |
| /// </param> |
| /// </signature> |
| dest = requireSupportedForProcessing(dest); |
| var value = getValue(source, sourceProperties); |
| if (Array.isArray(value)) { |
| value.forEach(function (className) { |
| _ElementUtilities.addClass(dest, className); |
| }); |
| } else if (value) { |
| _ElementUtilities.addClass(dest, value); |
| } |
| } |
| |
| var defaultBindImpl = converter(function defaultBind_passthrough(v) { return v; }); |
| |
| function defaultBind(source, sourceProperties, dest, destProperties, initialValue) { |
| /// <signature helpKeyword="WinJS.Binding.defaultBind"> |
| /// <summary locid="WinJS.Binding.defaultBind"> |
| /// Creates a one-way binding between the source object and |
| /// the destination object. |
| /// </summary> |
| /// <param name="source" type="Object" locid="WinJS.Binding.defaultBind_p:source"> |
| /// The source object. |
| /// </param> |
| /// <param name="sourceProperties" type="Array" locid="WinJS.Binding.defaultBind_p:sourceProperties"> |
| /// The path on the source object to the source property. |
| /// </param> |
| /// <param name="dest" type="Object" locid="WinJS.Binding.defaultBind_p:dest"> |
| /// The destination object. |
| /// </param> |
| /// <param name="destProperties" type="Array" locid="WinJS.Binding.defaultBind_p:destProperties"> |
| /// The path on the destination object to the destination property. |
| /// </param> |
| /// <param name="initialValue" optional="true" locid="WinJS.Binding.defaultBind_p:initialValue"> |
| /// The known initial value of the target, if the source value is the same as this initial |
| /// value (using ===) then the target is not set the first time. |
| /// </param> |
| /// <returns type="{ cancel: Function }" locid="WinJS.Binding.defaultBind_returnValue"> |
| /// An object with a cancel method that is used to coalesce bindings. |
| /// </returns> |
| /// </signature> |
| |
| return defaultBindImpl(source, sourceProperties, dest, destProperties, initialValue); |
| } |
| function bindWorker(bindable, sourceProperties, func) { |
| if (sourceProperties.length > 1) { |
| var root = {}; |
| var current = root; |
| for (var i = 0, l = sourceProperties.length - 1; i < l; i++) { |
| current = current[sourceProperties[i]] = {}; |
| } |
| current[sourceProperties[sourceProperties.length - 1]] = func; |
| |
| return _Data.bind(bindable, root, true); |
| } else if (sourceProperties.length === 1) { |
| bindable.bind(sourceProperties[0], func, true); |
| return { |
| cancel: function () { |
| bindable.unbind(sourceProperties[0], func); |
| this.cancel = noop; |
| } |
| }; |
| } else { |
| // can't bind to object, so we just push it through |
| // |
| func(bindable); |
| } |
| } |
| function noop() { } |
| function oneTime(source, sourceProperties, dest, destProperties) { |
| /// <signature helpKeyword="WinJS.Binding.oneTime"> |
| /// <summary locid="WinJS.Binding.oneTime"> |
| /// Sets the destination property to the value of the source property. |
| /// </summary> |
| /// <param name="source" type="Object" locid="WinJS.Binding.oneTime_p:source"> |
| /// The source object. |
| /// </param> |
| /// <param name="sourceProperties" type="Array" locid="WinJS.Binding.oneTime_p:sourceProperties"> |
| /// The path on the source object to the source property. |
| /// </param> |
| /// <param name="dest" type="Object" locid="WinJS.Binding.oneTime_p:dest"> |
| /// The destination object. |
| /// </param> |
| /// <param name="destProperties" type="Array" locid="WinJS.Binding.oneTime_p:destProperties"> |
| /// The path on the destination object to the destination property. |
| /// </param> |
| /// <returns type="{ cancel: Function }" locid="WinJS.Binding.oneTime_returnValue"> |
| /// An object with a cancel method that is used to coalesce bindings. |
| /// </returns> |
| /// </signature> |
| nestedSet(dest, destProperties, getValue(source, sourceProperties)); |
| return { cancel: noop }; |
| } |
| |
| function initializer(customInitializer) { |
| /// <signature helpKeyword="WinJS.Binding.initializer"> |
| /// <summary locid="WinJS.Binding.initializer"> |
| /// Marks a custom initializer function as being compatible with declarative data binding. |
| /// </summary> |
| /// <param name="customInitializer" type="Function" locid="WinJS.Binding.initializer_p:customInitializer"> |
| /// The custom initializer to be marked as compatible with declarative data binding. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.Binding.initializer_returnValue"> |
| /// The input customInitializer. |
| /// </returns> |
| /// </signature> |
| return markSupportedForProcessing(customInitializer); |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| processAll: declarativeBind, |
| oneTime: initializer(oneTime), |
| defaultBind: initializer(defaultBind), |
| converter: converter, |
| initializer: initializer, |
| getValue: getValue, |
| setAttribute: initializer(setAttribute), |
| setAttributeOneTime: initializer(setAttributeOneTime), |
| addClassOneTime: initializer(addClassOneTime), |
| }); |
| |
| }); |
| |
| define('WinJS/Binding',[ |
| './Binding/_BindingParser', |
| './Binding/_Data', |
| './Binding/_Declarative', |
| './Binding/_DomWeakRefTable'], function () { |
| //Wrapper module |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/BindingTemplate/_DataTemplateCompiler',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_ErrorFromName', |
| '../Core/_Log', |
| '../Core/_Resources', |
| '../Core/_WriteProfilerMark', |
| '../Binding/_BindingParser', |
| '../Binding/_Declarative', |
| '../ControlProcessor', |
| '../ControlProcessor/_OptionsParser', |
| '../Fragments', |
| '../Promise', |
| '../_Signal', |
| '../Utilities/_Dispose', |
| '../Utilities/_SafeHtml', |
| '../Utilities/_ElementUtilities' |
| ], function templateCompilerInit(exports, _Global, _Base, _BaseUtils, _ErrorFromName, _Log, _Resources, _WriteProfilerMark, _BindingParser, _Declarative, ControlProcessor, _OptionsParser, Fragments, Promise, _Signal, _Dispose, _SafeHtml, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var strings = { |
| get attributeBindingSingleProperty() { return "Attribute binding requires a single destination attribute name, often in the form \"this['aria-label']\" or \"width\"."; }, |
| get cannotBindToThis() { return "Can't bind to 'this'."; }, |
| get idBindingNotSupported() { return "Declarative binding to ID field is not supported. Initializer: {0}"; }, |
| }; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| _TemplateCompiler: _Base.Namespace._lazy(function () { |
| |
| var cancelBlocker = Promise._cancelBlocker; |
| |
| // Eagerly bind to stuff that will be needed by the compiler |
| // |
| var init_defaultBind = _Declarative.defaultBind; |
| var init_oneTime = _Declarative.oneTime; |
| var init_setAttribute = _Declarative.setAttribute; |
| var init_setAttributeOneTime = _Declarative.setAttributeOneTime; |
| var init_addClassOneTime = _Declarative.addClassOneTime; |
| var promise_as = Promise.as; |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| var insertAdjacentHTMLUnsafe = _SafeHtml.insertAdjacentHTMLUnsafe; |
| var utilities_data = _ElementUtilities.data; |
| var markDisposable = _Dispose.markDisposable; |
| var ui_processAll = ControlProcessor.processAll; |
| var binding_processAll = _Declarative.processAll; |
| var options_parser = _OptionsParser._optionsParser; |
| var CallExpression = _OptionsParser._CallExpression; |
| var IdentifierExpression = _OptionsParser._IdentifierExpression; |
| var binding_parser = _BindingParser._bindingParser2; |
| var scopedSelect = ControlProcessor.scopedSelect; |
| var writeProfilerMark = _WriteProfilerMark; |
| |
| // Runtime helper functions |
| // |
| function disposeInstance(container, workPromise, renderCompletePromise) { |
| var bindings = _ElementUtilities.data(container).bindTokens; |
| if (bindings) { |
| bindings.forEach(function (binding) { |
| if (binding && binding.cancel) { |
| binding.cancel(); |
| } |
| }); |
| } |
| if (workPromise) { |
| workPromise.cancel(); |
| } |
| if (renderCompletePromise) { |
| renderCompletePromise.cancel(); |
| } |
| } |
| function delayedBindingProcessing(data, defaultInitializer) { |
| return function (element) { |
| return _Declarative.processAll(element, data, false, null, defaultInitializer); |
| }; |
| } |
| |
| function targetSecurityCheck(value) { |
| value = requireSupportedForProcessing(value); |
| return value instanceof _Global.Node ? null : value; |
| } |
| |
| // Compiler formatting functions |
| // |
| var identifierRegEx = /^[A-Za-z]\w*$/; |
| var identifierCharacterRegEx = /[^A-Za-z\w$]/g; |
| var encodeHtmlRegEx = /[&<>'"]/g; |
| var encodeHtmlEscapeMap = { |
| "&": "&", |
| "<": "<", |
| ">": ">", |
| "'": "'", |
| '"': """ |
| }; |
| var formatRegEx = /({{)|(}})|{(\w+)}|({)|(})/g; |
| var semiColonOnlyLineRegEx = /^\s*;\s*$/; |
| var capitalRegEx = /[A-Z]/g; |
| |
| function format(string, parts) { |
| var multiline = string.indexOf("\n") !== -1; |
| var args = arguments; |
| // |
| // This allows you to format a string like: "hello{there}you{0} {{encased in curlies}}" and will |
| // replace the holes {there} and {0} while turning the {{ and }} into single curlies. |
| // |
| // If the replacement is a number then it is inferred to be off of arguments, otherwise it is |
| // a member on parts. |
| // |
| // If the replacement is a multiline string and the hole is indented then the entirety of the |
| // replacement will have the same indentation as the hole. |
| // |
| var result = string.replace(formatRegEx, function (unused, left, right, part, illegalLeft, illegalRight, replacementIndex) { |
| if (illegalLeft || illegalRight) { |
| throw new _ErrorFromName( |
| "Format:MalformedInputString", |
| "Did you forget to escape a: " + (illegalLeft || illegalRight) + " at: " + replacementIndex); |
| } |
| if (left) { return "{"; } |
| if (right) { return "}"; } |
| var result; |
| var index = +part; |
| if (index === +index) { |
| result = args[index + 1]; |
| } else { |
| result = parts[part]; |
| } |
| if (result === undefined) { |
| throw new _ErrorFromName( |
| "Format:MissingPart", |
| "Missing part '" + part + "'" |
| ); |
| } |
| if (multiline) { |
| var pos = replacementIndex; |
| while (pos > 0 && string[--pos] === " ") { /* empty */ } |
| if (pos >= 0 && string[pos] === "\n") { |
| result = indent(replacementIndex - pos - 1, result); |
| } |
| } |
| return result; |
| }); |
| return result; |
| } |
| function indent(numberOfSpaces, multilineStringToBeIndented) { |
| var indent = ""; |
| for (var i = 0; i < numberOfSpaces; i++) { indent += " "; } |
| return multilineStringToBeIndented.split("\n").map(function (line, index) { return index ? indent + line : line; }).join("\n"); |
| } |
| function trim(s) { |
| return s.trim(); |
| } |
| function statements(array) { |
| return array.join(";\n"); |
| } |
| function declarationList(array) { |
| return array.join(", ") || "empty"; |
| } |
| function identifierAccessExpression(parts) { |
| return parts.map(function (part) { |
| // If this can be a member access optimize to that instead of a string lookup |
| // |
| if (part.match(identifierRegEx)) { return "." + part; } |
| if (+part === part) { return format("[{0}]", part); } |
| return format("[{0}]", literal(part)); |
| }).join(""); |
| } |
| function nullableFilteredIdentifierAccessExpression(initial, parts, temporary, filter) { |
| // |
| // generates: "(t = initial) && filter(t = t.p0) && filter(t = t.p1) && t" |
| // |
| // There are a number of contexts in which we will be derefernceing developer provided |
| // identifier access expressions, in those case we don't know whether or not the target |
| // property exists or in fact if anything exists along the path. |
| // |
| // In order to provide 'correct' behavior we dereference conditionally on whether |
| // we have a non-null value. This results in returning undefined unless the entire |
| // path is defined. |
| // |
| // In these cases we also want to filter the result for security purposes. |
| // |
| var parts = parts.map(function (part) { |
| // If this can be a member access optimize to that instead of a string lookup |
| // |
| if (part.match(identifierRegEx)) { return "." + part; } |
| if (+part === part) { part = +part; } |
| return brackets(literal(part)); |
| }).map(function (part) { |
| return format("{filter}({temp} = {temp}{part})", { |
| filter: filter, |
| temp: temporary, |
| part: part |
| }); |
| }); |
| parts.unshift(parens(assignment(temporary, initial))); |
| parts.push(temporary); |
| return parens(parts.join(" && ")); |
| } |
| function literal(instance) { |
| return JSON.stringify(instance); |
| } |
| function newArray(N) { |
| return N ? "new Array(" + (+N) + ")" : "[]"; |
| } |
| function assignment(target, source) { |
| return "" + target + " = " + source; |
| } |
| function parens(expression) { |
| return "(" + expression + ")"; |
| } |
| function brackets(expression) { |
| return "[" + expression + "]"; |
| } |
| function propertyName(name) { |
| if (name.match(identifierRegEx)) { return name; } |
| if (+name === name) { return +name; } |
| return literal(name); |
| } |
| function htmlEscape(str) { |
| str = "" + str; |
| return str.replace(encodeHtmlRegEx, function (m) { |
| return encodeHtmlEscapeMap[m] || " "; |
| }); |
| } |
| function createIdentifier(prefix, count, suffix) { |
| if (suffix) { |
| return new String("" + prefix + count + "_" + suffix); |
| } else { |
| return new String("" + prefix + count); |
| } |
| } |
| function multiline(str) { |
| return str.replace(/\\n/g, "\\n\\\n"); |
| } |
| |
| // Compiler helper functions |
| // |
| function keys(object) { |
| return Object.keys(object); |
| } |
| function values(object) { |
| return Object.keys(object).map(function (key) { return object[key]; }); |
| } |
| function merge(a, b) { |
| return mergeAll([a, b]); |
| } |
| function mergeAll(list) { |
| var o = {}; |
| for (var i = 0, len = list.length; i < len; i++) { |
| var part = list[i]; |
| var keys = Object.keys(part); |
| for (var j = 0, len2 = keys.length; j < len2; j++) { |
| var key = keys[j]; |
| o[key] = part[key]; |
| } |
| } |
| return o; |
| } |
| function globalLookup(parts) { |
| return parts.reduce( |
| function (current, name) { |
| if (current) { |
| return requireSupportedForProcessing(current[name]); |
| } |
| return null; |
| }, |
| _Global |
| ); |
| } |
| function visit(node, key, pre, post) { |
| var children = node.children; |
| if (children) { |
| var keys = Object.keys(children); |
| (key && pre) && pre(node, key, keys.length); |
| for (var i = 0, len = keys.length; i < len; i++) { |
| var childKey = keys[i]; |
| var child = children[childKey]; |
| visit(child, childKey, pre, post); |
| } |
| (key && post) && post(node, key, Object.keys(children).length); |
| } else { |
| (key && pre) && pre(node, key, 0); |
| (key && post) && post(node, key, 0); |
| } |
| } |
| |
| // Compiler helper types |
| // |
| var TreeCSE = _Base.Class.define(function (compiler, name, kind, accessExpression, filter) { |
| |
| var that = this; |
| this.compiler = compiler; |
| this.kind = kind; |
| this.base = new String(name); |
| this.tree = { |
| children: {}, |
| parent: this.base, |
| reference: function () { return that.base; } |
| }; |
| this.accessExpression = accessExpression; |
| this.filter = filter || ""; |
| |
| }, { |
| |
| createPathExpression: function (path, name) { |
| |
| if (path.length) { |
| var that = this; |
| var tail = path.reduce( |
| function (node, part) { |
| node.children = node.children || {}; |
| node.children[part] = node.children[part] || { parent: node }; |
| return node.children[part]; |
| }, |
| this.tree |
| ); |
| tail.name = tail.name || that.compiler.defineInstance( |
| that.kind, |
| name || "", |
| function () { |
| return that.accessExpression( |
| /*l*/tail.parent.name ? tail.parent.name : tail.parent.reference(), |
| /*r*/path.slice(-1)[0], |
| /*root*/tail.parent.parent === that.base, |
| /*filter*/that.filter, |
| /*last*/true |
| ); |
| } |
| ); |
| return tail.name; |
| } else { |
| return this.base; |
| } |
| |
| }, |
| |
| lower: function () { |
| |
| var that = this; |
| var aggregatedName = []; |
| var reference = function (node, name, last) { |
| return that.accessExpression( |
| /*l*/node.parent.name ? node.parent.name : node.parent.reference(), |
| /*r*/name, |
| /*root*/node.parent.parent === that.base, |
| /*filter*/that.filter, |
| /*last*/last |
| ); |
| }; |
| |
| // Ensure that all shared internal nodes have names and that all nodes |
| // know who they reference |
| // |
| visit(this.tree, "", |
| function pre(node, key, childCount) { |
| aggregatedName.push(key); |
| |
| if (childCount > 1) { |
| node.name = node.name || that.compiler.defineInstance( |
| that.kind, |
| aggregatedName.join("_"), |
| reference.bind(null, node, key, true) |
| ); |
| node.reference = function () { return node.name; }; |
| } else if (childCount === 1) { |
| node.reference = reference.bind(null, node, key); |
| } |
| }, |
| function post() { |
| aggregatedName.pop(); |
| } |
| ); |
| |
| }, |
| |
| deadNodeElimination: function () { |
| |
| // Kill all dead nodes from the tree |
| // |
| visit(this.tree, "", null, function post(node, key, childCount) { |
| if (!node.name || node.name.dead) { |
| if (childCount === 0) { |
| if (node.parent && node.parent.children) { |
| delete node.parent.children[key]; |
| } |
| } |
| } |
| }); |
| |
| }, |
| |
| definitions: function () { |
| |
| var nodes = []; |
| |
| // Gather the nodes in a depth first ordering, any node which has a name |
| // needs to have a definition generated |
| // |
| visit(this.tree, "", function pre(node) { |
| if (node.name) { |
| nodes.push(node); |
| } |
| }); |
| |
| return nodes.map(function (n) { return n.name.definition(); }); |
| |
| }, |
| |
| }); |
| |
| var InstanceKind = { |
| "capture": "capture", |
| "temporary": "temporary", |
| "variable": "variable", |
| "data": "data", |
| "global": "global", |
| }; |
| var InstanceKindPrefixes = { |
| "capture": "c", |
| "temporary": "t", |
| "variable": "iv", |
| "data": "d", |
| "global": "g", |
| }; |
| |
| var StaticKind = { |
| "imported": "import", |
| "variable": "variable", |
| }; |
| var StaticKindPrefixes = { |
| "imported": "i", |
| "variable": "sv", |
| }; |
| |
| var BindingKind = { |
| "tree": "tree", |
| "text": "text", |
| "initializer": "initializer", |
| "template": "template", |
| "error": "error", |
| }; |
| |
| var TextBindingKind = { |
| "attribute": "attribute", |
| "booleanAttribute": "booleanAttribute", |
| "inlineStyle": "inlineStyle", |
| "textContent": "textContent", |
| }; |
| |
| // Constants |
| // |
| var IMPORTS_ARG_NAME = "imports"; |
| |
| var Stage = { |
| initial: 0, |
| analyze: 1, |
| optimze: 2, |
| lower: 3, |
| compile: 4, |
| link: 5, |
| done: 6, |
| }; |
| |
| // Compiler |
| // |
| var TemplateCompiler = _Base.Class.define(function (templateElement, options) { |
| this._stage = Stage.initial; |
| this._staticVariables = {}; |
| this._staticVariablesCount = 0; |
| this._instanceVariables = {}; |
| this._instanceVariablesCount = {}; |
| this._debugBreak = options.debugBreakOnRender; |
| this._defaultInitializer = requireSupportedForProcessing(options.defaultInitializer || init_defaultBind); |
| this._optimizeTextBindings = !options.disableTextBindingOptimization; |
| this._templateElement = templateElement; |
| this._templateContent = _Global.document.createElement(templateElement.tagName); |
| this._extractChild = options.extractChild || false; |
| this._controls = null; |
| this._bindings = null; |
| this._bindTokens = null; |
| this._textBindingPrefix = null; |
| this._textBindingId = 0; |
| this._suffix = []; |
| this._htmlProcessors = []; |
| this._profilerMarkIdentifier = options.profilerMarkIdentifier; |
| this._captureCSE = new TreeCSE(this, "container", InstanceKind.capture, this.generateElementCaptureAccess.bind(this)); |
| this._dataCSE = new TreeCSE(this, "data", InstanceKind.data, this.generateNormalAccess.bind(this), this.importFunctionSafe("dataSecurityCheck", requireSupportedForProcessing)); |
| this._globalCSE = new TreeCSE(this, this.importFunctionSafe("global", _Global), InstanceKind.global, this.generateNormalAccess.bind(this), this.importFunctionSafe("globalSecurityCheck", requireSupportedForProcessing)); |
| |
| // Clone the template content and import it into its own HTML document for further processing |
| Fragments.renderCopy(this._templateElement, this._templateContent); |
| |
| // If we are extracting the first child we only bother compiling the one child |
| if (this._extractChild) { |
| while (this._templateContent.childElementCount > 1) { |
| this._templateContent.removeChild(this._templateContent.lastElementChild); |
| } |
| } |
| }, { |
| |
| addClassOneTimeTextBinding: function (binding) { |
| var that = this; |
| var id = this.createTextBindingHole(binding.elementCapture.element.tagName, "class", ++this._textBindingId); |
| binding.textBindingId = id; |
| binding.kind = BindingKind.text; |
| binding.elementCapture.element.classList.add(id); |
| binding.elementCapture.refCount--; |
| binding.definition = function () { |
| return that.formatCode("{htmlEscape}({value})", { |
| htmlEscape: that._staticVariables.htmlEscape, |
| value: binding.value(), |
| }); |
| }; |
| }, |
| |
| addClassOneTimeTreeBinding: function (binding) { |
| |
| var that = this; |
| binding.pathExpression = this.bindingExpression(binding); |
| binding.value = function () { |
| return binding.pathExpression; |
| }; |
| binding.kind = BindingKind.tree; |
| binding.definition = function () { |
| return that.formatCode("{element}.classList.add({value})", { |
| element: binding.elementCapture, |
| value: binding.value(), |
| }); |
| }; |
| |
| }, |
| |
| analyze: function () { |
| |
| if (this._stage > Stage.analyze) { |
| throw "Illegal: once we have moved past analyze we cannot revist it"; |
| } |
| this._stage = Stage.analyze; |
| |
| // find activatable and bound elements |
| this._controls = this.gatherControls(); |
| this._bindings = this.gatherBindings(); |
| this._children = this.gatherChildren(); |
| |
| // remove attributes which are no longer needed since we will inline bindings and controls |
| this.cleanControlAndBindingAttributes(); |
| |
| if (this.async) { |
| this.createAsyncParts(); |
| } |
| |
| this.nullableIdentifierAccessTemporary = this.defineInstance(InstanceKind.temporary); |
| |
| // snapshot html |
| var html = this._templateContent.innerHTML; |
| this._html = function () { return multiline(literal(html)); }; |
| this._html.text = html; |
| |
| }, |
| |
| bindingExpression: function (binding) { |
| |
| return this._dataCSE.createPathExpression(binding.source, binding.source.join("_")); |
| |
| }, |
| |
| capture: function (element) { |
| |
| var capture = element._capture; |
| if (capture) { |
| capture.refCount++; |
| return capture; |
| } |
| |
| // Find the path to the captured element |
| // |
| var path = [element]; |
| var e = element.parentNode; |
| var name = element.tagName; |
| while (e !== this._templateContent) { |
| name = e.tagName + "_" + name; |
| path.unshift(e); |
| e = e.parentNode; |
| } |
| // Identify which child each path member is so we can form an indexed lookup |
| // |
| for (var i = 0, len = path.length; i < len; i++) { |
| var child = path[i]; |
| path[i] = Array.prototype.indexOf.call(e.children, child); |
| e = child; |
| } |
| // Create the capture and put it on the |
| // |
| capture = this._captureCSE.createPathExpression(path, name.toLowerCase()); |
| capture.element = element; |
| capture.element._capture = capture; |
| capture.refCount = 1; |
| return capture; |
| |
| }, |
| |
| cleanControlAndBindingAttributes: function () { |
| var selector = "[data-win-bind],[data-win-control]"; |
| var elements = this._templateContent.querySelectorAll(selector); |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var element = elements[i]; |
| if (element.isDeclarativeControlContainer) { |
| i += element.querySelectorAll("[data-win-bind],[data-win-control]").length; |
| } |
| element.removeAttribute("data-win-bind"); |
| element.removeAttribute("data-win-control"); |
| element.removeAttribute("data-win-options"); |
| } |
| }, |
| |
| compile: function (bodyTemplate, replacements, supportDelayBindings) { |
| |
| if (this._stage > Stage.compile) { |
| throw "Illegal: once we have moved past compile we cannot revist it"; |
| } |
| this._stage = Stage.compile; |
| |
| var that = this; |
| |
| this._returnedElement = this._extractChild ? "container.firstElementChild" : "container"; |
| |
| var control_processing = this._controls.map(function (control) { |
| var constructionFormatString; |
| if (control.async) { |
| constructionFormatString = "{target}.winControl = {target}.winControl || new {SafeConstructor}({target}, {options}, controlDone)"; |
| } else { |
| constructionFormatString = "{target}.winControl = {target}.winControl || new {SafeConstructor}({target}, {options})"; |
| } |
| var construction = that.formatCode( |
| constructionFormatString, |
| { |
| target: control.elementCapture, |
| SafeConstructor: control.SafeConstructor, |
| options: that.generateOptionsLiteral(control.optionsParsed, control.elementCapture), |
| } |
| ); |
| if (control.isDeclarativeControlContainer && typeof control.isDeclarativeControlContainer.imported === "function") { |
| var result = [construction]; |
| result.push(that.formatCode( |
| "{isDeclarativeControlContainer}({target}.winControl, {delayedControlProcessing})", |
| { |
| target: control.elementCapture, |
| isDeclarativeControlContainer: control.isDeclarativeControlContainer, |
| delayedControlProcessing: that._staticVariables.ui_processAll |
| } |
| )); |
| result.push(that.formatCode( |
| "{isDeclarativeControlContainer}({target}.winControl, {delayedBindingProcessing}(data, {templateDefaultInitializer}))", |
| { |
| target: control.elementCapture, |
| isDeclarativeControlContainer: control.isDeclarativeControlContainer, |
| delayedBindingProcessing: that._staticVariables.delayedBindingProcessing, |
| templateDefaultInitializer: that._staticVariables.templateDefaultInitializer || literal(null), |
| } |
| )); |
| return result.join(";\n"); |
| } else { |
| return construction; |
| } |
| }); |
| |
| var all_binding_processing = this._bindings.map(function (binding) { |
| switch (binding.kind) { |
| case BindingKind.template: |
| return that.formatCode( |
| "({nestedTemplates}[{nestedTemplate}] = {template}.render({path}, {dest}))", |
| { |
| nestedTemplates: that._nestedTemplates, |
| nestedTemplate: literal(binding.nestedTemplate), |
| template: binding.template, |
| path: binding.pathExpression, |
| dest: binding.elementCapture, |
| } |
| ); |
| |
| case BindingKind.initializer: |
| var formatString; |
| if (binding.initialValue) { |
| formatString = "({bindTokens}[{bindToken}] = {initializer}(data, {sourceProperties}, {dest}, {destProperties}, {initialValue}))"; |
| } else { |
| formatString = "({bindTokens}[{bindToken}] = {initializer}(data, {sourceProperties}, {dest}, {destProperties}))"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| bindTokens: that._bindTokens, |
| bindToken: literal(binding.bindToken), |
| initializer: binding.initializer, |
| sourceProperties: literal(binding.source), |
| destProperties: literal(binding.destination), |
| dest: binding.elementCapture, |
| initialValue: binding.initialValue, |
| } |
| ); |
| |
| case BindingKind.tree: |
| return binding.definition(); |
| |
| case BindingKind.text: |
| // do nothing, text bindings are taken care of seperately |
| break; |
| |
| case BindingKind.error: |
| // do nothing, errors are reported and ignored |
| break; |
| |
| default: |
| throw "NYI"; |
| } |
| }); |
| var binding_processing, delayed_binding_processing; |
| if (supportDelayBindings) { |
| binding_processing = all_binding_processing.filter(function (unused, index) { |
| return !that._bindings[index].delayable; |
| }); |
| delayed_binding_processing = all_binding_processing.filter(function (unused, index) { |
| return that._bindings[index].delayable; |
| }); |
| } else { |
| binding_processing = all_binding_processing; |
| delayed_binding_processing = []; |
| } |
| |
| var instances = values(this._instanceVariables); |
| |
| var instanceDefinitions = instances |
| .filter(function (instance) { return instance.kind === InstanceKind.variable; }) |
| .map(function (variable) { return variable.definition(); }); |
| |
| var captures = this._captureCSE.definitions(); |
| var globals = this._globalCSE.definitions(); |
| var data = this._dataCSE.definitions(); |
| |
| var set_msParentSelectorScope = this._children.map(function (child) { |
| return that.formatCodeN("{0}.msParentSelectorScope = true", child); |
| }); |
| var suffix = this._suffix.map(function (statement) { |
| return statement(); |
| }); |
| |
| var renderComplete = ""; |
| if (supportDelayBindings && delayed_binding_processing.length) { |
| renderComplete = that.formatCode( |
| renderItemImplRenderCompleteTemplate, |
| { |
| delayed_binding_processing: statements(delayed_binding_processing) |
| } |
| ); |
| } |
| |
| var result = that.formatCode( |
| bodyTemplate, |
| mergeAll([ |
| this._staticVariables, |
| replacements || {}, |
| { |
| profilerMarkIdentifierStart: literal("WinJS.Binding.Template:render" + this._profilerMarkIdentifier + ",StartTM"), |
| profilerMarkIdentifierStop: literal("WinJS.Binding.Template:render" + this._profilerMarkIdentifier + ",StopTM"), |
| html: this._html(), |
| tagName: literal(this._templateElement.tagName), |
| instance_variable_declarations: declarationList(instances), |
| global_definitions: statements(globals), |
| data_definitions: statements(data), |
| instance_variable_definitions: statements(instanceDefinitions), |
| capture_definitions: statements(captures), |
| set_msParentSelectorScope: statements(set_msParentSelectorScope), |
| debug_break: this.generateDebugBreak(), |
| control_processing: statements(control_processing), |
| control_counter: this._controlCounter, |
| binding_processing: statements(binding_processing), |
| renderComplete: renderComplete, |
| suffix_statements: statements(suffix), |
| nestedTemplates: this._nestedTemplates, |
| returnedElement: this._returnedElement, |
| }, |
| ]) |
| ); |
| |
| return this.prettify(result); |
| |
| }, |
| |
| createAsyncParts: function () { |
| |
| this._nestedTemplates = this._nestedTemplates || this.defineInstance( |
| InstanceKind.variable, |
| "nestedTemplates", |
| function () { return newArray(0); } |
| ); |
| |
| this._controlCounter = this._controlCounter || this.defineInstance( |
| InstanceKind.variable, |
| "controlCounter", |
| function () { return literal(1); } |
| ); |
| |
| }, |
| |
| createTextBindingHole: function (tagName, attribute, id) { |
| if (!this._textBindingPrefix) { |
| var c = ""; |
| while (this._html.text.indexOf("textbinding" + c) !== -1) { |
| c = c || 0; |
| c++; |
| } |
| this._textBindingPrefix = "textbinding" + c; |
| // NOTE: the form of this regex needs to be coordinated with any special cases which |
| // are introduced by the switch below. |
| this._textBindingRegex = new RegExp("(#?" + this._textBindingPrefix + "_\\d+)"); |
| } |
| |
| // Sometimes text bindings need to be of a particular form to suppress warnings from |
| // the host, specifically there is a case with IMG/src attribute where if you assign |
| // a naked textbinding_X to it you get a warning in the console of an unresolved image |
| // instead we prefix it with a # which is enough to suppress that message. |
| // |
| var result = this._textBindingPrefix + "_" + id; |
| if (tagName === "IMG" && attribute === "src") { |
| result = "#" + result; |
| } |
| |
| return result; |
| }, |
| |
| deadCodeElimination: function () { |
| var that = this; |
| |
| // Eliminate all captured elements which are no longer in the tree, this can happen if |
| // these captured elements are children of a node which had a text binding to 'innerText' |
| // or 'textContent' as those kill the subtree. |
| // |
| Object.keys(this._instanceVariables).forEach(function (key) { |
| var iv = that._instanceVariables[key]; |
| if (iv.kind === InstanceKind.capture) { |
| if (!that._templateContent.contains(iv.element)) { |
| iv.dead = true; |
| } |
| if (iv.refCount === 0) { |
| iv.dead = true; |
| } |
| if (iv.dead) { |
| // This dead instance variable returns a blank definition which will then get |
| // cleaned up by prettify. |
| iv.definition = function () { }; |
| iv.name = null; |
| delete that._instanceVariables[key]; |
| } |
| } |
| }); |
| |
| // Eliminate all control activations which target elements which are no longer in the tree |
| // |
| this._controls = this._controls.filter(function (c) { return !c.elementCapture.dead; }); |
| |
| // Eliminate all bindings which target elements which are no longer in the tree |
| // |
| this._bindings = this._bindings.filter(function (b) { return !b.elementCapture.dead; }); |
| |
| // Cleanup the capture CSE tree now that we know dead nodes are marked as such. |
| // |
| this._captureCSE.deadNodeElimination(); |
| |
| }, |
| |
| defineInstance: function (kind, name, definition) { |
| |
| if (this._stage >= Stage.compile) { |
| throw "Illegal: define instance variable after compilation stage has started"; |
| } |
| |
| var variableCount = this._instanceVariablesCount[kind] || 0; |
| var suffix = name ? name.replace(identifierCharacterRegEx, "_") : ""; |
| var identifier = createIdentifier(InstanceKindPrefixes[kind], variableCount, suffix); |
| identifier.definition = function () { return assignment(identifier, definition()); }; |
| identifier.kind = kind; |
| this._instanceVariables[identifier] = identifier; |
| this._instanceVariablesCount[kind] = variableCount + 1; |
| return identifier; |
| |
| }, |
| |
| defineStatic: function (kind, name, definition) { |
| |
| if (this._stage >= Stage.link) { |
| throw "Illegal: define static variable after link stage has started"; |
| } |
| |
| if (name) { |
| var known = this._staticVariables[name]; |
| if (known) { |
| return known; |
| } |
| } |
| var suffix = name ? name.replace(identifierCharacterRegEx, "_") : ""; |
| var identifier = createIdentifier(StaticKindPrefixes[kind], this._staticVariablesCount, suffix); |
| identifier.definition = function () { return assignment(identifier, definition()); }; |
| identifier.kind = kind; |
| this._staticVariables[name || identifier] = identifier; |
| this._staticVariablesCount++; |
| return identifier; |
| |
| }, |
| |
| done: function () { |
| |
| if (this._stage > Stage.done) { |
| throw "Illegal: once we have moved past done we cannot revist it"; |
| } |
| this._stage = Stage.done; |
| |
| }, |
| |
| emitScopedSelect: function (selector, elementCapture) { |
| return this.formatCode( |
| "{scopedSelect}({selector}, {element})", |
| { |
| scopedSelect: this._staticVariables.scopedSelect, |
| selector: literal(selector), |
| element: elementCapture, |
| } |
| ); |
| }, |
| |
| emitOptionsNode: function (node, parts, elementCapture) { |
| |
| var that = this; |
| if (node) { |
| switch (typeof node) { |
| case "object": |
| if (Array.isArray(node)) { |
| parts.push("["); |
| for (var i = 0, len = node.length; i < len; i++) { |
| this.emitOptionsNode(node[i], parts, elementCapture); |
| parts.push(","); |
| } |
| parts.push("]"); |
| } else if (node instanceof CallExpression) { |
| parts.push(node.target === "select" ? this.emitScopedSelect(node.arg0Value, elementCapture) : literal(null)); |
| } else if (node instanceof IdentifierExpression && node.parts[0] instanceof CallExpression) { |
| var call = node.parts[0]; |
| parts.push( |
| nullableFilteredIdentifierAccessExpression( |
| call.target === "select" ? this.emitScopedSelect(call.arg0Value, elementCapture) : literal(null), |
| node.parts.slice(1), |
| this.nullableIdentifierAccessTemporary, |
| this.importFunctionSafe("requireSupportedForProcessing", requireSupportedForProcessing) |
| ) |
| ); |
| } else if (node instanceof IdentifierExpression) { |
| parts.push(node.pathExpression); |
| } else { |
| parts.push("{"); |
| Object.keys(node).forEach(function (key) { |
| |
| parts.push(propertyName(key)); |
| parts.push(":"); |
| that.emitOptionsNode(node[key], parts, elementCapture); |
| parts.push(","); |
| |
| }); |
| parts.push("}"); |
| } |
| break; |
| |
| default: |
| parts.push(literal(node)); |
| break; |
| } |
| } else { |
| parts.push(literal(null)); |
| } |
| |
| }, |
| |
| findGlobalIdentifierExpressions: function (obj, results) { |
| |
| results = results || []; |
| var that = this; |
| Object.keys(obj).forEach(function (key) { |
| var prop = obj[key]; |
| if (typeof prop === "object") { |
| if (prop instanceof IdentifierExpression) { |
| if (!(prop.parts[0] instanceof CallExpression)) { |
| results.push(prop); |
| } |
| } else { |
| that.findGlobalIdentifierExpressions(prop, results); |
| } |
| } |
| }); |
| return results; |
| |
| }, |
| |
| formatCodeN: function () { |
| |
| if (this._stage < Stage.compile) { |
| throw "Illegal: format code at before compilation stage has started"; |
| } |
| return format.apply(null, arguments); |
| |
| }, |
| |
| formatCode: function (string, parts) { |
| |
| if (this._stage < Stage.compile) { |
| throw "Illegal: format code at before compilation stage has started"; |
| } |
| return format(string, parts); |
| |
| }, |
| |
| gatherBindings: function () { |
| |
| var bindTokens = -1; |
| var that = this; |
| var nestedTemplates = -1; |
| var bindings = []; |
| var selector = "[data-win-bind],[data-win-control]"; |
| var elements = this._templateContent.querySelectorAll(selector); |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var element = elements[i]; |
| |
| // If we run into a declarative control container (e.g. Binding.Template) we don't |
| // bind its children, but we will give it an opportunity to process later using the |
| // same data context. |
| if (element.isDeclarativeControlContainer) { |
| i += element.querySelectorAll(selector).length; |
| } |
| |
| // Since we had to look for controls as well as bindings in order to skip controls |
| // which are declarative control containers we have to check if this element is bound |
| if (!element.hasAttribute("data-win-bind")) { |
| continue; |
| } |
| |
| var bindingText = element.getAttribute("data-win-bind"); |
| var elementBindings = binding_parser(bindingText, _Global); |
| elementBindings.forEach(function (binding) { |
| if (binding.initializer) { |
| // If an initializer is specified it may be a nested template |
| var initializerName = binding.initializer.join("."); |
| var initializer = globalLookup(binding.initializer); |
| if (initializer.render) { |
| requireSupportedForProcessing(initializer.render); |
| // We have already chceked this to be safe for import |
| binding.template = that.importFunctionSafe(initializerName, initializer); |
| binding.pathExpression = that.bindingExpression(binding); |
| binding.nestedTemplate = ++nestedTemplates; |
| binding.kind = BindingKind.template; |
| } else if (initializer.winControl && initializer.winControl.render) { |
| requireSupportedForProcessing(initializer.winControl.render); |
| // We have already checked this to be safe to import |
| binding.template = that.importFunctionSafe(initializerName, initializer.winControl); |
| binding.pathExpression = that.bindingExpression(binding); |
| binding.nestedTemplate = ++nestedTemplates; |
| binding.kind = BindingKind.template; |
| } else { |
| // Don't get the path expression here, we will do it if needed in optimize |
| binding.initializer = that.importFunction(initializerName, initializer); |
| binding.bindToken = ++bindTokens; |
| binding.kind = BindingKind.initializer; |
| } |
| } else { |
| // Don't get the path expression here, we will do it if needed in optimize |
| // We have already checked this to be safe to import |
| binding.initializer = that.importFunctionSafe("templateDefaultInitializer", that._defaultInitializer); |
| binding.bindToken = ++bindTokens; |
| binding.kind = BindingKind.initializer; |
| } |
| binding.elementCapture = that.capture(element); |
| binding.bindingText = bindingText; |
| }); |
| bindings.push.apply(bindings, elementBindings); |
| } |
| |
| var nestedTemplateCount = nestedTemplates + 1; |
| if (nestedTemplateCount > 0) { |
| this.async = true; |
| this._nestedTemplates = this.defineInstance( |
| InstanceKind.variable, |
| "nestedTemplates", |
| function () { return newArray(nestedTemplateCount); } |
| ); |
| } |
| |
| var bindTokenCount = bindTokens + 1; |
| if (bindTokenCount > 0) { |
| this._bindTokens = this.defineInstance( |
| InstanceKind.variable, |
| "bindTokens", |
| function () { return newArray(bindTokenCount); } |
| ); |
| this._suffix.push(function () { |
| // NOTE: returnedElement is a local in the template which is set to either be the container |
| // or in the extractChild: true case the first child. |
| return that.formatCode( |
| "{utilities_data}(returnedElement).bindTokens = {bindTokens}", |
| { |
| utilities_data: that._staticVariables.utilities_data, |
| bindTokens: that._bindTokens, |
| } |
| ); |
| }); |
| } |
| |
| return bindings; |
| |
| }, |
| |
| gatherChildren: function () { |
| |
| var that = this; |
| return Array.prototype.map.call(this._templateContent.children, function (child) { return that.capture(child); }); |
| |
| }, |
| |
| gatherControls: function () { |
| |
| var that = this; |
| var asyncCount = 0; |
| var controls = []; |
| var selector = "[data-win-control]"; |
| var elements = this._templateContent.querySelectorAll(selector); |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var element = elements[i]; |
| var name = element.getAttribute("data-win-control"); |
| // Control constructors are checked along the entirety of their path to be supported |
| // for processing when they are bound |
| var ControlConstructor = _BaseUtils._getMemberFiltered(name.trim(), _Global, requireSupportedForProcessing); |
| if (!ControlConstructor) { |
| continue; |
| } |
| |
| var optionsText = element.getAttribute("data-win-options") || literal({}); |
| var async = ControlConstructor.length > 2; |
| if (async) { |
| asyncCount++; |
| this.async = true; |
| } |
| |
| var isDeclarativeControlContainer = ControlConstructor.isDeclarativeControlContainer; |
| if (isDeclarativeControlContainer) { |
| if (typeof isDeclarativeControlContainer === "function") { |
| isDeclarativeControlContainer = this.importFunction(name + "_isDeclarativeControlContainer", isDeclarativeControlContainer); |
| } |
| |
| element.isDeclarativeControlContainer = isDeclarativeControlContainer; |
| i += element.querySelectorAll(selector).length; |
| } |
| |
| var control = { |
| elementCapture: this.capture(element), |
| name: name, |
| // We have already checked this for requireSupportedForProcessing |
| SafeConstructor: this.importFunctionSafe(name, ControlConstructor), |
| async: async, |
| optionsText: literal(optionsText), |
| optionsParsed: options_parser(optionsText), |
| isDeclarativeControlContainer: isDeclarativeControlContainer, |
| }; |
| controls.push(control); |
| |
| var globalReferences = this.findGlobalIdentifierExpressions(control.optionsParsed); |
| globalReferences.forEach(function (identifierExpression) { |
| identifierExpression.pathExpression = that.globalExpression(identifierExpression.parts); |
| }); |
| } |
| |
| if (asyncCount > 0) { |
| this._controlCounter = this.defineInstance( |
| InstanceKind.variable, |
| "controlCounter", |
| // +1 because we call it once to start in case we have no async controls in the async template |
| function () { return literal(asyncCount + 1); } |
| ); |
| } |
| |
| return controls; |
| |
| }, |
| |
| generateElementCaptureAccess: function (l, r, root) { |
| |
| if (root) { |
| // Clean up the right hand side so we don't end up with "startIndex + 0" |
| var right = ("" + r === "0" ? "" : " + " + r); |
| |
| return this.formatCodeN("{0}.children[startIndex{1}]", l, right); |
| } |
| return this.formatCodeN("{0}.children[{1}]", l, r); |
| |
| }, |
| |
| generateNormalAccess: function (left, right, root, filter, last) { |
| |
| // The 'last' parameter indicates that this path access is the last part of a greater |
| // access expression and therefore does not need to be further assigned to the temp. |
| |
| if (left.indexOf(this.nullableIdentifierAccessTemporary) >= 0) { |
| // If the nullableIdentifierAccessTemporary is on the LHS then the |
| // LHS is already an access expression and does not need to be null-checked again |
| var formatString; |
| if (last) { |
| formatString = "{left} && {filter}({temp}{right})"; |
| } else { |
| formatString = "{left} && ({temp} = {filter}({temp}{right}))"; |
| } |
| return this.formatCode(formatString, { |
| temp: this.nullableIdentifierAccessTemporary, |
| left: left, |
| right: identifierAccessExpression([right]), |
| filter: filter |
| }); |
| } |
| var formatString; |
| if (last) { |
| formatString = "({temp} = {left}) && {filter}({temp}{right})"; |
| } else { |
| formatString = "({temp} = {left}) && ({temp} = {filter}({temp}{right}))"; |
| } |
| return this.formatCode(formatString, { |
| temp: this.nullableIdentifierAccessTemporary, |
| left: left, |
| right: identifierAccessExpression([right]), |
| filter: filter |
| }); |
| |
| }, |
| |
| generateOptionsLiteral: function (optionsParsed, elementCapture) { |
| |
| var parts = []; |
| this.emitOptionsNode(optionsParsed, parts, elementCapture); |
| return parts.join(" "); |
| |
| }, |
| |
| generateDebugBreak: function () { |
| |
| if (this._debugBreak) { |
| var counter = this.defineStatic( |
| StaticKind.variable, |
| "debugCounter", |
| function () { return literal(0); } |
| ); |
| return this.formatCodeN("if (++{0} === 1) {{ debugger; }}", counter); |
| } |
| return ""; |
| |
| }, |
| |
| globalExpression: function (path) { |
| |
| return this._globalCSE.createPathExpression(path, path.join("_")); |
| |
| }, |
| |
| importFunction: function (name, i) { |
| |
| // Used for functions which are gathered from user code (e.g. binding initializers and |
| // control constructors). For these functions we need to assert that they are safe for |
| // use in a declarative context, however since the values are known at compile time we |
| // can do that check once. |
| // |
| return this.importFunctionSafe(name, requireSupportedForProcessing(i)); |
| |
| }, |
| |
| importFunctionSafe: function (name, i) { |
| |
| // Used for functions and objects which are intrinsic to the template compiler and are safe |
| // for their intended usages and don't need to be marked requireSupportedForProcessing. |
| // |
| var that = this; |
| var identifier = this.defineStatic( |
| StaticKind.imported, |
| name, |
| function () { return that.formatCodeN("({0}{1})", IMPORTS_ARG_NAME, identifierAccessExpression([name])); } |
| ); |
| if (identifier.imported && identifier.imported !== i) { |
| throw "Duplicate import: '" + name + "'"; |
| } |
| identifier.imported = i; |
| return identifier; |
| |
| }, |
| |
| importAll: function (imports) { |
| Object.keys(imports).forEach(function (key) { |
| requireSupportedForProcessing(imports[key]); |
| }); |
| return this.importAllSafe(imports); |
| }, |
| |
| importAllSafe: function (imports) { |
| |
| var that = this; |
| var result = Object.keys(imports).reduce( |
| function (o, key) { |
| o[key] = that.importFunctionSafe(key, imports[key]); |
| return o; |
| }, |
| {} |
| ); |
| return result; |
| |
| }, |
| |
| link: function (body) { |
| |
| if (this._stage > Stage.link) { |
| throw "Illegal: once we have moved past link we cannot revist it"; |
| } |
| this._stage = Stage.link; |
| |
| var that = this; |
| |
| // Gather the set of imported instances (functions mostly). All of these are runtime values which |
| // are already safety checked for things like requireSupportedForProcessing. |
| // |
| var imports = keys(this._staticVariables) |
| .filter(function (key) { return that._staticVariables[key].kind === StaticKind.imported; }) |
| .reduce( |
| function (o, key) { |
| o[key] = that._staticVariables[key].imported; |
| return o; |
| }, |
| {} |
| ); |
| |
| var statics = values(this._staticVariables); |
| |
| return new Function(IMPORTS_ARG_NAME, // jshint ignore:line |
| this.formatCode( |
| linkerCodeTemplate, |
| { |
| static_variable_declarations: declarationList(statics), |
| static_variable_definitions: statements(statics.map(function (s) { return s.definition(); })), |
| body: body.trim(), |
| } |
| ) |
| )(imports); |
| |
| }, |
| |
| lower: function () { |
| |
| if (this._stage > Stage.lower) { |
| throw "Illegal: once we have moved past lower we cannot revist it"; |
| } |
| this._stage = Stage.lower; |
| |
| this._captureCSE.lower(); |
| this._dataCSE.lower(); |
| this._globalCSE.lower(); |
| |
| }, |
| |
| markBindingAsError: function (binding) { |
| if (binding) { |
| binding.kind = BindingKind.error; |
| this.markBindingAsError(binding.original); |
| } |
| }, |
| |
| oneTimeTextBinding: function (binding) { |
| |
| var that = this; |
| var result = this.oneTimeTextBindingAnalyze(binding); |
| if (result) { |
| var initialValue; |
| if (binding.original) { |
| initialValue = binding.original.initialValue; |
| } |
| var id = this.createTextBindingHole(binding.elementCapture.element.tagName, result.attribute, ++this._textBindingId); |
| binding.textBindingId = id; |
| binding.kind = BindingKind.text; |
| binding.elementCapture.refCount--; |
| binding.definition = function () { |
| var formatString; |
| if (initialValue) { |
| formatString = "{htmlEscape}({initialValue})"; |
| } else { |
| formatString = "{htmlEscape}({getter})"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| htmlEscape: that._staticVariables.htmlEscape, |
| getter: binding.value(), |
| initialValue: initialValue, |
| } |
| ); |
| }; |
| |
| switch (result.kind) { |
| case TextBindingKind.attribute: |
| binding.elementCapture.element.setAttribute(result.attribute, id); |
| break; |
| |
| case TextBindingKind.booleanAttribute: |
| // Boolean attributes work differently, the presence of the attribute in any |
| // form means true and its absence means false. This means that we need to |
| // add or remove the whole thing and make the definition of the binding |
| // expression at runtime add it back. |
| // |
| binding.elementCapture.element.setAttribute(result.attribute, id); |
| |
| // Wrap the definition in a ternary expression which yields either the attribute |
| // name or an empty string. |
| // |
| binding.definition = function () { |
| var formatString; |
| if (initialValue) { |
| formatString = "({initialValue} ? {attribute} : \"\")"; |
| } else { |
| formatString = "({value} ? {attribute} : \"\")"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| value: binding.value(), |
| attribute: literal(result.attribute), |
| initialValue: initialValue |
| } |
| ); |
| }; |
| |
| // Arrange for the attribute in the HTML with the 'id' as a value to be wholy |
| // replaced by the ID. |
| // |
| this._htmlProcessors.push(function (html) { |
| return html.replace(new RegExp(result.attribute + "=\"" + id + "\"", "i"), id); |
| }); |
| break; |
| |
| case TextBindingKind.textContent: |
| binding.elementCapture.element.textContent = id; |
| break; |
| |
| case TextBindingKind.inlineStyle: |
| var element = binding.elementCapture.element; |
| // Inline styles require a little finesseing, their form always needs to be |
| // legal CSS include in the value space. We could attempt to special case |
| // all CSS properties and produce something which is legal in their value |
| // space but instead we wholesale replace the inline CSS with a extension |
| // property temporarially in order to get valid HTML. Later we go replace |
| // that well-known hole with the original inline CSS text as well as any |
| // new properties we are setting as a result of data binding. |
| // |
| if (!element.msReplaceStyle) { |
| element.msReplaceStyle = element.getAttribute("style") || ""; |
| // Ensure that there is always a trailing ';' |
| if (element.msReplaceStyle !== "" && element.msReplaceStyle[element.msReplaceStyle.length - 1] !== ";") { |
| element.msReplaceStyle = element.msReplaceStyle + ";"; |
| } |
| element.setAttribute("style", "msReplaceStyle:'" + id + "'"); |
| var temp = element.getAttribute("style"); |
| this._htmlProcessors.push(function (html) { |
| return html.replace(temp, element.msReplaceStyle); |
| }); |
| } |
| element.msReplaceStyle = element.msReplaceStyle + result.property + ":" + id + ";"; |
| break; |
| |
| default: |
| throw "NYI"; |
| } |
| } |
| |
| }, |
| |
| oneTimeTextBindingAnalyze: function (binding) { |
| var element = binding.elementCapture.element; |
| var elementType = element.tagName; |
| var targetProperty = binding.destination[0]; |
| |
| // Properties which can only be optimized for a given element types |
| // |
| switch (elementType) { |
| case "A": |
| switch (targetProperty) { |
| case "href": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "IMG": |
| switch (targetProperty) { |
| case "alt": |
| case "src": |
| case "width": |
| case "height": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "SELECT": |
| switch (targetProperty) { |
| case "disabled": |
| case "multiple": |
| case "required": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| |
| case "size": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "OPTION": |
| switch (targetProperty) { |
| case "label": |
| case "value": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| |
| case "disabled": |
| case "selected": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "INPUT": |
| switch (targetProperty) { |
| case "checked": |
| switch (element.type) { |
| case "checkbox": |
| case "radio": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "disabled": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| |
| case "max": |
| case "maxLength": |
| case "min": |
| case "step": |
| case "value": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| |
| case "size": |
| switch (element.type) { |
| case "text": |
| case "search": |
| case "tel": |
| case "url": |
| case "email": |
| case "password": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "readOnly": |
| switch (element.type) { |
| case "hidden": |
| case "range": |
| case "color": |
| case "checkbox": |
| case "radio": |
| case "file": |
| case "button": |
| // not supported: |
| break; |
| |
| default: |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| } |
| break; |
| } |
| break; |
| |
| case "BUTTON": |
| switch (targetProperty) { |
| case "disabled": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| |
| case "value": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| |
| case "TEXTAREA": |
| switch (targetProperty) { |
| case "disabled": |
| case "readOnly": |
| case "required": |
| return { kind: TextBindingKind.booleanAttribute, attribute: targetProperty }; |
| |
| case "cols": |
| case "maxLength": |
| case "placeholder": |
| case "rows": |
| case "wrap": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| } |
| break; |
| } |
| |
| // Properties which can be optimized for all element types |
| // |
| switch (targetProperty) { |
| case "className": |
| return { kind: TextBindingKind.attribute, attribute: "class" }; |
| |
| case "dir": |
| case "lang": |
| case "name": |
| case "title": |
| case "tabIndex": |
| return { kind: TextBindingKind.attribute, attribute: targetProperty }; |
| |
| case "style": |
| if (binding.destination.length > 1) { |
| var targetCssProperty = binding.destination[1]; |
| if (targetCssProperty === "cssText") { |
| // We don't support optimizing the cssText property on styles |
| // |
| return; |
| } |
| // If this is a supported css property we will get a string (frequently empty) |
| // from the style object. |
| // |
| var supported = typeof element.style[targetCssProperty] === "string"; |
| if (supported) { |
| // The mapping from css property name to JS property name is regular: |
| // Chrome uses webkit as the JS property name prefix. |
| // IE uses ms as the JS property name prefix. |
| // Firefox uses Moz as the JS property name prefix. |
| // |
| // To calculate the css property name we replace capital letters with |
| // a dash followed by the lowercase version of that letter. |
| // |
| // For Chrome and IE we have to add the leading dash manually since |
| // the JS property name prefix is lowercase. For Firefox the replace |
| // call will take care of this for us since their JS property name |
| // prefix begins with a capital letter. |
| if (targetCssProperty[0] === "m" && targetCssProperty[1] === "s" || |
| targetCssProperty.substring(0, 6) === "webkit") { |
| targetCssProperty = "-" + targetCssProperty; |
| } |
| targetCssProperty = targetCssProperty.replace(capitalRegEx, function (l) { |
| return "-" + l.toLowerCase(); |
| }); |
| return { kind: TextBindingKind.inlineStyle, property: targetCssProperty, attribute: "style" }; |
| } |
| } |
| break; |
| |
| case "innerText": |
| case "textContent": |
| return { kind: TextBindingKind.textContent, attribute: "textContent" }; |
| } |
| }, |
| |
| oneTimeTreeBinding: function (binding) { |
| |
| if (binding.destination.length === 1 && binding.destination[0] === "id") { |
| if (_BaseUtils.validation) { |
| throw new _ErrorFromName("WinJS.Binding.IdBindingNotSupported", _Resources._formatString(strings.idBindingNotSupported, binding.bindingText)); |
| } |
| _Log.log && _Log.log(_Resources._formatString(strings.idBindingNotSupported, binding.bindingText), "winjs binding", "error"); |
| this.markBindingAsError(binding); |
| return; |
| } |
| |
| if (binding.destination.length === 0) { |
| _Log.log && _Log.log(strings.cannotBindToThis, "winjs binding", "error"); |
| this.markBindingAsError(binding); |
| return; |
| } |
| |
| var that = this; |
| var initialValue; |
| binding.pathExpression = this.bindingExpression(binding); |
| binding.value = function () { |
| return binding.pathExpression; |
| }; |
| if (binding.original) { |
| initialValue = binding.pathExpression; |
| binding.original.initialValue = initialValue; |
| } |
| binding.kind = BindingKind.tree; |
| binding.definition = function () { |
| var formatString; |
| if (initialValue) { |
| formatString = "({targetPath} || {{}}){prop} = {initialValue}"; |
| } else { |
| formatString = "({targetPath} || {{}}){prop} = {sourcePath}"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| targetPath: nullableFilteredIdentifierAccessExpression( |
| binding.elementCapture, |
| binding.destination.slice(0, -1), |
| that.nullableIdentifierAccessTemporary, |
| that.importFunctionSafe("targetSecurityCheck", targetSecurityCheck) |
| ), |
| prop: identifierAccessExpression(binding.destination.slice(-1)), |
| sourcePath: binding.value(), |
| initialValue: initialValue, |
| } |
| ); |
| }; |
| |
| }, |
| |
| optimize: function () { |
| |
| if (this._stage > Stage.optimze) { |
| throw "Illegal: once we have moved past link we cannot revist it"; |
| } |
| this._stage = Stage.optimze; |
| |
| // Identify all bindings which can be turned into tree bindings, in some cases this consists |
| // of simply changing their type and providing a definition, in other cases it involves |
| // adding a new tree binding to complement the other binding |
| // |
| for (var i = 0; i < this._bindings.length; i++) { |
| var binding = this._bindings[i]; |
| if (binding.template) { |
| continue; |
| } |
| |
| switch (binding.initializer.imported) { |
| case init_defaultBind: |
| // Add a new tree binding for one-time binding and mark the defaultBind as delayable |
| var newBinding = merge(binding, { |
| kind: BindingKind.tree, |
| initializer: this.importFunctionSafe("init_oneTime", init_oneTime), |
| original: binding, |
| }); |
| newBinding.elementCapture.refCount++; |
| this.oneTimeTreeBinding(newBinding); |
| this._bindings.splice(i, 0, newBinding); |
| binding.delayable = true; |
| i++; |
| break; |
| |
| case init_setAttribute: |
| // Add a new tree binding for one-time setAttribute and mark the setAttribute as delayable |
| var newBinding = merge(binding, { |
| kind: BindingKind.tree, |
| initializer: this.importFunctionSafe("init_setAttributeOneTime", init_setAttributeOneTime), |
| original: binding, |
| }); |
| newBinding.elementCapture.refCount++; |
| this.setAttributeOneTimeTreeBinding(newBinding); |
| this._bindings.splice(i, 0, newBinding); |
| binding.delayable = true; |
| i++; |
| break; |
| |
| case init_oneTime: |
| this.oneTimeTreeBinding(binding); |
| break; |
| |
| case init_setAttributeOneTime: |
| this.setAttributeOneTimeTreeBinding(binding); |
| break; |
| |
| case init_addClassOneTime: |
| this.addClassOneTimeTreeBinding(binding); |
| break; |
| |
| default: |
| if (binding.initializer) { |
| binding.delayable = !!binding.initializer.imported.delayable; |
| } |
| break; |
| } |
| } |
| |
| if (this._optimizeTextBindings) { |
| |
| // Identifiy all potential text bindings and generate text replacement expressions |
| // |
| var textBindings = {}; |
| for (var i = 0; i < this._bindings.length; i++) { |
| var binding = this._bindings[i]; |
| if (binding.template) { |
| continue; |
| } |
| if (binding.kind === BindingKind.error) { |
| continue; |
| } |
| |
| switch (binding.initializer.imported) { |
| case init_oneTime: |
| this.oneTimeTextBinding(binding); |
| break; |
| |
| case init_setAttributeOneTime: |
| this.setAttributeOneTimeTextBinding(binding); |
| break; |
| |
| case init_addClassOneTime: |
| this.addClassOneTimeTextBinding(binding); |
| break; |
| |
| default: |
| break; |
| } |
| if (binding.textBindingId) { |
| textBindings[binding.textBindingId] = binding; |
| } |
| } |
| |
| if (Object.keys(textBindings).length) { |
| var newHtml = this._templateContent.innerHTML; |
| |
| // Perform any adjustments to the HTML that are needed for things like styles and |
| // boolean attributes |
| // |
| newHtml = this._htmlProcessors.reduce( |
| function (html, replacer) { |
| return replacer(html); |
| }, |
| newHtml |
| ); |
| |
| // All the even indexes are content and all the odds are replacements |
| // |
| // NOTE: this regular expression is |
| var parts = newHtml.split(this._textBindingRegex); |
| for (var i = 1; i < parts.length; i += 2) { |
| var binding = textBindings[parts[i]]; |
| parts[i] = binding.definition; |
| } |
| |
| // Generate the function which will code-gen the HTML replacements. |
| // |
| this._html = function () { |
| var result = parts.map(function (p) { |
| // the strings are the literal parts of the HTML that came directly from the DOM |
| // the functions are the definitions for string replacements |
| return typeof p === "string" ? literal(p) : p(); |
| }).join(" + "); |
| return multiline(result); |
| }; |
| } |
| |
| } |
| |
| }, |
| |
| prettify: function (result) { |
| |
| // remove all lines which contain nothing but a semi-colon |
| var lines = result.split("\n"); |
| return lines.filter(function (line) { return !semiColonOnlyLineRegEx.test(line); }).join("\n"); |
| |
| }, |
| |
| setAttributeOneTimeTextBinding: function (binding) { |
| |
| var that = this; |
| var attribute = binding.destination[0]; |
| var id = this.createTextBindingHole(binding.elementCapture.element.tagName, attribute, ++this._textBindingId); |
| var initialValue; |
| if (binding.original) { |
| initialValue = binding.original.initialValue; |
| } |
| binding.textBindingId = id; |
| binding.kind = BindingKind.text; |
| binding.elementCapture.element.setAttribute(attribute, id); |
| binding.elementCapture.refCount--; |
| binding.definition = function () { |
| var formatString; |
| if (initialValue) { |
| formatString = "{htmlEscape}({initialValue})"; |
| } else { |
| formatString = "{htmlEscape}({value})"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| htmlEscape: that._staticVariables.htmlEscape, |
| initialValue: initialValue, |
| value: binding.value(), |
| } |
| ); |
| }; |
| |
| }, |
| |
| setAttributeOneTimeTreeBinding: function (binding) { |
| |
| if (binding.destination.length === 1 && binding.destination[0] === "id") { |
| if (_BaseUtils.validation) { |
| throw new _ErrorFromName("WinJS.Binding.IdBindingNotSupported", _Resources._formatString(strings.idBindingNotSupported, binding.bindingText)); |
| } |
| _Log.log && _Log.log(_Resources._formatString(strings.idBindingNotSupported, binding.bindingText), "winjs binding", "error"); |
| this.markBindingAsError(binding); |
| return; |
| } |
| |
| if (binding.destination.length !== 1 || !binding.destination[0]) { |
| _Log.log && _Log.log(strings.attributeBindingSingleProperty, "winjs binding", "error"); |
| this.markBindingAsError(binding); |
| return; |
| } |
| |
| var that = this; |
| var initialValue; |
| binding.pathExpression = this.bindingExpression(binding); |
| binding.value = function () { |
| return binding.pathExpression; |
| }; |
| if (binding.original) { |
| initialValue = this.defineInstance(InstanceKind.variable, "", binding.value); |
| binding.original.initialValue = initialValue; |
| } |
| binding.kind = BindingKind.tree; |
| binding.definition = function () { |
| var formatString; |
| if (initialValue) { |
| formatString = "{element}.setAttribute({attribute}, \"\" + {initialValue})"; |
| } else { |
| formatString = "{element}.setAttribute({attribute}, \"\" + {value})"; |
| } |
| return that.formatCode( |
| formatString, |
| { |
| element: binding.elementCapture, |
| attribute: literal(binding.destination[0]), |
| initialValue: initialValue, |
| value: binding.value(), |
| } |
| ); |
| }; |
| |
| }, |
| |
| }, { |
| _TreeCSE: TreeCSE, |
| |
| compile: function TemplateCompiler_compile(template, templateElement, options) { |
| |
| if (!(templateElement instanceof _Global.HTMLElement)) { |
| throw "Illegal"; |
| } |
| |
| writeProfilerMark("WinJS.Binding.Template:compile" + options.profilerMarkIdentifier + ",StartTM"); |
| |
| var compiler = new TemplateCompiler(templateElement, options); |
| |
| compiler.analyze(); |
| |
| var importAliases = compiler.importAllSafe({ |
| Signal: _Signal, |
| global: _Global, |
| document: _Global.document, |
| cancelBlocker: cancelBlocker, |
| promise_as: promise_as, |
| disposeInstance: disposeInstance, |
| markDisposable: markDisposable, |
| ui_processAll: ui_processAll, |
| binding_processAll: binding_processAll, |
| insertAdjacentHTMLUnsafe: insertAdjacentHTMLUnsafe, |
| promise: Promise, |
| utilities_data: utilities_data, |
| requireSupportedForProcessing: requireSupportedForProcessing, |
| htmlEscape: htmlEscape, |
| scopedSelect: scopedSelect, |
| delayedBindingProcessing: delayedBindingProcessing, |
| writeProfilerMark: writeProfilerMark |
| }); |
| |
| compiler.optimize(); |
| |
| compiler.deadCodeElimination(); |
| |
| compiler.lower(); |
| |
| var codeTemplate; |
| var delayBindings; |
| switch (options.target) { |
| case "render": |
| codeTemplate = compiler.async ? renderImplCodeAsyncTemplate : renderImplCodeTemplate; |
| delayBindings = false; |
| break; |
| |
| case "renderItem": |
| codeTemplate = compiler.async ? renderItemImplCodeAsyncTemplate : renderItemImplCodeTemplate; |
| delayBindings = true; |
| break; |
| } |
| |
| var body = compiler.compile(codeTemplate, importAliases, delayBindings); |
| var render = compiler.link(body); |
| |
| compiler.done(); |
| |
| writeProfilerMark("WinJS.Binding.Template:compile" + options.profilerMarkIdentifier + ",StopTM"); |
| |
| return render; |
| } |
| }); |
| |
| // |
| // Templates |
| // |
| |
| function trimLinesRight(string) { |
| // Replace all empty lines with just a newline |
| // Remove all trailing spaces |
| return string.replace(/^\s*$/gm, "").replace(/^(.*[^\s])( *)$/gm, function (unused, content) { |
| return content; |
| }); |
| } |
| |
| |
| var renderImplMainCodePrefixTemplate = trimLinesRight( |
| "container.classList.add(\"win-template\"); \n" + |
| "var html = {html}; \n" + |
| "{insertAdjacentHTMLUnsafe}(container, \"beforeend\", html); \n" + |
| "returnedElement = {returnedElement}; \n" + |
| " \n" + |
| "// Capture Definitions \n" + |
| "{capture_definitions}; \n" + |
| "{set_msParentSelectorScope}; \n" + |
| " \n" |
| ); |
| |
| var renderImplControlAndBindingProcessing = trimLinesRight( |
| "// Control Processing \n" + |
| "{control_processing}; \n" + |
| " \n" + |
| "// Binding Processing \n" + |
| "{binding_processing}; \n" + |
| " \n" + |
| "var result = {promise_as}(returnedElement); \n" |
| ); |
| |
| var renderImplAsyncControlAndBindingProcessing = trimLinesRight( |
| "var controlSignal = new {Signal}(); \n" + |
| "var controlDone = function () {{ if (--{control_counter} === 0) {{ controlSignal.complete(); }} }}; \n" + |
| "controlDone(); \n" + |
| " \n" + |
| "// Control Processing \n" + |
| "{control_processing}; \n" + |
| " \n" + |
| "var result = controlSignal.promise.then(function () {{ \n" + |
| " // Binding Processing \n" + |
| " {binding_processing}; \n" + |
| " return {promise}.join({nestedTemplates}); \n" + |
| "}}).then(function () {{ \n" + |
| " return returnedElement; \n" + |
| "}}).then(null, function (e) {{ \n" + |
| " if (typeof e === \"object\" && e.name === \"Canceled\") {{ returnedElement.dispose(); }} \n" + |
| " return {promise}.wrapError(e); \n" + |
| "}}); \n" |
| ); |
| |
| |
| var renderImplMainCodeSuffixTemplate = trimLinesRight( |
| "{markDisposable}(returnedElement, function () {{ {disposeInstance}(returnedElement, result); }}); \n" + |
| "{suffix_statements}; \n" |
| ); |
| |
| var renderImplCodeTemplate = trimLinesRight( |
| "function render(data, container) {{ \n" + |
| " {debug_break} \n" + |
| " if (typeof data === \"object\" && typeof data.then === \"function\") {{ \n" + |
| " // async data + a container falls back to interpreted path \n" + |
| " if (container) {{ \n" + |
| " var result = this._renderInterpreted(data, container); \n" + |
| " return result.element.then(function () {{ return result.renderComplete; }}); \n" + |
| " }} \n" + |
| " return {cancelBlocker}(data).then(function(data) {{ return render(data); }}); \n" + |
| " }} \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStart}); \n" + |
| " \n" + |
| " // Declarations \n" + |
| " var {instance_variable_declarations}; \n" + |
| " var returnedElement; \n" + |
| " \n" + |
| " // Global Definitions \n" + |
| " {global_definitions}; \n" + |
| " \n" + |
| " // Data Definitions \n" + |
| " data = (data === {global} ? data : {requireSupportedForProcessing}(data)); \n" + |
| " {data_definitions}; \n" + |
| " \n" + |
| " // Instance Variable Definitions \n" + |
| " {instance_variable_definitions}; \n" + |
| " \n" + |
| " // HTML Processing \n" + |
| " container = container || {document}.createElement({tagName}); \n" + |
| " var startIndex = container.childElementCount; \n" + |
| " " + trim(indent(4, renderImplMainCodePrefixTemplate)) + " \n" + |
| " \n" + |
| " " + trim(indent(4, renderImplControlAndBindingProcessing)) + " \n" + |
| " " + trim(indent(4, renderImplMainCodeSuffixTemplate)) + " \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStop}); \n" + |
| " \n" + |
| " return result; \n" + |
| "}} \n" |
| ); |
| |
| var renderImplCodeAsyncTemplate = trimLinesRight( |
| "function render(data, container) {{ \n" + |
| " {debug_break} \n" + |
| " if (typeof data === \"object\" && typeof data.then === \"function\") {{ \n" + |
| " // async data + a container falls back to interpreted path \n" + |
| " if (container) {{ \n" + |
| " var result = this._renderInterpreted(data, container); \n" + |
| " return result.element.then(function () {{ return result.renderComplete; }}); \n" + |
| " }} \n" + |
| " return {cancelBlocker}(data).then(function(data) {{ return render(data, container); }}); \n" + |
| " }} \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStart}); \n" + |
| " \n" + |
| " // Declarations \n" + |
| " var {instance_variable_declarations}; \n" + |
| " var returnedElement; \n" + |
| " \n" + |
| " // Global Definitions \n" + |
| " {global_definitions}; \n" + |
| " \n" + |
| " // Data Definitions \n" + |
| " data = (data === {global} ? data : {requireSupportedForProcessing}(data)); \n" + |
| " {data_definitions}; \n" + |
| " \n" + |
| " // Instance Variable Definitions \n" + |
| " {instance_variable_definitions}; \n" + |
| " \n" + |
| " // HTML Processing \n" + |
| " container = container || {document}.createElement({tagName}); \n" + |
| " var startIndex = container.childElementCount; \n" + |
| " " + trim(indent(4, renderImplMainCodePrefixTemplate)) + " \n" + |
| " \n" + |
| " " + trim(indent(4, renderImplAsyncControlAndBindingProcessing)) + " \n" + |
| " " + trim(indent(4, renderImplMainCodeSuffixTemplate)) + " \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStop}); \n" + |
| " \n" + |
| " return result; \n" + |
| "}} \n" |
| ); |
| |
| var renderItemImplMainCodeSuffixTemplate = trimLinesRight( |
| "{markDisposable}(returnedElement, function () {{ {disposeInstance}(returnedElement, result, renderComplete); }});\n" + |
| "{suffix_statements}; \n" |
| ); |
| |
| var renderItemImplCodeTemplate = trimLinesRight( |
| "function renderItem(itemPromise) {{ \n" + |
| " {debug_break} \n" + |
| " // Declarations \n" + |
| " var {instance_variable_declarations}; \n" + |
| " var element, renderComplete, data, returnedElement; \n" + |
| " \n" + |
| " element = itemPromise.then(function renderItem(item) {{ \n" + |
| " if (typeof item.data === \"object\" && typeof item.data.then === \"function\") {{ \n" + |
| " return {cancelBlocker}(item.data).then(function (data) {{ return renderItem({{ data: data }}); }});\n" + |
| " }} \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStart}); \n" + |
| " \n" + |
| " // Global Definitions \n" + |
| " {global_definitions}; \n" + |
| " \n" + |
| " // Data Definitions \n" + |
| " data = item.data; \n" + |
| " data = (data === {global} ? data : {requireSupportedForProcessing}(data)); \n" + |
| " {data_definitions}; \n" + |
| " \n" + |
| " // Instance Variable Definitions \n" + |
| " {instance_variable_definitions}; \n" + |
| " \n" + |
| " // HTML Processing \n" + |
| " var container = {document}.createElement({tagName}); \n" + |
| " var startIndex = 0; \n" + |
| " " + trim(indent(8, renderImplMainCodePrefixTemplate)) + " \n" + |
| " \n" + |
| " " + trim(indent(8, renderImplControlAndBindingProcessing)) + " \n" + |
| " " + trim(indent(8, renderItemImplMainCodeSuffixTemplate)) + " \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStop}); \n" + |
| " \n" + |
| " return result; \n" + |
| " }}); \n" + |
| " {renderComplete}; \n" + |
| " return {{ \n" + |
| " element: element, \n" + |
| " renderComplete: renderComplete || element, \n" + |
| " }}; \n" + |
| "}} \n" |
| ); |
| |
| var renderItemImplRenderCompleteTemplate = trimLinesRight( |
| "renderComplete = element.then(function () {{ \n" + |
| " return itemPromise; \n" + |
| "}}).then(function (item) {{ \n" + |
| " return item.ready || item; \n" + |
| "}}).then(function (item) {{ \n" + |
| " {delayed_binding_processing}; \n" + |
| " return element; \n" + |
| "}}); \n" |
| ); |
| |
| var renderItemImplCodeAsyncTemplate = trimLinesRight( |
| "function renderItem(itemPromise) {{ \n" + |
| " {debug_break} \n" + |
| " // Declarations \n" + |
| " var {instance_variable_declarations}; \n" + |
| " var element, renderComplete, data, returnedElement; \n" + |
| " \n" + |
| " element = itemPromise.then(function renderItem(item) {{ \n" + |
| " if (typeof item.data === \"object\" && typeof item.data.then === \"function\") {{ \n" + |
| " return {cancelBlocker}(item.data).then(function (data) {{ return renderItem({{ data: data }}); }});\n" + |
| " }} \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStart}); \n" + |
| " \n" + |
| " // Global Definitions \n" + |
| " {global_definitions}; \n" + |
| " \n" + |
| " // Data Definitions \n" + |
| " data = item.data; \n" + |
| " data = (data === {global} ? data : {requireSupportedForProcessing}(data)); \n" + |
| " {data_definitions}; \n" + |
| " \n" + |
| " // Instance Variable Definitions \n" + |
| " {instance_variable_definitions}; \n" + |
| " \n" + |
| " // HTML Processing \n" + |
| " var container = {document}.createElement({tagName}); \n" + |
| " var startIndex = 0; \n" + |
| " " + trim(indent(8, renderImplMainCodePrefixTemplate)) + " \n" + |
| " \n" + |
| " " + trim(indent(8, renderImplAsyncControlAndBindingProcessing)) + " \n" + |
| " " + trim(indent(8, renderItemImplMainCodeSuffixTemplate)) + " \n" + |
| " \n" + |
| " {writeProfilerMark}({profilerMarkIdentifierStop}); \n" + |
| " \n" + |
| " return result; \n" + |
| " }}); \n" + |
| " {renderComplete}; \n" + |
| " return {{ \n" + |
| " element: element, \n" + |
| " renderComplete: renderComplete || element, \n" + |
| " }}; \n" + |
| "}} \n" |
| ); |
| |
| var linkerCodeTemplate = trimLinesRight( |
| "\"use strict\"; \n" + |
| " \n" + |
| "// statics \n" + |
| "var {static_variable_declarations}; \n" + |
| "{static_variable_definitions}; \n" + |
| " \n" + |
| "// generated template rendering function \n" + |
| "return {body}; \n" |
| ); |
| |
| // |
| // End Templates |
| // |
| |
| return TemplateCompiler; |
| }) |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/BindingTemplate',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_WinRT', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_Log', |
| './Core/_WriteProfilerMark', |
| './Binding/_Declarative', |
| './BindingTemplate/_DataTemplateCompiler', |
| './ControlProcessor', |
| './Fragments', |
| './Promise', |
| './Utilities/_Dispose', |
| './Utilities/_ElementUtilities' |
| ], function dataTemplateInit(exports, _Global, _WinRT, _Base, _BaseUtils, _Log, _WriteProfilerMark, _Declarative, _DataTemplateCompiler, ControlProcessor, Fragments, Promise, _Dispose, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var cancelBlocker = Promise._cancelBlocker; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| |
| /// <field> |
| /// <summary locid="WinJS.Binding.Template"> |
| /// Provides a reusable declarative binding element. |
| /// </summary> |
| /// </field> |
| /// <name locid="WinJS.Binding.Template_name">Template</name> |
| /// <htmlSnippet supportsContent="true"><![CDATA[<div data-win-control="WinJS.Binding.Template"><div>Place content here</div></div>]]></htmlSnippet> |
| /// <icon src="base_winjs.ui.template.12x12.png" width="12" height="12" /> |
| /// <icon src="base_winjs.ui.template.16x16.png" width="16" height="16" /> |
| /// <resource type="javascript" src="//WinJS.4.4/js/WinJS.js" shared="true" /> |
| /// <resource type="css" src="//WinJS.4.4/css/ui-dark.css" shared="true" /> |
| Template: _Base.Namespace._lazy(function () { |
| function interpretedRender(template, dataContext, container) { |
| _WriteProfilerMark("WinJS.Binding:templateRender" + template._profilerMarkIdentifier + ",StartTM"); |
| |
| if (++template._counter === 1 && (template.debugBreakOnRender || Template._debugBreakOnRender)) { |
| debugger; // jshint ignore:line |
| } |
| |
| var workPromise = Promise.wrap(); |
| var d = container || _Global.document.createElement(template.element.tagName); |
| |
| _ElementUtilities.addClass(d, "win-template"); |
| _ElementUtilities.addClass(d, "win-loading"); |
| var that = template; |
| function done() { |
| _ElementUtilities.removeClass(d, "win-loading"); |
| _WriteProfilerMark("WinJS.Binding:templateRender" + template._profilerMarkIdentifier + ",StopTM"); |
| return extractedChild || d; |
| } |
| var initial = d.children.length; |
| var element; |
| var extractedChild; |
| var dispose = function () { |
| var bindings = _ElementUtilities.data(d).winBindings; |
| if (bindings) { |
| bindings.forEach(function (item) { |
| item.cancel(); |
| }); |
| } |
| workPromise.cancel(); |
| }; |
| if (template.extractChild) { |
| element = Fragments.renderCopy(that.href || that.element, _Global.document.createElement(that.element.tagName)).then(function (frag) { |
| var child = frag.firstElementChild; |
| extractedChild = child; |
| _Dispose.markDisposable(child, dispose); |
| d.appendChild(child); |
| return child; |
| }); |
| } else { |
| _Dispose.markDisposable(d, dispose); |
| element = Fragments.renderCopy(that.href || that.element, d); |
| } |
| var renderComplete = element. |
| then(function Template_renderImpl_renderComplete_then() { |
| var work; |
| // If no existing children, we can do the faster path of just calling |
| // on the root element... |
| // |
| if (initial === 0) { |
| work = function (f, a, b, c) { return f(extractedChild || d, a, b, c); }; |
| } else { |
| // We only grab the newly added nodes (always at the end) |
| // and in the common case of only adding a single new element |
| // we avoid the "join" overhead |
| // |
| var all = d.children; |
| if (all.length === initial + 1) { |
| work = function (f, a, b, c) { return f(all[initial], a, b, c); }; |
| } else { |
| // we have to capture the elements first, in case |
| // doing the work affects the children order/content |
| // |
| var elements = []; |
| for (var i = initial, l = all.length; i < l; i++) { |
| elements.push(all[i]); |
| } |
| work = function (f, a, b, c) { |
| var join = []; |
| elements.forEach(function (e) { |
| join.push(f(e, a, b, c)); |
| }); |
| return Promise.join(join); |
| }; |
| } |
| } |
| |
| var child = d.firstElementChild; |
| while (child) { |
| child.msParentSelectorScope = true; |
| child = child.nextElementSibling; |
| } |
| |
| // This allows "0" to mean no timeout (at all) and negative values |
| // mean setImmediate (no setTimeout). Since Promise.timeout uses |
| // zero to mean setImmediate, we have to coerce. |
| // |
| var timeout = that.processTimeout; |
| function complete() { |
| return work(ControlProcessor.processAll). |
| then(function () { return cancelBlocker(dataContext); }). |
| then(function Template_renderImpl_Binding_processAll(data) { |
| return work(_Declarative.processAll, data, !extractedChild && !initial, that.bindingCache); |
| }). |
| then(null, function (e) { |
| if (typeof e === "object" && e.name === "Canceled") { |
| (extractedChild || d).dispose(); |
| } |
| return Promise.wrapError(e); |
| }); |
| } |
| if (timeout) { |
| if (timeout < 0) { timeout = 0; } |
| return Promise.timeout(timeout).then(function () { |
| workPromise = complete(); |
| return workPromise; |
| }); |
| } else { |
| workPromise = complete(); |
| return workPromise; |
| } |
| }).then(done, function (err) { done(); return Promise.wrapError(err); }); |
| |
| return { element: element, renderComplete: renderComplete }; |
| } |
| |
| var Template = _Base.Class.define(function Template_ctor(element, options) { |
| /// <signature helpKeyword="WinJS.Binding.Template.Template"> |
| /// <summary locid="WinJS.Binding.Template.constructor"> |
| /// Creates a template that provides a reusable declarative binding element. |
| /// </summary> |
| /// <param name="element" type="DOMElement" locid="WinJS.Binding.Template.constructor_p:element"> |
| /// The DOM element to convert to a template. |
| /// </param> |
| /// <param name="options" type="{href:String}" optional="true" locid="WinJS.Binding.Template.constructor_p:options"> |
| /// If this parameter is supplied, the template is loaded from the URI and |
| /// the content of the element parameter is ignored. |
| /// </param> |
| /// </signature> |
| |
| this._element = element || _Global.document.createElement("div"); |
| this._element.winControl = this; |
| |
| this._profilerMarkIdentifier = _BaseUtils._getProfilerMarkIdentifier(this._element); |
| _WriteProfilerMark("WinJS.Binding:newTemplate" + this._profilerMarkIdentifier + ",StartTM"); |
| |
| var that = this; |
| this._element.renderItem = function (itemPromise, recycled) { return that._renderItemImpl(itemPromise, recycled); }; |
| |
| options = options || {}; |
| this.href = options.href; |
| this.enableRecycling = !!options.enableRecycling; |
| this.processTimeout = options.processTimeout || 0; |
| this.bindingInitializer = options.bindingInitializer; |
| this.debugBreakOnRender = options.debugBreakOnRender; |
| this.disableOptimizedProcessing = options.disableOptimizedProcessing; |
| this.extractChild = options.extractChild; |
| this._counter = 0; |
| |
| // This will eventually change name and reverse polarity, starting opt-in. |
| // |
| this._compile = !!options._compile; |
| |
| if (!this.href) { |
| this.element.style.display = "none"; |
| } |
| this.bindingCache = { expressions: {} }; |
| |
| _WriteProfilerMark("WinJS.Binding:newTemplate" + this._profilerMarkIdentifier + ",StopTM"); |
| }, { |
| _shouldCompile: { |
| get: function () { |
| // This is the temporary switch to opt-in to compilation, eventually replaced |
| // by default opt-in with an opt-out switch. |
| // |
| var shouldCompile = true; |
| shouldCompile = shouldCompile && !Template._interpretAll; |
| shouldCompile = shouldCompile && !this.disableOptimizedProcessing; |
| |
| if (shouldCompile) { |
| shouldCompile = shouldCompile && this.processTimeout === 0; |
| shouldCompile = shouldCompile && (!this.href || this.href instanceof _Global.HTMLElement); |
| |
| if (!shouldCompile) { |
| _Log.log && _Log.log("Cannot compile templates which use processTimeout or href properties", "winjs binding", "warn"); |
| } |
| } |
| |
| return shouldCompile; |
| } |
| }, |
| |
| /// <field type="Function" locid="WinJS.Binding.Template.bindingInitializer" helpKeyword="WinJS.Binding.Template.bindingInitializer"> |
| /// If specified this function is used as the default initializer for any data bindings which do not explicitly specify one. The |
| /// provided function must be marked as supported for processing. |
| /// </field> |
| bindingInitializer: { |
| get: function () { return this._bindingInitializer; }, |
| set: function (value) { |
| this._bindingInitializer = value; |
| this._reset(); |
| } |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Binding.Template.debugBreakOnRender" helpKeyword="WinJS.Binding.Template.debugBreakOnRender"> |
| /// Indicates whether a templates should break in the debugger on first render |
| /// </field> |
| debugBreakOnRender: { |
| get: function () { return this._debugBreakOnRender; }, |
| set: function (value) { |
| this._debugBreakOnRender = !!value; |
| this._reset(); |
| } |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Binding.Template.disableOptimizedProcessing" helpKeyword="WinJS.Binding.Template.disableOptimizedProcessing"> |
| /// Set this property to true to resotre classic template processing and data binding and disable template compilation. |
| /// </field> |
| disableOptimizedProcessing: { |
| get: function () { return this._disableOptimizedProcessing; }, |
| set: function (value) { |
| this._disableOptimizedProcessing = !!value; |
| this._reset(); |
| } |
| }, |
| |
| /// <field type="HTMLElement" domElement="true" hidden="true" locid="WinJS.Binding.Template.element" helpKeyword="WinJS.Binding.Template.element"> |
| /// Gets the DOM element that is used as the template. |
| /// </field> |
| element: { |
| get: function () { return this._element; }, |
| }, |
| |
| /// <field type="Boolean" locid="WinJS.Binding.Template.extractChild" helpKeyword="WinJS.Binding.Template.extractChild"> |
| /// Return the first element child of the template instead of a wrapper element hosting all the template content. |
| /// </field> |
| extractChild: { |
| get: function () { return this._extractChild; }, |
| set: function (value) { |
| this._extractChild = !!value; |
| this._reset(); |
| } |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.Binding.Template.processTimeout" helpKeyword="WinJS.Binding.Template.processTimeout"> |
| /// Number of milliseconds to delay instantiating declarative controls. Zero (0) will result in no delay, any negative number |
| /// will result in a setImmediate delay, any positive number will be treated as the number of milliseconds. |
| /// </field> |
| processTimeout: { |
| get: function () { return this._processTimeout || 0; }, |
| set: function (value) { |
| this._processTimeout = value; |
| this._reset(); |
| } |
| }, |
| |
| render: _BaseUtils.markSupportedForProcessing(function (dataContext, container) { |
| /// <signature helpKeyword="WinJS.Binding.Template.render"> |
| /// <summary locid="WinJS.Binding.Template.render"> |
| /// Binds values from the specified data context to elements that are descendents of the specified root element |
| /// and have the declarative binding attributes (data-win-bind). |
| /// </summary> |
| /// <param name="dataContext" type="Object" optional="true" locid="WinJS.Binding.Template.render_p:dataContext"> |
| /// The object to use for default data binding. |
| /// </param> |
| /// <param name="container" type="DOMElement" optional="true" locid="WinJS.Binding.Template.render_p:container"> |
| /// The element to which to add this rendered template. If this parameter is omitted, a new DIV is created. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Binding.Template.render_returnValue"> |
| /// A promise that is completed after binding has finished. The value is |
| /// either the element specified in the container parameter or the created DIV. |
| /// </returns> |
| /// </signature> |
| |
| return this._renderImpl(dataContext, container); |
| }), |
| |
| // Hook point for compiled template |
| // |
| _renderImpl: function (dataContext, container) { |
| if (this._shouldCompile) { |
| try { |
| this._renderImpl = this._compileTemplate({ target: "render" }); |
| return this._renderImpl(dataContext, container); |
| } catch (e) { |
| return Promise.wrapError(e); |
| } |
| } |
| |
| var render = interpretedRender(this, dataContext, container); |
| return render.element.then(function () { return render.renderComplete; }); |
| }, |
| |
| _renderInterpreted: function (dataContext, container) { |
| return interpretedRender(this, dataContext, container); |
| }, |
| |
| renderItem: function (item, recycled) { |
| /// <signature helpKeyword="WinJS.Binding.Template.renderItem"> |
| /// <summary locid="WinJS.Binding.Template.renderItem"> |
| /// Renders an instance of this template bound to the data contained in item. If |
| /// the recycled parameter is present, and enableRecycling is true, then the template attempts |
| /// to reuse the DOM elements from the recycled parameter. |
| /// </summary> |
| /// <param name="item" type="Object" optional="false" locid="WinJS.Binding.Template.renderItem_p:item"> |
| /// The object that contains the data to bind to. Only item.data is required. |
| /// </param> |
| /// <param name="recycled" type="DOMElement" optional="true" locid="WinJS.Binding.Template.renderItem_p:recycled"> |
| /// A previously-generated template instance. |
| /// </param> |
| /// <returns type="DOMElement" locid="WinJS.Binding.Template.renderItem_returnValue"> |
| /// The DOM element. |
| /// </returns> |
| /// </signature> |
| return this._renderItemImpl(item, recycled); |
| }, |
| |
| // Hook point for compiled template |
| // |
| _renderItemImpl: function (item, recycled) { |
| if (this._shouldCompile) { |
| try { |
| this._renderItemImpl = this._compileTemplate({ target: "renderItem" }); |
| return this._renderItemImpl(item); |
| } catch (e) { |
| return { |
| element: Promise.wrapError(e), |
| renderComplete: Promise.wrapError(e), |
| }; |
| } |
| } |
| |
| var that = this; |
| |
| // we only enable element cache when we are trying |
| // to recycle. Otherwise our element cache would |
| // grow unbounded. |
| // |
| if (this.enableRecycling && !this.bindingCache.elements) { |
| this.bindingCache.elements = {}; |
| } |
| |
| if (this.enableRecycling |
| && recycled |
| && recycled.msOriginalTemplate === this) { |
| |
| // If we are asked to recycle, we cleanup any old work no matter what |
| // |
| var cacheEntry = this.bindingCache.elements[recycled.id]; |
| var okToReuse = true; |
| if (cacheEntry) { |
| cacheEntry.bindings.forEach(function (v) { v(); }); |
| cacheEntry.bindings = []; |
| okToReuse = !cacheEntry.nocache; |
| } |
| |
| // If our cache indicates that we hit a non-cancelable thing, then we are |
| // in an unknown state, so we actually can't recycle the tree. We have |
| // cleaned up what we can, but at this point we need to reset and create |
| // a new tree. |
| // |
| if (okToReuse) { |
| // Element recycling requires that there be no other content in "recycled" other than this |
| // templates' output. |
| // |
| return { |
| element: recycled, |
| renderComplete: item.then(function (item) { |
| return _Declarative.processAll(recycled, item.data, true, that.bindingCache); |
| }), |
| }; |
| } |
| } |
| |
| var render = interpretedRender(this, item.then(function (item) { return item.data; })); |
| render.element = render.element.then(function (e) { e.msOriginalTemplate = that; return e; }); |
| return render; |
| }, |
| |
| _compileTemplate: function (options) { |
| |
| var that = this; |
| |
| var result = _DataTemplateCompiler._TemplateCompiler.compile(this, this.href || this.element, { |
| debugBreakOnRender: this.debugBreakOnRender || Template._debugBreakOnRender, |
| defaultInitializer: this.bindingInitializer || options.defaultInitializer, |
| disableTextBindingOptimization: options.disableTextBindingOptimization || false, |
| target: options.target, |
| extractChild: this.extractChild, |
| profilerMarkIdentifier: this._profilerMarkIdentifier |
| }); |
| |
| var resetOnFragmentChange = options.resetOnFragmentChange || _WinRT.Windows.ApplicationModel.DesignMode.designModeEnabled; |
| if (resetOnFragmentChange) { |
| // For platforms that don't support MutationObserver the shim |
| // currently will never fire. This is OK because only MutationObserver |
| // can monitor DocFragments and this feature is only for |
| // assisting authoring tools. |
| var mo = new _ElementUtilities._MutationObserver(function () { |
| that._reset(); |
| mo.disconnect(); |
| }); |
| mo.observe(_ElementUtilities.data(this.element).docFragment, { |
| childList: true, |
| attributes: true, |
| characterData: true, |
| subtree: true, |
| }); |
| } |
| |
| return result; |
| |
| }, |
| |
| _reset: function () { |
| // Reset the template to being not compiled. In design mode this triggers on a mutation |
| // of the original document fragment. |
| delete this._renderImpl; |
| delete this._renderItemImpl; |
| }, |
| |
| }, { |
| isDeclarativeControlContainer: { value: true, writable: false, configurable: false }, |
| render: { |
| value: function (href, dataContext, container) { |
| /// <signature helpKeyword="WinJS.Binding.Template.render.value"> |
| /// <summary locid="WinJS.Binding.Template.render.value"> |
| /// Renders a template based on a URI. |
| /// </summary> |
| /// <param name="href" type="String" locid="WinJS.Binding.Template.render.value_p:href"> |
| /// The URI from which to load the template. |
| /// </param> |
| /// <param name="dataContext" type="Object" optional="true" locid="WinJS.Binding.Template.render.value_p:dataContext"> |
| /// The object to use for default data binding. |
| /// </param> |
| /// <param name="container" type="DOMElement" optional="true" locid="WinJS.Binding.Template.render.value_p:container"> |
| /// The element to which to add this rendered template. If this parameter is omitted, a new DIV is created. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.Binding.Template.render.value_returnValue"> |
| /// A promise that is completed after binding has finished. The value is |
| /// either the object in the container parameter or the created DIV. |
| /// </returns> |
| /// </signature> |
| return new Template(null, { href: href }).render(dataContext, container); |
| } |
| } |
| }); |
| |
| return Template; |
| }) |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| // WinJS.Binding.ListDataSource |
| // |
| define('WinJS/BindingList/_BindingListDataSource',[ |
| 'exports', |
| '../Core/_WinRT', |
| '../Core/_Base', |
| '../Core/_ErrorFromName', |
| '../Binding/_DomWeakRefTable', |
| '../Promise', |
| '../Scheduler', |
| '../Utilities/_UI' |
| ], function bindingListDataSourceInit(exports, _WinRT, _Base, _ErrorFromName, _DomWeakRefTable, Promise, Scheduler, _UI) { |
| "use strict"; |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| _BindingListDataSource: _Base.Namespace._lazy(function () { |
| var errors = { |
| get noLongerMeaningful() { return Promise.wrapError(new _ErrorFromName(_UI.EditError.noLongerMeaningful)); } |
| }; |
| |
| function findNextKey(list, index) { |
| var len = list.length; |
| while (index < len - 1) { |
| var item = list.getItem(++index); |
| if (item) { |
| return item.key; |
| } |
| } |
| return null; |
| } |
| |
| function findPreviousKey(list, index) { |
| while (index > 0) { |
| var item = list.getItem(--index); |
| if (item) { |
| return item.key; |
| } |
| } |
| return null; |
| } |
| |
| function subscribe(target, handlers) { |
| Object.keys(handlers).forEach(function (handler) { |
| target.addEventListener(handler, handlers[handler]); |
| }); |
| } |
| |
| function unsubscribe(target, handlers) { |
| Object.keys(handlers).forEach(function (handler) { |
| target.removeEventListener(handler, handlers[handler]); |
| }); |
| } |
| |
| var CompletePromise = Promise.wrap().constructor; |
| |
| var NullWrappedItem = _Base.Class.derive(CompletePromise, |
| function () { |
| this._value = null; |
| }, { |
| release: function () { }, |
| retain: function () { return this; } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| var WrappedItem = _Base.Class.derive(CompletePromise, |
| function (listBinding, item) { |
| this._value = item; |
| this._listBinding = listBinding; |
| }, { |
| handle: { |
| get: function () { return this._value.key; } |
| }, |
| index: { |
| get: function () { return this._value.index; } |
| }, |
| release: function () { |
| this._listBinding._release(this._value, this._listBinding._list.indexOfKey(this._value.key)); |
| }, |
| retain: function () { |
| this._listBinding._addRef(this._value, this._listBinding._list.indexOfKey(this._value.key)); |
| return this; |
| } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| var AsyncWrappedItem = _Base.Class.derive(Promise, |
| function (listBinding, item, name) { |
| var that = this; |
| this._item = item; |
| this._listBinding = listBinding; |
| Promise.call(this, function (c) { |
| Scheduler.schedule(function BindingList_async_item() { |
| if (listBinding._released) { |
| that.cancel(); |
| return; |
| } |
| c(item); |
| }, Scheduler.Priority.normal, null, "WinJS.Binding.List." + name); |
| }); |
| }, { |
| handle: { |
| get: function () { return this._item.key; } |
| }, |
| index: { |
| get: function () { return this._item.index; } |
| }, |
| release: function () { |
| this._listBinding._release(this._item, this._listBinding._list.indexOfKey(this._item.key)); |
| }, |
| retain: function () { |
| this._listBinding._addRef(this._item, this._listBinding._list.indexOfKey(this._item.key)); |
| return this; |
| } |
| }, { |
| supportedForProcessing: false, |
| } |
| ); |
| |
| function wrap(listBinding, item) { |
| return item ? new WrappedItem(listBinding, item) : new NullWrappedItem(); |
| } |
| |
| function wrapAsync(listBinding, item, name) { |
| return item ? new AsyncWrappedItem(listBinding, item, name) : new NullWrappedItem(); |
| } |
| |
| function cloneWithIndex(list, item, index) { |
| return item && list._annotateWithIndex(item, index); |
| } |
| |
| var ListBinding = _Base.Class.define(function ListBinding_ctor(dataSource, list, notificationHandler, id) { |
| this._dataSource = dataSource; |
| this._list = list; |
| this._editsCount = 0; |
| this._notificationHandler = notificationHandler; |
| this._pos = -1; |
| this._retained = []; |
| this._retained.length = list.length; |
| this._retainedKeys = {}; |
| this._affectedRange = null; |
| // When in WebContext, weakref utility functions don't work as desired so we capture this |
| // ListBinding object in the handler's closure. This causes the same leak as in 1.0. |
| var fallbackReference = null; |
| if (!_WinRT.msSetWeakWinRTProperty || !_WinRT.msGetWeakWinRTProperty) { |
| fallbackReference = this; |
| } |
| if (notificationHandler) { |
| var handleEvent = function (eventName, eventArg) { |
| var lb = _DomWeakRefTable._getWeakRefElement(id) || fallbackReference; |
| if (lb) { |
| lb["_" + eventName](eventArg); |
| return true; |
| } |
| return false; |
| }; |
| |
| this._handlers = { |
| itemchanged: function handler(event) { |
| if (!handleEvent("itemchanged", event)) { |
| list.removeEventListener("itemchanged", handler); |
| } |
| }, |
| iteminserted: function handler(event) { |
| if (!handleEvent("iteminserted", event)) { |
| list.removeEventListener("iteminserted", handler); |
| } |
| }, |
| itemmoved: function handler(event) { |
| if (!handleEvent("itemmoved", event)) { |
| list.removeEventListener("itemmoved", handler); |
| } |
| }, |
| itemremoved: function handler(event) { |
| if (!handleEvent("itemremoved", event)) { |
| list.removeEventListener("itemremoved", handler); |
| } |
| }, |
| reload: function handler() { |
| if (!handleEvent("reload")) { |
| list.removeEventListener("reload", handler); |
| } |
| } |
| }; |
| subscribe(this._list, this._handlers); |
| } |
| }, { |
| _itemchanged: function (event) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| this._updateAffectedRange(index, "changed"); |
| var newItem = event.detail.newItem; |
| var oldItem = this._retained[index]; |
| if (oldItem) { |
| var handler = this._notificationHandler; |
| if (oldItem.index !== index) { |
| var oldIndex = oldItem.index; |
| oldItem.index = index; |
| if (handler && handler.indexChanged) { |
| handler.indexChanged(newItem.key, index, oldIndex); |
| } |
| } |
| newItem = cloneWithIndex(this._list, newItem, index); |
| newItem._retainedCount = oldItem._retainedCount; |
| this._retained[index] = newItem; |
| this._retainedKeys[key] = newItem; |
| |
| this._beginEdits(this._list.length); |
| if (handler && handler.changed) { |
| handler.changed( |
| newItem, |
| oldItem |
| ); |
| } |
| this._endEdits(); |
| } else { |
| // Item was not retained, but we still want to batch this change with the other edits to send the affectedRange notification. |
| this._beginEdits(this._list.length); |
| this._endEdits(); |
| } |
| }, |
| |
| _iteminserted: function (event) { |
| var index = event.detail.index; |
| this._updateAffectedRange(index, "inserted"); |
| this._beginEdits(this._list.length - 1); |
| if (index <= this._pos) { |
| this._pos = Math.min(this._pos + 1, this._list.length); |
| } |
| var retained = this._retained; |
| // create a hole for this thing and then immediately make it undefined |
| retained.splice(index, 0, 0); |
| delete retained[index]; |
| if (this._shouldNotify(index) || this._list.length === 1) { |
| var handler = this._notificationHandler; |
| if (handler && handler.inserted) { |
| handler.inserted( |
| wrap(this, cloneWithIndex(this._list, this._list.getItem(index), index)), |
| findPreviousKey(this._list, index), |
| findNextKey(this._list, index) |
| ); |
| } |
| } |
| this._endEdits(); |
| }, |
| |
| _itemmoved: function (event) { |
| var oldIndex = event.detail.oldIndex; |
| var newIndex = event.detail.newIndex; |
| this._updateAffectedRange(oldIndex, "moved"); |
| this._updateAffectedRange(newIndex, "moved"); |
| this._beginEdits(this._list.length); |
| if (oldIndex < this._pos || newIndex <= this._pos) { |
| if (newIndex > this._pos) { |
| this._pos = Math.max(-1, this._pos - 1); |
| } else if (oldIndex > this._pos) { |
| this._pos = Math.min(this._pos + 1, this._list.length); |
| } |
| } |
| var retained = this._retained; |
| var item = retained.splice(oldIndex, 1)[0]; |
| retained.splice(newIndex, 0, item); |
| if (!item) { |
| delete retained[newIndex]; |
| item = cloneWithIndex(this._list, this._list.getItem(newIndex), newIndex); |
| } |
| item._moved = true; |
| this._addRef(item, newIndex); |
| this._endEdits(); |
| }, |
| |
| _itemremoved: function (event) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| this._updateAffectedRange(index, "removed"); |
| this._beginEdits(this._list.length + 1); |
| if (index < this._pos) { |
| this._pos = Math.max(-1, this._pos - 1); |
| } |
| var retained = this._retained; |
| var retainedKeys = this._retainedKeys; |
| var wasRetained = index in retained; |
| retained.splice(index, 1); |
| delete retainedKeys[key]; |
| var handler = this._notificationHandler; |
| if (wasRetained && handler && handler.removed) { |
| handler.removed(key, false); |
| } |
| this._endEdits(); |
| }, |
| |
| _reload: function () { |
| this._retained = []; |
| this._retainedKeys = {}; |
| var handler = this._notificationHandler; |
| if (handler && handler.reload) { |
| handler.reload(); |
| } |
| }, |
| |
| _addRef: function (item, index) { |
| if (index in this._retained) { |
| this._retained[index]._retainedCount++; |
| } else { |
| this._retained[index] = item; |
| this._retainedKeys[item.key] = item; |
| item._retainedCount = 1; |
| } |
| }, |
| _release: function (item, index) { |
| var retained = this._retained[index]; |
| if (retained) { |
| if (retained._retainedCount === 1) { |
| delete this._retained[index]; |
| delete this._retainedKeys[retained.key]; |
| } else { |
| retained._retainedCount--; |
| } |
| } |
| }, |
| _shouldNotify: function (index) { |
| var retained = this._retained; |
| return index in retained || index + 1 in retained || index - 1 in retained; |
| }, |
| |
| _updateAffectedRange: function ListBinding_updateAffectedRange(index, operation) { |
| // Creates a range of affected indices [start, end). |
| // Definition of _affectedRange.start: All items in the set of data with indices < _affectedRange.start have not been directly modified. |
| // Definition of _affectedRange.end: All items in the set of data with indices >= _affectedRange.end have not been directly modified. |
| |
| if (!this._notificationHandler.affectedRange) { |
| return; |
| } |
| |
| //[newStart, newEnd) |
| var newStart = index; |
| var newEnd = (operation !== "removed") ? |
| index + 1 : index; |
| |
| if (this._affectedRange) { |
| switch (operation) { |
| case "inserted": |
| if (index <= this._affectedRange.end) { |
| ++this._affectedRange.end; |
| } |
| break; |
| case "removed": |
| if (index < this._affectedRange.end) { |
| --this._affectedRange.end; |
| } |
| break; |
| case "moved": |
| case "changed": |
| break; |
| } |
| this._affectedRange.start = Math.min(this._affectedRange.start, newStart); |
| this._affectedRange.end = Math.max(this._affectedRange.end, newEnd); |
| } else { |
| // Handle the initial state |
| this._affectedRange = { start: newStart, end: newEnd }; |
| } |
| }, |
| |
| _notifyAffectedRange: function ListBinding_notifyAffectedRange() { |
| if (this._affectedRange) { |
| if (this._notificationHandler && this._notificationHandler.affectedRange) { |
| this._notificationHandler.affectedRange(this._affectedRange); |
| } |
| // reset range |
| this._affectedRange = null; |
| } |
| }, |
| _notifyCountChanged: function () { |
| var oldCount = this._countAtBeginEdits; |
| var newCount = this._list.length; |
| if (oldCount !== newCount) { |
| var handler = this._notificationHandler; |
| if (handler && handler.countChanged) { |
| handler.countChanged(newCount, oldCount); |
| } |
| } |
| }, |
| _notifyIndicesChanged: function () { |
| var retained = this._retained; |
| for (var i = 0, len = retained.length; i < len; i++) { |
| var item = retained[i]; |
| if (item && item.index !== i) { |
| var newIndex = i; |
| var oldIndex = item.index; |
| item.index = newIndex; |
| var handler = this._notificationHandler; |
| if (handler && handler.indexChanged) { |
| handler.indexChanged(item.key, newIndex, oldIndex); |
| } |
| } |
| } |
| }, |
| _notifyMoved: function () { |
| var retained = this._retained; |
| for (var i = 0, len = retained.length; i < len; i++) { |
| var item = retained[i]; |
| if (item && item._moved) { |
| item._moved = false; |
| this._release(item, i); |
| if (this._shouldNotify(i)) { |
| var handler = this._notificationHandler; |
| if (handler && handler.moved) { |
| handler.moved( |
| wrap(this, item), |
| findPreviousKey(this._list, i), |
| findNextKey(this._list, i) |
| ); |
| } |
| } |
| } |
| } |
| }, |
| |
| _beginEdits: function (length, explicit) { |
| this._editsCount++; |
| var handler = this._notificationHandler; |
| if (this._editsCount === 1 && handler) { |
| if (!explicit) { |
| // Batch all edits between now and the job running. This has the effect |
| // of batching synchronous edits. |
| // |
| this._editsCount++; |
| var that = this; |
| Scheduler.schedule(function BindingList_async_batchedEdits() { |
| that._endEdits(); |
| }, Scheduler.Priority.high, null, "WinJS.Binding.List._endEdits"); |
| } |
| if (handler.beginNotifications) { |
| handler.beginNotifications(); |
| } |
| this._countAtBeginEdits = length; |
| } |
| }, |
| _endEdits: function () { |
| this._editsCount--; |
| var handler = this._notificationHandler; |
| if (this._editsCount === 0 && handler) { |
| this._notifyIndicesChanged(); |
| this._notifyMoved(); |
| this._notifyCountChanged(); |
| // It's important to notify the affectedRange after _notifyCountChanged since we expect developers |
| // may take a dependancy on the count being up to date when they recieve the affected range. |
| this._notifyAffectedRange(); |
| if (handler.endNotifications) { |
| handler.endNotifications(); |
| } |
| } |
| }, |
| |
| jumpToItem: function (item) { |
| var index = this._list.indexOfKey(item.handle); |
| if (index === -1) { |
| return Promise.wrap(null); |
| } |
| this._pos = index; |
| return this.current(); |
| }, |
| current: function () { |
| return this.fromIndex(this._pos); |
| }, |
| previous: function () { |
| this._pos = Math.max(-1, this._pos - 1); |
| return this._fromIndex(this._pos, true, "previous"); |
| }, |
| next: function () { |
| this._pos = Math.min(this._pos + 1, this._list.length); |
| return this._fromIndex(this._pos, true, "next"); |
| }, |
| releaseItem: function (item) { |
| if (item.release) { |
| item.release(); |
| } else { |
| this._release(item, this._list.indexOfKey(item.key)); |
| } |
| }, |
| release: function () { |
| if (this._notificationHandler) { |
| unsubscribe(this._list, this._handlers); |
| } |
| this._notificationHandler = null; |
| this._dataSource._releaseBinding(this); |
| this._released = true; |
| }, |
| first: function () { |
| return this.fromIndex(0); |
| }, |
| last: function () { |
| return this.fromIndex(this._list.length - 1); |
| }, |
| fromKey: function (key) { |
| var retainedKeys = this._retainedKeys; |
| var item; |
| if (key in retainedKeys) { |
| item = retainedKeys[key]; |
| } else { |
| item = cloneWithIndex(this._list, this._list.getItemFromKey(key), this._list.indexOfKey(key)); |
| } |
| return wrap(this, item); |
| }, |
| fromIndex: function (index) { |
| return this._fromIndex(index, false, "fromIndex"); |
| }, |
| _fromIndex: function (index, async, name) { |
| var retained = this._retained; |
| var item; |
| if (index in retained) { |
| item = retained[index]; |
| } else { |
| item = cloneWithIndex(this._list, this._list.getItem(index), index); |
| } |
| return async ? wrapAsync(this, item, name) : wrap(this, item); |
| }, |
| }, { |
| supportedForProcessing: false, |
| }); |
| |
| function insertAtStart(unused, data) { |
| /*jshint validthis: true */ |
| // List ignores the key because its key management is internal |
| this._list.unshift(data); |
| return this.itemFromIndex(0); |
| } |
| function insertBefore(unused, data, nextKey) { |
| /*jshint validthis: true */ |
| // List ignores the key because its key management is internal |
| var index = this._list.indexOfKey(nextKey); |
| if (index === -1) { |
| return errors.noLongerMeaningful; |
| } |
| this._list.splice(index, 0, data); |
| return this.itemFromIndex(index); |
| } |
| function insertAfter(unused, data, previousKey) { |
| /*jshint validthis: true */ |
| // List ignores the key because its key management is internal |
| var index = this._list.indexOfKey(previousKey); |
| if (index === -1) { |
| return errors.noLongerMeaningful; |
| } |
| index += 1; |
| this._list.splice(index, 0, data); |
| return this.itemFromIndex(index); |
| } |
| function insertAtEnd(unused, data) { |
| /*jshint validthis: true */ |
| // List ignores the key because its key management is internal |
| this._list.push(data); |
| return this.itemFromIndex(this._list.length - 1); |
| } |
| function change(key, newData) { |
| /*jshint validthis: true */ |
| var index = this._list.indexOfKey(key); |
| if (index === -1) { |
| return errors.noLongerMeaningful; |
| } |
| this._list.setAt(index, newData); |
| return this.itemFromIndex(index); |
| } |
| function moveToStart(key) { |
| /*jshint validthis: true */ |
| var sourceIndex = this._list.indexOfKey(key); |
| if (sourceIndex === -1) { |
| return errors.noLongerMeaningful; |
| } |
| var targetIndex = 0; |
| this._list.move(sourceIndex, targetIndex); |
| return this.itemFromIndex(targetIndex); |
| } |
| function moveBefore(key, nextKey) { |
| /*jshint validthis: true */ |
| var sourceIndex = this._list.indexOfKey(key); |
| var targetIndex = this._list.indexOfKey(nextKey); |
| if (sourceIndex === -1 || targetIndex === -1) { |
| return errors.noLongerMeaningful; |
| } |
| targetIndex = sourceIndex < targetIndex ? targetIndex - 1 : targetIndex; |
| this._list.move(sourceIndex, targetIndex); |
| return this.itemFromIndex(targetIndex); |
| } |
| function moveAfter(key, previousKey) { |
| /*jshint validthis: true */ |
| var sourceIndex = this._list.indexOfKey(key); |
| var targetIndex = this._list.indexOfKey(previousKey); |
| if (sourceIndex === -1 || targetIndex === -1) { |
| return errors.noLongerMeaningful; |
| } |
| targetIndex = sourceIndex <= targetIndex ? targetIndex : targetIndex + 1; |
| this._list.move(sourceIndex, targetIndex); |
| return this.itemFromIndex(targetIndex); |
| } |
| function moveToEnd(key) { |
| /*jshint validthis: true */ |
| var sourceIndex = this._list.indexOfKey(key); |
| if (sourceIndex === -1) { |
| return errors.noLongerMeaningful; |
| } |
| var targetIndex = this._list.length - 1; |
| this._list.move(sourceIndex, targetIndex); |
| return this.itemFromIndex(targetIndex); |
| } |
| function remove(key) { |
| /*jshint validthis: true */ |
| var index = this._list.indexOfKey(key); |
| if (index === -1) { |
| return errors.noLongerMeaningful; |
| } |
| this._list.splice(index, 1); |
| return Promise.wrap(); |
| } |
| |
| var bindingId = 0; |
| var DataSource = _Base.Class.define(function DataSource_ctor(list) { |
| this._usingWeakRef = _WinRT.msSetWeakWinRTProperty && _WinRT.msGetWeakWinRTProperty; |
| this._bindings = {}; |
| this._list = list; |
| |
| if (list.unshift) { |
| this.insertAtStart = insertAtStart; |
| } |
| if (list.push) { |
| this.insertAtEnd = insertAtEnd; |
| } |
| if (list.setAt) { |
| this.change = change; |
| } |
| if (list.splice) { |
| this.insertAfter = insertAfter; |
| this.insertBefore = insertBefore; |
| this.remove = remove; |
| } |
| if (list.move) { |
| this.moveAfter = moveAfter; |
| this.moveBefore = moveBefore; |
| this.moveToEnd = moveToEnd; |
| this.moveToStart = moveToStart; |
| } |
| }, { |
| _releaseBinding: function (binding) { |
| delete this._bindings[binding._id]; |
| }, |
| |
| addEventListener: function () { |
| // nop, we don't send statusChanged |
| }, |
| removeEventListener: function () { |
| // nop, we don't send statusChanged |
| }, |
| |
| createListBinding: function (notificationHandler) { |
| var id = "ds_" + (++bindingId); |
| var binding = new ListBinding(this, this._list, notificationHandler, id); |
| binding._id = id; |
| |
| if (this._usingWeakRef) { |
| _DomWeakRefTable._createWeakRef(binding, id); |
| this._bindings[id] = id; |
| } else { |
| this._bindings[id] = binding; |
| } |
| |
| return binding; |
| }, |
| |
| getCount: function () { |
| return Promise.wrap(this._list.length); |
| }, |
| |
| itemFromKey: function (key) { |
| // Clone with a dummy index |
| var list = this._list, |
| item = cloneWithIndex(list, list.getItemFromKey(key), -1); |
| |
| // Override the index property with a getter |
| Object.defineProperty(item, "index", { |
| get: function () { |
| return list.indexOfKey(key); |
| }, |
| enumerable: false, |
| configurable: true |
| }); |
| |
| return Promise.wrap(item); |
| }, |
| itemFromIndex: function (index) { |
| return Promise.wrap(cloneWithIndex(this._list, this._list.getItem(index), index)); |
| }, |
| |
| list: { |
| get: function () { return this._list; } |
| }, |
| |
| beginEdits: function () { |
| var length = this._list.length; |
| this._forEachBinding(function (binding) { |
| binding._beginEdits(length, true); |
| }); |
| }, |
| endEdits: function () { |
| this._forEachBinding(function (binding) { |
| binding._endEdits(); |
| }); |
| }, |
| _forEachBinding: function (callback) { |
| if (this._usingWeakRef) { |
| var toBeDeleted = []; |
| Object.keys(this._bindings).forEach(function (id) { |
| var lb = _DomWeakRefTable._getWeakRefElement(id); |
| if (lb) { |
| callback(lb); |
| } else { |
| toBeDeleted.push(id); |
| } |
| }); |
| for (var i = 0, len = toBeDeleted.length; i < len; i++) { |
| delete this._bindings[toBeDeleted[i]]; |
| } |
| } else { |
| var that = this; |
| Object.keys(this._bindings).forEach(function (id) { |
| callback(that._bindings[id]); |
| }); |
| } |
| }, |
| |
| invalidateAll: function () { |
| return Promise.wrap(); |
| }, |
| |
| // |
| // insert* and change are not implemented as I don't understand how they are |
| // used by the controls since it is hard to fathom how they would be able |
| // to make up unique keys. Manual editing of the List is meant to go through |
| // the list itself. |
| // |
| // move* are implemented only if the underlying list supports move(). The |
| // GroupsListProjection for instance does not. |
| // |
| moveAfter: undefined, |
| moveBefore: undefined, |
| moveToEnd: undefined, |
| moveToStart: undefined |
| |
| }, { |
| supportedForProcessing: false, |
| }); |
| return DataSource; |
| }) |
| }); |
| |
| }); |
| |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| |
| // WinJS.Binding.List |
| // |
| define('WinJS/BindingList',[ |
| 'exports', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_ErrorFromName', |
| './Core/_Events', |
| './Core/_Resources', |
| './Binding/_Data', |
| './BindingList/_BindingListDataSource' |
| ], function listInit(exports, _Base, _BaseUtils, _ErrorFromName, _Events, _Resources, _Data, _BindingListDataSource) { |
| "use strict"; |
| |
| var strings = { |
| get sparseArrayNotSupported() { return "Sparse arrays are not supported with proxy: true"; }, |
| get illegalListLength() { return "List length must be assigned a finite positive number"; }, |
| }; |
| |
| function copyargs(args) { |
| return Array.prototype.slice.call(args, 0); |
| } |
| |
| function cloneItem(item) { |
| return { |
| handle: item.handle, |
| key: item.key, |
| data: item.data, |
| groupKey: item.groupKey, |
| groupSize: item.groupSize, |
| firstItemKey: item.firstItemKey, |
| firstItemIndexHint: item.firstItemIndexHint |
| }; |
| } |
| |
| function asNumber(n) { |
| return n === undefined ? undefined : +n; |
| } |
| |
| var createEvent = _Events._createEventProperty; |
| |
| var emptyOptions = {}; |
| |
| // We need a stable sort in order to implement SortedListProjection because we want to be able to |
| // perform insertions in a predictable location s.t. if we were to apply another sorted projection |
| // over the same list (now containing the inserted data) the resulting order would be the same. |
| // |
| function mergeSort(arr, sorter) { |
| var temp = new Array(arr.length); |
| |
| function copyBack(start, end) { |
| for (; start < end; start++) { |
| arr[start] = temp[start]; |
| } |
| } |
| |
| function sort(start, end) { |
| if ((end - start) < 2) { |
| return; |
| } |
| var middle = Math.floor((end + start) / 2); |
| sort(start, middle); |
| sort(middle, end); |
| merge(start, middle, end); |
| copyBack(start, end); |
| } |
| |
| function merge(start, middle, end) { |
| for (var left = start, right = middle, i = start; i < end; i++) { |
| if (left < middle && (right >= end || sorter(arr[left], arr[right]) <= 0)) { |
| temp[i] = arr[left]; |
| left++; |
| } else { |
| temp[i] = arr[right]; |
| right++; |
| } |
| } |
| } |
| |
| sort(0, arr.length); |
| |
| return arr; |
| } |
| |
| // Private namespace used for local lazily init'd classes |
| var ns = _Base.Namespace.defineWithParent(null, null, { |
| ListBase: _Base.Namespace._lazy(function () { |
| var ListBase = _Base.Class.define(null, { |
| _annotateWithIndex: function (item, index) { |
| var result = cloneItem(item); |
| result.index = index; |
| return result; |
| }, |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.onitemchanged" helpKeyword="WinJS.Binding.ListBase.onitemchanged"> |
| /// The value identified by the specified key has been replaced with a different value. |
| /// </field> |
| onitemchanged: createEvent("itemchanged"), |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.oniteminserted" helpKeyword="WinJS.Binding.ListBase.oniteminserted"> |
| /// A new value has been inserted into the list. |
| /// </field> |
| oniteminserted: createEvent("iteminserted"), |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.onitemmoved" helpKeyword="WinJS.Binding.ListBase.onitemmoved"> |
| /// The value identified by the specified key has been moved from one index in the list to another index. |
| /// </field> |
| onitemmoved: createEvent("itemmoved"), |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.onitemmutated" helpKeyword="WinJS.Binding.ListBase.onitemmutated"> |
| /// The value identified by the specified key has been mutated. |
| /// </field> |
| onitemmutated: createEvent("itemmutated"), |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.onitemremoved" helpKeyword="WinJS.Binding.ListBase.onitemremoved"> |
| /// The value identified by the specified key has been removed from the list. |
| /// </field> |
| onitemremoved: createEvent("itemremoved"), |
| |
| /// <field type="Function" locid="WinJS.Binding.ListBase.onreload" helpKeyword="WinJS.Binding.ListBase.onreload"> |
| /// The list has been refreshed. Any references to items in the list may be incorrect. |
| /// </field> |
| onreload: createEvent("reload"), |
| |
| _notifyItemChanged: function (key, index, oldValue, newValue, oldItem, newItem) { |
| if (this._listeners && this._listeners.itemchanged) { |
| this.dispatchEvent("itemchanged", { key: key, index: index, oldValue: oldValue, newValue: newValue, oldItem: oldItem, newItem: newItem }); |
| } |
| }, |
| _notifyItemInserted: function (key, index, value) { |
| if (this._listeners && this._listeners.iteminserted) { |
| this.dispatchEvent("iteminserted", { key: key, index: index, value: value }); |
| } |
| var len = this.length; |
| if (len !== this._lastNotifyLength) { |
| this.notify("length", len, this._lastNotifyLength); |
| this._lastNotifyLength = len; |
| } |
| }, |
| _notifyItemMoved: function (key, oldIndex, newIndex, value) { |
| if (this._listeners && this._listeners.itemmoved) { |
| this.dispatchEvent("itemmoved", { key: key, oldIndex: oldIndex, newIndex: newIndex, value: value }); |
| } |
| }, |
| _notifyItemMutated: function (key, value, item) { |
| if (this._listeners && this._listeners.itemmutated) { |
| this.dispatchEvent("itemmutated", { key: key, value: value, item: item }); |
| } |
| }, |
| _notifyItemRemoved: function (key, index, value, item) { |
| if (this._listeners && this._listeners.itemremoved) { |
| this.dispatchEvent("itemremoved", { key: key, index: index, value: value, item: item }); |
| } |
| var len = this.length; |
| if (len !== this._lastNotifyLength) { |
| this.notify("length", len, this._lastNotifyLength); |
| this._lastNotifyLength = len; |
| } |
| }, |
| _notifyReload: function () { |
| if (this._listeners && this._listeners.reload) { |
| this.dispatchEvent("reload"); |
| } |
| if (len !== this._lastNotifyLength) { |
| var len = this.length; |
| this.notify("length", len, this._lastNotifyLength); |
| this._lastNotifyLength = len; |
| } |
| }, |
| |
| _normalizeIndex: function (index) { |
| index = asNumber(index); |
| return index < 0 ? this.length + index : index; |
| }, |
| |
| // ABSTRACT: length |
| |
| // Notifications: |
| // |
| // ABSTRACT: notifyMutated: function (index) |
| _notifyMutatedFromKey: function (key) { |
| var item = this.getItemFromKey(key); |
| this._notifyItemMutated(key, item.data, item); |
| }, |
| notifyReload: function () { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.notifyReload"> |
| /// <summary locid="WinJS.Binding.ListBase.notifyReload"> |
| /// Forces the list to send a reload notification to any listeners. |
| /// </summary> |
| /// </signature> |
| this._notifyReload(); |
| }, |
| |
| // NOTE: performance can be improved in a number of the projections by overriding getAt/_getArray/_getFromKey/_getKey |
| // |
| getAt: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.getAt"> |
| /// <summary locid="WinJS.Binding.ListBase.getAt"> |
| /// Gets the value at the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.ListBase.getAt_p:index">The index of the value to get.</param> |
| /// <returns type="Object" mayBeNull="true" locid="WinJS.Binding.ListBase.getAt_returnValue">The value at the specified index.</returns> |
| /// </signature> |
| index = asNumber(index); |
| var item = this.getItem(index); |
| return item && item.data; |
| }, |
| // returns [ data* ] |
| _getArray: function () { |
| var results = new Array(this.length); |
| for (var i = 0, len = this.length; i < len; i++) { |
| var item = this.getItem(i); |
| if (item) { |
| results[i] = item.data; |
| } |
| } |
| return results; |
| }, |
| // returns data |
| _getFromKey: function (key) { |
| var item = this.getItemFromKey(key); |
| return item && item.data; |
| }, |
| // ABSTRACT: getItem(index) |
| // ABSTRACT: getItemFromKey(key) |
| // returns string |
| _getKey: function (index) { |
| index = asNumber(index); |
| var item = this.getItem(index); |
| return item && item.key; |
| }, |
| |
| // Normal list non-modifiying operations |
| // |
| concat: function () { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.concat"> |
| /// <summary locid="WinJS.Binding.ListBase.concat"> |
| /// Returns a new list consisting of a combination of two arrays. |
| /// </summary> |
| /// <parameter name="item" type="Object" optional="true" parameterArray="true">Additional items to add to the end of the list.</parameter> |
| /// <returns type="Array" locid="WinJS.Binding.ListBase.concat_returnValue">An array containing the concatenation of the list and any other supplied items.</returns> |
| /// </signature> |
| var a = this._getArray(); |
| return a.concat.apply(a, arguments); |
| }, |
| join: function (separator) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.join"> |
| /// <summary locid="WinJS.Binding.ListBase.join"> |
| /// Returns a string consisting of all the elements of a list separated by the specified separator string. |
| /// </summary> |
| /// <param name="separator" type="String" optional="true" locid="WinJS.Binding.ListBase.join_p:separator">A string used to separate the elements of a list. If this parameter is omitted, the list elements are separated with a comma.</param> |
| /// <returns type="String" locid="WinJS.Binding.ListBase.join_returnValue">The elements of a list separated by the specified separator string.</returns> |
| /// </signature> |
| return this._getArray().join(separator || ","); |
| }, |
| slice: function (begin, end) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.slice"> |
| /// <summary locid="WinJS.Binding.ListBase.slice"> |
| /// Extracts a section of a list and returns a new list. |
| /// </summary> |
| /// <param name="begin" type="Number" integer="true" locid="WinJS.Binding.ListBase.slice_p:begin">The index that specifies the beginning of the section.</param> |
| /// <param name="end" type="Number" integer="true" optional="true" locid="WinJS.Binding.ListBase.slice_p:end">The index that specifies the end of the section.</param> |
| /// <returns type="Array" locid="WinJS.Binding.ListBase.slice_returnValue">Returns a section of an array.</returns> |
| /// </signature> |
| return this._getArray().slice(begin, end); |
| }, |
| indexOf: function (searchElement, fromIndex) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.indexOf"> |
| /// <summary locid="WinJS.Binding.ListBase.indexOf"> |
| /// Gets the index of the first occurrence of the specified value in a list. |
| /// </summary> |
| /// <param name="searchElement" type="Object" locid="WinJS.Binding.ListBase.indexOf_p:searchElement">The value to locate in the list.</param> |
| /// <param name="fromIndex" type="Number" integer="true" optional="true" locid="WinJS.Binding.ListBase.indexOf_p:fromIndex">The index at which to begin the search. If fromIndex is omitted, the search starts at index 0.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.ListBase.indexOf_returnValue">Index of the first occurrence of a value in a list or -1 if not found.</returns> |
| /// </signature> |
| fromIndex = asNumber(fromIndex); |
| fromIndex = Math.max(0, this._normalizeIndex(fromIndex) || 0); |
| for (var i = fromIndex, len = this.length; i < len; i++) { |
| var item = this.getItem(i); |
| if (item && item.data === searchElement) { |
| return i; |
| } |
| } |
| return -1; |
| }, |
| // ABSTRACT: indexOfKey(key) |
| lastIndexOf: function (searchElement, fromIndex) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.lastIndexOf"> |
| /// <summary locid="WinJS.Binding.ListBase.lastIndexOf"> |
| /// Gets the index of the last occurrence of the specified value in a list. |
| /// </summary> |
| /// <param name="searchElement" type="Object" locid="WinJS.Binding.ListBase.lastIndexOf_p:searchElement">The value to locate in the list.</param> |
| /// <param name="fromIndex" type="Number" integer="true" optional="true" locid="WinJS.Binding.ListBase.lastIndexOf_p:fromIndex">The index at which to begin the search. If fromIndex is omitted, the search starts at the last index in the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.ListBase.lastIndexOf_returnValue">The index of the last occurrence of a value in a list, or -1 if not found.</returns> |
| /// </signature> |
| fromIndex = asNumber(fromIndex); |
| var length = this.length; |
| fromIndex = Math.min(this._normalizeIndex(fromIndex !== undefined ? fromIndex : length), length - 1); |
| var i; |
| for (i = fromIndex; i >= 0; i--) { |
| var item = this.getItem(i); |
| if (item && item.data === searchElement) { |
| return i; |
| } |
| } |
| return -1; |
| }, |
| |
| // |
| // Normal list projection operations |
| // |
| |
| every: function (callback, thisArg) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.every"> |
| /// <summary locid="WinJS.Binding.ListBase.every"> |
| /// Checks whether the specified callback function returns true for all elements in a list. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.every_p:callback">A function that accepts up to three arguments. This function is called for each element in the list until it returns false or the end of the list is reached.</param> |
| /// <param name="thisArg" type="Object" optional="true" locid="WinJS.Binding.ListBase.every_p:thisArg">An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used.</param> |
| /// <returns type="Boolean" locid="WinJS.Binding.ListBase.every_returnValue">True if the callback returns true for all elements in the list.</returns> |
| /// </signature> |
| return this._getArray().every(callback, thisArg); |
| }, |
| filter: function (callback, thisArg) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.filter"> |
| /// <summary locid="WinJS.Binding.ListBase.filter"> |
| /// Returns the elements of a list that meet the condition specified in a callback function. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.filter_p:callback">A function that accepts up to three arguments. The function is called for each element in the list.</param> |
| /// <param name="thisArg" type="Object" optional="true" locid="WinJS.Binding.ListBase.filter_p:thisArg">An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used.</param> |
| /// <returns type="Array" locid="WinJS.Binding.ListBase.filter_returnValue">An array containing the elements that meet the condition specified in the callback function.</returns> |
| /// </signature> |
| return this._getArray().filter(callback, thisArg); |
| }, |
| forEach: function (callback, thisArg) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.forEach"> |
| /// <summary locid="WinJS.Binding.ListBase.forEach"> |
| /// Calls the specified callback function for each element in a list. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.forEach_p:callback">A function that accepts up to three arguments. The function is called for each element in the list.</param> |
| /// <param name="thisArg" type="Object" optional="true" locid="WinJS.Binding.ListBase.forEach_p:thisArg">An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used.</param> |
| /// </signature> |
| this._getArray().forEach(callback, thisArg); |
| }, |
| map: function (callback, thisArg) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.map"> |
| /// <summary locid="WinJS.Binding.ListBase.map"> |
| /// Calls the specified callback function on each element of a list, and returns an array that contains the results. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.map_p:callback">A function that accepts up to three arguments. The function is called for each element in the list.</param> |
| /// <param name="thisArg" type="Object" optional="true" locid="WinJS.Binding.ListBase.map_p:thisArg">An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used.</param> |
| /// <returns type="Array" locid="WinJS.Binding.ListBase.map_returnValue">An array containing the result of calling the callback function on each element in the list.</returns> |
| /// </signature> |
| return this._getArray().map(callback, thisArg); |
| }, |
| some: function (callback, thisArg) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.some"> |
| /// <summary locid="WinJS.Binding.ListBase.some"> |
| /// Checks whether the specified callback function returns true for any element of a list. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.some_p:callback">A function that accepts up to three arguments. The function is called for each element in the list until it returns true, or until the end of the list.</param> |
| /// <param name="thisArg" type="Object" optional="true" locid="WinJS.Binding.ListBase.some_p:thisArg">An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used.</param> |
| /// <returns type="Boolean" locid="WinJS.Binding.ListBase.some_returnValue">True if callback returns true for any element in the list.</returns> |
| /// </signature> |
| return this._getArray().some(callback, thisArg); |
| }, |
| reduce: function (callback, initialValue) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.reduce"> |
| /// <summary locid="WinJS.Binding.ListBase.reduce"> |
| /// Accumulates a single result by calling the specified callback function for all elements in a list. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.reduce_p:callback">A function that accepts up to four arguments. The function is called for each element in the list.</param> |
| /// <param name="initialValue" type="Object" optional="true" locid="WinJS.Binding.ListBase.reduce_p:initialValue">If initialValue is specified, it is used as the value with which to start the accumulation. The first call to the function provides this value as an argument instead of a list value.</param> |
| /// <returns type="Object" locid="WinJS.Binding.ListBase.reduce_returnValue">The return value from the last call to the callback function.</returns> |
| /// </signature> |
| if (arguments.length > 1) { |
| return this._getArray().reduce(callback, initialValue); |
| } |
| return this._getArray().reduce(callback); |
| }, |
| reduceRight: function (callback, initialValue) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.reduceRight"> |
| /// <summary locid="WinJS.Binding.ListBase.reduceRight"> |
| /// Accumulates a single result by calling the specified callback function for all elements in a list, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
| /// </summary> |
| /// <param name="callback" type="Function" locid="WinJS.Binding.ListBase.reduceRight_p:callback">A function that accepts up to four arguments. The function is called for each element in the list.</param> |
| /// <param name="initialValue" type="Object" optional="true" locid="WinJS.Binding.ListBase.reduceRight_p:initialValue">If initialValue is specified, it is used as the value with which to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of a list value.</param> |
| /// <returns type="Object" locid="WinJS.Binding.ListBase.reduceRight_returnValue">The return value from last call to callback function.</returns> |
| /// </signature> |
| if (arguments.length > 1) { |
| return this._getArray().reduceRight(callback, initialValue); |
| } |
| return this._getArray().reduceRight(callback); |
| }, |
| |
| // |
| // Live Projections - if you want the lifetime of the returned projections to |
| // be shorter than that of the list object on which they are based you have |
| // to remember to call .dispose() on them when done. |
| // |
| |
| createFiltered: function (predicate) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.createFiltered"> |
| /// <summary locid="WinJS.Binding.ListBase.createFiltered"> |
| /// Creates a live filtered projection over this list. As the list changes, the filtered projection reacts to those changes and may also change. |
| /// </summary> |
| /// <param name="predicate" type="Function" locid="WinJS.Binding.ListBase.createFiltered_p:predicate">A function that accepts a single argument. The createFiltered function calls the callback with each element in the list. If the function returns true, that element will be included in the filtered list.</param> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.ListBase.createFiltered_returnValue">Filtered projection over the list.</returns> |
| /// </signature> |
| return new ns.FilteredListProjection(this, predicate); |
| }, |
| createGrouped: function (groupKey, groupData, groupSorter) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.createGrouped"> |
| /// <summary locid="WinJS.Binding.ListBase.createGrouped"> |
| /// Creates a live grouped projection over this list. As the list changes, the grouped projection reacts to those changes and may also change. The grouped projection sorts all the elements of the list to be in group-contiguous order. The grouped projection also contains a .groups property which is a WinJS.Binding.List representing the groups that were found in the list. |
| /// </summary> |
| /// <param name="groupKey" type="Function" locid="WinJS.Binding.ListBase.createGrouped_p:groupKey">A function that accepts a single argument. The function is called with each element in the list, the function should return a string representing the group containing the element.</param> |
| /// <param name="groupData" type="Function" locid="WinJS.Binding.ListBase.createGrouped_p:groupData">A function that accepts a single argument. The function is called on an element in the list for each group. It should return the value that should be set as the data of the .groups list element for this group.</param> |
| /// <param name="groupSorter" type="Function" optional="true" locid="WinJS.Binding.ListBase.createGrouped_p:groupSorter">A function that accepts two arguments. The function is called with the key of groups found in the list. It must return one of the following numeric values: negative if the first argument is less than the second, zero if the two arguments are equivalent, positive if the first argument is greater than the second. If omitted, the groups are sorted in ascending, ASCII character order.</param> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.ListBase.createGrouped_returnValue">A grouped projection over the list.</returns> |
| /// </signature> |
| return new ns.GroupedSortedListProjection(this, groupKey, groupData, groupSorter); |
| }, |
| createSorted: function (sorter) { |
| /// <signature helpKeyword="WinJS.Binding.ListBase.createSorted"> |
| /// <summary locid="WinJS.Binding.ListBase.createSorted"> |
| /// Creates a live sorted projection over this list. As the list changes, the sorted projection reacts to those changes and may also change. |
| /// </summary> |
| /// <param name="sorter" type="Function" locid="WinJS.Binding.ListBase.createSorted_p:sorter">A function that accepts two arguments. The function is called with elements in the list. It must return one of the following numeric values: negative if the first argument is less than the second, zero if the two arguments are equivalent, positive if the first argument is greater than the second.</param> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.ListBase.createSorted_returnValue">A sorted projection over the list.</returns> |
| /// </signature> |
| return new ns.SortedListProjection(this, sorter); |
| }, |
| |
| dataSource: { |
| get: function () { |
| return (this._dataSource = this._dataSource || new _BindingListDataSource._BindingListDataSource(this)); |
| } |
| }, |
| |
| }, { |
| supportedForProcessing: false, |
| }); |
| _Base.Class.mix(ListBase, _Data.observableMixin); |
| _Base.Class.mix(ListBase, _Events.eventMixin); |
| return ListBase; |
| }), |
| |
| ListBaseWithMutators: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListBase, null, { |
| // ABSTRACT: setAt(index, value) |
| |
| // Normal list modifying operations |
| // |
| // returns data from tail of list |
| pop: function () { |
| /// <signature helpKeyword="WinJS.Binding.ListBaseWithMutators.pop"> |
| /// <summary locid="WinJS.Binding.ListBaseWithMutators.pop"> |
| /// Removes the last element from a list and returns it. |
| /// </summary> |
| /// <returns type="Object" locid="WinJS.Binding.ListBaseWithMutators.pop_returnValue">Last element from the list.</returns> |
| /// </signature> |
| return this.splice(-1, 1)[0]; |
| }, |
| push: function (value) { |
| /// <signature helpKeyword="WinJS.Binding.ListBaseWithMutators.push"> |
| /// <summary locid="WinJS.Binding.ListBaseWithMutators.push"> |
| /// Appends new element(s) to a list, and returns the new length of the list. |
| /// </summary> |
| /// <param name="value" type="Object" parameterArray="true" locid="WinJS.Binding.ListBaseWithMutators.push_p:value">The element to insert at the end of the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.ListBaseWithMutators.push_returnValue">The new length of the list.</returns> |
| /// </signature> |
| if (arguments.length === 1) { |
| this.splice(this.length, 0, value); |
| return this.length; |
| } else { |
| var args = copyargs(arguments); |
| args.splice(0, 0, this.length, 0); |
| this.splice.apply(this, args); |
| return this.length; |
| } |
| }, |
| // returns data from head of list |
| shift: function () { |
| /// <signature helpKeyword="WinJS.Binding.ListBaseWithMutators.shift"> |
| /// <summary locid="WinJS.Binding.ListBaseWithMutators.shift"> |
| /// Removes the first element from a list and returns it. |
| /// </summary> |
| /// <returns type="Object" locid="WinJS.Binding.ListBaseWithMutators.shift_returnValue">First element from the list.</returns> |
| /// </signature> |
| return this.splice(0, 1)[0]; |
| }, |
| unshift: function (value) { |
| /// <signature helpKeyword="WinJS.Binding.ListBaseWithMutators.unshift"> |
| /// <summary locid="WinJS.Binding.ListBaseWithMutators.unshift"> |
| /// Appends new element(s) to a list, and returns the new length of the list. |
| /// </summary> |
| /// <param name="value" type="Object" parameterArray="true" locid="WinJS.Binding.ListBaseWithMutators.unshift_p:value">The element to insert at the start of the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.ListBaseWithMutators.unshift_returnValue">The new length of the list.</returns> |
| /// </signature> |
| if (arguments.length === 1) { |
| this.splice(0, 0, value); |
| } else { |
| var args = copyargs(arguments); |
| // Wow, this looks weird. Insert 0, 0 at the beginning of splice. |
| args.splice(0, 0, 0, 0); |
| this.splice.apply(this, args); |
| } |
| return this.length; |
| } |
| |
| // ABSTRACT: splice(index, howMany, values...) |
| // ABSTRACT: _spliceFromKey(key, howMany, values...) |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| ListProjection: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListBaseWithMutators, null, { |
| _list: null, |
| _myListeners: null, |
| |
| _addListListener: function (name, func) { |
| var l = { name: name, handler: func.bind(this) }; |
| this._myListeners = this._myListeners || []; |
| this._myListeners.push(l); |
| this._list.addEventListener(name, l.handler); |
| }, |
| |
| // ABSTRACT: _listReload() |
| |
| dispose: function () { |
| /// <signature helpKeyword="WinJS.Binding.ListProjection.dispose"> |
| /// <summary locid="WinJS.Binding.ListProjection.dispose"> |
| /// Disconnects this WinJS.Binding.List projection from its underlying WinJS.Binding.List. This is important only if they have different lifetimes. |
| /// </summary> |
| /// </signature> |
| var list = this._list; |
| |
| var listeners = this._myListeners; |
| this._myListeners = []; |
| |
| for (var i = 0, len = listeners.length; i < len; i++) { |
| var l = listeners[i]; |
| list.removeEventListener(l.name, l.handler); |
| } |
| |
| // Set this to an empty list and tell everyone that they need to reload to avoid |
| // consumers null-refing on an empty list. |
| this._list = new exports.List(); |
| this._listReload(); |
| }, |
| |
| getItemFromKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.ListProjection.getItemFromKey"> |
| /// <summary locid="WinJS.Binding.ListProjection.getItemFromKey"> |
| /// Gets a key/data pair for the specified key. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.ListProjection.getItemFromKey_p:key">The key of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.ListProjection.getItemFromKey_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| return this._list.getItemFromKey(key); |
| }, |
| |
| move: function (index, newIndex) { |
| /// <signature helpKeyword="WinJS.Binding.ListProjection.move"> |
| /// <summary locid="WinJS.Binding.ListProjection.move"> |
| /// Moves the value at index to position newIndex. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.ListProjection.move_p:index">The original index of the value.</param> |
| /// <param name="newIndex" type="Number" integer="true" locid="WinJS.Binding.ListProjection.move_p:newIndex">The index of the value after the move.</param> |
| /// </signature> |
| index = asNumber(index); |
| newIndex = asNumber(newIndex); |
| if (index === newIndex || index < 0 || newIndex < 0 || index >= this.length || newIndex >= this.length) { |
| return; |
| } |
| index = this._list.indexOfKey(this._getKey(index)); |
| newIndex = this._list.indexOfKey(this._getKey(newIndex)); |
| this._list.move(index, newIndex); |
| }, |
| |
| _notifyMutatedFromKey: function (key) { |
| this._list._notifyMutatedFromKey(key); |
| }, |
| |
| splice: function (index, howMany, item) { |
| /// <signature helpKeyword="WinJS.Binding.ListProjection.splice"> |
| /// <summary locid="WinJS.Binding.ListProjection.splice"> |
| /// Removes elements from a list and, if necessary, inserts new elements in their place, returning the deleted elements. |
| /// </summary> |
| /// <param name="start" type="Number" integer="true" locid="WinJS.Binding.ListProjection.splice_p:start">The zero-based location in the list from which to start removing elements.</param> |
| /// <param name="howMany" type="Number" integer="true" locid="WinJS.Binding.ListProjection.splice_p:howMany">The number of elements to remove.</param> |
| /// <param name="item" type="Object" optional="true" parameterArray="true" locid="WinJS.Binding.ListProjection.splice_p:item">The elements to insert into the list in place of the deleted elements.</param> |
| /// <returns type="Array" locid="WinJS.Binding.ListProjection.splice_returnValue">The deleted elements.</returns> |
| /// </signature> |
| index = asNumber(index); |
| index = Math.max(0, this._normalizeIndex(index)); |
| var args = copyargs(arguments); |
| if (index === this.length) { |
| // In order to getAt the tail right we just push on to the end of the underlying list |
| args[0] = this._list.length; |
| return this._list.splice.apply(this._list, args); |
| } else { |
| args[0] = this._getKey(index); |
| return this._spliceFromKey.apply(this, args); |
| } |
| }, |
| |
| _setAtKey: function (key, value) { |
| this._list._setAtKey(key, value); |
| }, |
| |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| FilteredListProjection: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListProjection, function (list, filter) { |
| this._list = list; |
| this._addListListener("itemchanged", this._listItemChanged); |
| this._addListListener("iteminserted", this._listItemInserted); |
| this._addListListener("itemmutated", this._listItemMutated); |
| this._addListListener("itemmoved", this._listItemMoved); |
| this._addListListener("itemremoved", this._listItemRemoved); |
| this._addListListener("reload", this._listReload); |
| this._filter = filter; |
| this._initFilteredKeys(); |
| }, { |
| _filter: null, |
| _filteredKeys: null, |
| _initFilteredKeys: function () { |
| var filter = this._filter; |
| var list = this._list; |
| var keys = []; |
| for (var i = 0, len = list.length; i < len; i++) { |
| var item = list.getItem(i); |
| if (item && filter(item.data)) { |
| keys.push(item.key); |
| } |
| } |
| this._filteredKeys = keys; |
| }, |
| |
| _findInsertionPosition: function (key, index) { |
| // find the spot to insert this by identifing the previous element in the list |
| var filter = this._filter; |
| var previousKey; |
| while ((--index) >= 0) { |
| var item = this._list.getItem(index); |
| if (item && filter(item.data)) { |
| previousKey = item.key; |
| break; |
| } |
| } |
| var filteredKeys = this._filteredKeys; |
| var filteredIndex = previousKey ? (filteredKeys.indexOf(previousKey) + 1) : 0; |
| return filteredIndex; |
| }, |
| |
| _listItemChanged: function (event) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var oldValue = event.detail.oldValue; |
| var newValue = event.detail.newValue; |
| var oldItem = event.detail.oldItem; |
| var newItem = event.detail.newItem; |
| var filter = this._filter; |
| var oldInFilter = filter(oldValue); |
| var newInFilter = filter(newValue); |
| if (oldInFilter && newInFilter) { |
| var filteredKeys = this._filteredKeys; |
| var filteredIndex = filteredKeys.indexOf(key); |
| this._notifyItemChanged(key, filteredIndex, oldValue, newValue, oldItem, newItem); |
| } else if (oldInFilter && !newInFilter) { |
| this._listItemRemoved({ detail: { key: key, index: index, value: oldValue, item: oldItem } }); |
| } else if (!oldInFilter && newInFilter) { |
| this._listItemInserted({ detail: { key: key, index: index, value: newValue } }); |
| } |
| }, |
| _listItemInserted: function (event) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var value = event.detail.value; |
| var filter = this._filter; |
| if (filter(value)) { |
| var filteredIndex = this._findInsertionPosition(key, index); |
| var filteredKeys = this._filteredKeys; |
| filteredKeys.splice(filteredIndex, 0, key); |
| this._notifyItemInserted(key, filteredIndex, value); |
| } |
| }, |
| _listItemMoved: function (event) { |
| var key = event.detail.key; |
| var newIndex = event.detail.newIndex; |
| var value = event.detail.value; |
| var filteredKeys = this._filteredKeys; |
| var oldFilteredIndex = filteredKeys.indexOf(key); |
| if (oldFilteredIndex !== -1) { |
| filteredKeys.splice(oldFilteredIndex, 1); |
| var newFilteredIndex = this._findInsertionPosition(key, newIndex); |
| filteredKeys.splice(newFilteredIndex, 0, key); |
| this._notifyItemMoved(key, oldFilteredIndex, newFilteredIndex, value); |
| } |
| }, |
| _listItemMutated: function (event) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var item = event.detail.item; |
| var filter = this._filter; |
| var filteredKeys = this._filteredKeys; |
| var filteredIndex = filteredKeys.indexOf(key); |
| var oldInFilter = filteredIndex !== -1; |
| var newInFilter = filter(value); |
| if (oldInFilter && newInFilter) { |
| this._notifyItemMutated(key, value, item); |
| } else if (oldInFilter && !newInFilter) { |
| filteredKeys.splice(filteredIndex, 1); |
| this._notifyItemRemoved(key, filteredIndex, value, item); |
| } else if (!oldInFilter && newInFilter) { |
| this._listItemInserted({ detail: { key: key, index: this._list.indexOfKey(key), value: value } }); |
| } |
| }, |
| _listItemRemoved: function (event) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var item = event.detail.item; |
| var filteredKeys = this._filteredKeys; |
| var filteredIndex = filteredKeys.indexOf(key); |
| if (filteredIndex !== -1) { |
| filteredKeys.splice(filteredIndex, 1); |
| this._notifyItemRemoved(key, filteredIndex, value, item); |
| } |
| }, |
| _listReload: function () { |
| this._initFilteredKeys(); |
| this._notifyReload(); |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.Binding.FilteredListProjection.length" helpKeyword="WinJS.Binding.FilteredListProjection.length">Returns an integer value one higher than the highest element defined in an list.</field> |
| length: { |
| get: function () { return this._filteredKeys.length; }, |
| set: function (value) { |
| if (typeof value === "number" && value >= 0) { |
| var current = this.length; |
| if (current > value) { |
| this.splice(value, current - value); |
| } |
| } else { |
| throw new _ErrorFromName("WinJS.Binding.List.IllegalLength", strings.illegalListLength); |
| } |
| } |
| }, |
| |
| getItem: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.FilteredListProjection.getItem"> |
| /// <summary locid="WinJS.Binding.FilteredListProjection.getItem"> |
| /// Returns a key/data pair for the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.FilteredListProjection.getItem_p:index">The index of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.FilteredListProjection.getItem_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| index = asNumber(index); |
| return this.getItemFromKey(this._filteredKeys[index]); |
| }, |
| |
| indexOfKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.FilteredListProjection.indexOfKey"> |
| /// <summary locid="WinJS.Binding.FilteredListProjection.indexOfKey"> |
| /// Returns the index of the first occurrence of a key in a list. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.FilteredListProjection.indexOfKey_p:key">The key to locate in the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.FilteredListProjection.indexOfKey_returnValue">The index of the first occurrence of a key in a list, or -1 if not found.</returns> |
| /// </signature> |
| return this._filteredKeys.indexOf(key); |
| }, |
| |
| notifyMutated: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.FilteredListProjection.notifyMutated"> |
| /// <summary locid="WinJS.Binding.FilteredListProjection.notifyMutated"> |
| /// Forces the list to send a itemmutated notification to any listeners for the value at the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.FilteredListProjection.notifyMutated_p:index">The index of the value that was mutated.</param> |
| /// </signature> |
| index = asNumber(index); |
| return this._notifyMutatedFromKey(this._filteredKeys[index]); |
| }, |
| |
| setAt: function (index, value) { |
| /// <signature helpKeyword="WinJS.Binding.FilteredListProjection.setAt"> |
| /// <summary locid="WinJS.Binding.FilteredListProjection.setAt"> |
| /// Replaces the value at the specified index with a new value. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.FilteredListProjection.setAt_p:index">The index of the value that was replaced.</param> |
| /// <param name="newValue" type="Object" locid="WinJS.Binding.FilteredListProjection.setAt_p:newValue">The new value.</param> |
| /// </signature> |
| index = asNumber(index); |
| this._setAtKey(this._filteredKeys[index], value); |
| }, |
| |
| // returns [ data* ] of removed items |
| _spliceFromKey: function (key, howMany) { |
| // first add in all the new items if we have any, this should serve to push key to the right |
| if (arguments.length > 2) { |
| var args = copyargs(arguments); |
| args[1] = 0; // howMany |
| this._list._spliceFromKey.apply(this._list, args); |
| } |
| // now we can remove anything that needs to be removed, since they are not necessarially contiguous |
| // in the underlying list we remove them one by one. |
| var result = []; |
| if (howMany) { |
| var keysToRemove = []; |
| var filteredKeys = this._filteredKeys; |
| var filteredKeyIndex = filteredKeys.indexOf(key); |
| for (var i = filteredKeyIndex, len = filteredKeys.length; i < len && (i - filteredKeyIndex) < howMany; i++) { |
| var key = filteredKeys[i]; |
| keysToRemove.push(key); |
| } |
| var that = this; |
| keysToRemove.forEach(function (key) { |
| result.push(that._list._spliceFromKey(key, 1)[0]); |
| }); |
| } |
| return result; |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| SortedListProjection: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListProjection, function (list, sortFunction) { |
| this._list = list; |
| this._addListListener("itemchanged", this._listItemChanged); |
| this._addListListener("iteminserted", this._listItemInserted); |
| this._addListListener("itemmoved", this._listItemMoved); |
| this._addListListener("itemmutated", this._listItemMutated); |
| this._addListListener("itemremoved", this._listItemRemoved); |
| this._addListListener("reload", this._listReload); |
| this._sortFunction = sortFunction; |
| this._initSortedKeys(); |
| }, { |
| _sortFunction: null, |
| _sortedKeys: null, |
| _initSortedKeys: function () { |
| var list = this._list; |
| var keys = []; |
| for (var i = 0, len = list.length; i < len; i++) { |
| var item = list.getItem(i); |
| if (item) { |
| keys[i] = item.key; |
| } |
| } |
| var sorter = this._sortFunction; |
| var sorted = mergeSort(keys, function (l, r) { |
| l = list.getItemFromKey(l).data; |
| r = list.getItemFromKey(r).data; |
| return sorter(l, r); |
| }); |
| this._sortedKeys = sorted; |
| }, |
| |
| _findInsertionPos: function (key, index, value, startingMin, startingMax) { |
| var sorter = this._sortFunction; |
| var sortedKeys = this._sortedKeys; |
| var min = Math.max(0, startingMin || -1); |
| var max = Math.min(sortedKeys.length, startingMax || Number.MAX_VALUE); |
| var mid = min; |
| while (min <= max) { |
| mid = ((min + max) / 2) >>> 0; |
| var sortedKey = sortedKeys[mid]; |
| if (!sortedKey) { |
| break; |
| } |
| var sortedItem = this.getItemFromKey(sortedKey); |
| var r = sorter(sortedItem.data, value); |
| if (r < 0) { |
| min = mid + 1; |
| } else if (r === 0) { |
| return this._findStableInsertionPos(key, index, min, max, mid, value); |
| } else { |
| max = mid - 1; |
| } |
| } |
| return min; |
| }, |
| _findBeginningOfGroup: function (mid, sorter, list, sortedKeys, value) { |
| // we made it to the beginning of the list without finding something |
| // that sorts equal to this value, insert this key at the beginning of |
| // this section of keys. |
| var min = 0; |
| var max = mid; |
| while (min <= max) { |
| mid = ((min + max) / 2) >>> 0; |
| var sortedKey = sortedKeys[mid]; |
| var sortedItem = list.getItemFromKey(sortedKey); |
| var r = sorter(sortedItem.data, value); |
| if (r < 0) { |
| min = mid + 1; |
| } else { |
| max = mid - 1; |
| } |
| } |
| return min; |
| }, |
| _findEndOfGroup: function (mid, sorter, list, sortedKeys, value) { |
| // we made it ot the end of the list without finding something that sorts |
| // equal to this value, insert this key at the end of this section of |
| // keys. |
| var min = mid; |
| var max = sortedKeys.length; |
| while (min <= max) { |
| mid = ((min + max) / 2) >>> 0; |
| var sortedKey = sortedKeys[mid]; |
| if (!sortedKey) { |
| return sortedKeys.length; |
| } |
| var sortedItem = list.getItemFromKey(sortedKey); |
| var r = sorter(sortedItem.data, value); |
| if (r <= 0) { |
| min = mid + 1; |
| } else { |
| max = mid - 1; |
| } |
| } |
| return min; |
| }, |
| _findStableInsertionPos: function (key, index, min, max, mid, value) { |
| var list = this._list; |
| var length = list.length; |
| var sorter = this._sortFunction; |
| var sortedKeys = this._sortedKeys; |
| if (index < (length / 2)) { |
| for (var i = index - 1; i >= 0; i--) { |
| var item = list.getItem(i); |
| if (sorter(item.data, value) === 0) { |
| // we have found the next item to the left, insert this item to |
| // the right of that. |
| if ((length - min) > max) { |
| return sortedKeys.indexOf(item.key, min) + 1; |
| } else { |
| return sortedKeys.lastIndexOf(item.key, max) + 1; |
| } |
| } |
| } |
| return this._findBeginningOfGroup(mid, sorter, list, sortedKeys, value); |
| } else { |
| for (var i = index + 1; i < length; i++) { |
| var item = list.getItem(i); |
| if (sorter(item.data, value) === 0) { |
| // we have found the next item to the right, insert this item |
| // to the left of that. |
| if ((length - min) > max) { |
| return sortedKeys.indexOf(item.key, min); |
| } else { |
| return sortedKeys.lastIndexOf(item.key, max); |
| } |
| } |
| } |
| return this._findEndOfGroup(mid, sorter, list, sortedKeys, value); |
| } |
| }, |
| |
| _listItemChanged: function (event) { |
| var key = event.detail.key; |
| var newValue = event.detail.newValue; |
| var oldValue = event.detail.oldValue; |
| var sortFunction = this._sortFunction; |
| if (sortFunction(oldValue, newValue) === 0) { |
| var sortedIndex = this.indexOfKey(key); |
| this._notifyItemChanged(key, sortedIndex, oldValue, newValue, event.detail.oldItem, event.detail.newItem); |
| } else { |
| this._listItemRemoved({ detail: { key: key, index: event.detail.index, value: event.detail.oldValue, item: event.detail.oldItem } }); |
| this._listItemInserted({ detail: { key: key, index: event.detail.index, value: event.detail.newValue } }); |
| } |
| }, |
| _listItemInserted: function (event, knownMin, knownMax) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var value = event.detail.value; |
| var sortedIndex = this._findInsertionPos(key, index, value, knownMin, knownMax); |
| this._sortedKeys.splice(sortedIndex, 0, key); |
| this._notifyItemInserted(key, sortedIndex, value); |
| }, |
| _listItemMoved: function (event, knownMin, knownMax) { |
| var key = event.detail.key; |
| var newIndex = event.detail.newIndex; |
| var value = event.detail.value; |
| var sortedKeys = this._sortedKeys; |
| var oldSortedIndex = sortedKeys.indexOf(key, knownMin); |
| sortedKeys.splice(oldSortedIndex, 1); |
| var newSortedIndex = this._findInsertionPos(key, newIndex, value, knownMin, knownMax); |
| sortedKeys.splice(newSortedIndex, 0, key); |
| if (newSortedIndex !== oldSortedIndex) { |
| // The move in the underlying list resulted in a move in the sorted list |
| // |
| this._notifyItemMoved(key, oldSortedIndex, newSortedIndex, value); |
| } else { |
| // The move in the underlying list resulted in no change in the sorted list |
| // |
| } |
| }, |
| _listItemMutated: function (event) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var item = event.detail.item; |
| var index = this._list.indexOfKey(key); |
| var sortedIndex = this._sortedKeys.indexOf(key); |
| this._sortedKeys.splice(sortedIndex, 1); |
| var targetIndex = this._findInsertionPos(key, index, value); |
| this._sortedKeys.splice(sortedIndex, 0, key); |
| if (sortedIndex === targetIndex) { |
| this._notifyItemMutated(key, value, item); |
| return; |
| } |
| this._listItemRemoved({ detail: { key: key, index: index, value: value, item: item } }); |
| this._listItemInserted({ detail: { key: key, index: index, value: value } }); |
| }, |
| _listItemRemoved: function (event, knownMin) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var item = event.detail.item; |
| var sortedKeys = this._sortedKeys; |
| var sortedIndex = sortedKeys.indexOf(key, knownMin); |
| sortedKeys.splice(sortedIndex, 1); |
| this._notifyItemRemoved(key, sortedIndex, value, item); |
| }, |
| _listReload: function () { |
| this._initSortedKeys(); |
| this._notifyReload(); |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.Binding.SortedListProjection.length" helpKeyword="WinJS.Binding.SortedListProjection.length">Gets or sets the length of the list. Returns an integer value one higher than the highest element defined in a list.</field> |
| length: { |
| get: function () { return this._sortedKeys.length; }, |
| set: function (value) { |
| if (typeof value === "number" && value >= 0) { |
| var current = this.length; |
| if (current > value) { |
| this.splice(value, current - value); |
| } |
| } else { |
| throw new _ErrorFromName("WinJS.Binding.List.IllegalLength", strings.illegalListLength); |
| } |
| } |
| }, |
| |
| getItem: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.SortedListProjection.getItem"> |
| /// <summary locid="WinJS.Binding.SortedListProjection.getItem"> |
| /// Returns a key/data pair for the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.SortedListProjection.getItem_p:index">The index of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.SortedListProjection.getItem_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| index = asNumber(index); |
| return this.getItemFromKey(this._sortedKeys[index]); |
| }, |
| |
| indexOfKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.SortedListProjection.getItem"> |
| /// <summary locid="WinJS.Binding.SortedListProjection.getItem"> |
| /// Returns the index of the first occurrence of a key. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.SortedListProjection.indexOfKey_p:key">The key to locate in the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.SortedListProjection.indexOfKey_returnValue">The index of the first occurrence of a key in a list, or -1 if not found.</returns> |
| /// </signature> |
| return this._sortedKeys.indexOf(key); |
| }, |
| |
| notifyMutated: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.SortedListProjection.notifyMutated"> |
| /// <summary locid="WinJS.Binding.SortedListProjection.notifyMutated"> |
| /// Forces the list to send a itemmutated notification to any listeners for the value at the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.SortedListProjection.notifyMutated_p:index">The index of the value that was mutated.</param> |
| /// </signature> |
| index = asNumber(index); |
| this._notifyMutatedFromKey(this._sortedKeys[index]); |
| }, |
| |
| setAt: function (index, value) { |
| /// <signature helpKeyword="WinJS.Binding.SortedListProjection.setAt"> |
| /// <summary locid="WinJS.Binding.SortedListProjection.setAt"> |
| /// Replaces the value at the specified index with a new value. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.SortedListProjection.setAt_p:index">The index of the value that was replaced.</param> |
| /// <param name="newValue" type="Object" locid="WinJS.Binding.SortedListProjection.setAt_p:newValue">The new value.</param> |
| /// </signature> |
| index = asNumber(index); |
| this._setAtKey(this._sortedKeys[index], value); |
| }, |
| |
| // returns [ data* ] of removed items |
| _spliceFromKey: function (key, howMany) { |
| // first add in all the new items if we have any, this should serve to push key to the right |
| if (arguments.length > 2) { |
| var args = copyargs(arguments); |
| args[1] = 0; // howMany |
| this._list._spliceFromKey.apply(this._list, args); |
| } |
| // now we can remove anything that needs to be removed, since they are not necessarially contiguous |
| // in the underlying list we remove them one by one. |
| var result = []; |
| if (howMany) { |
| var keysToRemove = []; |
| var sortedKeys = this._sortedKeys; |
| var sortedKeyIndex = sortedKeys.indexOf(key); |
| for (var i = sortedKeyIndex, len = sortedKeys.length; i < len && (i - sortedKeyIndex) < howMany; i++) { |
| keysToRemove.push(sortedKeys[i]); |
| } |
| var that = this; |
| keysToRemove.forEach(function (key) { |
| result.push(that._list._spliceFromKey(key, 1)[0]); |
| }); |
| } |
| return result; |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| // This projection sorts the underlying list by group key and within a group |
| // respects the position of the item in the underlying list. It is built on top |
| // of the SortedListProjection and has an intimate contract with |
| // GroupsListProjection. |
| // |
| GroupedSortedListProjection: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.SortedListProjection, function (list, groupKeyOf, groupDataOf, groupSorter) { |
| this._list = list; |
| this._addListListener("itemchanged", this._listGroupedItemChanged); |
| this._addListListener("iteminserted", this._listGroupedItemInserted); |
| this._addListListener("itemmoved", this._listGroupedItemMoved); |
| this._addListListener("itemmutated", this._listGroupedItemMutated); |
| this._addListListener("itemremoved", this._listGroupedItemRemoved); |
| this._addListListener("reload", this._listReload); |
| this._sortFunction = function (l, r) { |
| l = groupKeyOf(l); |
| r = groupKeyOf(r); |
| if (groupSorter) { |
| return groupSorter(l, r); |
| } else { |
| return l < r ? -1 : l === r ? 0 : 1; |
| } |
| }; |
| this._groupKeyOf = groupKeyOf; |
| this._groupDataOf = groupDataOf; |
| this._initSortedKeys(); |
| this._initGroupedItems(); |
| }, { |
| _groupKeyOf: null, |
| _groupDataOf: null, |
| |
| _groupedItems: null, |
| _initGroupedItems: function () { |
| var groupedItems = {}; |
| var list = this._list; |
| var groupKeyOf = this._groupKeyOf; |
| for (var i = 0, len = list.length; i < len; i++) { |
| var item = cloneItem(list.getItem(i)); |
| item.groupKey = groupKeyOf(item.data); |
| groupedItems[item.key] = item; |
| } |
| this._groupedItems = groupedItems; |
| }, |
| |
| _groupsProjection: null, |
| |
| _listGroupedItemChanged: function (event) { |
| var key = event.detail.key; |
| var oldValue = event.detail.oldValue; |
| var newValue = event.detail.newValue; |
| var groupedItems = this._groupedItems; |
| var oldGroupedItem = groupedItems[key]; |
| var newGroupedItem = cloneItem(oldGroupedItem); |
| newGroupedItem.data = newValue; |
| newGroupedItem.groupKey = this._groupKeyOf(newValue); |
| groupedItems[key] = newGroupedItem; |
| var index; |
| if (oldGroupedItem.groupKey === newGroupedItem.groupKey) { |
| index = this.indexOfKey(key); |
| this._notifyItemChanged(key, index, oldValue, newValue, oldGroupedItem, newGroupedItem); |
| } else { |
| index = event.detail.index; |
| this._listItemChanged({ detail: { key: key, index: index, oldValue: oldValue, newValue: newValue, oldItem: oldGroupedItem, newItem: newGroupedItem } }); |
| } |
| }, |
| _listGroupedItemInserted: function (event) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var groupKey = this._groupKeyOf(value); |
| this._groupedItems[key] = { |
| handle: key, |
| key: key, |
| data: value, |
| groupKey: groupKey |
| }; |
| var groupMin, groupMax; |
| if (this._groupsProjection) { |
| var groupItem = this._groupsProjection._groupItems[groupKey]; |
| if (groupItem) { |
| groupMin = groupItem.firstItemIndexHint; |
| groupMax = groupMin + groupItem.groupSize; |
| } |
| } |
| this._listItemInserted(event, groupMin, groupMax); |
| }, |
| _listGroupedItemMoved: function (event) { |
| var groupMin, groupMax; |
| var groupKey = this._groupedItems[event.detail.key].groupKey; |
| if (this._groupsProjection) { |
| var groupItem = this._groupsProjection._groupItems[groupKey]; |
| groupMin = groupItem.firstItemIndexHint; |
| groupMax = groupMin + groupItem.groupSize; |
| } |
| this._listItemMoved(event, groupMin, groupMax); |
| }, |
| _listGroupedItemMutated: function (event) { |
| var key = event.detail.key; |
| var value = event.detail.value; |
| var groupedItems = this._groupedItems; |
| var oldGroupedItem = groupedItems[key]; |
| var groupKey = this._groupKeyOf(value); |
| if (oldGroupedItem.groupKey === groupKey) { |
| this._notifyItemMutated(key, value, oldGroupedItem); |
| } else { |
| var newGroupedItem = cloneItem(oldGroupedItem); |
| newGroupedItem.groupKey = groupKey; |
| groupedItems[key] = newGroupedItem; |
| var index = this._list.indexOfKey(key); |
| this._listItemRemoved({ detail: { key: key, index: index, value: value, item: oldGroupedItem } }); |
| this._listItemInserted({ detail: { key: key, index: index, value: value } }); |
| } |
| }, |
| _listGroupedItemRemoved: function (event) { |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var value = event.detail.value; |
| var groupedItems = this._groupedItems; |
| var groupedItem = groupedItems[key]; |
| delete groupedItems[key]; |
| var groupMin, groupMax; |
| if (this._groupsProjection) { |
| var groupItem = this._groupsProjection._groupItems[groupedItem.groupKey]; |
| groupMin = groupItem.firstItemIndexHint; |
| groupMax = groupMin + groupItem.groupSize; |
| } |
| this._listItemRemoved({ detail: { key: key, index: index, value: value, item: groupedItem } }, groupMin, groupMax); |
| }, |
| |
| // override _listReload |
| _listReload: function () { |
| this._initGroupedItems(); |
| ns.SortedListProjection.prototype._listReload.call(this); |
| }, |
| |
| /// <field type="WinJS.Binding.List" locid="WinJS.Binding.GroupedSortedListProjection.groups" helpKeyword="WinJS.Binding.GroupedSortedListProjection.groups">Gets a WinJS.Binding.List, which is a projection of the groups that were identified in this list.</field> |
| groups: { |
| get: function () { |
| if (this._groupsProjection === null) { |
| this._groupsProjection = new ns.GroupsListProjection(this, this._groupKeyOf, this._groupDataOf); |
| } |
| return this._groupsProjection; |
| } |
| }, |
| |
| // We have to implement this because we keep our own set of items so that we can |
| // tag them with groupKey. |
| // |
| getItemFromKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.GroupedSortedListProjection.getItemFromKey"> |
| /// <summary locid="WinJS.Binding.GroupedSortedListProjection.getItemFromKey"> |
| /// Gets a key/data pair for the specified item key. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.GroupedSortedListProjection.getItemFromKey_p:key">The key of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.GroupedSortedListProjection.getItemFromKey_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| return this._groupedItems[key]; |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| |
| // This is really an implementation detail of GroupedSortedListProjection and takes a |
| // dependency on its internals and implementation details. |
| // |
| GroupsListProjection: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListBase, function (list, groupKeyOf, groupDataOf) { |
| this._list = list; |
| this._addListListener("itemchanged", this._listItemChanged); |
| this._addListListener("iteminserted", this._listItemInserted); |
| this._addListListener("itemmoved", this._listItemMoved); |
| // itemmutated is handled by the GroupedSortedListProjection because if the item |
| // changes groups it turns into a remove/insert. |
| this._addListListener("itemremoved", this._listItemRemoved); |
| this._addListListener("reload", this._listReload); |
| this._groupKeyOf = groupKeyOf; |
| this._groupDataOf = groupDataOf; |
| this._initGroupKeysAndItems(); |
| }, { |
| _list: null, |
| |
| _addListListener: function (name, func) { |
| // interestingly, since GroupsListProjection has the same lifetime as the GroupedSortedListProjection |
| // we don't have to worry about cleaning up the cycle here. |
| this._list.addEventListener(name, func.bind(this)); |
| }, |
| |
| _groupDataOf: null, |
| _groupKeyOf: null, |
| _groupOf: function (item) { |
| return this.getItemFromKey(this._groupKeyOf(item.data)); |
| }, |
| |
| _groupKeys: null, |
| _groupItems: null, |
| _initGroupKeysAndItems: function () { |
| var groupDataOf = this._groupDataOf; |
| var list = this._list; |
| var groupItems = {}; |
| var groupKeys = []; |
| var currentGroupKey = null; |
| var currentGroupItem = null; |
| var groupCount; |
| for (var i = 0, len = list.length; i < len; i++) { |
| var item = list.getItem(i); |
| var groupKey = item.groupKey; |
| if (groupKey !== currentGroupKey) { |
| // new group |
| if (currentGroupItem) { |
| currentGroupItem.groupSize = groupCount; |
| } |
| groupCount = 1; |
| currentGroupKey = groupKey; |
| currentGroupItem = { |
| handle: groupKey, |
| key: groupKey, |
| data: groupDataOf(item.data), |
| firstItemKey: item.key, |
| firstItemIndexHint: i |
| }; |
| groupItems[groupKey] = currentGroupItem; |
| groupKeys.push(groupKey); |
| } else { |
| // existing group |
| groupCount++; |
| } |
| } |
| if (currentGroupItem) { |
| currentGroupItem.groupSize = groupCount; |
| } |
| this._groupKeys = groupKeys; |
| this._groupItems = groupItems; |
| }, |
| |
| _listItemChanged: function (event) { |
| // itemchanged is only interesting if the item that changed is the first item |
| // of a group at which point we need to regenerate the group item. |
| // |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var newValue = event.detail.newValue; |
| var list = this._list; |
| var groupKey = list.getItemFromKey(key).groupKey; |
| var groupItems = this._groupItems; |
| var groupItem = groupItems[groupKey]; |
| if (groupItem.firstItemIndexHint === index) { |
| var newGroupItem = cloneItem(groupItem); |
| newGroupItem.data = this._groupDataOf(newValue); |
| newGroupItem.firstItemKey = key; |
| groupItems[groupKey] = newGroupItem; |
| this._notifyItemChanged(groupKey, this._groupKeys.indexOf(groupKey), groupItem.data, newGroupItem.data, groupItem, newGroupItem); |
| } |
| }, |
| _listItemInserted: function (event) { |
| // iteminserted is only interesting if this is a new group, or is the first |
| // item of the group at which point the group data is regenerated. It will |
| // however always result in a +1 to all the following firstItemIndexHints |
| // |
| var key = event.detail.key; |
| var index = event.detail.index; |
| var value = event.detail.value; |
| var list = this._list; |
| var groupKey = list.getItemFromKey(key).groupKey; |
| var groupItems = this._groupItems; |
| var groupKeys = this._groupKeys; |
| var groupItem = groupItems[groupKey]; |
| var groupIndex; |
| var oldGroupItem, newGroupItem; |
| |
| var i, len; |
| if (!groupItem) { |
| // we have a new group, add it |
| for (i = 0, len = groupKeys.length; i < len; i++) { |
| groupItem = groupItems[groupKeys[i]]; |
| if (groupItem.firstItemIndexHint >= index) { |
| break; |
| } |
| } |
| groupIndex = i; |
| groupItem = { |
| handle: groupKey, |
| key: groupKey, |
| data: this._groupDataOf(value), |
| groupSize: 1, |
| firstItemKey: key, |
| firstItemIndexHint: index |
| }; |
| groupKeys.splice(groupIndex, 0, groupKey); |
| groupItems[groupKey] = groupItem; |
| this._notifyItemInserted(groupKey, groupIndex, groupItem.data); |
| } else { |
| oldGroupItem = groupItem; |
| newGroupItem = cloneItem(oldGroupItem); |
| newGroupItem.groupSize++; |
| if (oldGroupItem.firstItemIndexHint === index) { |
| newGroupItem.groupData = this._groupDataOf(value); |
| newGroupItem.firstItemKey = key; |
| newGroupItem.firstItemIndexHint = index; |
| } |
| groupItems[groupKey] = newGroupItem; |
| groupIndex = groupKeys.indexOf(groupKey); |
| this._notifyItemChanged(groupKey, groupIndex, oldGroupItem.data, newGroupItem.data, oldGroupItem, newGroupItem); |
| } |
| // update the firstItemIndexHint on following groups |
| for (i = groupIndex + 1, len = groupKeys.length; i < len; i++) { |
| oldGroupItem = groupItems[groupKeys[i]]; |
| newGroupItem = cloneItem(oldGroupItem); |
| newGroupItem.firstItemIndexHint++; |
| groupItems[newGroupItem.key] = newGroupItem; |
| this._notifyItemChanged(newGroupItem.key, i, oldGroupItem.data, newGroupItem.data, oldGroupItem, newGroupItem); |
| } |
| }, |
| _listItemMoved: function (event) { |
| // itemmoved is not important to grouping unless the move resulted in a new |
| // first item in the group at which point we will regenerate the group data |
| // |
| var key = event.detail.key; |
| var oldIndex = event.detail.oldIndex; |
| var newIndex = event.detail.newIndex; |
| var list = this._list; |
| var groupKey = list.getItemFromKey(key).groupKey; |
| var groupItems = this._groupItems; |
| var groupItem = groupItems[groupKey]; |
| if (groupItem.firstItemIndexHint === newIndex || |
| groupItem.firstItemIndexHint === oldIndex) { |
| // the first item of the group has changed, update it. |
| var item = list.getItem(groupItem.firstItemIndexHint); |
| var newGroupItem = cloneItem(groupItem); |
| newGroupItem.data = this._groupDataOf(item.data); |
| newGroupItem.firstItemKey = item.key; |
| groupItems[groupKey] = newGroupItem; |
| this._notifyItemChanged(groupKey, this._groupKeys.indexOf(groupKey), groupItem.data, newGroupItem.data, groupItem, newGroupItem); |
| } |
| }, |
| _listItemRemoved: function (event) { |
| // itemremoved is only interesting if the group was of size 1 or was the |
| // first item of the group at which point the group data is regenerated. |
| // It will however always result in a -1 to all of the following |
| // firstItemIndexHints. |
| // |
| var index = event.detail.index; |
| var item = event.detail.item; |
| var groupItems = this._groupItems; |
| var groupKeys = this._groupKeys; |
| // since the value is no longer in the list we can't ask for its item and |
| // get the group key from there. |
| var groupKey = item.groupKey; |
| var groupItem = groupItems[groupKey]; |
| var groupIndex = groupKeys.indexOf(groupKey); |
| var oldGroupItem, newGroupItem; |
| |
| if (groupItem.groupSize === 1) { |
| groupKeys.splice(groupIndex, 1); |
| delete groupItems[groupKey]; |
| this._notifyItemRemoved(groupKey, groupIndex, groupItem.data, groupItem); |
| // after removing the group we need to decrement the index because it is used |
| // for modifying subsequent group firstItemIndexHint's |
| groupIndex--; |
| } else { |
| oldGroupItem = groupItem; |
| newGroupItem = cloneItem(oldGroupItem); |
| newGroupItem.groupSize--; |
| if (oldGroupItem.firstItemIndexHint === index) { |
| // find the next group item, it will be at the same index as the old |
| // first group item. |
| var newFirstItem = this._list.getItem(index); |
| newGroupItem.data = this._groupDataOf(newFirstItem.data); |
| newGroupItem.firstItemKey = newFirstItem.key; |
| } |
| groupItems[groupKey] = newGroupItem; |
| this._notifyItemChanged(groupKey, groupIndex, oldGroupItem.data, newGroupItem.data, oldGroupItem, newGroupItem); |
| } |
| for (var i = groupIndex + 1, len = groupKeys.length; i < len; i++) { |
| oldGroupItem = groupItems[groupKeys[i]]; |
| newGroupItem = cloneItem(oldGroupItem); |
| newGroupItem.firstItemIndexHint--; |
| groupItems[newGroupItem.key] = newGroupItem; |
| this._notifyItemChanged(newGroupItem.key, i, oldGroupItem.data, newGroupItem.data, oldGroupItem, newGroupItem); |
| } |
| }, |
| _listReload: function () { |
| this._initGroupKeysAndItems(); |
| this._notifyReload(); |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.Binding.GroupsListProjection.length" helpKeyword="WinJS.Binding.GroupsListProjection.length">Gets the length of the list. Returns an integer value one higher than the highest element defined in a list.</field> |
| length: { |
| get: function () { return this._groupKeys.length; } |
| }, |
| |
| getItem: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.GroupsListProjection.getItem"> |
| /// <summary locid="WinJS.Binding.GroupsListProjection.getItem"> |
| /// Gets a key/data pair for the specified index . |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.GroupsListProjection.getItem_p:index">The index of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.GroupsListProjection.getItem_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| index = asNumber(index); |
| return this._groupItems[this._groupKeys[index]]; |
| }, |
| getItemFromKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.GroupsListProjection.getItemFromKey"> |
| /// <summary locid="WinJS.Binding.GroupsListProjection.getItemFromKey"> |
| /// Gets a key/data pair for the specified key. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.GroupsListProjection.getItemFromKey_p:key">The key of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.GroupsListProjection.getItemFromKey_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| return this._groupItems[key]; |
| }, |
| |
| indexOfKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.GroupsListProjection.indexOfKey"> |
| /// <summary locid="WinJS.Binding.GroupsListProjection.indexOfKey"> |
| /// Returns the index of the first occurrence of a key in a list. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.GroupsListProjection.indexOfKey_p:key">The key to locate in the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.GroupsListProjection.indexOfKey_returnValue">The index of the first occurrence of a key in a list, or -1 if not found.</returns> |
| /// </signature> |
| return this._groupKeys.indexOf(key); |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }), |
| }); |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Binding", { |
| List: _Base.Namespace._lazy(function () { |
| return _Base.Class.derive(ns.ListBaseWithMutators, function (list, options) { |
| /// <signature helpKeyword="WinJS.Binding.List.List"> |
| /// <summary locid="WinJS.Binding.List.constructor"> |
| /// Creates a WinJS.Binding.List object. |
| /// </summary> |
| /// <param name="list" type="Array" optional="true" locid="WinJS.Binding.List.constructor_p:list">The array containing the elements to initalize the list.</param> |
| /// <param name="options" type="Object" optional="true" locid="WinJS.Binding.List.constructor_p:options">If options.binding is true, the list will contain the result of calling WinJS.Binding.as() on the element values. If options.proxy is true, the list specified as the first parameter is used as the storage for the WinJS.Binding.List. This option should be used with care because uncoordinated edits to the data storage will result in errors.</param> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.List.constructor_returnValue">The newly-constructed WinJS.Binding.List instance.</returns> |
| /// </signature> |
| |
| this._currentKey = 0; |
| this._keys = null; |
| this._keyMap = {}; |
| |
| // options: |
| // - binding: binding.as on items |
| // - proxy: proxy over input data |
| // |
| options = options || emptyOptions; |
| this._proxy = options.proxy; |
| this._binding = options.binding; |
| if (this._proxy) { |
| if (Object.keys(list).length !== list.length) { |
| throw new _ErrorFromName("WinJS.Binding.List.NotSupported", strings.sparseArrayNotSupported); |
| } |
| this._data = list; |
| this._currentKey = list.length; |
| } else if (list) { |
| var keyDataMap = this._keyMap; |
| var pos = 0, i = 0; |
| for (var len = list.length; i < len; i++) { |
| if (i in list) { |
| var item = list[i]; |
| if (this._binding) { |
| item = _Data.as(item); |
| } |
| var key = pos.toString(); |
| pos++; |
| keyDataMap[key] = { handle: key, key: key, data: item }; |
| } |
| } |
| if (pos !== i) { |
| this._initializeKeys(); |
| } |
| this._currentKey = pos; |
| } |
| }, { |
| _currentKey: 0, |
| |
| _keys: null, |
| _keyMap: null, |
| |
| _modifyingData: 0, |
| |
| _initializeKeys: function () { |
| if (this._keys) { |
| return; |
| } |
| |
| var keys = []; |
| if (this._data) { |
| // If this list is a proxy over the data then we will have been lazily initializing |
| // the entries in the list, however the 1:1 mapping between index and key is about |
| // to go away so this is our last chance to pull the items out of the data. |
| // |
| var keyMap = this._keyMap; |
| var data = this._data; |
| for (var i = 0, len = data.length; i < len; i++) { |
| if (i in data) { |
| var key = i.toString(); |
| keys[i] = key; |
| if (!(key in keyMap)) { |
| var item = data[i]; |
| if (this._binding) { |
| item = _Data.as(item); |
| } |
| keyMap[key] = { handle: key, key: key, data: item }; |
| } |
| } |
| } |
| } else { |
| // In the case where List owns the data we will have created the keyMap at initialization |
| // time and can use that to harvest all the keys into the _keys list. |
| // |
| Object.keys(this._keyMap).forEach(function (key) { |
| keys[key >>> 0] = key; |
| }); |
| } |
| this._keys = keys; |
| }, |
| _lazyPopulateEntry: function (index) { |
| if (this._data && index in this._data) { |
| var item = this._data[index]; |
| if (this._binding) { |
| item = _Data.as(item); |
| } |
| var key = index.toString(); |
| var entry = { handle: key, key: key, data: item }; |
| this._keyMap[entry.key] = entry; |
| return entry; |
| } |
| }, |
| |
| _assignKey: function () { |
| return (++this._currentKey).toString(); |
| }, |
| |
| /// <field type="Number" integer="true" locid="WinJS.Binding.List.length" helpKeyword="WinJS.Binding.List.length">Gets or sets the length of the list, which is an integer value one higher than the highest element defined in the list.</field> |
| length: { |
| get: function () { |
| // If we are proxying use the underlying list's length |
| // If we have already allocated keys use that length |
| // If we haven't allocated keys then we can use _currentKey which was set at initialization time |
| // to be length of the input list. |
| if (this._data) { |
| return this._data.length; |
| } else if (this._keys) { |
| return this._keys.length; |
| } else { |
| return this._currentKey; |
| } |
| }, |
| set: function (value) { |
| if (typeof value === "number" && value >= 0) { |
| this._initializeKeys(); |
| var current = this.length; |
| if (current > value) { |
| this.splice(value, current - value); |
| } else { |
| // We don't support setting lengths to longer in order to have sparse behavior |
| value = current; |
| } |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.length = value; |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| if (this._keys) { |
| this._keys.length = value; |
| } |
| } else { |
| throw new _ErrorFromName("WinJS.Binding.List.IllegalLength", strings.illegalListLength); |
| } |
| } |
| }, |
| |
| getItem: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.List.getItem"> |
| /// <summary locid="WinJS.Binding.List.getItem"> |
| /// Gets a key/data pair for the specified list index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.List.getItem_p:index">The index of value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.List.getItem_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| var entry; |
| var key; |
| index = asNumber(index); |
| if (this._keys) { |
| key = this._keys[index]; |
| entry = key && this._keyMap[key]; |
| } else { |
| key = index.toString(); |
| entry = this._keyMap[key] || this._lazyPopulateEntry(index); |
| } |
| return entry; |
| }, |
| getItemFromKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.List.getItemFromKey"> |
| /// <summary locid="WinJS.Binding.List.getItemFromKey"> |
| /// Gets a key/data pair for the list item key specified. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.List.getItemFromKey_p:key">The key of the value to retrieve.</param> |
| /// <returns type="Object" locid="WinJS.Binding.List.getItemFromKey_returnValue">An object with .key and .data properties.</returns> |
| /// </signature> |
| var entry; |
| // if we have a keys list we know to go through the keyMap, or if we are not |
| // proxying through _data we also know to go through the keyMap. |
| if (this._keys || !this._data) { |
| entry = this._keyMap[key]; |
| } else { |
| entry = this.getItem(key >>> 0); |
| } |
| return entry; |
| }, |
| |
| indexOfKey: function (key) { |
| /// <signature helpKeyword="WinJS.Binding.List.indexOfKey"> |
| /// <summary locid="WinJS.Binding.List.indexOfKey"> |
| /// Gets the index of the first occurrence of a key in a list. |
| /// </summary> |
| /// <param name="key" type="String" locid="WinJS.Binding.List.indexOfKey_p:key">The key to locate in the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.List.indexOfKey_returnValue">The index of the first occurrence of a key in a list, or -1 if not found.</returns> |
| /// </signature> |
| var index = -1; |
| if (this._keys) { |
| index = this._keys.indexOf(key); |
| } else { |
| var t = key >>> 0; |
| if (t < this._currentKey) { |
| index = t; |
| } |
| } |
| return index; |
| }, |
| |
| move: function (index, newIndex) { |
| /// <signature helpKeyword="WinJS.Binding.List.move"> |
| /// <summary locid="WinJS.Binding.List.move"> |
| /// Moves the value at index to the specified position. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.List.move_p:index">The original index of the value.</param> |
| /// <param name="newIndex" type="Number" integer="true" locid="WinJS.Binding.List.move_p:newIndex">The index of the value after the move.</param> |
| /// </signature> |
| index = asNumber(index); |
| newIndex = asNumber(newIndex); |
| this._initializeKeys(); |
| if (index === newIndex || index < 0 || newIndex < 0 || index >= this.length || newIndex >= this.length) { |
| return; |
| } |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| var item = this._data.splice(index, 1)[0]; |
| this._data.splice(newIndex, 0, item); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| var key = this._keys.splice(index, 1)[0]; |
| this._keys.splice(newIndex, 0, key); |
| this._notifyItemMoved(key, index, newIndex, this.getItemFromKey(key).data); |
| }, |
| |
| notifyMutated: function (index) { |
| /// <signature helpKeyword="WinJS.Binding.List.notifyMutated"> |
| /// <summary locid="WinJS.Binding.List.notifyMutated"> |
| /// Forces the list to send a itemmutated notification to any listeners for the value at the specified index. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.List.notifyMutated_p:index">The index of the value that was mutated.</param> |
| /// </signature> |
| index = asNumber(index); |
| var key = this._keys ? this._keys[index] : index.toString(); |
| this._notifyMutatedFromKey(key); |
| }, |
| |
| setAt: function (index, newValue) { |
| /// <signature helpKeyword="WinJS.Binding.List.setAt"> |
| /// <summary locid="WinJS.Binding.List.setAt"> |
| /// Replaces the value at the specified index with a new value. |
| /// </summary> |
| /// <param name="index" type="Number" integer="true" locid="WinJS.Binding.List.setAt_p:index">The index of the value that was replaced.</param> |
| /// <param name="newValue" type="Object" locid="WinJS.Binding.List.setAt_p:newValue">The new value.</param> |
| /// </signature> |
| index = asNumber(index); |
| this._initializeKeys(); |
| var length = this.length; |
| if (index === length) { |
| this.push(newValue); |
| } else if (index < length) { |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data[index] = newValue; |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| if (this._binding) { |
| newValue = _Data.as(newValue); |
| } |
| if (index in this._keys) { |
| var key = this._keys[index]; |
| var oldEntry = this._keyMap[key]; |
| var newEntry = cloneItem(oldEntry); |
| newEntry.data = newValue; |
| this._keyMap[key] = newEntry; |
| this._notifyItemChanged(key, index, oldEntry.data, newValue, oldEntry, newEntry); |
| } |
| } |
| }, |
| |
| _setAtKey: function (key, newValue) { |
| this.setAt(this.indexOfKey(key), newValue); |
| }, |
| |
| // These are the traditional Array mutators, they don't result in projections. In particular |
| // having both sort and sorted is a bit confusing. It may be the case that we want to eliminate |
| // the various array helpers outside of the standard push/pop,shift/unshift,splice,get*,setAt |
| // and then offer up the specific projections: filter, sorted, grouped. Anything else can be |
| // obtained through _getArray(). |
| // |
| reverse: function () { |
| /// <signature helpKeyword="WinJS.Binding.List.reverse"> |
| /// <summary locid="WinJS.Binding.List.reverse"> |
| /// Returns a list with the elements reversed. This method reverses the elements of a list object in place. It does not create a new list object during execution. |
| /// </summary> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.List.reverse_returnValue">The reversed list.</returns> |
| /// </signature> |
| this._initializeKeys(); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.reverse(); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| this._keys.reverse(); |
| this._notifyReload(); |
| return this; |
| }, |
| sort: function (sortFunction) { |
| /// <signature helpKeyword="WinJS.Binding.List.sort"> |
| /// <summary locid="WinJS.Binding.List.sort"> |
| /// Returns a list with the elements sorted. This method sorts the elements of a list object in place. It does not create a new list object during execution. |
| /// </summary> |
| /// <param name="sortFunction" type="Function" locid="WinJS.Binding.List.sort_p:sortFunction">The function used to determine the order of the elements. If omitted, the elements are sorted in ascending, ASCII character order.</param> |
| /// <returns type="WinJS.Binding.List" locid="WinJS.Binding.List.sort_returnValue">The sorted list.</returns> |
| /// </signature> |
| this._initializeKeys(); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.sort(sortFunction); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| var that = this; |
| this._keys.sort(function (l, r) { |
| l = that._keyMap[l]; |
| r = that._keyMap[r]; |
| if (sortFunction) { |
| return sortFunction(l.data, r.data); |
| } |
| l = (l && l.data || "").toString(); |
| r = (l && r.data || "").toString(); |
| return l < r ? -1 : l === r ? 0 : 1; |
| }); |
| this._notifyReload(); |
| return this; |
| }, |
| |
| pop: function () { |
| /// <signature helpKeyword="WinJS.Binding.List.pop"> |
| /// <summary locid="WinJS.Binding.List.pop"> |
| /// Removes the last element from a list and returns it. |
| /// </summary> |
| /// <returns type="Object" locid="WinJS.Binding.List.pop_returnValue">Last element from the list.</returns> |
| /// </signature> |
| if (this.length === 0) { |
| return; |
| } |
| this._initializeKeys(); |
| var key = this._keys.pop(); |
| var entry = this._keyMap[key]; |
| var data = entry && entry.data; |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.pop(); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| delete this._keyMap[key]; |
| this._notifyItemRemoved(key, this._keys.length, data, entry); |
| return data; |
| }, |
| |
| push: function () { |
| /// <signature helpKeyword="WinJS.Binding.List.push"> |
| /// <summary locid="WinJS.Binding.List.push"> |
| /// Appends new element(s) to a list, and returns the new length of the list. |
| /// </summary> |
| /// <param name="value" type="Object" parameterArray="true" locid="WinJS.Binding.List.push_p:value">The element to insert at the end of the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.List.push_returnValue">The new length of the list.</returns> |
| /// </signature> |
| this._initializeKeys(); |
| var length = arguments.length; |
| for (var i = 0; i < length; i++) { |
| var item = arguments[i]; |
| if (this._binding) { |
| item = _Data.as(item); |
| } |
| var key = this._assignKey(); |
| this._keys.push(key); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.push(arguments[i]); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| this._keyMap[key] = { handle: key, key: key, data: item }; |
| this._notifyItemInserted(key, this._keys.length - 1, item); |
| } |
| return this.length; |
| }, |
| |
| shift: function () { |
| /// <signature helpKeyword="WinJS.Binding.List.shift"> |
| /// <summary locid="WinJS.Binding.List.shift"> |
| /// Removes the first element from a list and returns it. |
| /// </summary> |
| /// <returns type="Object" locid="WinJS.Binding.List.shift_returnValue">First element from the list.</returns> |
| /// </signature> |
| if (this.length === 0) { |
| return; |
| } |
| |
| this._initializeKeys(); |
| var key = this._keys.shift(); |
| var entry = this._keyMap[key]; |
| var data = entry && entry.data; |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.shift(); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| delete this._keyMap[key]; |
| this._notifyItemRemoved(key, 0, data, entry); |
| return data; |
| }, |
| |
| unshift: function () { |
| /// <signature helpKeyword="WinJS.Binding.List.unshift"> |
| /// <summary locid="WinJS.Binding.List.unshift"> |
| /// Appends new element(s) to a list, and returns the new length of the list. |
| /// </summary> |
| /// <param name="value" type="Object" parameterArray="true" locid="WinJS.Binding.List.unshift_p:value">The element to insert at the start of the list.</param> |
| /// <returns type="Number" integer="true" locid="WinJS.Binding.List.unshift_returnValue">The new length of the list.</returns> |
| /// </signature> |
| this._initializeKeys(); |
| var length = arguments.length; |
| for (var i = length - 1; i >= 0; i--) { |
| var item = arguments[i]; |
| if (this._binding) { |
| item = _Data.as(item); |
| } |
| var key = this._assignKey(); |
| this._keys.unshift(key); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.unshift(arguments[i]); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| this._keyMap[key] = { handle: key, key: key, data: item }; |
| this._notifyItemInserted(key, 0, item); |
| } |
| return this.length; |
| }, |
| |
| splice: function (index, howMany, item) { |
| /// <signature helpKeyword="WinJS.Binding.List.splice"> |
| /// <summary locid="WinJS.Binding.List.splice"> |
| /// Removes elements from a list and, if necessary, inserts new elements in their place, returning the deleted elements. |
| /// </summary> |
| /// <param name="start" type="Number" integer="true" locid="WinJS.Binding.List.splice_p:start">The zero-based location in the list from which to start removing elements.</param> |
| /// <param name="howMany" type="Number" integer="true" locid="WinJS.Binding.List.splice_p:howMany">The number of elements to remove.</param> |
| /// <param name="item" type="Object" optional="true" parameterArray="true" locid="WinJS.Binding.List.splice_p:item">The elements to insert into the list in place of the deleted elements.</param> |
| /// <returns type="Array" locid="WinJS.Binding.List.splice_returnValue">The deleted elements.</returns> |
| /// </signature> |
| index = asNumber(index); |
| this._initializeKeys(); |
| index = Math.max(0, this._normalizeIndex(index)); |
| howMany = Math.max(0, Math.min(howMany || 0, this.length - index)); |
| var result = []; |
| while (howMany) { |
| var key = this._keys[index]; |
| var entry = this._keyMap[key]; |
| var data = entry && entry.data; |
| result.push(data); |
| this._keys.splice(index, 1); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.splice(index, 1); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| delete this._keyMap[key]; |
| this._notifyItemRemoved(key, index, data, entry); |
| --howMany; |
| } |
| if (arguments.length > 2) { |
| for (var i = 2, len = arguments.length; i < len; i++) { |
| var additionalItem = arguments[i]; |
| if (this._binding) { |
| additionalItem = _Data.as(additionalItem); |
| } |
| var pos = Math.min(index + i - 2, this.length); |
| var newKey = this._assignKey(); |
| this._keys.splice(pos, 0, newKey); |
| if (this._data) { |
| this._modifyingData++; |
| try { |
| this._data.splice(pos, 0, arguments[i]); |
| } finally { |
| this._modifyingData--; |
| } |
| } |
| this._keyMap[newKey] = { handle: newKey, key: newKey, data: additionalItem }; |
| this._notifyItemInserted(newKey, pos, additionalItem); |
| } |
| } |
| return result; |
| }, |
| // returns [ data* ] of removed items |
| _spliceFromKey: function (key) { |
| this._initializeKeys(); |
| var args = copyargs(arguments); |
| args[0] = this._keys.indexOf(key); |
| return this.splice.apply(this, args); |
| } |
| }, { |
| supportedForProcessing: false, |
| }); |
| }) |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Res',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './Core/_ErrorFromName', |
| './Core/_Resources', |
| './ControlProcessor/_OptionsParser', |
| './Promise' |
| ], function resInit(exports, _Global, _Base, _BaseUtils, _ErrorFromName, _Resources, _OptionsParser, Promise) { |
| "use strict"; |
| |
| var readyComplete = false; |
| |
| var requireSupportedForProcessing = _BaseUtils.requireSupportedForProcessing; |
| |
| function processAllImpl(rootElement, count) { |
| rootElement = rootElement || _Global.document.body; |
| |
| var count = count || 0; |
| |
| if (count < 4) { |
| // Only 3 depth is supported in the innerHTML |
| if (count === 0) { |
| if (rootElement.getAttribute) { |
| // Fragment-loaded root element isn't caught by querySelectorAll |
| var rootElementNode = rootElement.getAttribute('data-win-res'); |
| if (rootElementNode) { |
| var decls = _OptionsParser.optionsParser(rootElementNode); |
| setMembers(rootElement, rootElement, decls, count); |
| } |
| } |
| } |
| |
| var selector = "[data-win-res],[data-win-control]"; |
| var elements = rootElement.querySelectorAll(selector); |
| if (elements.length === 0) { |
| return Promise.as(rootElement); |
| } |
| |
| for (var i = 0, len = elements.length; i < len; i++) { |
| var e = elements[i]; |
| |
| if (e.winControl && e.winControl.constructor && e.winControl.constructor.isDeclarativeControlContainer) { |
| var idcc = e.winControl.constructor.isDeclarativeControlContainer; |
| if (typeof idcc === "function") { |
| idcc = requireSupportedForProcessing(idcc); |
| idcc(e.winControl, processAll); |
| |
| // Skip all children of declarative control container |
| i += e.querySelectorAll(selector).length; |
| } |
| } |
| |
| if (!e.hasAttribute("data-win-res")) { |
| continue; |
| } |
| // Use optionsParser that accept string format |
| // {name="value", name2="value2"} |
| var decls = _OptionsParser.optionsParser(e.getAttribute('data-win-res')); |
| setMembers(e, e, decls, count); |
| } |
| |
| } else if (_BaseUtils.validation) { |
| throw new _ErrorFromName("WinJS.Res.NestingExceeded", "NestingExceeded"); |
| } |
| |
| return Promise.as(rootElement); |
| } |
| |
| function setAttributes(root, descriptor) { |
| var names = Object.keys(descriptor); |
| |
| for (var k = 0, l = names.length ; k < l; k++) { |
| var name = names[k]; |
| var value = descriptor[name]; |
| |
| var data = _Resources.getString(value); |
| |
| if (!data || !data.empty) { |
| root.setAttribute(name, data.value); |
| |
| if ((data.lang !== undefined) && |
| (root.lang !== undefined) && |
| (root.lang !== data.lang)) { |
| |
| root.lang = data.lang; |
| } |
| } else if (_BaseUtils.validation) { |
| notFound(value); |
| } |
| } |
| } |
| |
| function notFound(name) { |
| throw new _ErrorFromName("WinJS.Res.NotFound", _Resources._formatString("NotFound: {0}", name)); |
| } |
| |
| function setMembers(root, target, descriptor, count) { |
| var names = Object.keys(descriptor); |
| target = requireSupportedForProcessing(target); |
| |
| for (var k = 0, l = names.length ; k < l; k++) { |
| var name = names[k]; |
| var value = descriptor[name]; |
| |
| if (typeof value === "string") { |
| var data = _Resources.getString(value); |
| |
| if (!data || !data.empty) { |
| target[name] = data.value; |
| |
| if ((data.lang !== undefined) && |
| (root.lang !== undefined) && |
| (root.lang !== data.lang)) { |
| // When lang property is different, we set the language with selected string's language |
| root.lang = data.lang; |
| } |
| |
| if (name === "innerHTML") { |
| processAllImpl(target, count + 1); |
| } |
| } else if (_BaseUtils.validation) { |
| notFound(value); |
| } |
| } else if (root === target && name === "attributes") { |
| //Exposing setAttribute for attributes that don't have HTML properties, like aria, through a fake 'attributes' property |
| setAttributes(root, value); |
| } else { |
| setMembers(root, target[name], value, count); |
| } |
| } |
| } |
| |
| function processAll(rootElement) { |
| /// <signature helpKeyword="WinJS.Resources.processAll"> |
| /// <summary locid="WinJS.Resources.processAll"> |
| /// Processes resources tag and replaces strings |
| /// with localized strings. |
| /// </summary> |
| /// <param name="rootElement" locid="WinJS.Resources.processAll_p:rootElement"> |
| /// The DOM element at which to start processing. processAll processes the element and its child elements. |
| /// If you don't specify root element, processAll processes the entire document. |
| /// </param> |
| /// </signature> |
| |
| if (!readyComplete) { |
| return _BaseUtils.ready().then(function () { |
| readyComplete = true; |
| return processAllImpl(rootElement); |
| }); |
| } else { |
| try { |
| return processAllImpl(rootElement); |
| } |
| catch (e) { |
| return Promise.wrapError(e); |
| } |
| } |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.Resources", { |
| processAll: processAll |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Pages/_BasePage',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Core/_BaseUtils', |
| '../Core/_WriteProfilerMark', |
| '../Promise', |
| '../Utilities/_Control', |
| '../Utilities/_Dispose', |
| '../Utilities/_ElementUtilities' |
| ], function pagesInit(exports, _Global, _Base, _BaseUtils, _WriteProfilerMark, Promise, _Control, _Dispose, _ElementUtilities) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| function abs(uri) { |
| var a = _Global.document.createElement("a"); |
| a.href = uri; |
| return a.href; |
| } |
| var viewMap = {}; |
| |
| function selfhost(uri) { |
| return _Global.document.location.href.toLowerCase() === uri.toLowerCase(); |
| } |
| |
| var _mixin = { |
| dispose: function () { |
| /// <signature helpKeyword="WinJS.UI.Pages.dispose"> |
| /// <summary locid="WinJS.UI.Pages.dispose"> |
| /// Disposes this Page. |
| /// </summary> |
| /// </signature> |
| if (this._disposed) { |
| return; |
| } |
| |
| this._disposed = true; |
| _Dispose.disposeSubTree(this.element); |
| this.element = null; |
| }, |
| load: function (uri) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.load"> |
| /// <summary locid="WinJS.UI.Pages._mixin.load"> |
| /// Creates a copy of the DOM elements from the specified URI. In order for this override |
| /// to be used, the page that contains the load override needs to be defined by calling |
| /// WinJS.UI.Pages.define() before WinJS.UI.Pages.render() is called. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages._mixin.load_p:uri"> |
| /// The URI from which to copy the DOM elements. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.load_returnValue"> |
| /// A promise whose fulfilled value is the set of unparented DOM elements, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| }, |
| init: function (element, options) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.init"> |
| /// <summary locid="WinJS.UI.Pages._mixin.init"> |
| /// Initializes the control before the content of the control is set. |
| /// Use the processed method for any initialization that should be done after the content |
| /// of the control has been set. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.init_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.init_p:options"> |
| /// The options passed to the constructor of the page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.init_returnValue"> |
| /// A promise that is fulfilled when initialization is complete, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| }, |
| process: function (element, options) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.process"> |
| /// <summary locid="WinJS.UI.Pages._mixin.process"> |
| /// Processes the unparented DOM elements returned by load. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.process_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.process_p:options"> |
| /// The options that are to be passed to the constructor of the page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.process_returnValue"> |
| /// A promise that is fulfilled when processing is complete. |
| /// </returns> |
| /// </signature> |
| }, |
| processed: function (element, options) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.processed"> |
| /// <summary locid="WinJS.UI.Pages._mixin.processed"> |
| /// Initializes the control after the content of the control is set. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.processed_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.processed_p:options"> |
| /// The options that are to be passed to the constructor of the page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.processed_returnValue"> |
| /// A promise that is fulfilled when initialization is complete, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| }, |
| render: function (element, options, loadResult) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.render"> |
| /// <summary locid="WinJS.UI.Pages._mixin.render"> |
| /// Renders the control, typically by adding the elements specified in the loadResult parameter to the specified element. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.render_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.render_p:options"> |
| /// The options passed into the constructor of the page. |
| /// </param> |
| /// <param name="loadResult" locid="WinJS.UI.Pages._mixin.render_p:loadResult"> |
| /// The elements returned from the load method. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.render_returnValue"> |
| /// A promise that is fulfilled when rendering is complete, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| }, |
| ready: function (element, options) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.ready"> |
| /// <summary locid="WinJS.UI.Pages._mixin.ready"> |
| /// Called after all initialization and rendering is complete. At this |
| /// time the element is ready for use. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.ready_p:element"> |
| /// The DOM element that contains all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.ready_p:options"> |
| /// The options passed into the constructor of the page |
| /// </param> |
| /// </signature> |
| }, |
| error: function (err) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.error"> |
| /// <summary locid="WinJS.UI.Pages._mixin.error"> |
| /// Called if any error occurs during the processing of the page. |
| /// </summary> |
| /// <param name="err" locid="WinJS.UI.Pages._mixin.error_p:err"> |
| /// The error that occurred. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.error_returnValue"> |
| /// Nothing if the error was handled, or an error promise if the error was not handled. |
| /// </returns> |
| /// </signature> |
| return Promise.wrapError(err); |
| } |
| }; |
| |
| function Pages_define(uri, members) { |
| /// <signature helpKeyword="WinJS.UI.Pages.define"> |
| /// <summary locid="WinJS.UI.Pages.define"> |
| /// Creates a new page control from the specified URI that contains the specified members. |
| /// Multiple calls to this method for the same URI are allowed, and all members will be |
| /// merged. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages.define_p:uri"> |
| /// The URI for the content that defines the page. |
| /// </param> |
| /// <param name="members" locid="WinJS.UI.Pages.define_p:members"> |
| /// Additional members that the control will have. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.UI.Pages.define_returnValue"> |
| /// A constructor function that creates the page. |
| /// </returns> |
| /// </signature> |
| |
| var base = get(uri); |
| uri = abs(uri); |
| |
| if (!base) { |
| base = _Base.Class.define( |
| // This needs to follow the WinJS.UI.processAll "async constructor" |
| // pattern to interop nicely in the "Views.Control" use case. |
| // |
| function PageControl_ctor(element, options, complete, parentedPromise) { |
| var that = this; |
| this._disposed = false; |
| this.element = element = element || _Global.document.createElement("div"); |
| _ElementUtilities.addClass(element, "win-disposable"); |
| element.msSourceLocation = uri; |
| this.uri = uri; |
| this.selfhost = selfhost(uri); |
| element.winControl = this; |
| _ElementUtilities.addClass(element, "pagecontrol"); |
| |
| var profilerMarkIdentifier = " uri='" + uri + "'" + _BaseUtils._getProfilerMarkIdentifier(this.element); |
| |
| _WriteProfilerMark("WinJS.UI.Pages:createPage" + profilerMarkIdentifier + ",StartTM"); |
| |
| var load = Promise.wrap(). |
| then(function Pages_load() { return that.load(uri); }); |
| |
| var renderCalled = load.then(function Pages_init(loadResult) { |
| return Promise.join({ |
| loadResult: loadResult, |
| initResult: that.init(element, options) |
| }); |
| }).then(function Pages_render(result) { |
| return that.render(element, options, result.loadResult); |
| }); |
| |
| this.elementReady = renderCalled.then(function () { return element; }); |
| |
| this.renderComplete = renderCalled. |
| then(function Pages_process() { |
| return that.process(element, options); |
| }).then(function Pages_processed() { |
| return that.processed(element, options); |
| }).then(function () { |
| return that; |
| }); |
| |
| var callComplete = function () { |
| complete && complete(that); |
| _WriteProfilerMark("WinJS.UI.Pages:createPage" + profilerMarkIdentifier + ",StopTM"); |
| }; |
| |
| // promises guarantee order, so this will be called prior to ready path below |
| // |
| this.renderComplete.then(callComplete, callComplete); |
| |
| this.readyComplete = this.renderComplete.then(function () { |
| return parentedPromise; |
| }).then(function Pages_ready() { |
| that.ready(element, options); |
| return that; |
| }).then( |
| null, |
| function Pages_error(err) { |
| return that.error(err); |
| } |
| ); |
| }, |
| _mixin |
| ); |
| base = _Base.Class.mix(base, _Control.DOMEventMixin); |
| viewMap[uri.toLowerCase()] = base; |
| } |
| |
| // Lazily mix in the members, allowing for multiple definitions of "define" to augment |
| // the shared definition of the member. |
| // |
| if (members) { |
| base = _Base.Class.mix(base, members); |
| } |
| |
| base.selfhost = selfhost(uri); |
| |
| return base; |
| } |
| |
| function get(uri) { |
| uri = abs(uri); |
| return viewMap[uri.toLowerCase()]; |
| } |
| |
| function remove(uri) { |
| uri = abs(uri); |
| delete viewMap[uri.toLowerCase()]; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, null, { |
| abs: abs, |
| define: Pages_define, |
| get: get, |
| remove: remove, |
| viewMap: viewMap |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Pages',[ |
| 'exports', |
| './Core/_Global', |
| './Core/_Base', |
| './Core/_BaseUtils', |
| './ControlProcessor', |
| './Fragments', |
| './Pages/_BasePage', |
| './Promise', |
| ], function pagesInit(exports, _Global, _Base, _BaseUtils, ControlProcessor, Fragments, _BasePage, Promise) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| var _mixin = { |
| load: function (uri) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.load"> |
| /// <summary locid="WinJS.UI.Pages._mixin.load"> |
| /// Creates a copy of the DOM elements from the specified URI. In order for this override |
| /// to be used, the page that contains the load override needs to be defined by calling |
| /// WinJS.UI.Pages.define() before WinJS.UI.Pages.render() is called. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages._mixin.load_p:uri"> |
| /// The URI from which to copy the DOM elements. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.load_returnValue"> |
| /// A promise whose fulfilled value is the set of unparented DOM elements, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| if (!this.selfhost) { |
| return Fragments.renderCopy(_BasePage.abs(uri)); |
| } |
| }, |
| process: function (element, options) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.process"> |
| /// <summary locid="WinJS.UI.Pages._mixin.process"> |
| /// Processes the unparented DOM elements returned by load. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.process_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.process_p:options"> |
| /// The options that are to be passed to the constructor of the page. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.process_returnValue"> |
| /// A promise that is fulfilled when processing is complete. |
| /// </returns> |
| /// </signature> |
| return ControlProcessor.processAll(element); |
| }, |
| render: function (element, options, loadResult) { |
| /// <signature helpKeyword="WinJS.UI.Pages._mixin.render"> |
| /// <summary locid="WinJS.UI.Pages._mixin.render"> |
| /// Renders the control, typically by adding the elements specified in the loadResult parameter to the specified element. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.Pages._mixin.render_p:element"> |
| /// The DOM element that will contain all the content for the page. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.Pages._mixin.render_p:options"> |
| /// The options passed into the constructor of the page. |
| /// </param> |
| /// <param name="loadResult" locid="WinJS.UI.Pages._mixin.render_p:loadResult"> |
| /// The elements returned from the load method. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages._mixin.render_returnValue"> |
| /// A promise that is fulfilled when rendering is complete, if asynchronous processing is necessary. If not, returns nothing. |
| /// </returns> |
| /// </signature> |
| if (!this.selfhost) { |
| element.appendChild(loadResult); |
| } |
| return element; |
| } |
| }; |
| |
| function Pages_define(uri, members) { |
| /// <signature helpKeyword="WinJS.UI.Pages.define"> |
| /// <summary locid="WinJS.UI.Pages.define"> |
| /// Creates a new page control from the specified URI that contains the specified members. |
| /// Multiple calls to this method for the same URI are allowed, and all members will be |
| /// merged. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages.define_p:uri"> |
| /// The URI for the content that defines the page. |
| /// </param> |
| /// <param name="members" locid="WinJS.UI.Pages.define_p:members"> |
| /// Additional members that the control will have. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.UI.Pages.define_returnValue"> |
| /// A constructor function that creates the page. |
| /// </returns> |
| /// </signature> |
| |
| var Page = _BasePage.get(uri); |
| |
| if (!Page) { |
| Page = _BasePage.define(uri, _mixin); |
| } |
| |
| if (members) { |
| Page = _Base.Class.mix(Page, members); |
| } |
| |
| if (Page.selfhost) { |
| _BaseUtils.ready(function () { |
| render(_BasePage.abs(uri), _Global.document.body); |
| }, true); |
| } |
| |
| return Page; |
| } |
| |
| function get(uri) { |
| /// <signature helpKeyword="WinJS.UI.Pages.get"> |
| /// <summary locid="WinJS.UI.Pages.get"> |
| /// Gets an already-defined page control for the specified URI, or creates a new one. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages.get_p:uri"> |
| /// The URI for the content that defines the page. |
| /// </param> |
| /// <returns type="Function" locid="WinJS.UI.Pages.get_returnValue"> |
| /// A constructor function that creates the page. |
| /// </returns> |
| /// </signature> |
| |
| var ctor = _BasePage.get(uri); |
| if (!ctor) { |
| ctor = Pages_define(uri); |
| } |
| return ctor; |
| } |
| |
| function _remove(uri) { |
| Fragments.clearCache(_BasePage.abs(uri)); |
| _BasePage.remove(uri); |
| } |
| |
| function render(uri, element, options, parentedPromise) { |
| /// <signature helpKeyword="WinJS.UI.Pages.render"> |
| /// <summary locid="WinJS.UI.Pages.render"> |
| /// Creates a page control from the specified URI inside |
| /// the specified element with the specified options. |
| /// </summary> |
| /// <param name="uri" locid="WinJS.UI.Pages.render_p:uri"> |
| /// The URI for the content that defines the page. |
| /// </param> |
| /// <param name="element" isOptional="true" locid="WinJS.UI.Pages.render_p:element"> |
| /// The element to populate with the page. |
| /// </param> |
| /// <param name="options" isOptional="true" locid="WinJS.UI.Pages.render_p:options"> |
| /// The options for configuring the page. |
| /// </param> |
| /// <param name="parentedPromise" isOptional="true" locid="WinJS.UI.Pages.render_p:parentedPromise"> |
| /// A promise that is fulfilled when the specified element is parented to the final document. |
| /// </param> |
| /// <returns type="WinJS.Promise" locid="WinJS.UI.Pages.render_returnValue"> |
| /// A promise that is fulfilled when the page is done rendering |
| /// </returns> |
| /// </signature> |
| var Ctor = get(uri); |
| var control = new Ctor(element, options, null, parentedPromise); |
| return control.renderComplete.then(null, function (err) { |
| return Promise.wrapError({ |
| error: err, |
| page: control |
| }); |
| }); |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI.Pages", { |
| define: Pages_define, |
| get: get, |
| _remove: _remove, |
| render: render, |
| _viewMap: _BasePage.viewMap |
| }); |
| |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('WinJS/Controls/HtmlControl',[ |
| 'exports', |
| '../Core/_Global', |
| '../Core/_Base', |
| '../Pages' |
| ], function htmlControlInit(exports, _Global, _Base, Pages) { |
| "use strict"; |
| |
| // not supported in WebWorker |
| if (!_Global.document) { |
| return; |
| } |
| |
| _Base.Namespace._moduleDefine(exports, "WinJS.UI", { |
| /// <field> |
| /// <summary locid="WinJS.UI.HtmlControl"> |
| /// Enables you to include an HTML page dynamically. |
| /// </summary> |
| /// </field> |
| /// <name locid="WinJS.UI.HtmlControl_name">HtmlControl</name> |
| /// <icon src="base_winjs.ui.htmlcontrol.12x12.png" width="12" height="12" /> |
| /// <icon src="base_winjs.ui.htmlcontrol.16x16.png" width="16" height="16" /> |
| /// <htmlSnippet><![CDATA[<div data-win-control="WinJS.UI.HtmlControl" data-win-options="{ uri: 'somePage.html' }"></div>]]></htmlSnippet> |
| /// <resource type="javascript" src="//WinJS.4.4/js/WinJS.js" shared="true" /> |
| /// <resource type="css" src="//WinJS.4.4/css/ui-dark.css" shared="true" /> |
| HtmlControl: _Base.Class.define(function HtmlControl_ctor(element, options, complete) { |
| /// <signature helpKeyword="WinJS.UI.HtmlControl.HtmlControl"> |
| /// <summary locid="WinJS.UI.HtmlControl.constructor"> |
| /// Initializes a new instance of HtmlControl to define a new page control. |
| /// </summary> |
| /// <param name="element" locid="WinJS.UI.HtmlControl.constructor_p:element"> |
| /// The element that hosts the HtmlControl. |
| /// </param> |
| /// <param name="options" locid="WinJS.UI.HtmlControl.constructor_p:options"> |
| /// The options for configuring the page. The uri option is required in order to specify the source |
| /// document for the content of the page. |
| /// </param> |
| /// </signature> |
| Pages.render(options.uri, element, options). |
| then(complete, function () { complete(); }); |
| }) |
| }); |
| }); |
| // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. |
| define('base',[ |
| 'WinJS/Core/_WinJS', |
| 'WinJS/Core', |
| 'WinJS/Promise', |
| 'WinJS/_Signal', |
| 'WinJS/Scheduler', |
| 'WinJS/Utilities', |
| 'WinJS/XYFocus', |
| 'WinJS/Fragments', |
| 'WinJS/Application', |
| 'WinJS/Navigation', |
| 'WinJS/Animations', |
| 'WinJS/Binding', |
| 'WinJS/BindingTemplate', |
| 'WinJS/BindingList', |
| 'WinJS/Res', |
| 'WinJS/Pages', |
| 'WinJS/ControlProcessor', |
| 'WinJS/Controls/HtmlControl', |
| ], function (_WinJS) { |
| "use strict"; |
| |
| _WinJS.Namespace.define("WinJS.Utilities", { |
| _require: require, |
| _define: define |
| }); |
| |
| return _WinJS; |
| }); |
| |
| require(['WinJS/Core/_WinJS', 'base'], function (_WinJS) { |
| // WinJS always publishes itself to global |
| globalObject.WinJS = _WinJS; |
| if (typeof module !== 'undefined') { |
| // This is a CommonJS context so publish to exports |
| module.exports = _WinJS; |
| } |
| }); |
| return globalObject.WinJS; |
| })); |
| }()); |
| |