From 9a87f1595660a1715f3448172d6ce008e308adec Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sat, 21 Feb 2015 03:44:13 -0500 Subject: [PATCH] Toolbar button overhaul The address bar icon now lives in a new combo buttonset containing the main Z, "Save to Zotero", and a dropmarker for the former save-icon right-click menu (which we could conceivably use more heavily going forward now that it's more accessible). There's also a separate dedicated Save to Zotero (+ dropmarker) button, not shown by default, that can be swapped in for people who don't want the Z. The tooltip for the save icon also now shows the keyboard shortcut (though that unfortunately makes for a lot of parentheses). Known issues: - Untested on ESR - Untested on Linux - Might need refinement on Windows - Weird 1px horizontal area at bottom of save button that highlights dropmarker (at least on OS X) - Probably needs a third button option with just the Z icon so that the main button and the save button can be placed separately (e.g., save button in toolbar, Z in panel) - Combo buttonset needs an inactive single-icon state for the palette and either needs a state for the panel (which might need to span all three columns?) or if possible should just move the other two icons in and put itself back in the palette - The absurd amount of time and CSS it took to get the toolbar icons looking right on OS X, since apparently no one has put a menu-button inside a combined toolbar button before --- .../content/zotero-platform/mac/overlay.css | 76 ++++++ chrome/content/zotero/browser.js | 209 +++++++++++------ chrome/content/zotero/icon.js | 216 +++++++++++++++--- chrome/content/zotero/overlay.xul | 15 +- chrome/content/zotero/xpcom/zotero.js | 1 + chrome/skin/default/zotero/zotero.css | 47 +++- 6 files changed, 440 insertions(+), 124 deletions(-) diff --git a/chrome/content/zotero-platform/mac/overlay.css b/chrome/content/zotero-platform/mac/overlay.css index 6d0d9eeeef..d601b763db 100644 --- a/chrome/content/zotero-platform/mac/overlay.css +++ b/chrome/content/zotero-platform/mac/overlay.css @@ -1,3 +1,79 @@ +/* + As of Fx36, the built-in Mac styles don't properly handle a menu-button within a combined + button, so we need this ungodly mess. +*/ +#zotero-toolbar-buttons[cui-areatype="toolbar"] > separator, +#zotero-toolbar-save-button[cui-areatype="toolbar"]:not(:hover) > .toolbarbutton-menubutton-dropmarker::before, +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button { + box-shadow: none; +} + +#zotero-toolbar-save-button[cui-areatype="toolbar"] { + margin-top: 3px !important; + margin-bottom: 3px !important; + border-right: 0; + border-width: 1px; + border-style: solid; + border-color: transparent; +} + +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-button, +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-dropmarker { + border-width: 1px; + border-style: solid; + border-color: var(--toolbarbutton-hover-bordercolor) !important; + box-shadow: var(--toolbarbutton-hover-boxshadow) !important; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-dropmarker::before { + background: none; +} + +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-button { + border-right: 1px solid transparent; +} + +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-dropmarker { + border-left: 1px solid transparent; +} + +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > .toolbarbutton-menubutton-dropmarker { + background: inherit; +} + +#zotero-toolbar-save-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover { + background: var(--toolbarbutton-hover-background); +} + +#zotero-toolbar-main-button[cui-areatype="toolbar"] { + margin-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + padding-right: 1px; +} +#zotero-toolbar-save-button[cui-areatype="toolbar"] { + margin-top: 3px; + margin-bottom: 3px; + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 0 solid transparent; +} + +#zotero-toolbar-main-button[cui-areatype="toolbar"] { + border-right: 1px solid transparent; +} +#zotero-toolbar-save-button[cui-areatype="toolbar"]:hover { + border-left: 0 solid transparent; +} +#zotero-toolbar-buttons[cui-areatype="toolbar"]:hover > #zotero-toolbar-save-button > .toolbarbutton-menubutton-button { + border-left: 1px solid transparent; +} +/* End toolbar icons */ + + #zotero-splitter { border-top: none; diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js index 78aa6e5642..91910f94f1 100644 --- a/chrome/content/zotero/browser.js +++ b/chrome/content/zotero/browser.js @@ -53,7 +53,6 @@ var Zotero_Browser = new function() { this.tabbrowser = null; this.appcontent = null; - this.statusImage = null; this.isScraping = false; var _browserData = new Object(); @@ -235,7 +234,6 @@ var Zotero_Browser = new function() { function chromeLoad() { this.tabbrowser = gBrowser; this.appcontent = document.getElementById("appcontent"); - this.statusImage = document.getElementById("zotero-status-image"); // this gives us onLocationChange, for updating when tabs are switched/created gBrowser.tabContainer.addEventListener("TabClose", @@ -282,6 +280,7 @@ var Zotero_Browser = new function() { function(e) { Zotero_Browser.resize(e) }, false); } + /* * An event handler called when a new document is loaded. Creates a new document * object, and updates the status of the capture icon @@ -429,26 +428,32 @@ var Zotero_Browser = new function() { function updateStatus() { var tab = _getTabObject(Zotero_Browser.tabbrowser.selectedBrowser); - var state = tab.getCaptureState(); - if (state != tab.CAPTURE_STATE_DISABLED) { - Zotero_Browser.statusImage.src = tab.getCaptureIcon(); - Zotero_Browser.statusImage.tooltipText = tab.getCaptureTooltip(); - if (state == tab.CAPTURE_STATE_TRANSLATABLE) { - Zotero_Browser.statusImage.classList.add('translate'); + Components.utils.import("resource:///modules/CustomizableUI.jsm"); + var buttons = getSaveButtons(); + if (buttons.length) { + let state = tab.getCaptureState(); + let icon = tab.getCaptureIcon(); + let tooltiptext = tab.getCaptureTooltip(); + for (let { button, placement } of buttons) { + button.image = icon; + button.tooltipText = tooltiptext; + if (state == tab.CAPTURE_STATE_TRANSLATABLE) { + button.classList.add('translate'); + + // Show guidance panel if necessary + + if (placement.area == 'nav-bar') { + button.addEventListener("load", function() { + document.getElementById("zotero-status-image-guidance").show(); + }); + } + // TODO: Different guidance for web pages? + } + else { + button.classList.remove('translate'); + } + button.removeAttribute('disabled'); } - else { - Zotero_Browser.statusImage.classList.remove('translate'); - } - Zotero_Browser.statusImage.hidden = false; - - if (state == tab.CAPTURE_STATE_TRANSLATABLE) { - Zotero_Browser.statusImage.addEventListener("load", function() { - document.getElementById("zotero-status-image-guidance").show(); - }, false); - } - // TODO: Different guidance for web pages? - } else { - Zotero_Browser.statusImage.hidden = true; } // set annotation bar status @@ -460,6 +465,35 @@ var Zotero_Browser = new function() { } } + function getSaveButtons() { + Components.utils.import("resource:///modules/CustomizableUI.jsm"); + var buttons = []; + + var placement = CustomizableUI.getPlacementOfWidget("zotero-toolbar-buttons"); + if (placement) { + let button = document.getElementById("zotero-toolbar-save-button"); + if (button) { + buttons.push({ + button: button, + placement: placement + }); + } + } + + placement = CustomizableUI.getPlacementOfWidget("zotero-toolbar-save-button-single"); + if (placement) { + let button = document.getElementById("zotero-toolbar-save-button-single"); + if (button) { + buttons.push({ + button: button, + placement: placement + }); + } + } + + return buttons; + } + /** * Called when status bar icon is right-clicked */ @@ -468,50 +502,78 @@ var Zotero_Browser = new function() { while(popup.hasChildNodes()) popup.removeChild(popup.lastChild); var tab = _getTabObject(this.tabbrowser.selectedBrowser); - var translators = tab.page.translators; - // Don't show context menu for web page items, for now - // TODO: Show with/without snapshots option? - if (!translators) return; - - for(var i=0, n=translators.length; i { + return { + name: button, + id: getID(button), + tooltiptext: getTooltipText(button), + oncommand: getCommand(button) + }; + }).forEach(function(attribs, index) { + if (index != 0) { + item.appendChild(document.createElementNS(kNSXUL, "separator")); + } + let button = document.createElementNS(kNSXUL, "toolbarbutton"); + if (attribs.name == 'save') { + button.setAttribute('disabled', 'true'); + button.setAttribute('type', 'menu-button'); + let menupopup = document.createElementNS(kNSXUL, "menupopup"); + menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)"); + button.appendChild(menupopup); + } + delete attribs.name; + setAttributes(button, attribs); + item.appendChild(button); + }); + + updateItemForArea(item, this.currentArea) + + return item; + } +}); + + +// Create the independent save button, which isn't shown by default +CustomizableUI.createWidget({ + id: getID('save') + '-single', + label: Zotero.getString('ingester.saveToZotero'), + tooltiptext: getTooltipText('save'), + defaultArea: false, + onCommand: function (event) { + Zotero_Browser.scrapeThisPage(null, event); }, - onCreated: function (node) { + onCreated: function (button) { + const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + button.setAttribute('disabled', 'true'); + button.setAttribute('type', 'menu-button'); + let menupopup = document.createElementNS(kNSXUL, "menupopup"); + menupopup.setAttribute('onpopupshowing', "Zotero_Browser.onStatusPopupShowing(event)"); + button.appendChild(menupopup); + } +}); + + +function getID(button) { + switch (button) { + case 'main': + return "zotero-toolbar-main-button"; + + case 'save': + return "zotero-toolbar-save-button"; + } +} + +function getCommand(button) { + switch (button) { + case 'main': + return "ZoteroOverlay.toggleDisplay()"; + + case 'save': + return "Zotero_Browser.scrapeThisPage(null, event)"; + } +} + +function getTooltipText(button) { + var text; + switch (button) { + case 'main': if (Zotero && Zotero.initialized) { - // TODO: move to strings - let str = 'Zotero'; + text = 'Zotero'; let key = Zotero.Keys.getKeyForCommand('openZotero'); if (key) { - str += ' (' - + (Zotero.isMac ? '⇧⌘' : Zotero.getString('general.keys.ctrlShift')) - + key + // Add RLE mark in RTL mode to make shortcut render the right way + text += (Zotero.rtl ? ' \u202B' : ' ') + '(' + + (Zotero.isMac ? '⇧⌘' : Zotero.getString('general.keys.ctrlShift')) + + key + ')'; } - node.setAttribute('tooltiptext', str); - var placement = CustomizableUI.getPlacementOfWidget(buttonID); - // If icon is in toolbar, show guidance panel if necessary - if (placement && placement.area == 'nav-bar') { - window.setTimeout(function() { - var isUpgrade = false; - try { - isUpgrade = Zotero.Prefs.get("firstRunGuidanceShown.saveIcon"); - } catch(e) {} - var property = "firstRunGuidance.toolbarButton."+(isUpgrade ? "upgrade" : "new"); - var shortcut = Zotero.getString(Zotero.isMac ? "general.keys.cmdShift" : "general.keys.ctrlShift")+ - Zotero.Prefs.get("keys.openZotero"); - document.getElementById("zotero-toolbar-button-guidance").show(null, Zotero.getString(property, shortcut)); - }); - } } else { if (Zotero) { @@ -72,19 +189,42 @@ CustomizableUI.createWidget({ // Use defaults if necessary if (!errMsg) { // Get the stringbundle manually - var src = 'chrome://zotero/locale/zotero.properties'; - var localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1']. - getService(Components.interfaces.nsILocaleService); - var appLocale = localeService.getApplicationLocale(); - var stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"] + let src = 'chrome://zotero/locale/zotero.properties'; + let localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1'] + .getService(Components.interfaces.nsILocaleService); + let appLocale = localeService.getApplicationLocale(); + let stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"] .getService(Components.interfaces.nsIStringBundleService); - var stringBundle = stringBundleService.createBundle(src, appLocale); - - var errMsg = stringBundle.GetStringFromName('startupError'); + let stringBundle = stringBundleService.createBundle(src, appLocale); + text = stringBundle.GetStringFromName('startupError'); } - - node.setAttribute('tooltiptext', errMsg); - node.setAttribute('error', 'true'); } + break; + + case 'save': + text = Zotero.getString('ingester.saveToZotero'); } -}); + return text; +} + +/** + * Set various attributes that allow treeitem and subelements to be styled properly + */ +function updateItemForArea(item, area) { + var areaType = CustomizableUI.getAreaType(area); + var inPanel = area == CustomizableUI.AREA_PANEL; + var classes = inPanel ? "panel-combined-button" : "toolbarbutton-1 toolbarbutton-combined"; + item.setAttribute("cui-areatype", areaType); + var buttons = item.getElementsByTagName('toolbarbutton'); + for (let i = 0; i < buttons.length; i++) { + let button = buttons[i]; + button.setAttribute("class", classes); + button.setAttribute("cui-areatype", areaType); + } +} + +function setAttributes(elem, attrs) { + for (let i in attrs) { + elem.setAttribute(i, attrs[i]); + } +} diff --git a/chrome/content/zotero/overlay.xul b/chrome/content/zotero/overlay.xul index 87c163fda2..9b28b60168 100644 --- a/chrome/content/zotero/overlay.xul +++ b/chrome/content/zotero/overlay.xul @@ -52,7 +52,9 @@