Commit 4b3c1325 authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #298 from hypothesis/top-bar-component

Convert `<top-bar>` to a component
parents b39a0869 8d9bfa62
...@@ -156,9 +156,7 @@ module.exports = angular.module('h', [ ...@@ -156,9 +156,7 @@ module.exports = angular.module('h', [
.component('tagEditor', require('./components/tag-editor')) .component('tagEditor', require('./components/tag-editor'))
.component('threadList', require('./components/thread-list')) .component('threadList', require('./components/thread-list'))
.component('timestamp', require('./components/timestamp')) .component('timestamp', require('./components/timestamp'))
.component('topBar', require('./components/top-bar'))
// These should use `component()` but will require some changes.
.directive('topBar', require('./directive/top-bar'))
.directive('formInput', require('./directive/form-input')) .directive('formInput', require('./directive/form-input'))
.directive('formValidate', require('./directive/form-validate')) .directive('formValidate', require('./directive/form-validate'))
......
...@@ -2,12 +2,21 @@ ...@@ -2,12 +2,21 @@
var angular = require('angular'); var angular = require('angular');
var util = require('./util'); var util = require('../../directive/test/util');
describe('topBar', function () { describe('topBar', function () {
before(function () { before(function () {
angular.module('app', []) angular.module('app', [])
.directive('topBar', require('../top-bar')); .component('topBar', require('../top-bar'))
.component('loginControl', {
bindings: require('../login-control').bindings,
})
.component('searchInput', {
bindings: require('../search-input').bindings,
})
.component('sortDropdown', {
bindings: require('../sort-dropdown').bindings,
});
}); });
beforeEach(function () { beforeEach(function () {
...@@ -52,4 +61,68 @@ describe('topBar', function () { ...@@ -52,4 +61,68 @@ describe('topBar', function () {
applyBtn.click(); applyBtn.click();
assert.called(onApplyPendingUpdates); assert.called(onApplyPendingUpdates);
}); });
it('displays the login control and propagates callbacks', function () {
var onShowHelpPanel = sinon.stub();
var onLogin = sinon.stub();
var onLogout = sinon.stub();
var el = createTopBar({
onShowHelpPanel: onShowHelpPanel,
onLogin: onLogin,
onLogout: onLogout,
});
var loginControl = el.find('login-control').controller('loginControl');
loginControl.onShowHelpPanel();
assert.called(onShowHelpPanel);
loginControl.onLogin();
assert.called(onLogin);
loginControl.onLogout();
assert.called(onLogout);
});
it('displays the share page when "Share this page" is clicked', function () {
var onSharePage = sinon.stub();
var el = createTopBar({ onSharePage: onSharePage });
el.find('[title="Share this page"]').click();
assert.called(onSharePage);
});
it('displays the search input and propagates query changes', function () {
var onSearch = sinon.stub();
var el = createTopBar({
searchController: {
query: sinon.stub().returns('query'),
update: onSearch,
},
});
var searchInput = el.find('search-input').controller('searchInput');
assert.equal(searchInput.query, 'query');
searchInput.onSearch({$query: 'new-query'});
assert.calledWith(onSearch, 'new-query');
});
it('displays the sort dropdown and propagates sort key changes', function () {
var onChangeSortKey = sinon.stub();
var el = createTopBar({
sortKeysAvailable: ['Newest', 'Oldest'],
sortKey: 'Newest',
onChangeSortKey: {
args: ['sortKey'],
callback: onChangeSortKey,
},
});
var sortDropdown = el.find('sort-dropdown').controller('sortDropdown');
assert.deepEqual(sortDropdown.sortKeysAvailable, ['Newest', 'Oldest']);
assert.deepEqual(sortDropdown.sortKey, 'Newest');
sortDropdown.onChangeSortKey({sortKey: 'Oldest'});
assert.calledWith(onChangeSortKey, 'Oldest');
});
}); });
'use strict';
module.exports = {
controllerAs: 'vm',
bindings: {
auth: '<',
isSidebar: '<',
onShowHelpPanel: '&',
onLogin: '&',
onLogout: '&',
onSharePage: '&',
onSignUp: '&',
searchController: '<',
sortKey: '<',
sortKeysAvailable: '<',
onChangeSortKey: '&',
pendingUpdateCount: '<',
onApplyPendingUpdates: '&',
},
template: require('../templates/top_bar.html'),
};
'use strict';
module.exports = function () {
return {
controller: function () {},
restrict: 'E',
scope: {
auth: '<',
isSidebar: '<',
onShowHelpPanel: '&',
onLogin: '&',
onSignUp: '&',
onLogout: '&',
onSharePage: '&',
searchController: '<',
accountDialog: '<',
shareDialog: '<',
sortKey: '<',
sortKeysAvailable: '<',
onChangeSortKey: '&',
pendingUpdateCount: '<',
onApplyPendingUpdates: '&',
},
template: require('../templates/top_bar.html'),
};
};
<!-- top bar for the sidebar and the stream. <!-- top bar for the sidebar and the stream.
!--> !-->
<div class="top-bar" ng-class="frame.visible && 'shown'" ng-cloak> <div class="top-bar">
<!-- Legacy design for top bar, as used in the stream !--> <!-- Legacy design for top bar, as used in the stream !-->
<div class="top-bar__inner content" ng-if="::!isSidebar"> <div class="top-bar__inner content" ng-if="::!vm.isSidebar">
<search-input <search-input
class="search-input" class="search-input"
query="searchController.query()" query="vm.searchController.query()"
on-search="searchController.update($query)" on-search="vm.searchController.update($query)"
always-expanded="true"> always-expanded="true">
</search-input> </search-input>
<div class="top-bar__expander"></div> <div class="top-bar__expander"></div>
<login-control <login-control
auth="auth" auth="vm.auth"
new-style="false" new-style="false"
on-show-help-panel="onShowHelpPanel()" on-show-help-panel="vm.onShowHelpPanel()"
on-login="onLogin()" on-login="vm.onLogin()"
on-logout="onLogout()"> on-logout="vm.onLogout()">
</login-control> </login-control>
</div> </div>
<!-- New design for the top bar, as used in the sidebar. <!-- New design for the top bar, as used in the sidebar.
...@@ -23,41 +23,41 @@ ...@@ -23,41 +23,41 @@
The inner div is styled with 'content' to center it in The inner div is styled with 'content' to center it in
the stream view. the stream view.
!--> !-->
<div class="top-bar__inner content" ng-if="::isSidebar"> <div class="top-bar__inner content" ng-if="::vm.isSidebar">
<group-list class="group-list" auth="auth"></group-list> <group-list class="group-list" auth="vm.auth"></group-list>
<div class="top-bar__expander"></div> <div class="top-bar__expander"></div>
<a class="top-bar__apply-update-btn" <a class="top-bar__apply-update-btn"
ng-if="pendingUpdateCount > 0" ng-if="vm.pendingUpdateCount > 0"
ng-click="onApplyPendingUpdates()" ng-click="vm.onApplyPendingUpdates()"
h-tooltip h-tooltip
tooltip-direction="up" tooltip-direction="up"
aria-label="Show {{pendingUpdateCount}} new/updated annotation(s)"> aria-label="Show {{vm.pendingUpdateCount}} new/updated annotation(s)">
<svg-icon class="top-bar__apply-icon" name="'refresh'"></svg-icon> <svg-icon class="top-bar__apply-icon" name="'refresh'"></svg-icon>
</a> </a>
<search-input <search-input
class="search-input" class="search-input"
query="searchController.query()" query="vm.searchController.query()"
on-search="searchController.update($query)" on-search="vm.searchController.update($query)"
title="Filter the annotation list"> title="Filter the annotation list">
</search-input> </search-input>
<sort-dropdown <sort-dropdown
sort-keys-available="sortKeysAvailable" sort-keys-available="vm.sortKeysAvailable"
sort-key="sortKey" sort-key="vm.sortKey"
on-change-sort-key="onChangeSortKey({sortKey: sortKey})"> on-change-sort-key="vm.onChangeSortKey({sortKey: sortKey})">
</sort-dropdown> </sort-dropdown>
<a class="top-bar__btn" <a class="top-bar__btn"
ng-click="onSharePage()" ng-click="vm.onSharePage()"
title="Share this page"> title="Share this page">
<i class="h-icon-annotation-share"></i> <i class="h-icon-annotation-share"></i>
</a> </a>
<login-control <login-control
class="login-control" class="login-control"
auth="auth" auth="vm.auth"
new-style="true" new-style="true"
on-show-help-panel="onShowHelpPanel()" on-show-help-panel="vm.onShowHelpPanel()"
on-login="onLogin()" on-login="vm.onLogin()"
on-logout="onLogout()" on-logout="vm.onLogout()"
on-sign-up="onSignUp()"> on-sign-up="vm.onSignUp()">
</login-control> </login-control>
</div> </div>
</div> </div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment