From 4e0f9302bdf39478ac40b408c0c219fef4599e3e Mon Sep 17 00:00:00 2001 From: David Critchley Date: Thu, 8 Oct 2015 11:30:06 +0100 Subject: [PATCH] Bug 1212074 - Remove the tabs from Loop's panel. r=Standard8 --- browser/components/loop/content/css/panel.css | 146 +--------------- browser/components/loop/content/js/panel.js | 158 +----------------- browser/components/loop/content/js/panel.jsx | 158 +----------------- .../loop/test/desktop-local/panel_test.js | 63 ------- browser/components/loop/ui/ui-showcase.js | 28 ++-- browser/components/loop/ui/ui-showcase.jsx | 28 ++-- .../en-US/chrome/browser/loop/loop.properties | 3 - 7 files changed, 35 insertions(+), 549 deletions(-) diff --git a/browser/components/loop/content/css/panel.css b/browser/components/loop/content/css/panel.css index 285834b3fe64..8997eab0768d 100644 --- a/browser/components/loop/content/css/panel.css +++ b/browser/components/loop/content/css/panel.css @@ -76,147 +76,6 @@ body { border-radius: 3px; } -/* Tabs and tab selection buttons */ - -.tab-view-container { - width: 100%; - background-image: url("../shared/img/beta-ribbon.svg#beta-ribbon"); - background-color: #fbfbfb; - background-size: 36px 36px; - background-repeat: no-repeat; - flex: 1; - display: flex; - flex-flow: column nowrap; - overflow: hidden; -} - -.tab-view { - position: relative; - width: 100%; - height: 4rem; - line-height: 3.7rem; - color: #4A4A4A; - list-style: none; - border-bottom: 2px solid #ccc; -} - -.tab-view > li { - display: inline-block; - text-align: center; - padding: 0; - cursor: pointer; -} - -.tab-view > .slide-bar { - position: absolute; - bottom: -2px; - left: 0; - height: .2em; - width: 50%; - background: #00A9DC; - border: none; - transition: margin .3s ease-in-out; -} - -.tab-view li:nth-child(1).selected ~ .slide-bar { - margin-left: 0; -} - -.tab-view li:nth-child(2).selected ~ .slide-bar { - margin-left: 50%; -} - -html[dir="rtl"] .tab-view li:nth-child(1).selected ~ .slide-bar { - margin-left: 50%; -} - -html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar { - margin-left: 0; -} - -.tab-view > li > div { - font-size: 1.2rem; - pointer-events: none; - display: inline; -} - -.tab-view > li:before { - content: ""; - pointer-events: none; - display: inline-block; - -moz-margin-end: .5rem; - vertical-align: middle; - height: 1.4rem; - width: 1.4rem; - transition-property: background-image; -} - -.tab-view > li.selected { - transition-delay: .3s; -} - -.tab-view > li[data-tab-name="rooms"]:before { - background-image: url("../shared/img/icons-14x14.svg#hello"); -} - -.tab-view > li[data-tab-name="rooms"]:hover:before { - background-image: url("../shared/img/icons-14x14.svg#hello-hover"); -} - -.tab-view > li[data-tab-name="rooms"].selected:before { - background-image: url("../shared/img/icons-14x14.svg#hello-active"); -} - -.tab-view > li[data-tab-name="contacts"]:before { - background-image: url("../shared/img/icons-14x14.svg#contacts"); -} - -.tab-view > li[data-tab-name="contacts"]:hover:before { - background-image: url("../shared/img/icons-14x14.svg#contacts-hover"); -} - -.tab-view > li[data-tab-name="contacts"].selected:before { - background-image: url("../shared/img/icons-14x14.svg#contacts-active"); -} - -/* Styling for one tab */ -.tab-view li:first-child:nth-last-child(2) { - width: 100%; -} - -.tab-view li:first-child:nth-last-child(2) > span { - display: none; -} - -.tab-view li:first-child:nth-last-child(2) > span { - display: none; -} - -.tab-view li:first-child:nth-last-child(2):before { - background-image: url("../shared/img/icons-14x14.svg#hello-hover"); -} - -.tab-view li:first-child:nth-last-child(2) ~ li { - /* hide the tab-slider when there is only one tab shown */ - display: none; -} - -.tab-view li:first-child:nth-last-child(3), -.tab-view li:first-child:nth-last-child(3) ~ li { - width: 50%; -} - -.tab { - display: none; - flex: 1; - overflow: auto; -} - -.tab.selected { - display: flex; - flex-flow: column nowrap; -} - /* Content area and input fields */ .content-area { @@ -232,8 +91,7 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar { -moz-padding-start: 20px; } -.fte-get-started-container + .generate-url > #share-link-header, -.tab-view + .tab .content-area > .generate-url > #share-link-header { +.fte-get-started-container + .generate-url > #share-link-header { /* The header shouldn't be indented if the tabs are present. */ -moz-padding-start: 0; } @@ -331,6 +189,7 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar { flex: 1; display: flex; flex-flow: column nowrap; + width: 100%; } .rooms > h1 { @@ -414,6 +273,7 @@ html[dir="rtl"] .tab-view li:nth-child(2).selected ~ .slide-bar { overflow-x: hidden; display: flex; flex-flow: column nowrap; + width: 100%; } .room-list-empty { diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js index 36a1e2561a76..fa74e0d85527 100644 --- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -10,109 +10,8 @@ loop.panel = (function(_, mozL10n) { var sharedModels = loop.shared.models; var sharedMixins = loop.shared.mixins; var sharedActions = loop.shared.actions; - var sharedUtils = loop.shared.utils; var Button = sharedViews.Button; - var ButtonGroup = sharedViews.ButtonGroup; var Checkbox = sharedViews.Checkbox; - var ContactsControllerView = loop.contacts.ContactsControllerView; - - var TabView = React.createClass({displayName: "TabView", - propTypes: { - buttonsHidden: React.PropTypes.array, - children: React.PropTypes.arrayOf(React.PropTypes.element), - mozLoop: React.PropTypes.object, - // The selectedTab prop is used by the UI showcase. - selectedTab: React.PropTypes.string - }, - - getDefaultProps: function() { - return { - buttonsHidden: [] - }; - }, - - shouldComponentUpdate: function(nextProps, nextState) { - var tabChange = this.state.selectedTab !== nextState.selectedTab; - if (tabChange) { - this.props.mozLoop.notifyUITour("Loop:PanelTabChanged", nextState.selectedTab); - } - - if (!tabChange && nextProps.buttonsHidden) { - if (nextProps.buttonsHidden.length !== this.props.buttonsHidden.length) { - tabChange = true; - } else { - for (var i = 0, l = nextProps.buttonsHidden.length; i < l && !tabChange; ++i) { - if (this.props.buttonsHidden.indexOf(nextProps.buttonsHidden[i]) === -1) { - tabChange = true; - } - } - } - } - return tabChange; - }, - - getInitialState: function() { - // XXX Work around props.selectedTab being undefined initially. - // When we don't need to rely on the pref, this can move back to - // getDefaultProps (bug 1100258). - return { - selectedTab: this.props.selectedTab || "rooms" - }; - }, - - handleSelectTab: function(event) { - var tabName = event.target.dataset.tabName; - this.setState({selectedTab: tabName}); - }, - - render: function() { - var cx = React.addons.classSet; - var tabButtons = []; - var tabs = []; - React.Children.forEach(this.props.children, function(tab, i) { - // Filter out null tabs (eg. rooms when the feature is disabled) - if (!tab) { - return; - } - var tabName = tab.props.name; - if (this.props.buttonsHidden.indexOf(tabName) > -1) { - return; - } - var isSelected = (this.state.selectedTab === tabName); - if (!tab.props.hidden) { - var label = mozL10n.get(tabName + "_tab_button"); - tabButtons.push( - React.createElement("li", {className: cx({selected: isSelected}), - "data-tab-name": tabName, - key: i, - onClick: this.handleSelectTab}, - React.createElement("div", null, label) - ) - ); - } - tabs.push( - React.createElement("div", {className: cx({tab: true, selected: isSelected}), key: i}, - tab.props.children - ) - ); - }, this); - return ( - React.createElement("div", {className: "tab-view-container"}, - React.createElement("ul", {className: "tab-view"}, - tabButtons, - React.createElement("li", {className: "slide-bar"}) - ), - tabs - ) - ); - } - }); - - var Tab = React.createClass({displayName: "Tab", - render: function() { - return null; - } - }); /** * Availability drop down menu subview. @@ -1001,14 +900,10 @@ loop.panel = (function(_, mozL10n) { var PanelView = React.createClass({displayName: "PanelView", propTypes: { dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, - initialSelectedTabComponent: React.PropTypes.string, mozLoop: React.PropTypes.object.isRequired, notifications: React.PropTypes.object.isRequired, roomStore: - React.PropTypes.instanceOf(loop.store.RoomStore).isRequired, - selectedTab: React.PropTypes.string, - // Used only for unit tests. - showTabButtons: React.PropTypes.bool + React.PropTypes.instanceOf(loop.store.RoomStore).isRequired }, getInitialState: function() { @@ -1056,8 +951,6 @@ loop.panel = (function(_, mozL10n) { // Update the state of hasEncryptionKey as this might have changed now. this.setState({hasEncryptionKey: this.props.mozLoop.hasEncryptionKey}); } else { - // On profile change (login, logout), switch back to the default tab. - this.selectTab("rooms"); this.setState({userProfile: profile}); } this.updateServiceErrors(); @@ -1069,25 +962,6 @@ loop.panel = (function(_, mozL10n) { }); }, - _UIActionHandler: function(e) { - switch (e.detail.action) { - case "selectTab": - this.selectTab(e.detail.tab); - break; - default: - console.error("Invalid action", e.detail.action); - break; - } - }, - - selectTab: function(name) { - // The tab view might not be created yet (e.g. getting started or fxa - // re-sign in. - if (this.refs.tabView) { - this.refs.tabView.setState({ selectedTab: name }); - } - }, - componentWillMount: function() { this.updateServiceErrors(); }, @@ -1095,13 +969,11 @@ loop.panel = (function(_, mozL10n) { componentDidMount: function() { window.addEventListener("LoopStatusChanged", this._onStatusChanged); window.addEventListener("GettingStartedSeen", this._gettingStartedSeen); - window.addEventListener("UIAction", this._UIActionHandler); }, componentWillUnmount: function() { window.removeEventListener("LoopStatusChanged", this._onStatusChanged); window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen); - window.removeEventListener("UIAction", this._UIActionHandler); }, render: function() { @@ -1123,35 +995,15 @@ loop.panel = (function(_, mozL10n) { return React.createElement(SignInRequestView, {mozLoop: this.props.mozLoop}); } - // Determine which buttons to NOT show. - var hideButtons = []; - if (!this.state.userProfile && !this.props.showTabButtons) { - hideButtons.push("contacts"); - } - return ( React.createElement("div", {className: "panel-content"}, React.createElement(NotificationListView, { clearOnDocumentHidden: true, notifications: this.props.notifications}), - React.createElement(TabView, { - buttonsHidden: hideButtons, - mozLoop: this.props.mozLoop, - ref: "tabView", - selectedTab: this.props.selectedTab}, - React.createElement(Tab, {name: "rooms"}, - React.createElement(RoomList, {dispatcher: this.props.dispatcher, - mozLoop: this.props.mozLoop, - store: this.props.roomStore, - userProfile: this.state.userProfile}) - ), - React.createElement(Tab, {name: "contacts"}, - React.createElement(ContactsControllerView, {initialSelectedTabComponent: this.props.initialSelectedTabComponent, - mozLoop: this.props.mozLoop, - notifications: this.props.notifications, - ref: "contactControllerView"}) - ) - ), + React.createElement(RoomList, {dispatcher: this.props.dispatcher, + mozLoop: this.props.mozLoop, + store: this.props.roomStore, + userProfile: this.state.userProfile}), React.createElement("div", {className: "footer"}, React.createElement("div", {className: "user-details"}, React.createElement(AvailabilityDropdown, null) diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx index eeb0f4c289b3..ae133b8a7ca3 100644 --- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -10,109 +10,8 @@ loop.panel = (function(_, mozL10n) { var sharedModels = loop.shared.models; var sharedMixins = loop.shared.mixins; var sharedActions = loop.shared.actions; - var sharedUtils = loop.shared.utils; var Button = sharedViews.Button; - var ButtonGroup = sharedViews.ButtonGroup; var Checkbox = sharedViews.Checkbox; - var ContactsControllerView = loop.contacts.ContactsControllerView; - - var TabView = React.createClass({ - propTypes: { - buttonsHidden: React.PropTypes.array, - children: React.PropTypes.arrayOf(React.PropTypes.element), - mozLoop: React.PropTypes.object, - // The selectedTab prop is used by the UI showcase. - selectedTab: React.PropTypes.string - }, - - getDefaultProps: function() { - return { - buttonsHidden: [] - }; - }, - - shouldComponentUpdate: function(nextProps, nextState) { - var tabChange = this.state.selectedTab !== nextState.selectedTab; - if (tabChange) { - this.props.mozLoop.notifyUITour("Loop:PanelTabChanged", nextState.selectedTab); - } - - if (!tabChange && nextProps.buttonsHidden) { - if (nextProps.buttonsHidden.length !== this.props.buttonsHidden.length) { - tabChange = true; - } else { - for (var i = 0, l = nextProps.buttonsHidden.length; i < l && !tabChange; ++i) { - if (this.props.buttonsHidden.indexOf(nextProps.buttonsHidden[i]) === -1) { - tabChange = true; - } - } - } - } - return tabChange; - }, - - getInitialState: function() { - // XXX Work around props.selectedTab being undefined initially. - // When we don't need to rely on the pref, this can move back to - // getDefaultProps (bug 1100258). - return { - selectedTab: this.props.selectedTab || "rooms" - }; - }, - - handleSelectTab: function(event) { - var tabName = event.target.dataset.tabName; - this.setState({selectedTab: tabName}); - }, - - render: function() { - var cx = React.addons.classSet; - var tabButtons = []; - var tabs = []; - React.Children.forEach(this.props.children, function(tab, i) { - // Filter out null tabs (eg. rooms when the feature is disabled) - if (!tab) { - return; - } - var tabName = tab.props.name; - if (this.props.buttonsHidden.indexOf(tabName) > -1) { - return; - } - var isSelected = (this.state.selectedTab === tabName); - if (!tab.props.hidden) { - var label = mozL10n.get(tabName + "_tab_button"); - tabButtons.push( -
  • -
    {label}
    -
  • - ); - } - tabs.push( -
    - {tab.props.children} -
    - ); - }, this); - return ( -
    - - {tabs} -
    - ); - } - }); - - var Tab = React.createClass({ - render: function() { - return null; - } - }); /** * Availability drop down menu subview. @@ -1001,14 +900,10 @@ loop.panel = (function(_, mozL10n) { var PanelView = React.createClass({ propTypes: { dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, - initialSelectedTabComponent: React.PropTypes.string, mozLoop: React.PropTypes.object.isRequired, notifications: React.PropTypes.object.isRequired, roomStore: - React.PropTypes.instanceOf(loop.store.RoomStore).isRequired, - selectedTab: React.PropTypes.string, - // Used only for unit tests. - showTabButtons: React.PropTypes.bool + React.PropTypes.instanceOf(loop.store.RoomStore).isRequired }, getInitialState: function() { @@ -1056,8 +951,6 @@ loop.panel = (function(_, mozL10n) { // Update the state of hasEncryptionKey as this might have changed now. this.setState({hasEncryptionKey: this.props.mozLoop.hasEncryptionKey}); } else { - // On profile change (login, logout), switch back to the default tab. - this.selectTab("rooms"); this.setState({userProfile: profile}); } this.updateServiceErrors(); @@ -1069,25 +962,6 @@ loop.panel = (function(_, mozL10n) { }); }, - _UIActionHandler: function(e) { - switch (e.detail.action) { - case "selectTab": - this.selectTab(e.detail.tab); - break; - default: - console.error("Invalid action", e.detail.action); - break; - } - }, - - selectTab: function(name) { - // The tab view might not be created yet (e.g. getting started or fxa - // re-sign in. - if (this.refs.tabView) { - this.refs.tabView.setState({ selectedTab: name }); - } - }, - componentWillMount: function() { this.updateServiceErrors(); }, @@ -1095,13 +969,11 @@ loop.panel = (function(_, mozL10n) { componentDidMount: function() { window.addEventListener("LoopStatusChanged", this._onStatusChanged); window.addEventListener("GettingStartedSeen", this._gettingStartedSeen); - window.addEventListener("UIAction", this._UIActionHandler); }, componentWillUnmount: function() { window.removeEventListener("LoopStatusChanged", this._onStatusChanged); window.removeEventListener("GettingStartedSeen", this._gettingStartedSeen); - window.removeEventListener("UIAction", this._UIActionHandler); }, render: function() { @@ -1123,35 +995,15 @@ loop.panel = (function(_, mozL10n) { return ; } - // Determine which buttons to NOT show. - var hideButtons = []; - if (!this.state.userProfile && !this.props.showTabButtons) { - hideButtons.push("contacts"); - } - return (
    - - - - - - - - +
    diff --git a/browser/components/loop/test/desktop-local/panel_test.js b/browser/components/loop/test/desktop-local/panel_test.js index cb51b81fe3e4..4881694f622d 100644 --- a/browser/components/loop/test/desktop-local/panel_test.js +++ b/browser/components/loop/test/desktop-local/panel_test.js @@ -210,69 +210,6 @@ describe("loop.panel", function() { .to.have.length.of(0); }); - describe("TabView", function() { - var view, callTab, roomsTab, contactsTab; - - beforeEach(function() { - navigator.mozLoop.getLoopPref = function(pref) { - if (pref === "gettingStarted.seen") { - return true; - } - }; - - view = createTestPanelView(); - - [roomsTab, contactsTab] = - TestUtils.scryRenderedDOMComponentsWithClass(view, "tab"); - }); - - it("should select contacts tab when clicking tab button", function() { - TestUtils.Simulate.click( - view.getDOMNode().querySelector("li[data-tab-name=\"contacts\"]")); - - expect(contactsTab.getDOMNode().classList.contains("selected")) - .to.be.true; - }); - - it("should select rooms tab when clicking tab button", function() { - TestUtils.Simulate.click( - view.getDOMNode().querySelector("li[data-tab-name=\"rooms\"]")); - - expect(roomsTab.getDOMNode().classList.contains("selected")) - .to.be.true; - }); - }); - - describe("Contacts", function() { - var view, roomsTab, contactsTab; - - beforeEach(function() { - view = TestUtils.renderIntoDocument( - React.createElement(loop.panel.PanelView, { - dispatcher: dispatcher, - initialSelectedTabComponent: "contactList", - mozLoop: navigator.mozLoop, - notifications: notifications, - roomStore: roomStore, - selectedTab: "contacts", - showTabButtons: true - })); - - [roomsTab, contactsTab] = - TestUtils.scryRenderedDOMComponentsWithClass(view, "tab"); - }); - - it("should expect Contacts tab to be selected when Contacts List displayed", function() { - expect(contactsTab.getDOMNode().classList.contains("selected")) - .to.be.true; - }); - - it("should expect Rooms tab to be not selected when Contacts List displayed", function() { - expect(roomsTab.getDOMNode().classList.contains("selected")) - .to.be.false; - }); - }); - describe("AccountLink", function() { beforeEach(function() { navigator.mozLoop.calls = { clearCallInProgress: function() {} }; diff --git a/browser/components/loop/ui/ui-showcase.js b/browser/components/loop/ui/ui-showcase.js index 5863803c7e31..bc4b4493b6a2 100644 --- a/browser/components/loop/ui/ui-showcase.js +++ b/browser/components/loop/ui/ui-showcase.js @@ -766,8 +766,7 @@ dispatcher: dispatcher, mozLoop: firstTimeUseMozLoop, notifications: notifications, - roomStore: roomStore, - selectedTab: "rooms"}) + roomStore: roomStore}) ) ), @@ -784,75 +783,70 @@ React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 410, - summary: "Room list tab", + summary: "Room list", width: 330}, React.createElement("div", {className: "panel"}, React.createElement(PanelView, {client: mockClient, dispatcher: dispatcher, mozLoop: mockMozLoopLoggedIn, notifications: notifications, - roomStore: roomStore, - selectedTab: "rooms"}) + roomStore: roomStore}) ) ), React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 410, - summary: "Room list tab (No Context)", + summary: "Room list (No Context)", width: 330}, React.createElement("div", {className: "panel"}, React.createElement(PanelView, {client: mockClient, dispatcher: dispatcher, mozLoop: mockMozLoopLoggedInNoContext, notifications: notifications, - roomStore: roomStore, - selectedTab: "rooms"}) + roomStore: roomStore}) ) ), React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 410, - summary: "Room list tab (no rooms)", + summary: "Room list (no rooms)", width: 330}, React.createElement("div", {className: "panel"}, React.createElement(PanelView, {client: mockClient, dispatcher: dispatcher, mozLoop: mockMozLoopNoRooms, notifications: notifications, - roomStore: roomStoreNoRooms, - selectedTab: "rooms"}) + roomStore: roomStoreNoRooms}) ) ), React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 410, - summary: "Room list tab (no rooms and no context)", + summary: "Room list (no rooms and no context)", width: 330}, React.createElement("div", {className: "panel"}, React.createElement(PanelView, {client: mockClient, dispatcher: dispatcher, mozLoop: mockMozLoopNoRoomsNoContext, notifications: notifications, - roomStore: roomStoreNoRooms, - selectedTab: "rooms"}) + roomStore: roomStoreNoRooms}) ) ), React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 410, - summary: "Room list tab (loading view)", + summary: "Room list (loading view)", width: 330}, React.createElement("div", {className: "panel"}, React.createElement(PanelView, {client: mockClient, dispatcher: dispatcher, mozLoop: mockMozLoopNoRoomsNoContext, notifications: notifications, - roomStore: roomStoreNoRoomsPending, - selectedTab: "rooms"}) + roomStore: roomStoreNoRoomsPending}) ) ), diff --git a/browser/components/loop/ui/ui-showcase.jsx b/browser/components/loop/ui/ui-showcase.jsx index 243709c8c3b4..7a0300bdd133 100644 --- a/browser/components/loop/ui/ui-showcase.jsx +++ b/browser/components/loop/ui/ui-showcase.jsx @@ -766,8 +766,7 @@ dispatcher={dispatcher} mozLoop={firstTimeUseMozLoop} notifications={notifications} - roomStore={roomStore} - selectedTab="rooms" /> + roomStore={roomStore} />
    @@ -784,75 +783,70 @@
    + roomStore={roomStore} />
    + roomStore={roomStore} />
    + roomStore={roomStoreNoRooms} />
    + roomStore={roomStoreNoRooms} />
    + roomStore={roomStoreNoRoomsPending} />
    diff --git a/browser/locales/en-US/chrome/browser/loop/loop.properties b/browser/locales/en-US/chrome/browser/loop/loop.properties index 0c24eafd83a7..119c04746b7d 100644 --- a/browser/locales/en-US/chrome/browser/loop/loop.properties +++ b/browser/locales/en-US/chrome/browser/loop/loop.properties @@ -9,9 +9,6 @@ clientShortname2=Firefox Hello clientSuperShortname=Hello -rooms_tab_button=Conversations -contacts_tab_button=Contacts - ## LOCALIZATION_NOTE(sign_in_again_title_line_one, sign_in_again_title_line_two2): ## These are displayed together at the top of the panel when a user is needed to ## sign-in again. The emphesis is on the first line to get the user to sign-in again,