/** * The class that represents a child window. It's basically a convenient way to * pass a child webview handle around. You normally don't instantiate these objects * manually, but rather get them from window.open() or Ext.space.Window.open(): * * var child = window.open("http://example.com/"); * Ext.space.Logger.log(child instanceof Ext.space.window.Child); // true * * child.on("loadstop", function(evt) { * // evt.url has finished loading; do something... * }); * * // ... time passes ... * child.close(); * */Ext.define("Ext.space.window.Child", { /** * Internal identifier for this web view * * @type {String} * @private */ id: null, /** * URL specified at creation or when calling navigate(), or when a new URL is * successfully loaded into the web view. * * @type {String} * @private */ url: null, /** * Application-defined name for this web view. * * @type {String} * @private */ name: null, /** * Hash of features specified at the time of creation. So far, only openAnimation * and closeAnimation are supported. * * @type {Object} * @private */ features: null, /** * Internal hash of web view event listeners, which application code hooks into. * * @type {Object} * @private */ events: null, /** * Internal hash of callbacks for native web view events. * * @type {Object} * @private */ apiListeners: null, /** * Promise which indicates that this object is ready for use (i.e., has been * assigned an ID). * * @type {Ext.space.Promise} * @private */ initialized: null, /** * @private */ constructor: function(url, name, features, skipCreate) { var me = this; var events = this.events = { loadstart: new Ext.space.Observable(), loadstop: new Ext.space.Observable(), loaderror: new Ext.space.Observable(), close: new Ext.space.Observable() }; this.url = url; this.name = name; this.features = features; this.initialized = new Ext.space.Promise(); this.apiListeners = {}; if (!skipCreate) { // normal usage; create a native web view var command = { command: "ChildView#create", url: url, callbacks: { onSuccess: function(handle) { me.id = ""+handle; me.initialized.fulfill(); }, onError: function(error) { me.initialized.reject(); } } }; if (name) { command.name = name; } if (features) { if (features.openAnimation) { command.openAnimation = features.openAnimation; } if (features.closeAnimation) { command.closeAnimation = features.closeAnimation; } } Ext.space.Communicator.send(command); } else { // skip creation of the native object (useful for rebuilding after a refresh); // in this case, features.id should have the existing web view's ID if (features && features.id) { this.id = features.id; this.initialized.fulfill(); } else { this.initialized.reject(); } } this.on("loadstop", function(evt) { // try and keep the URL up to date as best we can if (evt && evt.url) { this.url = evt.url; } }.bind(this)); }, /** * Fetch the internal web view ID. Also useful as a guard to make sure the child * view is ready for use before doign too much with it. * * @return {Ext.space.Promise} Promise that resolves with the web view ID */ getId: function() { return this.initialized.then(function() { return this.id; }.bind(this)); }, /** * Alias of Ext.space.window.Child#open * * Navigate the web view to the given URL. * * @inheritdoc Ext.space.window.Child#open */ navigate: function(url) { return this.initialized.then(function() { return Ext.space.Window.navigate(this, url); }.bind(this)); }, /** * Navigate the web view to the given URL. * * @param {String} url The URL to open. * @return {Ext.space.Promise} Promise that resolves when the navigate operation is * dispatched; note that this is different from the URL * being completely loaded (listen for the 'loadstop' event * for that). */ open: function(url) { return this.navigate(url); }, /** * Close the web view. * * @return {Ext.space.Promise} Promise that resolves when the web view is closed. */ close: function() { return this.initialized.then(function() { return Ext.space.Window.close(this); }.bind(this)); }, /** * Wire up event listeners for the web view. * * There are four events applications can listen for: 'loadstart' (loading from * a URL has begun), 'loadstop' (loading from a URL has finished), 'loaderror' * (an error occurred while loading), and 'close' (the web view is closing). * * @param {String} event Event name to listen for (loadstart, loadstop, loaderror, close) * @param {Function} callback Callback to invoke when the event fires */ on: function(event, callback) { var events = this.events; var apiListeners = this.apiListeners; // allow "exit" as an alias for "close" (PhoneGap compatibility) if (event == "exit") { event = "close"; } // only register events we support; otherwise just silently swallow it if (events[event]) { events[event].addListener(callback); } // make sure to register our own listeners with the native bridge, on demand; // these will invoke the listeners app code has registered in this.events.* function makeListener(registry, eventname) { return function(loadEvent) { registry[eventname].invokeListeners(loadEvent); }; } if (!apiListeners[event]) { this.getId().then(function(id) { var cb = makeListener(events, event); Ext.space.Communicator.send({ command: "ChildView#addEventListener", id: id, eventname: event, callbacks: { onEvent: cb, onSuccess: function() { // mark that we have it registered apiListeners[event] = cb; }, onError: function() {} } }); }); } }, /** * Shorthand method, same as calling .on('loadstart', callback). * * @param {Function} callback Function to invoke when the loadstart event fires */ onloadstart: function(callback) { return this.on("loadstart", callback); }, /** * Shorthand method, same as calling .on('loadstop', callback). * * @param {Function} callback Function to invoke when the loadstop event fires */ onloadstop: function(callback) { return this.on("loadstop", callback); }, /** * Shorthand method, same as calling .on('loaderror', callback). * * @param {Function} callback Function to invoke when the loaderror event fires */ onloaderror: function(callback) { return this.on("loaderror", callback); }, /** * Shorthand method, same as calling .on('close', callback). * * @param {Function} callback Function to invoke when the close event fires */ onclose: function(callback) { return this.on("close", callback); }, /** * Add a listener for the specified event. This is mostly an alias for the .on() * method, except that for compatibility with PhoneGap applications, 'exit' is * also supported as an alias for the 'close' event. * * @param {String} event Event name to listen for (loadstart, loadstop, loaderror, close/exit) * @param {Function} callback Callback to invoke when the event fires */ addEventListener: function(event, callback) { return this.on.apply(this, arguments); }});