loader.js 3.9 KB

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