#if COPYRIGHT //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ #endif Sys._Application = function() { /// Sys._Application.initializeBase(this); this._disposableObjects = []; this._components = {}; this._createdComponents = []; this._secondPassComponents = []; // dispose the app in window.unload this._unloadHandlerDelegate = Function.createDelegate(this, this._unloadHandler); Sys.UI.DomEvent.addHandler(window, "unload", this._unloadHandlerDelegate); // automatically initialize when the dom is ready this._domReady(); } Sys._Application.prototype = { _creatingComponents: false, _disposing: false, _deleteCount: 0, get_isCreatingComponents: function() { /// return this._creatingComponents; }, get_isDisposing: function() { /// return this._disposing; }, add_init: function(handler) { /// if (this._initialized) { handler(this, Sys.EventArgs.Empty); } else { this.get_events().addHandler("init", handler); } }, remove_init: function(handler) { this.get_events().removeHandler("init", handler); }, add_load: function(handler) { /// this.get_events().addHandler("load", handler); }, remove_load: function(handler) { this.get_events().removeHandler("load", handler); }, add_unload: function(handler) { /// this.get_events().addHandler("unload", handler); }, remove_unload: function(handler) { this.get_events().removeHandler("unload", handler); }, addComponent: function(component) { /// Adds a top-level component to the application. /// The component to add. #if DEBUG var id = component.get_id(); if (!id) throw Error.invalidOperation(Sys.Res.cantAddWithoutId); if (typeof(this._components[id]) !== 'undefined') throw Error.invalidOperation(String.format(Sys.Res.appDuplicateComponent, id)); this._components[id] = component; #else this._components[component.get_id()] = component; #endif }, beginCreateComponents: function() { /// this._creatingComponents = true; }, dispose: function() { /// if (!this._disposing) { this._disposing = true; if (this._timerCookie) { window.clearTimeout(this._timerCookie); delete this._timerCookie; } if (this._endRequestHandler) { Sys.WebForms.PageRequestManager.getInstance().remove_endRequest(this._endRequestHandler); delete this._endRequestHandler; } if (this._beginRequestHandler) { Sys.WebForms.PageRequestManager.getInstance().remove_beginRequest(this._beginRequestHandler); delete this._beginRequestHandler; } if (window.pageUnload) { window.pageUnload(this, Sys.EventArgs.Empty); } var unloadHandler = this.get_events().getHandler("unload"); if (unloadHandler) { unloadHandler(this, Sys.EventArgs.Empty); } var disposableObjects = Array.clone(this._disposableObjects); for (var i = 0, l = disposableObjects.length; i < l; i++) { var object = disposableObjects[i]; // some entries are undefined, but we keep the density such that no more than 1000 are. if (typeof(object) !== "undefined") { object.dispose(); } } Array.clear(this._disposableObjects); Sys.UI.DomEvent.removeHandler(window, "unload", this._unloadHandlerDelegate); if (Sys._ScriptLoader) { var sl = Sys._ScriptLoader.getInstance(); if(sl) { sl.dispose(); } } Sys._Application.callBaseMethod(this, 'dispose'); } }, disposeElement: function(element, childNodesOnly) { /// Disposes of control and behavior resources associated with an element and its child nodes. /// The element to dispose. /// Whether to dispose of the element and its child nodes or only its child nodes. // note: cannot use domElement="true" for parameter because it fails for text nodes which we want to // allow here. if (element.nodeType === 1) { var i, allElements = element.getElementsByTagName("*"), length = allElements.length, children = new Array(length); // we must clone the array first as it is a reference to the actual live tree // and will change if disposed components modify the DOM // Also we cannot use Array.clone() because it is not actually a javascript array for (i = 0; i < length; i++) { children[i] = allElements[i]; } for (i = length - 1; i >= 0; i--) { var child = children[i]; // disposes of controls and behaviors attached to an element // logic adapted from PageRequestManager._destroyTree // This logic inlined because with a large number of DOM elements, the // overhead of calling a different method for each element adds up var d = child.dispose; if (d && typeof(d) === "function") { child.dispose(); } else { var c = child.control; if (c && typeof(c.dispose) === "function") { c.dispose(); } } var list = child._behaviors; if (list) { this._disposeComponents(list); } list = child._components; if (list) { this._disposeComponents(list); child._components = null; } } if (!childNodesOnly) { var d = element.dispose; if (d && typeof(d) === "function") { element.dispose(); } else { var c = element.control; if (c && typeof(c.dispose) === "function") { c.dispose(); } } var list = element._behaviors; if (list) { this._disposeComponents(list); } list = element._components; if (list) { this._disposeComponents(list); element._components = null; } } } }, endCreateComponents: function() { /// var components = this._secondPassComponents; for (var i = 0, l = components.length; i < l; i++) { var component = components[i].component; Sys$Component$_setReferences(component, components[i].references); component.endUpdate(); } this._secondPassComponents = []; this._creatingComponents = false; }, findComponent: function(id, parent) { /// /// Finds top-level components that were added through addComponent if no parent is specified /// or children of the specified parent. If parent is a component /// /// The id of the component to find. /// /// The component or element that contains the component to find. /// If not specified or null, the search is made on Application. /// /// The component, or null if it wasn't found. // Need to reference the application singleton directly beause the $find alias // points to the instance function without context. The 'this' pointer won't work here. return (parent ? ((Sys.IContainer.isInstanceOfType(parent)) ? parent.findComponent(id) : parent[id] || null) : Sys.Application._components[id] || null); }, getComponents: function() { /// /// var res = []; var components = this._components; for (var name in components) { res[res.length] = components[name]; } return res; }, initialize: function() { /// if(!this.get_isInitialized() && !this._disposing) { Sys._Application.callBaseMethod(this, 'initialize'); this._raiseInit(); if (this.get_stateString) { // only execute if history has been imported if (Sys.WebForms && Sys.WebForms.PageRequestManager) { // Subscribe to begin and end request events this._beginRequestHandler = Function.createDelegate(this, this._onPageRequestManagerBeginRequest); Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(this._beginRequestHandler); this._endRequestHandler = Function.createDelegate(this, this._onPageRequestManagerEndRequest); Sys.WebForms.PageRequestManager.getInstance().add_endRequest(this._endRequestHandler); } var loadedEntry = this.get_stateString(); if (loadedEntry !== this._currentEntry) { this._navigate(loadedEntry); } else { // Dev10 Bug: 599356 // necessary to ensure history is initialized, or there wont be any timer running to check for changes in the // hash. For example, if the user navigates a few times, then goes back to the first state and refreshes the // page, we will be loading the page with no state (this else case), yet they can click forward -- but we // never initialized history so it goes unnoticed. this._ensureHistory(); } } this.raiseLoad(); } }, notifyScriptLoaded: function() { /// Called by referenced scripts to indicate that they have completed loading. [Obsolete] }, registerDisposableObject: function(object) { /// Registers a disposable object with the application. /// The object to register. if (!this._disposing) { var objects = this._disposableObjects, i = objects.length; objects[i] = object; object.__msdisposeindex = i; } }, raiseLoad: function() { /// var h = this.get_events().getHandler("load"); var args = new Sys.ApplicationLoadEventArgs(Array.clone(this._createdComponents), !!this._loaded); this._loaded = true; if (h) { h(this, args); } if (window.pageLoad) { window.pageLoad(this, args); } this._createdComponents = []; }, removeComponent: function(component) { /// Removes a top-level component from the application. /// The component to remove. var id = component.get_id(); if (id) delete this._components[id]; }, unregisterDisposableObject: function(object) { /// Unregisters a disposable object from the application. /// The object to unregister. if (!this._disposing) { var i = object.__msdisposeindex; if (typeof(i) === "number") { // delete it from the array instead of removing it, so the msdisposeindex // remains correct on the other existing objects // When the array is enumerated we use for/in to skip over the deleted entries. var disposableObjects = this._disposableObjects; delete disposableObjects[i]; delete object.__msdisposeindex; if (++this._deleteCount > 1000) { // periodically rebuild the array to remove the sparse elements // to put a cap on the amount of memory it can consume var newArray = []; for (var j = 0, l = disposableObjects.length; j < l; j++) { object = disposableObjects[j]; if (typeof(object) !== "undefined") { object.__msdisposeindex = newArray.length; newArray.push(object); } } this._disposableObjects = newArray; this._deleteCount = 0; } } } }, _addComponentToSecondPass: function(component, references) { this._secondPassComponents[this._secondPassComponents.length] = {component: component, references: references}; }, _disposeComponents: function(list) { if (list) { for (var i = list.length - 1; i >= 0; i--) { var item = list[i]; if (typeof(item.dispose) === "function") { item.dispose(); } } } }, _domReady: function() { // note that the DOM might be ready immediately, in which case the application fires its // init and load events immediately during the constructor: new Sys._Application(). // Since the instance of Sys.Application is set to that value, Sys.Application does not yet // exist when _domReady is called. No script here or called by any of this scripts should use // Sys.Application. Use 'app' or 'this' instead. var check, er, app = this; function init() { app.initialize(); } // window.onload is the safe fallback. The rest is to try and initialize sooner, since onload // only fires once all images and other binary content is downloaded. var onload = function() { Sys.UI.DomEvent.removeHandler(window, "load", onload); init(); } Sys.UI.DomEvent.addHandler(window, "load", onload); if (document.addEventListener) { try { // try/catch in case the browser does not support DOMContentLoaded document.addEventListener("DOMContentLoaded", check = function() { document.removeEventListener("DOMContentLoaded", check, false); init(); }, false); } catch (er) { } } else if (document.attachEvent) { if ((window == window.top) && document.documentElement.doScroll) { // timer/doscroll trick works only when not in a frame var timeout, el = document.createElement("div"); check = function() { try { el.doScroll("left"); } catch (er) { timeout = window.setTimeout(check, 0); return; } el = null; init(); } check(); } else { // in a frame this is the only reliable way to fire before onload, however // testing has shown it is not much better than onload if at all better. // using a