|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 'use strict'; |
|
5 |
|
6 module.metadata = { |
|
7 "stability": "unstable" |
|
8 }; |
|
9 |
|
10 const { Cc, Ci } = require('chrome'), |
|
11 { setTimeout } = require('../timers'), |
|
12 { Trait } = require('../deprecated/traits'), |
|
13 { openDialog } = require('../window/utils'), |
|
14 |
|
15 ON_LOAD = 'load', |
|
16 ON_UNLOAD = 'unload', |
|
17 STATE_LOADED = 'complete'; |
|
18 |
|
19 /** |
|
20 * Trait provides private `_window` property and requires `_onLoad` property |
|
21 * that will be called when `_window` is loaded. If `_window` property value |
|
22 * is changed with already loaded window `_onLoad` still will be called. |
|
23 */ |
|
24 const WindowLoader = Trait.compose({ |
|
25 /** |
|
26 * Internal listener that is called when window is loaded. |
|
27 * Please keep in mind that this trait will not handle exceptions that may |
|
28 * be thrown by this method so method itself should take care of |
|
29 * handling them. |
|
30 * @param {nsIWindow} window |
|
31 */ |
|
32 _onLoad: Trait.required, |
|
33 _tabOptions: Trait.required, |
|
34 /** |
|
35 * Internal listener that is called when `_window`'s DOM 'unload' event |
|
36 * is dispatched. Please note that this trait will not handle exceptions that |
|
37 * may be thrown by this method so method itself should take care of |
|
38 * handling them. |
|
39 */ |
|
40 _onUnload: Trait.required, |
|
41 _load: function _load() { |
|
42 if (this.__window) |
|
43 return; |
|
44 |
|
45 this._window = openDialog({ |
|
46 private: this._isPrivate, |
|
47 args: this._tabOptions.map(function(options) options.url).join("|") |
|
48 }); |
|
49 }, |
|
50 /** |
|
51 * Private window who's load event is being tracked. Once window is loaded |
|
52 * `_onLoad` is called. |
|
53 * @type {nsIWindow} |
|
54 */ |
|
55 get _window() this.__window, |
|
56 set _window(window) { |
|
57 let _window = this.__window; |
|
58 if (!window) window = null; |
|
59 |
|
60 if (window !== _window) { |
|
61 if (_window) { |
|
62 _window.removeEventListener(ON_UNLOAD, this.__unloadListener, false); |
|
63 _window.removeEventListener(ON_LOAD, this.__loadListener, false); |
|
64 } |
|
65 |
|
66 if (window) { |
|
67 window.addEventListener( |
|
68 ON_UNLOAD, |
|
69 this.__unloadListener || |
|
70 (this.__unloadListener = this._unloadListener.bind(this)) |
|
71 , |
|
72 false |
|
73 ); |
|
74 |
|
75 this.__window = window; |
|
76 |
|
77 // If window is not loaded yet setting up a listener. |
|
78 if (STATE_LOADED != window.document.readyState) { |
|
79 window.addEventListener( |
|
80 ON_LOAD, |
|
81 this.__loadListener || |
|
82 (this.__loadListener = this._loadListener.bind(this)) |
|
83 , |
|
84 false |
|
85 ); |
|
86 } |
|
87 else { // If window is loaded calling listener next turn of event loop. |
|
88 this._onLoad(window) |
|
89 } |
|
90 } |
|
91 else { |
|
92 this.__window = null; |
|
93 } |
|
94 } |
|
95 }, |
|
96 __window: null, |
|
97 /** |
|
98 * Internal method used for listening 'load' event on the `_window`. |
|
99 * Method takes care of removing itself from 'load' event listeners once |
|
100 * event is being handled. |
|
101 */ |
|
102 _loadListener: function _loadListener(event) { |
|
103 let window = this._window; |
|
104 if (!event.target || event.target.defaultView != window) return; |
|
105 window.removeEventListener(ON_LOAD, this.__loadListener, false); |
|
106 this._onLoad(window); |
|
107 }, |
|
108 __loadListener: null, |
|
109 /** |
|
110 * Internal method used for listening 'unload' event on the `_window`. |
|
111 * Method takes care of removing itself from 'unload' event listeners once |
|
112 * event is being handled. |
|
113 */ |
|
114 _unloadListener: function _unloadListener(event) { |
|
115 let window = this._window; |
|
116 if (!event.target |
|
117 || event.target.defaultView != window |
|
118 || STATE_LOADED != window.document.readyState |
|
119 ) return; |
|
120 window.removeEventListener(ON_UNLOAD, this.__unloadListener, false); |
|
121 this._onUnload(window); |
|
122 }, |
|
123 __unloadListener: null |
|
124 }); |
|
125 exports.WindowLoader = WindowLoader; |
|
126 |