addon-sdk/source/lib/sdk/ui/sidebar.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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';
     6 module.metadata = {
     7   'stability': 'experimental',
     8   'engines': {
     9     'Firefox': '*'
    10   }
    11 };
    13 const { Class } = require('../core/heritage');
    14 const { merge } = require('../util/object');
    15 const { Disposable } = require('../core/disposable');
    16 const { off, emit, setListeners } = require('../event/core');
    17 const { EventTarget } = require('../event/target');
    18 const { URL } = require('../url');
    19 const { add, remove, has, clear, iterator } = require('../lang/weak-set');
    20 const { id: addonID } = require('../self');
    21 const { WindowTracker } = require('../deprecated/window-utils');
    22 const { isShowing } = require('./sidebar/utils');
    23 const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../window/utils');
    24 const { ns } = require('../core/namespace');
    25 const { remove: removeFromArray } = require('../util/array');
    26 const { show, hide, toggle } = require('./sidebar/actions');
    27 const { Worker } = require('../content/worker');
    28 const { contract: sidebarContract } = require('./sidebar/contract');
    29 const { create, dispose, updateTitle, updateURL, isSidebarShowing, showSidebar, hideSidebar } = require('./sidebar/view');
    30 const { defer } = require('../core/promise');
    31 const { models, views, viewsFor, modelFor } = require('./sidebar/namespace');
    32 const { isLocalURL } = require('../url');
    33 const { ensure } = require('../system/unload');
    34 const { identify } = require('./id');
    35 const { uuid } = require('../util/uuid');
    37 const sidebarNS = ns();
    39 const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
    41 let sidebars = {};
    43 const Sidebar = Class({
    44   implements: [ Disposable ],
    45   extends: EventTarget,
    46   setup: function(options) {
    47     // inital validation for the model information
    48     let model = sidebarContract(options);
    50     // save the model information
    51     models.set(this, model);
    53     // generate an id if one was not provided
    54     model.id = model.id || addonID + '-' + uuid();
    56     // further validation for the title and url
    57     validateTitleAndURLCombo({}, this.title, this.url);
    59     const self = this;
    60     const internals = sidebarNS(self);
    61     const windowNS = internals.windowNS = ns();
    63     // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=886148
    64     ensure(this, 'destroy');
    66     setListeners(this, options);
    68     let bars = [];
    69     internals.tracker = WindowTracker({
    70       onTrack: function(window) {
    71         if (!isBrowser(window))
    72           return;
    74         let sidebar = window.document.getElementById('sidebar');
    75         let sidebarBox = window.document.getElementById('sidebar-box');
    77         let bar = create(window, {
    78           id: self.id,
    79           title: self.title,
    80           sidebarurl: self.url
    81         });
    82         bars.push(bar);
    83         windowNS(window).bar = bar;
    85         bar.addEventListener('command', function() {
    86           if (isSidebarShowing(window, self)) {
    87             hideSidebar(window, self);
    88             return;
    89           }
    91           showSidebar(window, self);
    92         }, false);
    94         function onSidebarLoad() {
    95           // check if the sidebar is ready
    96           let isReady = sidebar.docShell && sidebar.contentDocument;
    97           if (!isReady)
    98             return;
   100           // check if it is a web panel
   101           let panelBrowser = sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
   102           if (!panelBrowser) {
   103             bar.removeAttribute('checked');
   104             return;
   105           }
   107           let sbTitle = window.document.getElementById('sidebar-title');
   108           function onWebPanelSidebarCreated() {
   109             if (panelBrowser.contentWindow.location != model.url ||
   110                 sbTitle.value != model.title) {
   111               return;
   112             }
   114             let worker = windowNS(window).worker = Worker({
   115               window: panelBrowser.contentWindow,
   116               injectInDocument: true
   117             });
   119             function onWebPanelSidebarUnload() {
   120               windowNS(window).onWebPanelSidebarUnload = null;
   122               // uncheck the associated menuitem
   123               bar.setAttribute('checked', 'false');
   125               emit(self, 'hide', {});
   126               emit(self, 'detach', worker);
   127               windowNS(window).worker = null;
   128             }
   129             windowNS(window).onWebPanelSidebarUnload = onWebPanelSidebarUnload;
   130             panelBrowser.contentWindow.addEventListener('unload', onWebPanelSidebarUnload, true);
   132             // check the associated menuitem
   133             bar.setAttribute('checked', 'true');
   135             function onWebPanelSidebarReady() {
   136               panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
   137               windowNS(window).onWebPanelSidebarReady = null;
   139               emit(self, 'ready', worker);
   140             }
   141             windowNS(window).onWebPanelSidebarReady = onWebPanelSidebarReady;
   142             panelBrowser.contentWindow.addEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
   144             function onWebPanelSidebarLoad() {
   145               panelBrowser.contentWindow.removeEventListener('load', onWebPanelSidebarLoad, true);
   146               windowNS(window).onWebPanelSidebarLoad = null;
   148               // TODO: decide if returning worker is acceptable..
   149               //emit(self, 'show', { worker: worker });
   150               emit(self, 'show', {});
   151             }
   152             windowNS(window).onWebPanelSidebarLoad = onWebPanelSidebarLoad;
   153             panelBrowser.contentWindow.addEventListener('load', onWebPanelSidebarLoad, true);
   155             emit(self, 'attach', worker);
   156           }
   157           windowNS(window).onWebPanelSidebarCreated = onWebPanelSidebarCreated;
   158           panelBrowser.addEventListener('DOMWindowCreated', onWebPanelSidebarCreated, true);
   159         }
   160         windowNS(window).onSidebarLoad = onSidebarLoad;
   161         sidebar.addEventListener('load', onSidebarLoad, true); // removed properly
   162       },
   163       onUntrack: function(window) {
   164         if (!isBrowser(window))
   165           return;
   167         // hide the sidebar if it is showing
   168         hideSidebar(window, self);
   170         // kill the menu item
   171         let { bar } = windowNS(window);
   172         if (bar) {
   173           removeFromArray(viewsFor(self), bar);
   174           dispose(bar);
   175         }
   177         // kill listeners
   178         let sidebar = window.document.getElementById('sidebar');
   180         if (windowNS(window).onSidebarLoad) {
   181           sidebar && sidebar.removeEventListener('load', windowNS(window).onSidebarLoad, true)
   182           windowNS(window).onSidebarLoad = null;
   183         }
   185         let panelBrowser = sidebar && sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
   186         if (windowNS(window).onWebPanelSidebarCreated) {
   187           panelBrowser && panelBrowser.removeEventListener('DOMWindowCreated', windowNS(window).onWebPanelSidebarCreated, true);
   188           windowNS(window).onWebPanelSidebarCreated = null;
   189         }
   191         if (windowNS(window).onWebPanelSidebarReady) {
   192           panelBrowser && panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', windowNS(window).onWebPanelSidebarReady, false);
   193           windowNS(window).onWebPanelSidebarReady = null;
   194         }
   196         if (windowNS(window).onWebPanelSidebarLoad) {
   197           panelBrowser && panelBrowser.contentWindow.removeEventListener('load', windowNS(window).onWebPanelSidebarLoad, true);
   198           windowNS(window).onWebPanelSidebarLoad = null;
   199         }
   201         if (windowNS(window).onWebPanelSidebarUnload) {
   202           panelBrowser && panelBrowser.contentWindow.removeEventListener('unload', windowNS(window).onWebPanelSidebarUnload, true);
   203           windowNS(window).onWebPanelSidebarUnload();
   204         }
   205       }
   206     });
   208     views.set(this, bars);
   210     add(sidebars, this);
   211   },
   212   get id() (modelFor(this) || {}).id,
   213   get title() (modelFor(this) || {}).title,
   214   set title(v) {
   215     // destroyed?
   216     if (!modelFor(this))
   217       return;
   218     // validation
   219     if (typeof v != 'string')
   220       throw Error('title must be a string');
   221     validateTitleAndURLCombo(this, v, this.url);
   222     // do update
   223     updateTitle(this, v);
   224     return modelFor(this).title = v;
   225   },
   226   get url() (modelFor(this) || {}).url,
   227   set url(v) {
   228     // destroyed?
   229     if (!modelFor(this))
   230       return;
   232     // validation
   233     if (!isLocalURL(v))
   234       throw Error('the url must be a valid local url');
   236     validateTitleAndURLCombo(this, this.title, v);
   238     // do update
   239     updateURL(this, v);
   240     modelFor(this).url = v;
   241   },
   242   show: function() {
   243     return showSidebar(null, this);
   244   },
   245   hide: function() {
   246     return hideSidebar(null, this);
   247   },
   248   dispose: function() {
   249     const internals = sidebarNS(this);
   251     off(this);
   253     remove(sidebars, this);
   255     // stop tracking windows
   256     if (internals.tracker) {
   257       internals.tracker.unload();
   258     }
   260     internals.tracker = null;
   261     internals.windowNS = null;
   263     views.delete(this);
   264     models.delete(this);
   265   }
   266 });
   267 exports.Sidebar = Sidebar;
   269 function validateTitleAndURLCombo(sidebar, title, url) {
   270   if (sidebar.title == title && sidebar.url == url) {
   271     return false;
   272   }
   274   for (let window of windows(null, { includePrivate: true })) {
   275     let sidebar = window.document.querySelector('menuitem[sidebarurl="' + url + '"][label="' + title + '"]');
   276     if (sidebar) {
   277       throw Error('The provided title and url combination is invalid (already used).');
   278     }
   279   }
   281   return false;
   282 }
   284 isShowing.define(Sidebar, isSidebarShowing.bind(null, null));
   285 show.define(Sidebar, showSidebar.bind(null, null));
   286 hide.define(Sidebar, hideSidebar.bind(null, null));
   288 identify.define(Sidebar, function(sidebar) {
   289   return sidebar.id;
   290 });
   292 function toggleSidebar(window, sidebar) {
   293   // TODO: make sure this is not private
   294   window = window || getMostRecentBrowserWindow();
   295   if (isSidebarShowing(window, sidebar)) {
   296     return hideSidebar(window, sidebar);
   297   }
   298   return showSidebar(window, sidebar);
   299 }
   300 toggle.define(Sidebar, toggleSidebar.bind(null, null));

mercurial