browser/metro/base/content/appbar.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 var Appbar = {
     7   get starButton()    { return document.getElementById('star-button'); },
     8   get pinButton()     { return document.getElementById('pin-button'); },
     9   get menuButton()    { return document.getElementById('menu-button'); },
    11   // track selected/active richgrid/tilegroup - the context for contextual action buttons
    12   activeTileset: null,
    14   init: function Appbar_init() {
    15     // fired from appbar bindings
    16     Elements.contextappbar.addEventListener('MozAppbarShowing', this, false);
    17     Elements.contextappbar.addEventListener('MozAppbarDismissing', this, false);
    19     // fired when a context sensitive item (bookmarks) changes state
    20     window.addEventListener('MozContextActionsChange', this, false);
    22     // browser events we need to update button state on
    23     Elements.browsers.addEventListener('URLChanged', this, true);
    24     Elements.tabList.addEventListener('TabSelect', this, true);
    26     // tilegroup selection events for all modules get bubbled up
    27     window.addEventListener("selectionchange", this, false);
    28     Services.obs.addObserver(this, "metro_on_async_tile_created", false);
    30     // gather appbar telemetry data
    31     try {
    32       UITelemetry.addSimpleMeasureFunction("metro-appbar",
    33                                            this.getAppbarMeasures.bind(this));
    34     } catch (ex) {
    35       // swallow exception that occurs if metro-appbar measure is already set up
    36     }
    37   },
    39   observe: function(aSubject, aTopic, aData) {
    40     switch (aTopic) {
    41       case "metro_on_async_tile_created":
    42         this._updatePinButton();
    43         break;
    44     }
    45   },
    47   handleEvent: function Appbar_handleEvent(aEvent) {
    48     switch (aEvent.type) {
    49       case 'URLChanged':
    50       case 'TabSelect':
    51         this.update();
    52         this.flushActiveTileset(aEvent.lastTab);
    53         break;
    55       case 'MozAppbarShowing':
    56         this.update();
    57         break;
    59       case 'MozAppbarDismissing':
    60         if (this.activeTileset && ('isBound' in this.activeTileset)) {
    61           this.activeTileset.clearSelection();
    62         }
    63         this._clearContextualActions();
    64         this.activeTileset = null;
    65         break;
    67       case 'MozContextActionsChange':
    68         let actions = aEvent.actions;
    69         let setName = aEvent.target.contextSetName;
    70         // could transition in old, new buttons?
    71         this.showContextualActions(actions, setName);
    72         break;
    74       case "selectionchange":
    75         let nodeName = aEvent.target.nodeName;
    76         if ('richgrid' === nodeName) {
    77           this._onTileSelectionChanged(aEvent);
    78         }
    79         break;
    80     }
    81   },
    83   flushActiveTileset: function flushActiveTileset(aTab) {
    84     try {
    85       let tab = aTab || Browser.selectedTab;
    86       // Switching away from or loading a site into a startui tab that has actions
    87       // pending, we consider this confirmation that the user wants to flush changes.
    88       if (this.activeTileset && tab && tab.browser && tab.browser.currentURI.spec == kStartURI) {
    89         ContextUI.dismiss();
    90       }
    91     } catch (ex) {}
    92   },
    94   shutdown: function shutdown() {
    95     this.flushActiveTileset();
    96   },
    98   /*
    99    * Called from various places when the visible content
   100    * has changed such that button states may need to be
   101    * updated.
   102    */
   103   update: function update() {
   104     this._updatePinButton();
   105     this._updateStarButton();
   106   },
   108   onPinButton: function() {
   109     if (this.pinButton.checked) {
   110       Browser.pinSite();
   111     } else {
   112       Browser.unpinSite();
   113     }
   114   },
   116   onStarButton: function(aValue) {
   117     if (aValue === undefined) {
   118       aValue = this.starButton.checked;
   119     }
   121     if (aValue) {
   122       Browser.starSite(function () {
   123         Appbar._updateStarButton();
   124       });
   125     } else {
   126       Browser.unstarSite(function () {
   127         Appbar._updateStarButton();
   128       });
   129     }
   130   },
   132   onMenuButton: function(aEvent) {
   133       let typesArray = [];
   135       if (BrowserUI.isPrivateBrowsingEnabled) {
   136         typesArray.push("private-browsing");
   137       }
   138       if (!BrowserUI.isStartTabVisible) {
   139         typesArray.push("find-in-page");
   140         if (ContextCommands.getPageSource())
   141           typesArray.push("view-page-source");
   142       }
   143       if (ContextCommands.getStoreLink())
   144         typesArray.push("ms-meta-data");
   145       if (ConsolePanelView.enabled)
   146         typesArray.push("open-error-console");
   147       if (!Services.metro.immersive)
   148         typesArray.push("open-jsshell");
   150       typesArray.push("view-on-desktop");
   152       var x = this.menuButton.getBoundingClientRect().left;
   153       var y = Elements.toolbar.getBoundingClientRect().top;
   154       ContextMenuUI.showContextMenu({
   155         json: {
   156           types: typesArray,
   157           string: '',
   158           xPos: x,
   159           yPos: y,
   160           leftAligned: true,
   161           bottomAligned: true
   162       }
   164       });
   165   },
   167   onViewOnDesktop: function() {
   168     let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
   169       getService(Components.interfaces.nsIAppStartup);
   171     Services.prefs.setBoolPref('browser.sessionstore.resume_session_once', true);
   172     this._incrementCountableEvent("switch-to-desktop-button");
   173     appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
   174                     Components.interfaces.nsIAppStartup.eRestart);
   175   },
   177   onAutocompleteCloseButton: function () {
   178     Elements.autocomplete.closePopup();
   179   },
   181   dispatchContextualAction: function(aActionName){
   182     let activeTileset = this.activeTileset;
   183     if (activeTileset && ('isBound' in this.activeTileset)) {
   184       // fire event on the richgrid, others can listen
   185       // but we keep coupling loose so grid doesn't need to know about appbar
   186       let event = document.createEvent("Events");
   187       event.action = aActionName;
   188       event.initEvent("context-action", true, true); // is cancelable
   189       activeTileset.dispatchEvent(event);
   190       if (!event.defaultPrevented) {
   191         activeTileset.clearSelection();
   192         Elements.contextappbar.dismiss();
   193       }
   194     }
   195   },
   197   showContextualActions: function(aVerbs, aSetName) {
   198     // When the appbar is not visible, we want the icons to refresh right away
   199     let immediate = !Elements.contextappbar.isShowing;
   201     if (aVerbs.length) {
   202       Elements.contextappbar.show();
   203     }
   205     // Look up all of the buttons for the verbs that should be visible.
   206     let idsToVisibleVerbs = new Map();
   207     for (let verb of aVerbs) {
   208       let id = verb + "-selected-button";
   209       if (!document.getElementById(id)) {
   210         throw new Error("Appbar.showContextualActions: no button for " + verb);
   211       }
   212       idsToVisibleVerbs.set(id, verb);
   213     }
   215     // Sort buttons into 2 buckets - needing showing and needing hiding.
   216     let toHide = [], toShow = [];
   217     let buttons = Elements.contextappbar.getElementsByTagName("toolbarbutton");
   218     for (let button of buttons) {
   219       let verb = idsToVisibleVerbs.get(button.id);
   220       if (verb != undefined) {
   221         // Button should be visible, and may or may not be showing.
   222         this._updateContextualActionLabel(button, verb, aSetName);
   223         if (button.hidden) {
   224           toShow.push(button);
   225         }
   226       } else if (!button.hidden) {
   227         // Button is visible, but shouldn't be.
   228         toHide.push(button);
   229       }
   230     }
   232     if (immediate) {
   233       toShow.forEach(function(element) {
   234         element.removeAttribute("fade");
   235         element.hidden = false;
   236       });
   237       toHide.forEach(function(element) {
   238         element.setAttribute("fade", true);
   239         element.hidden = true;
   240       });
   241       return;
   242     }
   244     return Task.spawn(function() {
   245       if (toHide.length) {
   246         yield Util.transitionElementVisibility(toHide, false);
   247       }
   248       if (toShow.length) {
   249         yield Util.transitionElementVisibility(toShow, true);
   250       }
   251     });
   252   },
   254   _clearContextualActions: function() {
   255     this.showContextualActions([]);
   256   },
   258   _updateContextualActionLabel: function(aButton, aVerb, aSetName) {
   259     // True if the action's label string contains the set name and
   260     // thus has to be selected based on the list passed in.
   261     let usesSetName = aButton.hasAttribute("label-uses-set-name");
   262     let name = "contextAppbar2." + aVerb + (usesSetName ? "." + aSetName : "");
   263     aButton.label = Strings.browser.GetStringFromName(name);
   264   },
   266   _onTileSelectionChanged: function _onTileSelectionChanged(aEvent){
   267     let activeTileset = aEvent.target;
   269     // deselect tiles in other tile groups,
   270     // ensure previousyl-activeTileset is bound before calling methods on it
   271     if (this.activeTileset &&
   272           ('isBound' in this.activeTileset) &&
   273           this.activeTileset !== activeTileset) {
   274       this.activeTileset.clearSelection();
   275     }
   276     // keep track of which view is the target/scope for the contextual actions
   277     this.activeTileset = activeTileset;
   279     // ask the view for the list verbs/action-names it thinks are
   280     // appropriate for the tiles selected
   281     let contextActions = activeTileset.contextActions;
   282     let verbs = [v for (v of contextActions)];
   284     // fire event with these verbs as payload
   285     let event = document.createEvent("Events");
   286     event.actions = verbs;
   287     event.initEvent("MozContextActionsChange", true, false);
   288     activeTileset.dispatchEvent(event);
   290     if (verbs.length) {
   291       Elements.contextappbar.show(); // should be no-op if we're already showing
   292     } else {
   293       Elements.contextappbar.dismiss();
   294     }
   295   },
   297   // track certain appbar events and interactions for the UITelemetry probe
   298   _countableEvents: {},
   300   _incrementCountableEvent: function(aName) {
   301     if (!(aName in this._countableEvents)) {
   302       this._countableEvents[aName] = 0;
   303     }
   304     this._countableEvents[aName]++;
   305   },
   307   getAppbarMeasures: function() {
   308     return {
   309       countableEvents: this._countableEvents
   310     };
   311   },
   313   _updatePinButton: function() {
   314     this.pinButton.checked = Browser.isSitePinned();
   315   },
   317   _updateStarButton: function() {
   318     Browser.isSiteStarredAsync(function (isStarred) {
   319       this.starButton.checked = isStarred;
   320     }.bind(this));
   321   },
   323 };

mercurial