/// /// /* © Microsoft. All rights reserved. This library is supported for use in Windows Tailored Apps only. Build: 6.2.8059.0 Version: 0.5 */ (function (WinJS, undefined) { var DOMEventMixin = { _domElement: null, addEventListener: function (type, listener, useCapture) { /// /// Adds an event listener to the control. /// /// /// The type (name) of the event. /// /// /// The listener to invoke when the event gets raised. /// /// /// Specifies whether or not to initiate capture. /// this._domElement.addEventListener(type, listener, useCapture || false); }, dispatchEvent: function (type, eventProperties) { /// /// Raises an event of the specified type and with additional properties. /// /// /// The type (name) of the event. /// /// /// The set of additional properties to be attached to the event object when the event is raised. /// /// /// Boolean indicating whether preventDefault was called on the event. /// var eventValue = document.createEvent("Event"); eventValue.initEvent(type, false, false); eventValue.detail = eventProperties; // @TODO, remove this when we remove WinJS.UI.Control, it is a breaking change. // if (typeof eventProperties === "object") { Object.keys(eventProperties).forEach(function (key) { eventValue[key] = eventProperties[key]; }); } this._domElement.dispatchEvent(eventValue); }, removeEventListener: function (type, listener, useCapture) { /// /// Removes an event listener from the control. /// /// /// The type (name) of the event. /// /// /// The listener to remove from the invoke list. /// /// /// Specifies whether or not to initiate capture. /// this._domElement.removeEventListener(type, listener, useCapture || false); } }; function setOptions(control, options) { /// /// Applies the set of declaratively specified options (properties and events) on the specified control. /// If the options property name begins with "on", the property value is a function and the control /// supports addEventListener setControl will call addEventListener on the control. /// /// /// The control on which the properties and events are to be applied. /// /// /// The set of options that were specified declaratively. /// 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; } } } } control[key] = value; } } }; WinJS.Namespace.defineWithParent(WinJS, "UI", { DOMEventMixin: DOMEventMixin, setOptions: setOptions }); })(WinJS); var InvalidHandler = "Invalid data-win-control attribute"; (function (WinJS, undefined) { var processedAllCalled = false; function activate(element, handler) { return new WinJS.Promise(function (complete, error) { try { var options; var optionsAttribute = element.getAttribute("data-win-options"); if (optionsAttribute) { options = WinJS.UI._optionsParser(optionsAttribute); } var ctl; var count = 1; // handler is required to call complete if it takes that parameter // if (handler.length > 2) { count++; } function checkComplete() { count--; if (count === 0) { WinJS.UI.setControl(element, ctl); complete(ctl); } } // UNDONE: async exceptions from the handler get dropped on the floor... // ctl = new handler(element, options, checkComplete); checkComplete(); } catch (err) { error(err); } }); } function processAllImpl(rootElement) { return new WinJS.Promise(function (complete, error) { msWriteProfilerMark("UI:processAll:S"); msWriteProfilerMark("UI:processAll:setup:S"); rootElement = rootElement || document.body; var pending = 0; var selector = "[data-win-control]"; var allElements = rootElement.querySelectorAll(selector); var elements = []; if (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) { complete(); return; } function checkAllComplete() { pending = pending - 1; if (pending < 0) { complete(); } } msWriteProfilerMark("UI:processAll:setup:E"); // First go through and determine which elements to activate // msWriteProfilerMark("UI:processAll:findControls:S"); var controls = new Array(elements.length); for (var i = 0, len = elements.length; i < len; i++) { var element = elements[i]; var control; var instance = WinJS.UI.getControl(element); 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; } } msWriteProfilerMark("UI:processAll:findControls:E"); // Now go through and activate those // msWriteProfilerMark("UI:processAll:activateControls:S"); for (var i = 0, len = elements.length; i < len; i++) { var ctl = controls[i]; if (ctl) { pending++; activate(elements[i], ctl).then(checkAllComplete, function (err) { error(err); }); } } msWriteProfilerMark("UI:processAll:activateControls:E"); if (checkAllComplete) { checkAllComplete(); } msWriteProfilerMark("UI:processAll:E"); }); } function getControlHandler(element) { if (element.getAttribute) { var evaluator = element.getAttribute("data-win-control"); if (evaluator) { return WinJS.Utilities.getMember(evaluator.trim()); } } } WinJS.Namespace.defineWithParent(WinJS, "UI", { getControl: function (element) { /// /// Given a DOM element, retrieves the associated Control. /// /// /// Element whose associated Control is requested. /// /// /// The control associated with the dom element. /// return element.winControl || element["data-win-control"]; }, processAll: function (rootElement) { /// /// Applies declarative control binding to all elements, starting optionally at rootElement. /// /// /// Element to start searching at, if not specified, the entire document is searched. /// /// /// Promise which is fulfilled when all the controls have been ativated /// if (!processedAllCalled) { return WinJS.Utilities.ready().then(function () { processedAllCalled = true; return processAllImpl(rootElement); }); } else { return processAllImpl(rootElement); } }, process: function (element) { /// /// Applies declarative control binding to the specified element. /// /// /// Element to bind. /// /// /// The control which was activated /// var handler = getControlHandler(element); if (!handler) { return WinJS.Promise.as(); // undefined, no handler } else { return activate(element, handler); } }, setControl: function (element, control) { /// /// Given a DOM element and a control attaches the control to the element /// /// /// Element to have control associated with. /// /// /// Control to attach to element. /// element.winControl = control; element["data-win-control"] = control; } }); })(WinJS); (function (WinJS, undefined) { var QueryCollection = WinJS.Class.derive(Array, function(items) { /// /// QueryCollection is the result of a query selector and provides /// various operations which perform actions over the elements of /// the collection. /// /// /// Items to store in the collection. /// if(items) { this.include(items); } }, { get: function(index) { /// /// Retrieve an item from the QueryCollection /// /// /// Index of the item to be returned /// /// /// A single item from the collection /// return this[index]; }, setAttribute: function(name, value) { /// /// Set an attribute value on all the items in the collection. /// /// /// Name of the attribute to be set /// /// /// Value of the attribute to be set /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { item.setAttribute(name, value); }); return this; }, getAttribute: function(name) { /// /// Gets an attribute value from the first element in the collection /// /// /// Name of the attribute to be set /// /// /// The value of the specified attribute /// if(this.length > 0) { return this[0].getAttribute(name); } }, addClass: function(name) { /// /// Adds the specified class to all the elements in the collection /// /// /// Name of the class to be added /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { WinJS.Utilities.addClass(item, name); }); return this; }, hasClass: function(name) { /// /// Tests whether the specified class exists on the first element of the collection /// /// /// Name of the desired class /// /// /// Whether or not the element has the specified class /// if(this.length > 0) { return WinJS.Utilities.hasClass(this[0], name); } return false; }, removeClass: function(name) { /// /// Removes the specified class to all the elements in the collection /// /// /// Name of the class to be removed /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { WinJS.Utilities.removeClass(item, name); }); return this; }, toggleClass: function(name) { /// /// Toggles the specified class on all the elements in the collection /// /// /// Name of the class to be toggled /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { WinJS.Utilities.toggleClass(item, name); }); return this; }, listen: function(eventType, listener, capture) { /// /// Registers the listener for the specified event on all the elements in the collection /// /// /// Name of the event to be listened to /// /// /// Event handler function to be called when event is triggered /// /// /// Capture value to be passed to addEventListener /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { item.addEventListener(eventType, listener, capture); }); return this; }, removeEventListener: function(eventType, listener, capture) { /// /// Unregisters the listener for the specified event on all the elements in the collection /// /// /// Name of the event being listened to /// /// /// Event handler function to be called when event is triggered /// /// /// Capture value to be passed to removeEventListener /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { item.removeEventListener(eventType, listener, capture); }); return this; }, setStyle: function(name, value) { /// /// Sets the specified style property for all the elements in the collection /// /// /// Name of the property on the style object associated each element /// /// /// Value to be set to the specified property on the style object /// associated with each element /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { item.style[name] = value; }); return this; }, clearStyle: function(name) { /// /// Clears the specified style property for all the elements in the collection. /// /// /// Name of the property on the style object associated each element to be cleared /// /// /// The QueryCollection instance to facilitate chaining /// this.forEach(function(item) { item.style[name] = ""; }); return this; }, query: function(query) { /// /// Executes a query selector against all the elements in the collection /// and aggregates the result. /// /// /// Query selector string /// /// /// QueryCollection instance containing the aggregate results of /// executing the query against all the elements in the collection /// var newCollection = new WinJS.Utilities.QueryCollection(); this.forEach(function(item) { newCollection.include(item.querySelectorAll(query)); }); return newCollection; }, include: function(items) { /// /// Includes a set of items in this QueryCollection /// /// /// The items to be included in the QueryCollection, may be an /// Array-like object, a document fragment or a single item. /// 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); } } }); WinJS.Namespace.defineWithParent(WinJS, "Utilities", { QueryCollection: QueryCollection, query: function (query, element) { /// /// Execute a query selector against the specified element or the document /// /// /// Query selector to be executed /// /// /// Element against which to execute the query. If not specified the /// query is executed against the document. /// /// /// The QueryCollection instance containing the results of the query /// return new WinJS.Utilities.QueryCollection((element || document).querySelectorAll(query)); }, id: function (id) { /// /// Look up an element by id and wrap the result in a QueryCollection /// /// /// Id of the element /// /// /// QueryCollection instance containing the element if it was found /// var e = document.getElementById(id); return new WinJS.Utilities.QueryCollection(e ? [e] : []); }, children: function (element) { /// /// Create a QueryCollection instance out of the specified element's children. /// /// /// Element whose children are wrapped in a QueryCollection /// /// /// The QueryCollection instance /// return new WinJS.Utilities.QueryCollection(element.children); } }); })(WinJS); (function (WinJS, undefined) { 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 getDimension(element, property) { return WinJS.Utilities.convertToPixels(element, window.getComputedStyle(element, null)[property]); } WinJS.Namespace.defineWithParent(WinJS, "Utilities", { _dataKey: "_msDataKey", _pixelsRE: /^-?\d+(px)?$/i, _numberRE: /^-?\d+/i, Key: { backspace: 8, tab: 9, enter: 13, shift: 16, ctrl: 17, alt: 18, pause: 19, capsLock: 20, escape: 27, space: 32, pageUp: 33, pageDown: 34, end: 35, home: 36, leftArrow: 37, upArrow: 38, rightArrow: 39, downArrow: 40, insert: 45, deleteKey: 46, num0: 48, num1: 49, num2: 50, num3: 51, num4: 52, num5: 53, num6: 54, num7: 55, num8: 56, num9: 57, a: 65, b: 66, c: 67, d: 68, e: 69, f: 70, g: 71, h: 72, i: 73, j: 74, k: 75, l: 76, m: 77, n: 78, o: 79, p: 80, q: 81, r: 82, s: 83, t: 84, u: 85, v: 86, w: 87, x: 88, y: 89, z: 90, leftWindows: 91, rightWindows: 92, numPad0: 96, numPad1: 97, numPad2: 98, numPad3: 99, numPad4: 100, numPad5: 101, numPad6: 102, numPad7: 103, numPad8: 104, numPad9: 105, multiply: 106, add: 107, subtract: 109, decimalPoint: 110, divide: 111, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, numLock: 144, scrollLock: 145, semicolon: 186, equal: 187, comma: 188, dash: 189, period: 190, forwardSlash: 191, graveAccent: 192, openBracket: 219, backSlash: 220, closeBracket: 221, singleQuote: 222 }, data: function (element) { /// /// Get the data value associated with the specified element /// /// /// Element to which the data is associated. /// /// /// Value assoicated with the element /// if (!element[WinJS.Utilities._dataKey]) { element[WinJS.Utilities._dataKey] = {}; } return element[WinJS.Utilities._dataKey]; }, hasClass: function (e, name) { /// /// Test whether the given element has the specified class /// /// /// Element to test for the presence of the named class /// /// /// Name of the class to test for /// /// /// Whether or not the specified element is annotated with the specified class. /// 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: function (e, name) { /// /// Add the specified class to the element /// /// /// Element to which to add the class /// /// /// Name of the class to add /// /// /// The input element /// 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); } } return e; }, removeClass: function (e, name) { /// /// Remove the specified class from the given element /// /// /// Element from which to remove the class /// /// /// Name of the class to remove /// /// /// The input element /// var names = getClassName(e).trim().split(" "); 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; }, toggleClass: function (e, name) { /// /// Toggle the specified class on the given element /// /// /// Element on which to toggle the class /// /// /// Name of the class to toggle /// /// /// The input element /// 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; }, getRelativeLeft: function (element, parent) { /// /// Gets the left coordinate of the element relative to the specified parent. /// /// /// Element whose relative coordinate is needed. /// /// /// Element to which the coordinate will be relative to. /// /// /// Relative left co-ordinate. /// if (element === null) return 0; var left = element.offsetLeft; var e = element.parentNode; while (e !== null) { left -= e.offsetLeft; if (e === parent) break; e = e.parentNode; } return left; }, getRelativeTop: function (element, parent) { /// /// Gets the top coordinate of the element relative to the specified parent. /// /// /// Element whose relative coordinate is needed. /// /// /// Element to which the coordinate will be relative to. /// /// /// Relative top co-ordinate. /// if (element === null) return 0; var top = element.offsetTop; var e = element.parentNode; while (e !== null) { top -= e.offsetTop; if (e === parent) break; e = e.parentNode; } return top; }, empty: function (element) { /// /// Removes all the child nodes from the specified element. /// /// /// The element whose child nodes will be removed. /// /// /// The input element /// 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) { /// /// Get the width of the content of the element which does not include border and padding /// /// /// Element to compute the width of /// /// /// Width of the element's content /// var border = getDimension(element, "borderLeftWidth") + getDimension(element, "borderRightWidth"), padding = getDimension(element, "paddingLeft") + getDimension(element, "paddingRight"); return element.offsetWidth - border - padding; }, getTotalWidth: function (element) { /// /// Get the width of the element including margins /// /// /// Element to compute the width of /// /// /// Width of element including margins /// var margin = getDimension(element, "marginLeft") + getDimension(element, "marginRight"); return element.offsetWidth + margin; }, getContentHeight: function (element) { /// /// Get the height of the content of the element which does not include border and padding /// /// /// Element to compute the height of /// /// /// Height of the element's content /// var border = getDimension(element, "borderTopWidth") + getDimension(element, "borderBottomWidth"), padding = getDimension(element, "paddingTop") + getDimension(element, "paddingBottom"); return element.offsetHeight - border - padding; }, getTotalHeight: function (element) { /// /// Get the height of the element including its margins /// /// /// Element to compute the height of /// /// /// Height of element including margins /// var margin = getDimension(element, "marginTop") + getDimension(element, "marginBottom"); return element.offsetHeight + margin; }, getPosition: function (element) { /// /// Get the position of the specified element /// /// /// Element for which the position is to be calculated /// /// /// Object containing left, top, width and height properties for the element. /// var fromElement = element, offsetParent = element.offsetParent, top = element.offsetTop, left = element.offsetLeft; while ((element = element.parentNode) !== null && element !== document.body && element !== document.documentElement) { top -= element.scrollTop; left -= 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 }; }, convertToPixels: function (element, value) { /// /// Convert a css positioning string to pixels /// /// /// Element to use for conversion /// /// /// Css positioning string to be converted /// /// /// Input as pixels /// if (!this._pixelsRE.test(value) && this._numberRE.test(value)) { var previousValue = element.style.left; element.style.left = value; value = element.style.pixelLeft; element.style.left = previousValue; return value; } else { return parseInt(value, 10) || 0; } }, generateID: function (idBase) { /// /// Generates a unique id for an element /// /// /// Prefix value /// /// /// Unique id string /// var id = idBase + (new Date()).getTime() + "-"; var rand = Math.random() + ""; id += rand.substring(2, rand.length); return id; } }); })(WinJS); (function (WinJS, globalObj, undefined) { var loaderStateProp = "-ms-fragmentLoader-state"; // UNDONE: should we hoist this to a shared location? // var forEach = function (arrayLikeValue, action) { for (var i = 0, l = arrayLikeValue.length; i < l; i++) { action(arrayLikeValue[i], i); } }; var head = document.head || document.getElementsByTagName("head")[0]; var nextFragmentId = 1; var scripts = {}; var styles = {}; var links = {}; var states = {}; var initialized = false; function idFromHref(href) { if (typeof (href) == "string") { return href.toLowerCase(); } else { var id = WinJS.Utilities.data(href).fragmentId; if (!id) { id = nextFragmentId++; WinJS.Utilities.data(href).fragmentId = id; } return id; } }; function addScript(scriptTag, fragmentHref, position) { // 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; if (!src) { src = fragmentHref + "script[" + position + "]"; } src = src.toLowerCase(); if (!(src in scripts)) { scripts[src] = true; var n = document.createElement("script"); if (scriptTag.language) { n.setAttribute("language", "javascript"); } if (scriptTag.type == "ms-deferred/javascript") { n.setAttribute("type", "text/javascript"); } else { n.setAttribute("type", scriptTag.type); } if (scriptTag.id) { n.setAttribute("id", scriptTag.id); } if (scriptTag.src) { n.setAttribute("src", scriptTag.src); } else { n.text = scriptTag.text; } head.appendChild(n); } }; 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); n.href = styleTag.href; head.appendChild(n); } }; function controlStaticState(href) { /// /// PRIVATE METHOD: retrieves the static (not per-instance) state for a fragment at the /// URL "href". Will complete either synchronously (for an already loaded /// fragment) or asynchronously when the fragment is loaded and ready to be used. /// // UNDONE: cancellation // return new WinJS.Promise(function (c,e,p) { var fragmentId = idFromHref(href); var state = states[fragmentId]; var intervalId; var tryCount = 4; var callback = function () { if (state.docfrag) { if (state.loadScript) { var load = WinJS.Utilities.getMember(state.loadScript); if (load) { msWriteProfilerMark("Fragment:cSS:makeDocFragNoHref:E"); c({load:load,state:states[fragmentId]}); if (intervalId) { clearInterval(intervalId); } return true; } else if (!(tryCount--)) { if (WinJS.validation) { e("Unable to find function '" + state.loadScript + "'"); } else { c({state:states[fragmentId]}); } if (intervalId) { clearInterval(intervalId); } } } else { msWriteProfilerMark("Fragment:cSS:makeDocFragNoHref:E"); c({state:states[fragmentId]}); if (intervalId) { clearInterval(intervalId); } return true; } } msWriteProfilerMark("Fragment:cSS:makeDocFragNoHref:E"); return false; }; // If the state record was found, then we either are ready to // roll immediately (everything is loaded & parsed) or are in // process of loading. If possible, we want to directly invoke // to avoid any flickering, however if we are still loading // the content, we must wait. // if (state) { if (!callback()) { intervalId = setInterval(callback, 20); } return; } else { states[fragmentId] = state = {}; } if (typeof (href) === "string") { msWriteProfilerMark("Fragment:cSS:makeDocFrag:S"); var temp = document.createElement('iframe'); document[loaderStateProp] = "loading"; temp.src = href; temp.style.display = 'none'; var domContentLoaded = null; var complete = function (load) { // This is to work around a weird bug where removing the // IFrame from the DOM triggers DOMContentLoaded a second time. temp.contentDocument.removeEventListener("DOMContentLoaded", domContentLoaded, false); temp.parentNode.removeChild(temp); temp = null; delete document[loaderStateProp]; msWriteProfilerMark("Fragment:cSS:makeDocFrag:E"); c({load:load, state:state}); }; domContentLoaded = function () { controlStaticStateLoaded(href, temp, state).then(complete); }; document.body.appendChild(temp); temp.contentDocument.addEventListener("DOMContentLoaded", domContentLoaded, false); } else { msWriteProfilerMark("Fragment:cSS:makeDocFragNoHref:S"); state.loadScript = href.getAttribute('data-win-fragmentLoad') || state.loadScript; var fragment = document.createDocumentFragment(); while (href.childNodes.length > 0) { fragment.appendChild(href.childNodes[0]); }; state.docfrag = fragment; if (!callback()) { intervalId = setInterval(callback, 20); } } }); }; function controlStaticStateLoaded(href, temp, state) { /// /// PRIVATE METHOD: 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). /// // UNDONE: cancelation // return new WinJS.Promise(function (c,e,p) { var cd = temp.contentDocument; var links = cd.querySelectorAll('link[rel="stylesheet"], link[type="text/css"]'); state.styles = links; forEach(links, addLink); // NOTE: no need to cache the style objects, as they are unique per fragment // forEach(cd.querySelectorAll('style'), function (e,i) { addStyle(e, href, i); }); var localScripts = cd.getElementsByTagName('script'); state.scripts = localScripts; forEach(localScripts, function (e,i) { addScript(e, href, i); }); var load; var loadTags = cd.querySelectorAll('[data-win-fragmentLoad]'); if (loadTags && loadTags.length > 0) { for (var i=0, l=loadTags.length; i 0) { localScripts[0].parentNode.removeChild(localScripts[0]); } var fragment = document.createDocumentFragment(); var imported = document.importNode(temp.contentDocument.body, true); while(imported.childNodes.length > 0) { fragment.appendChild(imported.childNodes[0]); } state.docfrag = fragment; // huge ugly kludge if (state.loadScript) { var intervalId = setInterval(function () { var load = WinJS.Utilities.getMember(state.loadScript); if (load) { c(load); clearInterval(intervalId); } }, 20); } else { c(); } }); }; function initialize() { /// /// PRIVATE METHOD: Initializes the fragment loader with the list of scripts and /// styles already present in the host document /// msWriteProfilerMark("Fragment:initialize:S"); if (initialized) { return; } initialized = true; msWriteProfilerMark("Fragment:initialize:getScripts:S"); var localScripts = head.querySelectorAll("script"); for (var i = 0, l = localScripts.length; i < l; i++) { scripts[localScripts[i].src.toLowerCase()] = true; } msWriteProfilerMark("Fragment:initialize:getScripts:E"); msWriteProfilerMark("Fragment:initialize:getStylesheets:S"); var csss = head.querySelectorAll('link[rel="stylesheet"], link[type="text/css"]'); for (var i = 0, l = csss.length; i < l; i++) { links[csss[i].href.toLowerCase()] = true; } msWriteProfilerMark("Fragment:initialize:getStylesheets:E"); msWriteProfilerMark("Fragment:initialize:E"); }; function renderFragment(href, options) { /// /// Returns the content of the fragment specified by "href" /// The "options" record is optionally passed to the load handler for the fragment. /// /// /// URI for fragment /// /// /// Fragment load options /// /// /// Promise which is completed when the fragment has been loaded. /// If a target element was not specified the cloned fragment is the /// completed value. /// return renderFragmentTo(href, options); }; function renderFragmentTo(href, options, target) { /// /// Clones the contents of href into target. /// The "options" record is optionally passed to the load handler for the fragment. /// /// /// URI for fragment /// /// /// Fragment load options /// /// /// Element which the fragment will be appended to /// /// /// Promise which is completed when the fragment has been loaded. /// If a target element was not specified the cloned fragment is the /// completed value. /// // UNDONE: support cancellation, route errors // msWriteProfilerMark("Fragment:clone:S"); initialize(); return controlStaticState(href).then(function (v) { var load = v.load; var state = v.state; msWriteProfilerMark("Fragment:clone:cloneChildren:S"); var clonedFrag = state.docfrag.cloneNode(true); msWriteProfilerMark("Fragment:clone:cloneChildren:E"); if (load) { load(clonedFrag, options); } if (target) { target.appendChild(clonedFrag); msWriteProfilerMark("Fragment:clone:E"); } else { msWriteProfilerMark("Fragment:clone:E"); return clonedFrag; } }); }; function prepareFragment(href) { /// /// Starts loading the fragment at the specified location, returned promise will complete /// when the fragment is ready to be cloned. /// /// /// URI for fragment /// /// /// Promise which is completed when the fragment has been prepared /// initialize(); return controlStaticState(href).then(function() { return; }); }; function unprepareFragment(href) { /// /// Removes any cached information about the fragment, this will not unload scripts /// or styles referenced by the fragment. /// /// /// URI for fragment /// delete states[idFromHref(href)]; }; function selfhost(load) { /// /// This is used in the fragment definition markup to allow a fragment to /// be loaded as a stand alone page. /// /// /// Function to be called when the fragment has loaded /// if (globalObj.parent) { if (globalObj.parent.document[loaderStateProp] != "loading") { forEach(globalObj.document.querySelectorAll('head > script[type="ms-deferred/javascript"]'), function (e) { addScript(e); }); globalObj.addEventListener("DOMContentLoaded", function (event) { load(globalObj.document.body); }, false); } } }; WinJS.Namespace.defineWithParent(WinJS, "UI.Fragments", { clone: renderFragment, cloneTo: renderFragmentTo, load: prepareFragment, unload: unprepareFragment, fragmentAsDocumentReady: selfhost }); })(WinJS, this); /* 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 */ (function (global, undefined) { 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, eof: 17, error: 18 }; // 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 }, trueLiteral: { type: tokenType.trueLiteral, length: 4, value: true }, falseLiteral: { type: tokenType.falseLiteral, length: 5, value: false }, eof: { type: tokenType.eof, length: 0 } }; function reservedWord(word) { return { type: tokenType.reservedWord, length: word.length }; } 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': 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 // | // 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 = eval('"' + 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 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; return { type: tokenType.stringLiteral, length: length, value: (hasEscape ? eval(text.substr(startOffset, length)) : text.substr(startOffset + 1, length - 2)) }; } 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 type = undefined; var token = undefined; switch (code) { case isWhitespace(code) && code: case isLineTerminator(code) && code: type = tokenType.separator; offset = readWhitespace(text, offset, limit); // don't include whitespace in the token stream. continue; case /*"*/34: case /*'*/39: token = readStringLiteralToken(text, offset - 1, limit); 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; } } type = tokenType.error; 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; } type = tokenType.error; break; } if (token) { offset += (token.length - 1); } else { token = { type: type, length: offset - startOffset }; } result.push(token); } } return function (text) { var result = []; lex(result, text, 0, text.length); result.push(tokens.eof); return result; }; })(); lexer.tokenType = tokenType; WinJS.Namespace.defineWithParent(WinJS, "UI", { _optionsLexer: lexer }); })(this); /* 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: ObjectProperty ObjectProperties, ObjectProperty ObjectProperty: PropertyName : Value PropertyName: (from ECMA-262-6, 11.1.5) StringLiteral NumberLiteral Identifier ArrayLiteral: [ ] [ ArrayElements ] ArrayElements: Value ArrayElements , Value Value: NullLiteral NumberLiteral BooleanLiteral StringLiteral ArrayLiteral ObjectLiteral IdentifierExpression AccessExpression: [ Value ] . Identifier AccessExpressions: AccessExpression AccessExpressions AccessExpression IdentifierExpression: Identifier Identifier 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 (global, undefined) { var lexer = WinJS.UI._optionsLexer; var tokenType = lexer.tokenType; function tokenTypeName(type) { var keys = Object.keys(tokenType); for (var i = 0, len = keys.length; i < len; i++) { if (type === tokenType[keys[i]]) { return keys[i]; } } return ""; } var BaseInterpreter = WinJS.Class.define(null, { _error: function (message) { var error = new Error(message); error.name = "WinJS.UI.ParseError"; throw error; }, _evaluateAccessExpression: function (value) { switch (this._current.type) { case tokenType.dot: this._read(); return this._evaluateIdentifier(true, value); case tokenType.leftBracket: this._read(); var index = this._evaluateValue(); this._read(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 tokenType.dot: case 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] || global[id]); return value; }, _evaluateIdentifierExpression: function () { var value = this._evaluateIdentifier(false); switch (this._current.type) { case tokenType.dot: case tokenType.leftBracket: return this._evaluateAccessExpressions(value); default: return value; } }, _initialize: function (tokens, context) { this._tokens = tokens; this._context = context; this._pos = 0; this._current = this._tokens[0]; }, _read: function (expected) { if (expected && this._current.type !== expected) { this._unexpectedToken(expected); } if (this._current !== tokenType.eof) { this._current = this._tokens[++this._pos]; } }, _readAccessExpression: function (parts) { switch (this._current.type) { case tokenType.dot: this._read(); parts.push(this._readIdentifier()); return; case tokenType.leftBracket: this._read(); parts.push(this._evaluateValue()); this._read(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 tokenType.dot: case tokenType.leftBracket: this._readAccessExpression(parts); break; default: return; } } }, _readIdentifier: function () { var id = this._current.value; this._read(tokenType.identifier); return id; }, _readIdentifierExpression: function () { var parts = []; parts.push(this._readIdentifier()); switch (this._current.type) { case tokenType.dot: case tokenType.leftBracket: this._readAccessExpressions(parts); break; } return parts; }, _unexpectedToken: function (expected) { if (expected) { if (arguments.length == 1) { this._error("Unexpected token: " + tokenTypeName(this._current.type) + ", expected token: " + tokenTypeName(expected) ); } else { var names = []; for (var i = 0, len = arguments.length; i < len; i++) { names.push(tokenTypeName(arguments[i])); } this._error("Unexpected token: " + tokenTypeName(this._current.type) + ", expected one of: " + names.join(", ") ); } } else { this._error("Unexpected token: " + tokenTypeName(this._current.type)); } } } ); var OptionsInterpreter = WinJS.Class.derive(BaseInterpreter, function (tokens, context) { this._initialize(tokens, context); }, { _error: function (message) { var error = new Error("Invalid options record, expected to be in the format of an object literal. " + message); error.name = "WinJS.UI.ParseError"; throw error; }, _evaluateArrayLiteral: function () { var a = []; this._read(tokenType.leftBracket); this._readArrayElements(a); this._read(tokenType.rightBracket); return a; }, _evaluateObjectLiteral: function () { var o = {}; this._read(tokenType.leftBrace); this._readObjectProperties(o); this._read(tokenType.rightBrace); return o; }, _evaluateOptionsLiteral: function () { var value = this._evaluateValue(); if (this._current.type !== tokenType.eof) { this._unexpectedToken(tokenType.eof); } return value; }, _evaluateValue: function () { switch (this._current.type) { case tokenType.falseLiteral: case tokenType.nullLiteral: case tokenType.stringLiteral: case tokenType.trueLiteral: case tokenType.numberLiteral: var value = this._current.value; this._read(); return value; case tokenType.leftBrace: return this._evaluateObjectLiteral(); case tokenType.leftBracket: return this._evaluateArrayLiteral(); case tokenType.identifier: return this._evaluateIdentifierExpression(); default: this._unexpectedToken(tokenType.falseLiteral, tokenType.nullLiteral, tokenType.stringLiteral, tokenType.trueLiteral, tokenType.numberLiteral, tokenType.leftBrace, tokenType.leftBracket, tokenType.identifier); break; } }, _readArrayElements: function (a) { var first = true; var index = 0; while (this._current.type !== tokenType.eof && this._current.type !== tokenType.rightBracket) { if (!first) { this._read(tokenType.comma); } a[index++] = this._evaluateValue(); first = false; } }, _readObjectProperties: function (o) { var first = true; while (this._current.type !== tokenType.eof && this._current.type !== tokenType.rightBrace) { if (!first) { this._read(tokenType.comma); } this._readObjectProperty(o); first = false; } }, _readObjectProperty: function (o) { switch (this._current.type) { case tokenType.numberLiteral: case tokenType.stringLiteral: case tokenType.identifier: var propertyName = this._current.value; this._read(); this._read(tokenType.colon); o[propertyName] = this._evaluateValue(); break; default: this._unexpectedToken(tokenType.numberLiteral, tokenType.stringLiteral, tokenType.identifier); break; } }, run: function () { return this._evaluateOptionsLiteral(); } } ); var parser = function (text, context) { var tokens = lexer(text); var interpreter = new OptionsInterpreter(tokens, context || {}); return interpreter.run(); }; parser._BaseInterpreter = BaseInterpreter; WinJS.Namespace.defineWithParent(WinJS, "UI", { _optionsParser: parser }); })(this); (function (WinJS, undefined) { function isSelectable(elem) { var name = elem.tagName; if (name === 'TEXTAREA' || name === 'INPUT') { return true; } while (elem) { if (elem.hasAttribute('data-win-selectable') || elem.contentEditable === 'true') { return true; } elem = elem.parentElement; } return false; } function selectionHandler(e) { if (!WinJS.UI._isSelectable(e.srcElement)) { e.preventDefault(); } } document.addEventListener('DOMContentLoaded', function() { document.body.addEventListener('selectstart', selectionHandler, false); }, false); WinJS.Namespace.defineWithParent(WinJS, "UI", { _isSelectable: {value:isSelectable, writable:true, enumerable:true} }); })(WinJS); (function (WinJS, undefined) { function TabHelperObject(element) { function fireEvent(name) { var event = document.createEvent('UIEvent'); event.initUIEvent(name, false, false, window, 1); element.dispatchEvent(event); }; function createCatcher(focusRule) { var fragment = document.createElement("DIV"); fragment.tabIndex = 0; fragment.attachEvent("onbeforeactivate", function (e) { var hasFocus = focusRule(e); fireEvent(hasFocus ? "onTabExit" : "onTabEnter"); e.cancelBubble = true; return false; }); return fragment; }; var parent = element.parentNode; // Insert prefix focus catcher var catcherBegin = createCatcher(function (e) { return e.shiftKey; }); parent.insertBefore(catcherBegin, element); // Insert postfix focus catcher var catcherEnd = createCatcher(function (e) { return !e.shiftKey; }); parent.insertBefore(catcherEnd, element.nextSibling); 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; }; } WinJS.Namespace.define("WinJS.UI.TrackTabBehavior", { attach: function (element) { if (!element["win-trackTabHelperObject"]) { element["win-trackTabHelperObject"] = new TabHelperObject(element); } else { element["win-trackTabHelperObject"].addRef(); } }, detach: function (element) { if (!element["win-trackTabHelperObject"].release()) { delete element["win-trackTabHelperObject"]; } } }); WinJS.Namespace.defineWithParent(WinJS, "UI", { TabContainer: WinJS.Class.define(function (element, options) { // TabContainer uses 2 TrackTabBehavior for its implementation: one for itself, another one for the active element. // When onTabEnter is caught on TabContainer, it directly set focus on the active element. // When onTabExit is caught on the active element (_tabExitHandler), it first prevents focus from being set on any element, // effectively letting the focus skip any remaining items in the TabContainer. Then, when onTabExit is caught on // TabContainer, it turns back on the possibility to receive focus on child elements. this._element = element; var that = this; this._tabExitHandler = function () { that._canFocus(false); }; element.addEventListener("onTabEnter", function () { if (that.childFocus) { that.childFocus.focus(); } else { that._canFocus(false); } }); element.addEventListener("onTabExit", function () { that._canFocus(true); }); WinJS.UI.TrackTabBehavior.attach(element); }, { // Public members childFocus: { /// /// Specifies the active element under this container /// set: function (e) { if (e != this._focusElement) { if (this._focusElement) { WinJS.UI.TrackTabBehavior.detach(this._focusElement); this._focusElement.removeEventListener("onTabExit", this._tabExitHandler); } this._focusElement = e; if (e) { WinJS.UI.TrackTabBehavior.attach(e); this._focusElement.addEventListener("onTabExit", this._tabExitHandler); } } }, get: function () { return this._focusElement; } }, // Private members _element: null, _skipper: function (e) { e.cancelBubble = true; return false; }, _canFocus: function (canfocus) { if (canfocus) { this._element.detachEvent("onbeforeactivate", this._skipper); } else { this._element.attachEvent("onbeforeactivate", this._skipper); } }, _focusElement: null }) }); })(WinJS); (function (WinJS, undefined) { var transitionRef = "WinJS.Animations.transition"; var styleRef = "WinJS.Animations.style"; function makeArray(elements) { if (elements instanceof Array || elements instanceof NodeList || elements instanceof HTMLCollection) { return elements; } else if (elements) { return [elements]; } else { return []; } } function addrefPVLAnimation(element, attrib) { var ref; if (element.getAttribute) { ref = element.getAttribute(attrib); if (!ref) { ref = 1; } else { ref = parseInt(ref) + 1; } element.setAttribute(attrib, ref); } return ref; } function releasePVLAnimation(element, attrib) { var ref; if (element.getAttribute) { ref = element.getAttribute(attrib); if (!ref) { ref = 0; } else { ref = parseInt(ref) - 1; } if (ref === 0) { element.removeAttribute(attrib); } else { element.setAttribute(attrib, ref); } } return ref; } var keyframeCounter = 0; function getUniqueKeyframeName() { return "WinJSUIAnimation" + ++keyframeCounter; } function getAnimationStaggerOffset(element, animArray, iElem) { for (var i = 0; i < animArray.length; i++) { if (iElem === 0) { animArray[i].initialDelay = animArray[i].delay; } animArray[i].keyframe = getUniqueKeyframeName(); if (typeof animArray[i].stagger === "function") { animArray[i].delay = animArray[i].stagger(iElem, animArray[i].initialDelay); } if (typeof animArray[i].fromCallback === "function") { animArray[i].from = animArray[i].fromCallback(iElem); } if (typeof animArray[i].toCallback === "function") { animArray[i].to = animArray[i].toCallback(iElem); } } } function getTransitionStaggerTransform(transArray, iElem) { for (var i = 0; i < transArray.length; i++) { if (iElem === 0) { transArray[i].initialDelay = transArray[i].delay; } if (typeof transArray[i].stagger === "function") { transArray[i].delay = transArray[i].stagger(iElem, transArray[i].initialDelay); } if (typeof transArray[i].transitionCallback === "function") { transArray[i].transition = transArray[i].transitionCallback(iElem); } } } function execElementTransition(elem, transitionArray) { elem.style.msTransitionProperty = transitionArray.map(function (t) { return t.name; }).join(","); elem.style.msTransitionDelay = transitionArray.map(function (t) { return t.delay + "ms"; }).join(","); elem.style.msTransitionDuration = transitionArray.map(function (t) { return t.duration + "ms"; }).join(","); elem.style.msTransitionTimingFunction = transitionArray.map(function (t) { return t.timing; }).join(","); var promise = new WinJS.Promise(function (c, e, p) { var onexecuteTransitionEnd = function (event) { if (event.srcElement === elem) { if (clearTransitionProperty(elem)) { elem.removeEventListener(event.type, onexecuteTransitionEnd, false); c(event); // complete after cleaning up the old transition } else { p(event); } } }; var waitForTransitionEnd = false; for (i = 0; i < transitionArray.length; i++) { if (transitionArray[i].transition(elem)) { waitForTransitionEnd = true; addrefPVLAnimation(elem, transitionRef); } } if (waitForTransitionEnd) { elem.addEventListener("MSTransitionEnd", onexecuteTransitionEnd, false); } else { clearTransitionProperty(elem); c(); } }); return promise; } function clearAnimation(element) { element.style.msAnimationName = null; element.style.msAnimationDelay = null; element.style.msAnimationDuration = null; element.style.msAnimationTimingFunction = null; element.style.msAnimationFillMode = "none"; } function clearTransitionProperty(elem) { if (releasePVLAnimation(elem, transitionRef) === 0) { elem.style.msTransitionProperty = null; elem.style.msTransitionDelay = null; elem.style.msTransitionDuration = null; elem.style.msTransitionTimingFunction = null; return true; } return false; } function executeElementAnimation(elem, animArray, styleelm) { var sheet = styleelm.sheet; for (var i = 0; i < animArray.length; i++) { var kf = "@-ms-keyframes " + animArray[i].keyframe + " { from {" + animArray[i].from + ";} to {" + animArray[i].to + ";}}"; sheet.insertRule(kf, sheet.cssRules.length); addrefPVLAnimation(styleelm, styleRef); } elem.style.msAnimationDelay = animArray.map(function (a) { return a.delay + "ms"; }).join(","); elem.style.msAnimationDuration = animArray.map(function (a) { return a.duration + "ms"; }).join(","); elem.style.msAnimationTimingFunction = animArray.map(function (a) { return a.timing; }).join(","); elem.style.msAnimationName = animArray.map(function (a) { return a.keyframe; }).join(","); elem.style.msAnimationFillMode = "both"; var promise = new WinJS.Promise(function (c, e, p) { var executeAnimationEnd = function (event) { if (event.srcElement === elem) { if ((releasePVLAnimation(styleelm, styleRef) === 0) && styleelm.parentElement) { styleelm.parentElement.removeChild(styleelm); } promise._cEvents -= 1; if (promise._cEvents === 0) { clearAnimation(event.srcElement); document.removeEventListener(event.type, executeAnimationEnd, false); c(event); // complete after cleaning up the old animation } else { p(event); } } }; document.addEventListener("MSAnimationEnd", executeAnimationEnd, false); }); promise._cEvents = animArray.length; return promise; } WinJS.Namespace.defineWithParent(WinJS, "UI", { executeAnimation: function (element, animation) { try { var promiseArray = []; var animArray = makeArray(animation); var elemArray = makeArray(element); var styleelm = document.createElement("STYLE"); document.documentElement.firstChild.appendChild(styleelm); if (elemArray.length !== 0) { for (var i = 0; i < elemArray.length; i++) { if (elemArray[i] instanceof Array) { for (var j = 0; j < elemArray[i].length; j++) { getAnimationStaggerOffset(elemArray[i][j], animArray, i); promiseArray.push(executeElementAnimation(elemArray[i][j], animArray, styleelm)); } } else { getAnimationStaggerOffset(elemArray[i], animArray, i); promiseArray.push(executeElementAnimation(elemArray[i], animArray, styleelm)); } } } else { return WinJS.Promise.wrap(); } return WinJS.Promise.join(promiseArray); } catch (e) { return WinJS.Promise.wrapError(e); } }, executeTransition: function (element, transition) { try { var promiseArray = []; var elemArray = makeArray(element); var transArray = makeArray(transition); if (elemArray.length !== 0) { for (var i = 0; i < elemArray.length; i++) { if (elemArray[i] instanceof Array) { for (var j = 0; j < elemArray[i].length; j++) { getTransitionStaggerTransform(transArray, i); promiseArray.push(execElementTransition(elemArray[i][j], transArray)); } } else { getTransitionStaggerTransform(transArray, i); promiseArray.push(execElementTransition(elemArray[i], transArray)); } } return WinJS.Promise.join(promiseArray); } else { return WinJS.Promise.wrap(); } } catch (e) { return WinJS.Promise.wrapError(e); } } }); })(WinJS);