modal.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 file,
  3. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const {utils: Cu} = Components;
  6. Cu.import("resource://gre/modules/Services.jsm");
  7. this.EXPORTED_SYMBOLS = ["modal"];
  8. const isFirefox = () => Services.appinfo.name == "Firefox";
  9. this.modal = {};
  10. modal = {
  11. COMMON_DIALOG_LOADED: "common-dialog-loaded",
  12. TABMODAL_DIALOG_LOADED: "tabmodal-dialog-loaded",
  13. handlers: {
  14. "common-dialog-loaded": new Set(),
  15. "tabmodal-dialog-loaded": new Set()
  16. }
  17. };
  18. /**
  19. * Add handler that will be called when a global- or tab modal dialogue
  20. * appears.
  21. *
  22. * This is achieved by installing observers for common-
  23. * and tab modal loaded events.
  24. *
  25. * This function is a no-op if called on any other product than Firefox.
  26. *
  27. * @param {function(Object, string)} handler
  28. * The handler to be called, which is passed the
  29. * subject (e.g. ChromeWindow) and the topic (one of
  30. * {@code modal.COMMON_DIALOG_LOADED} or
  31. * {@code modal.TABMODAL_DIALOG_LOADED}.
  32. */
  33. modal.addHandler = function (handler) {
  34. if (!isFirefox()) {
  35. return;
  36. }
  37. Object.keys(this.handlers).map(topic => {
  38. this.handlers[topic].add(handler);
  39. Services.obs.addObserver(handler, topic, false);
  40. });
  41. };
  42. /**
  43. * Remove modal dialogue handler by function reference.
  44. *
  45. * This function is a no-op if called on any other product than Firefox.
  46. *
  47. * @param {function} toRemove
  48. * The handler previously passed to modal.addHandler which will now
  49. * be removed.
  50. */
  51. modal.removeHandler = function (toRemove) {
  52. if (!isFirefox()) {
  53. return;
  54. }
  55. for (let topic of Object.keys(this.handlers)) {
  56. let handlers = this.handlers[topic];
  57. for (let handler of handlers) {
  58. if (handler == toRemove) {
  59. Services.obs.removeObserver(handler, topic);
  60. handlers.delete(handler);
  61. }
  62. }
  63. }
  64. };
  65. /**
  66. * Represents the current modal dialogue.
  67. *
  68. * @param {function(): browser.Context} curBrowserFn
  69. * Function that returns the current |browser.Context|.
  70. * @param {nsIWeakReference=} winRef
  71. * A weak reference to the current |ChromeWindow|.
  72. */
  73. modal.Dialog = class {
  74. constructor(curBrowserFn, winRef = undefined) {
  75. this.curBrowserFn_ = curBrowserFn;
  76. this.win_ = winRef;
  77. }
  78. get curBrowser_() { return this.curBrowserFn_(); }
  79. /**
  80. * Returns the ChromeWindow associated with an open dialog window if
  81. * it is currently attached to the DOM.
  82. */
  83. get window() {
  84. if (this.win_) {
  85. let win = this.win_.get();
  86. if (win && win.parent) {
  87. return win;
  88. }
  89. }
  90. return null;
  91. }
  92. get ui() {
  93. let win = this.window;
  94. if (win) {
  95. return win.Dialog.ui;
  96. }
  97. return this.curBrowser_.getTabModalUI();
  98. }
  99. };