Mercurial > snowl
changeset 348:b8fbfd7ecfdf
put the main menupopup into the main Firefox popupset and share it with the toolbar and statusbar buttons via the popup attribute for better robustness; add customizable toolbar buttons for the three views
author | alta88 <alta88@gmail.com> |
---|---|
date | Mon, 27 Oct 2008 17:07:35 -0700 |
parents | d95334ac5edc |
children | f95f6f24516f |
files | content/browser.css content/browser.js content/browser.xul content/icons/table_multiple.png locale/en-US/browser.dtd |
diffstat | 5 files changed, 277 insertions(+), 180 deletions(-) [+] |
line wrap: on
line diff
--- a/content/browser.css Fri Oct 24 16:48:59 2008 -0700 +++ b/content/browser.css Mon Oct 27 17:07:35 2008 -0700 @@ -35,14 +35,32 @@ * * ***** END LICENSE BLOCK ***** */ +#snowlMenu, +#snowlToolbarButton, +#snowlStatusbarButton, +tab[snowl] > image { + list-style-image: url("chrome://snowl/content/icons/snowl-16.png"); +} + #snowlToolbarButton { - list-style-image: url("chrome://snowl/content/icons/snowl-16.png"); /* temporary til bug 355143 */ -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu-vertical"); } +#snowlToggleListButton { + list-style-image: url("chrome://snowl/content/icons/layout.png"); +} + +#snowlToggleStreamButton { + list-style-image: url("chrome://snowl/content/icons/application_tile_horizontal.png"); +} + +#snowlToggleRiverButton { + list-style-image: url("chrome://snowl/content/icons/table_multiple.png"); +} + #snowlToggleHeaderButton[snowlHeader="none"] { - list-style-image: url("chrome://snowl/content/icons/application_split.png") + list-style-image: url("chrome://snowl/content/icons/application_split.png"); } #snowlToggleHeaderButton[snowlHeader="brief"] { @@ -57,15 +75,6 @@ opacity: .3; } -/* For correct orientation; type=menu cannot be vertical unless in customize.. */ -#palette-box toolbarbutton.snowlToolbarMenuButton { - -moz-box-orient: vertical; -} - tab[snowl] { background: white; } - -tab[snowl] > image { - list-style-image: url("chrome://snowl/content/icons/snowl-16.png"); -}
--- a/content/browser.js Fri Oct 24 16:48:59 2008 -0700 +++ b/content/browser.js Mon Oct 27 17:07:35 2008 -0700 @@ -87,63 +87,48 @@ }, - _snowlRiverTab: function() { - // Could be null if none else a reference to the tab - let gBrowser = document.getElementById("content"); - let snowlTab = null; - let snowlTabOpen = false; - - for (let index = 0; index < gBrowser.mTabs.length && !snowlTabOpen; index++) { - // Get the next tab - let currentTab = gBrowser.mTabs[index]; - if (currentTab.hasAttribute("snowl")) { - snowlTabOpen = true; - snowlTab = currentTab; - } - } - return snowlTab; - }, //**************************************************************************// - // Menu Popup Sharing - - // The menu popup through which users can access Snowl commands is accessible - // from both a menu item in the Tools menu and a statusbar button. This code - // shares the same popup between those two elements so we don't have to - // duplicate the popup code. + // Menu Popups - onStatusbarButtonMouseDown: function(event) { - let menuPopup = document.getElementById('snowlMenuPopup'); - let statusbarButton = document.getElementById("snowlStatusbarButton"); - let toolbarButton = document.getElementById("snowlToolbarButton"); - - // If the menu popup isn't on the statusbar or toolbar button, then move it - // onto the button so the popup appears when the user clicks the button. - // We'll move the popup back to the Tools > Snowl menu when the popup hides. - if (event.target.id == "snowlToolbarButton" && - menuPopup.parentNode != toolbarButton) - toolbarButton.appendChild(menuPopup); - if (event.target.id == "snowlStatusbarButton" && - menuPopup.parentNode != statusbarButton) - statusbarButton.appendChild(menuPopup); + onToolsMenuPopupShowing: function(event) { + // Reuse popup + let popup = document.getElementById("snowlMenuPopup"); + let element = document.getElementById("snowlMenu"); + document.popupNode = element; + popup.hidden = false; + popup.openPopup(element, "end_before", -3); }, - onPopupShowing: function(event) { + onToolsMenuPopupHiding: function(event) { + // Hide it manually, no idea why .hidePopup doesn't work.. + let popup = document.getElementById("snowlMenuPopup"); + //popup.hidePopup(); + popup.hidden = true; + }, + + onSnowlMenuPopupShowing: function(event) { // River view menuitem checkstate is off if its tab is not selected+focused let rivermenuitem = document.getElementById("viewSnowlRiver"); let isRiverTab = gBrowser.selectedTab.hasAttribute("snowl"); rivermenuitem.setAttribute("checked", isRiverTab); - // Header checked state - let menuitems = document.getElementsByAttribute("name", "snowlHeaderMenuitemGroup"); - let selectedIndex = this._prefs.get("message.headerView"); - if (menuitems) - menuitems[selectedIndex].setAttribute("checked", true); + if (event.target.id == "snowlMenuPopup") + if (document.popupNode.localName == "toolbarbutton") + document.popupNode.setAttribute("open", true); + }, + + onSnowlMenuPopupHiding: function(event) { + event.target.hidden = false; + if (event.target.id == "snowlMenuPopup") + if (document.popupNode.localName == "toolbarbutton") + document.popupNode.removeAttribute("open"); }, layoutName: ["classic", "vertical", "widemessage", "widethread", "stacked"], onLayoutPopupShowing: function(event) { + // Layout checked state let layoutmenu = document.getElementById("snowlLayoutMenu"); let lchecked = document.getElementById("viewSnowlList").hasAttribute("checked"); let schecked = document.getElementById("viewSnowlStream").hasAttribute("checked"); @@ -158,23 +143,35 @@ layoutmenuitems[i].setAttribute("checked", true); } } + + // Header checked state + let menuitems = document.getElementsByAttribute("name", "snowlHeaderMenuitemGroup"); + let selectedIndex = this._prefs.get("message.headerView"); + if (menuitems) { + for (var i = 0; i < menuitems.length; i++) { + menuitems[i].setAttribute("disabled", !this._listMessageHeader()); + if (i == selectedIndex) + menuitems[i].setAttribute("checked", true); + } + } + + // Toolbars document.getElementById("snowlToolbarMenuitem").setAttribute("disabled", (!lchecked && !schecked) ? true : false); document.getElementById("snowlViewToolbarMenuitem").setAttribute("disabled", (!lchecked) ? true : false) }, - onPopupHiding: function(event) { - let menuPopup = document.getElementById("snowlMenuPopup"); - let menu = document.getElementById("snowlMenu"); - event.target.parentNode.removeAttribute("open"); + onSnowlButtonMouseDown: function(event) { + // Jumping thru hoops to reuse popup for menupopup and button.. + let popup = document.getElementById("snowlMenuPopup"); + popup.hidden = false; + }, - // If the menu popup isn't on the Tools > Snowl menu, then move the popup - // back onto that menu so the popup appears when the user selects the menu. - // We'll move the popup back to the statusbar button when the user clicks - // on that button. - if (menuPopup.parentNode != menu) - menu.appendChild(menuPopup); + // Correct state of button based on message in current tab + // XXX better to add url change listener? + onSnowlToggleHeaderButtonMouseover: function(event) { + event.target.setAttribute("disabled", !this._listMessageHeader()); }, @@ -208,6 +205,11 @@ let tabIndex = gBrowser.mTabContainer.selectedIndex; this._mainWindow.setAttribute("snowltabindex", tabIndex); gBrowser.mTabs[tabIndex].setAttribute("snowl", "river"); + + let riverbroadcaster = document.getElementById("viewSnowlRiver"); + let isRiverTab = gBrowser.selectedTab.hasAttribute("snowl"); + if (riverbroadcaster) + riverbroadcaster.setAttribute("checked", isRiverTab); } }, @@ -219,7 +221,12 @@ onTabSelect: function() { // Make sure desired header view showing.. this._toggleHeader("TabSelect"); - // others.. + + // Set checkstate of River broadcaster + let riverbroadcaster = document.getElementById("viewSnowlRiver"); + let isRiverTab = gBrowser.selectedTab.hasAttribute("snowl"); + if (riverbroadcaster) + riverbroadcaster.setAttribute("checked", isRiverTab); }, onCheckForNewMessages: function() { @@ -265,9 +272,7 @@ _toggleHeader: function(val) { let contentWindowDoc = gBrowser.selectedBrowser.contentDocument; let selectedIndex = null; - let headerDeck = new XPCNativeWrapper(contentWindowDoc, "getElementById()") - .getElementById("headerDeck"); - + let headerDeck = this._listMessageHeader(); let button = document.getElementById("snowlToggleHeaderButton"); if (button) button.setAttribute("disabled", !headerDeck ? true : false); @@ -310,6 +315,13 @@ } }, + _listMessageHeader: function() { + let contentWindowDoc = gBrowser.selectedBrowser.contentDocument; + let headerDeck = new XPCNativeWrapper(contentWindowDoc, "getElementById()") + .getElementById("headerDeck"); + return headerDeck; + }, + // Need to init onLoad due to xul structure, toolbar exists in list and stream _initSnowlToolbar: function() { let menuitem = document.getElementById("snowlToolbarMenuitem"); @@ -334,11 +346,34 @@ } }, + // See if River tab exists + _snowlRiverTab: function() { + // Could be null if none else a reference to the tab + let gBrowser = document.getElementById("content"); + let snowlTab = null; + let snowlTabOpen = false; + + for (let index = 0; index < gBrowser.mTabs.length && !snowlTabOpen; index++) { + // Get the next tab + let currentTab = gBrowser.mTabs[index]; + if (currentTab.hasAttribute("snowl")) { + snowlTabOpen = true; + snowlTab = currentTab; + } + } + return snowlTab; + }, + // Need to init snowl River tab, if exists _initSnowlRiverTab: function() { let tabIndex = parseInt(this._mainWindow.getAttribute("snowltabindex")); if (tabIndex >= 0 && tabIndex <= gBrowser.mTabs.length) gBrowser.mTabs[tabIndex].setAttribute("snowl", "river"); + + let riverbroadcaster = document.getElementById("viewSnowlRiver"); + let isRiverTab = gBrowser.selectedTab.hasAttribute("snowl"); + if (riverbroadcaster) + riverbroadcaster.setAttribute("checked", isRiverTab); }, // Need to reset snowl River tab index
--- a/content/browser.xul Fri Oct 24 16:48:59 2008 -0700 +++ b/content/browser.xul Mon Oct 27 17:07:35 2008 -0700 @@ -68,138 +68,183 @@ sidebarurl="chrome://snowl/content/stream.xul" sidebartitle="&streamViewSidebar.label;" oncommand="toggleSidebar('viewSnowlStream')"/> + <broadcaster id="viewSnowlRiver" + autoCheck="false" + type="checkbox" + persist="checked" + oncommand="Snowl.onRiverView()"/> </broadcasterset> <menupopup id="menu_ToolsPopup"> - <menu id="snowlMenu" class="menu-iconic" label="&snowlMenu.label;" - image="chrome://snowl/content/icons/snowl-16.png" - accesskey="&snowlMenu.accesskey;" insertafter="menu_openAddons"> - <menupopup id="snowlMenuPopup" - onpopupshowing="Snowl.onPopupShowing(event)" - onpopuphiding="Snowl.onPopupHiding(event)"> - <menuitem observes="viewSnowlList" label="&listView.label;" - accesskey="&listView.accesskey;"/> - <menuitem observes="viewSnowlStream" label="&streamView.label;" - accesskey="&streamView.accesskey;"/> - <menuseparator/> - <menuitem id="viewSnowlRiver" - label="&riverView.label;" - accesskey="&riverView.accesskey;" - autoCheck="false" - type="checkbox" - persist="checked" - oncommand="Snowl.onRiverView()"/> - <menuseparator/> - <menuitem label="&checkForNewMessages.label;" - accesskey="&checkForNewMessages.accesskey;" - oncommand="Snowl.onCheckForNewMessages()"/> - <menuseparator/> - <menu id="snowlLayoutMenu" - label="&snowlLayoutMenu.label;" - accesskey="&snowlLayoutMenu.accesskey;"> - <menupopup id="snowlLayoutPopup" - onpopupshowing="Snowl.onLayoutPopupShowing(event)"> - <menuitem id="snowlLayoutMenuitemClassic" - label="&layoutClassic.label;" - type="radio" - checked="true" - accesskey="&layoutClassic.accesskey;" - name="snowlLayoutMenuitemGroup" - oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kClassicLayout)"/> - <menuitem id="snowlLayoutMenuitemVertical" - label="&layoutVertical.label;" - type="radio" - accesskey="&layoutVertical.accesskey;" - name="snowlLayoutMenuitemGroup" - oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kVerticalLayout)"/> - <menuitem id="snowlLayoutMenuitemWideMessage" - label="&layoutWideMessage.label;" - type="radio" - accesskey="&layoutWideMessage.accesskey;" - name="snowlLayoutMenuitemGroup" - oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kWideMessageLayout)"/> - <menuitem id="snowlLayoutMenuitemWideThread" - label="&layoutWideThread.label;" - type="radio" - accesskey="&layoutWideThread.accesskey;" - name="snowlLayoutMenuitemGroup" - oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kWideThreadLayout)"/> - <menuitem id="snowlLayoutMenuitemStacked" - label="&layoutStacked.label;" - type="radio" - accesskey="&layoutStacked.accesskey;" - name="snowlLayoutMenuitemGroup" - oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kStackedLayout)"/> - <menuseparator/> - <menuitem id="snowlHeaderMenuitemNone" - label="&headerNone.label;" - type="radio" - accesskey="&headerNone.accesskey;" - name="snowlHeaderMenuitemGroup" - headerType="Snowl.kNoHeader" - oncommand="Snowl._toggleHeader(event)"/> - <menuitem id="snowlHeaderMenuitemBrief" - label="&headerBrief.label;" - type="radio" - accesskey="&headerBrief.accesskey;" - name="snowlHeaderMenuitemGroup" - headerType="Snowl.kBriefHeader" - oncommand="Snowl._toggleHeader(event)"/> - <menuitem id="snowlHeaderMenuitemFull" - label="&headerFull.label;" - type="radio" - accesskey="&headerFull.accesskey;" - name="snowlHeaderMenuitemGroup" - headerType="Snowl.kFullHeader" - oncommand="Snowl._toggleHeader(event)"/> - <menuseparator/> - <menuitem id="snowlToolbarMenuitem" - label="&toolbar.label;" - type="checkbox" - accesskey="&toolbar.accesskey;" - name="snowlToolbar" - oncommand="Snowl._toggleToolbar(event)"/> - <menuitem id="snowlViewToolbarMenuitem" - label="&viewtoolbar.label;" - type="checkbox" - checked="true" - persist="checked" - accesskey="&viewtoolbar.accesskey;" - name="snowlViewToolbar" - oncommand="Snowl._toggleToolbar(event)"/> - </menupopup> - </menu> - <menuseparator/> - <menuitem label="&subscribe.label;" accesskey="&subscribe.accesskey;" - oncommand="Snowl.onSubscribe()"/> - <menuitem label="&importOPML.label;" accesskey="&importOPML.accesskey;" - oncommand="Snowl.onImportOPML()"/> - <menuitem label="&exportOPML.label;" accesskey="&exportOPML.accesskey;" - oncommand="Snowl.onExportOPML()"/> - </menupopup> + <menu id="snowlMenu" + class="menu-iconic" + label="&snowlMenu.label;" + accesskey="&snowlMenu.accesskey;" + insertafter="menu_openAddons"> + <menupopup id="snowlToolsMenuPopup" + style="visibility: collapse" + onpopupshowing="Snowl.onToolsMenuPopupShowing(event)" + onpopuphiding="Snowl.onToolsMenuPopupHiding(event)"/> </menu> </menupopup> + <popupset id="mainPopupSet"> + <popup id="snowlMenuPopup" + position="after_start" + onpopupshowing="Snowl.onSnowlMenuPopupShowing(event)" + onpopuphiding="Snowl.onSnowlMenuPopupHiding(event)"> + <menuitem observes="viewSnowlList" label="&listView.label;" + accesskey="&listView.accesskey;"/> + <menuitem observes="viewSnowlStream" label="&streamView.label;" + accesskey="&streamView.accesskey;"/> + <menuseparator/> + <menuitem observes="viewSnowlRiver" + label="&riverView.label;" + accesskey="&riverView.accesskey;"/> + <menuseparator/> + <menuitem label="&checkForNewMessages.label;" + accesskey="&checkForNewMessages.accesskey;" + oncommand="Snowl.onCheckForNewMessages()"/> + <menuseparator/> + <menu id="snowlLayoutMenu" + label="&snowlLayoutMenu.label;" + popup="snowlLayoutPopup" + accesskey="&snowlLayoutMenu.accesskey;"> + + <menupopup id="snowlLayoutPopup" + onpopupshowing="Snowl.onLayoutPopupShowing(event)"> + <menuitem id="snowlLayoutMenuitemClassic" + label="&layoutClassic.label;" + type="radio" + checked="true" + accesskey="&layoutClassic.accesskey;" + name="snowlLayoutMenuitemGroup" + oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kClassicLayout)"/> + <menuitem id="snowlLayoutMenuitemVertical" + label="&layoutVertical.label;" + type="radio" + accesskey="&layoutVertical.accesskey;" + name="snowlLayoutMenuitemGroup" + oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kVerticalLayout)"/> + <menuitem id="snowlLayoutMenuitemWideMessage" + label="&layoutWideMessage.label;" + type="radio" + accesskey="&layoutWideMessage.accesskey;" + name="snowlLayoutMenuitemGroup" + oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kWideMessageLayout)"/> + <menuitem id="snowlLayoutMenuitemWideThread" + label="&layoutWideThread.label;" + type="radio" + accesskey="&layoutWideThread.accesskey;" + name="snowlLayoutMenuitemGroup" + oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kWideThreadLayout)"/> + <menuitem id="snowlLayoutMenuitemStacked" + label="&layoutStacked.label;" + type="radio" + accesskey="&layoutStacked.accesskey;" + name="snowlLayoutMenuitemGroup" + oncommand="SnowlMessageView.switchLayout(SnowlMessageView.kStackedLayout)"/> + <menuseparator/> + <menuitem id="snowlHeaderMenuitemNone" + label="&headerNone.label;" + type="radio" + accesskey="&headerNone.accesskey;" + name="snowlHeaderMenuitemGroup" + headerType="Snowl.kNoHeader" + oncommand="Snowl._toggleHeader(event)"/> + <menuitem id="snowlHeaderMenuitemBrief" + label="&headerBrief.label;" + type="radio" + accesskey="&headerBrief.accesskey;" + name="snowlHeaderMenuitemGroup" + headerType="Snowl.kBriefHeader" + oncommand="Snowl._toggleHeader(event)"/> + <menuitem id="snowlHeaderMenuitemFull" + label="&headerFull.label;" + type="radio" + accesskey="&headerFull.accesskey;" + name="snowlHeaderMenuitemGroup" + headerType="Snowl.kFullHeader" + oncommand="Snowl._toggleHeader(event)"/> + <menuseparator/> + <menuitem id="snowlToolbarMenuitem" + label="&toolbar.label;" + type="checkbox" + accesskey="&toolbar.accesskey;" + name="snowlToolbar" + oncommand="Snowl._toggleToolbar(event)"/> + <menuitem id="snowlViewToolbarMenuitem" + label="&viewtoolbar.label;" + type="checkbox" + checked="true" + persist="checked" + accesskey="&viewtoolbar.accesskey;" + name="snowlViewToolbar" + oncommand="Snowl._toggleToolbar(event)"/> + </menupopup> + + </menu> + <menuseparator/> + <menuitem label="&subscribe.label;" accesskey="&subscribe.accesskey;" + oncommand="Snowl.onSubscribe()"/> + <menuitem label="&importOPML.label;" accesskey="&importOPML.accesskey;" + oncommand="Snowl.onImportOPML()"/> + <menuitem label="&exportOPML.label;" accesskey="&exportOPML.accesskey;" + oncommand="Snowl.onExportOPML()"/> + </popup> + + </popupset> + <toolbarpalette id="BrowserToolbarPalette"> <toolbarbutton id="snowlToolbarButton" type="menu" + class="toolbarbutton-1" + popup="snowlMenuPopup" label="&snowlMenu.label;" - tooltiptext="&snowlMenu.label;" - onmousedown="Snowl.onStatusbarButtonMouseDown(event)"/> + onmouseover="Snowl.onSnowlButtonMouseDown(event)" + tooltiptext="&snowlMenu.label;"/> + + <toolbarbutton id="snowlToggleListButton" + observes="viewSnowlList" + class="toolbarbutton-1" + label="&toggleList.label;" + type="checkbox" + oncommand="toggleSidebar('viewSnowlList')" + tooltiptext="&toggleList.tooltip;"/> + + <toolbarbutton id="snowlToggleStreamButton" + observes="viewSnowlStream" + class="toolbarbutton-1" + label="&toggleStream.label;" + type="checkbox" + oncommand="toggleSidebar('viewSnowlStream')" + tooltiptext="&toggleStream.tooltip;"/> + + <toolbarbutton id="snowlToggleRiverButton" + observes="viewSnowlRiver" + class="toolbarbutton-1" + label="&toggleRiver.label;" + type="checkbox" + oncommand="Snowl.onRiverView()" + tooltiptext="&toggleRiver.tooltip;"/> <toolbarbutton id="snowlToggleHeaderButton" class="toolbarbutton-1" oncommand="Snowl._toggleHeader('Toggle')" + onmouseover="Snowl.onSnowlToggleHeaderButtonMouseover(event)" label="&toggleHeader.label;" snowlHeader="full" + persist="disabled" tooltiptext="&toggleHeader.tooltip;"/> </toolbarpalette>> <statusbar id="status-bar"> - <statusbarpanel id="snowlStatusbarButton" class="statusbarpanel-menu-iconic" - insertbefore="statusbar-display" - src="chrome://snowl/content/icons/snowl-16.png" - onmousedown="Snowl.onStatusbarButtonMouseDown(event)"> + <statusbarpanel id="snowlStatusbarButton" + class="statusbarpanel-menu-iconic" + label="&snowlMenu.label;" + popup="snowlMenuPopup" + onmouseover="Snowl.onSnowlButtonMouseDown(event)" + insertbefore="statusbar-display"> </statusbarpanel> </statusbar>
--- a/locale/en-US/browser.dtd Fri Oct 24 16:48:59 2008 -0700 +++ b/locale/en-US/browser.dtd Mon Oct 27 17:07:35 2008 -0700 @@ -67,5 +67,13 @@ <!ENTITY viewtoolbar.label "List Toolbar"> <!ENTITY viewtoolbar.accesskey "i"> +<!-- These labels and access keys are for toolbar buttons --> + +<!ENTITY toggleList.label "Snowl Toggle List View"> +<!ENTITY toggleList.tooltip "Toggle List View"> +<!ENTITY toggleStream.label "Snowl Toggle Stream View"> +<!ENTITY toggleStream.tooltip "Toggle Stream View"> +<!ENTITY toggleRiver.label "Snowl Toggle River View"> +<!ENTITY toggleRiver.tooltip "Toggle River View"> +<!ENTITY toggleHeader.label "Snowl Toggle Header"> <!ENTITY toggleHeader.tooltip "Toggle message header to none, brief, or full"> -<!ENTITY toggleHeader.label "Snowl Toggle Header">