author | Mark Hammond <mhammond@skippinet.com.au> |
Tue, 29 Mar 2016 22:08:13 +1100 | |
changeset 290922 | 84008247ec173492c40caa6122ca121b4defe4e4 |
parent 290921 | a7031fdd9cb9952d03721942ef8b0639bd144b6d |
child 290923 | 31071bd61e48933cd2b142701e5324d1830463f3 |
push id | 74432 |
push user | kwierso@gmail.com |
push date | Thu, 31 Mar 2016 20:08:46 +0000 |
treeherder | mozilla-inbound@bccb11375f2a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Gijs |
bugs | 1247345 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/components/syncedtabs/SyncedTabsDeckView.js +++ b/browser/components/syncedtabs/SyncedTabsDeckView.js @@ -79,21 +79,26 @@ SyncedTabsDeckView.prototype = { }, destroy() { this._tabListComponent.uninit(); this.container.remove(); }, update(state) { + // Note that we may also want to update elements that are outside of the + // deck, so use the document to find the class names rather than our + // container. for (let panel of state.panels) { if (panel.selected) { - this.container.getElementsByClassName(panel.id).item(0).classList.add("selected"); + Array.prototype.map.call(this._doc.getElementsByClassName(panel.id), + item => item.classList.add("selected")); } else { - this.container.getElementsByClassName(panel.id).item(0).classList.remove("selected"); + Array.prototype.map.call(this._doc.getElementsByClassName(panel.id), + item => item.classList.remove("selected")); } } }, _clearChilden() { while (this.container.firstChild) { this.container.removeChild(this.container.firstChild); }
--- a/browser/components/syncedtabs/TabListView.js +++ b/browser/components/syncedtabs/TabListView.js @@ -67,25 +67,23 @@ TabListView.prototype = { }, // Create the initial DOM from templates _create(state) { let wrapper = this._doc.importNode(this._tabsContainerTemplate.content, true).firstElementChild; this._clearChilden(); this.container.appendChild(wrapper); - this.tabsFilter = this.container.querySelector(".tabsFilter"); - this.clearFilter = this.container.querySelector(".textbox-search-clear"); - this.searchBox = this.container.querySelector(".search-box"); + // The search-box is outside of our container (it's not scrollable) + this.tabsFilter = this._doc.querySelector(".tabsFilter"); + this.clearFilter = this._doc.querySelector(".textbox-search-clear"); + this.searchBox = this._doc.querySelector(".search-box"); + this.searchIcon = this._doc.querySelector(".textbox-search-icon"); + this.list = this.container.querySelector(".list"); - this.searchIcon = this.container.querySelector(".textbox-search-icon"); - - if (state.filter) { - this.tabsFilter.value = state.filter; - } this._createList(state); this._updateSearchBox(state); this._attachListeners(); }, _createList(state) { @@ -180,16 +178,17 @@ TabListView.prototype = { }, _updateSearchBox(state) { if (state.filter) { this.searchBox.classList.add("filtered"); } else { this.searchBox.classList.remove("filtered"); } + this.tabsFilter.value = state.filter; if (state.inputFocused) { this.searchBox.setAttribute("focused", true); this.tabsFilter.focus(); } else { this.searchBox.removeAttribute("focused"); } },
--- a/browser/components/syncedtabs/sidebar.js +++ b/browser/components/syncedtabs/sidebar.js @@ -12,17 +12,17 @@ Cu.import("resource:///modules/syncedtab XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", "resource://gre/modules/FxAccounts.jsm"); this.syncedTabsDeckComponent = new SyncedTabsDeckComponent({window, SyncedTabs, fxAccounts}); let onLoaded = () => { syncedTabsDeckComponent.init(); - document.body.appendChild(syncedTabsDeckComponent.container); + document.getElementById("template-container").appendChild(syncedTabsDeckComponent.container); }; let onUnloaded = () => { removeEventListener("DOMContentLoaded", onLoaded); removeEventListener("unload", onUnloaded); syncedTabsDeckComponent.uninit(); };
--- a/browser/components/syncedtabs/sidebar.xhtml +++ b/browser/components/syncedtabs/sidebar.xhtml @@ -58,27 +58,16 @@ <div class="item-icon-container"></div> <p class="item-title"></p> </div> </div> </template> <template id="tabs-container-template"> <div class="tabs-container"> - <div class="sidebar-search-container"> - <div class="search-box compact"> - <div class="textbox-input-box"> - <input type="text" class="tabsFilter textbox-input"/> - <div class="textbox-search-icons"> - <a class="textbox-search-clear"></a> - <a class="textbox-search-icon"></a> - </div> - </div> - </div> - </div> <div class="list" role="listbox" tabindex="1"></div> </div> </template> <template id="deck-template"> <div class="deck"> <div class="tabs-fetching sync-state"> <p>&syncedTabs.sidebar.fetching.label;</p> @@ -93,10 +82,29 @@ </div> <div class="tabs-disabled sync-state"> <p>&syncedTabs.sidebar.tabsnotsyncing.label;</p> <p><a href="#" class="sync-prefs text-link">&syncedTabs.sidebar.openprefs.label;</a></p> </div> </div> </template> + <div class="content-container"> + <!-- the non-scrollable header --> + <div class="content-header"> + <div class="sidebar-search-container tabs-container sync-state"> + <div class="search-box compact"> + <div class="textbox-input-box"> + <input type="text" class="tabsFilter textbox-input"/> + <div class="textbox-search-icons"> + <a class="textbox-search-clear"></a> + <a class="textbox-search-icon"></a> + </div> + </div> + </div> + </div> + </div> + <!-- the scrollable content area where our templates are inserted --> + <div id="template-container" class="content-scrollable"> + </div> + </div> </body> </html>
--- a/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js +++ b/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js @@ -152,17 +152,17 @@ add_task(function* testSyncedTabsSidebar sinon.stub(SyncedTabs._internal, "getTabClients", ()=> Promise.resolve(Cu.cloneInto(FIXTURE, {}))); yield syncedTabsDeckComponent.updatePanel(); // This is a hacky way of waiting for the view to render. The view renders // after the following promise (a different instance of which is triggered // in updatePanel) resolves, so we wait for it here as well yield syncedTabsDeckComponent.tabListComponent._store.getData(); - let filterInput = syncedTabsDeckComponent.container.querySelector(".tabsFilter"); + let filterInput = syncedTabsDeckComponent._window.document.querySelector(".tabsFilter"); filterInput.value = "filter text"; filterInput.blur(); yield syncedTabsDeckComponent.tabListComponent._store.getData("filter text"); let selectedPanel = syncedTabsDeckComponent.container.querySelector(".sync-state.selected"); Assert.ok(selectedPanel.classList.contains("tabs-container"), "tabs panel is selected"); @@ -348,17 +348,17 @@ function checkItem(node, item) { "Node should have .client class"); Assert.equal(node.dataset.id, item.id, "Node's ID should match item ID"); } } function* testContextMenu(syncedTabsDeckComponent, contextSelector, triggerSelector, menuSelectors) { let contextMenu = document.querySelector(contextSelector); - let triggerElement = syncedTabsDeckComponent.container.querySelector(triggerSelector); + let triggerElement = syncedTabsDeckComponent._window.document.querySelector(triggerSelector); let promisePopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown"); let chromeWindow = triggerElement.ownerDocument.defaultView.top; let rect = triggerElement.getBoundingClientRect(); let contentRect = chromeWindow.SidebarUI.browser.getBoundingClientRect(); // The offsets in `rect` are relative to the content window, but // `synthesizeMouseAtPoint` calls `nsIDOMWindowUtils.sendMouseEvent`,
--- a/browser/themes/shared/syncedtabs/sidebar.inc.css +++ b/browser/themes/shared/syncedtabs/sidebar.inc.css @@ -1,24 +1,44 @@ % This Source Code Form is subject to the terms of the Mozilla Public % License, v. 2.0. If a copy of the MPL was not distributed with this % file, You can obtain one at http://mozilla.org/MPL/2.0/. /* These styles are intended to mimic XUL trees and the XUL search box. */ -:root, body { - overflow-x: hidden; +html { + height: 100%; } body { + height: 100%; margin: 0; font: message-box; color: #333333; -moz-user-select: none; - overflow: hidden; +} + +/* The content-container holds the non-scrollable header and the scrollable + content area. +*/ +.content-container { + display: flex; + flex-flow: column; + height: 100%; +} + +/* The content header is not scrollable */ +.content-header { + flex: 0 1 auto; +} + +/* The main content area is scrollable and fills the rest of the area */ +.content-scrollable { + flex: 1 1 auto; + overflow: auto; } .emptyListInfo { cursor: default; padding: 3em 1em; text-align: center; } @@ -163,16 +183,20 @@ body { border-top: 0px; } .deck .sync-state.selected { display: unset; opacity: 100; } +.sidebar-search-container.tabs-container:not(.selected) { + display: none; +} + .textbox-search-clear:not([disabled]) { cursor: default; } .textbox-search-icons .textbox-search-clear, .filtered .textbox-search-icons .textbox-search-icon { display: none; }