Unverified Commit b22b7a3e authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #1161 from hypothesis/move-search-bar-funcs-to-search-bar

Move sidebar-content funcs to search-status-bar
parents 0198d32b cda20580
'use strict'; 'use strict';
const memoize = require('../util/memoize');
const uiConstants = require('../ui-constants'); const uiConstants = require('../ui-constants');
module.exports = { // @ngInject
controllerAs: 'vm', function SearchStatusBarController(store, rootThread) {
controller: function() {
this.TAB_ANNOTATIONS = uiConstants.TAB_ANNOTATIONS; this.TAB_ANNOTATIONS = uiConstants.TAB_ANNOTATIONS;
this.TAB_NOTES = uiConstants.TAB_NOTES; this.TAB_NOTES = uiConstants.TAB_NOTES;
this.TAB_ORPHANS = uiConstants.TAB_ORPHANS; this.TAB_ORPHANS = uiConstants.TAB_ORPHANS;
const thread = () => {
return rootThread.thread(store.getState());
};
const visibleCount = memoize(thread => {
return thread.children.reduce(
function(count, child) {
return count + visibleCount(child);
}, },
thread.visible ? 1 : 0
);
});
this.filterMatchCount = function() {
return visibleCount(thread());
};
this.areAllAnnotationsVisible = function() {
if (store.getState().directLinkedGroupFetchFailed) {
return true;
}
const selection = store.getState().selectedAnnotationMap;
if (!selection) {
return false;
}
return Object.keys(selection).length > 0;
};
}
module.exports = {
controller: SearchStatusBarController,
controllerAs: 'vm',
bindings: { bindings: {
filterActive: '<', filterActive: '<',
filterMatchCount: '<',
onClearSelection: '&', onClearSelection: '&',
searchQuery: '<', searchQuery: '<',
selectedTab: '<', selectedTab: '<',
// Boolean indicating all annotations are visible (none are hidden).
areAllAnnotationsVisible: '<',
totalAnnotations: '<', totalAnnotations: '<',
totalNotes: '<', totalNotes: '<',
}, },
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
const SearchClient = require('../search-client'); const SearchClient = require('../search-client');
const events = require('../events'); const events = require('../events');
const isThirdPartyService = require('../util/is-third-party-service'); const isThirdPartyService = require('../util/is-third-party-service');
const memoize = require('../util/memoize');
const tabs = require('../tabs'); const tabs = require('../tabs');
const uiConstants = require('../ui-constants'); const uiConstants = require('../ui-constants');
...@@ -279,17 +278,6 @@ function SidebarContentController( ...@@ -279,17 +278,6 @@ function SidebarContentController(
this.focus = focusAnnotation; this.focus = focusAnnotation;
this.scrollTo = scrollToAnnotation; this.scrollTo = scrollToAnnotation;
this.areAllAnnotationsVisible = function() {
if (store.getState().directLinkedGroupFetchFailed) {
return true;
}
const selection = store.getState().selectedAnnotationMap;
if (!selection) {
return false;
}
return Object.keys(selection).length > 0;
};
this.selectedGroupUnavailable = function() { this.selectedGroupUnavailable = function() {
return !this.isLoading() && store.getState().directLinkedGroupFetchFailed; return !this.isLoading() && store.getState().directLinkedGroupFetchFailed;
}; };
...@@ -328,23 +316,6 @@ function SidebarContentController( ...@@ -328,23 +316,6 @@ function SidebarContentController(
); );
}; };
const visibleCount = memoize(function(thread) {
return thread.children.reduce(
function(count, child) {
return count + visibleCount(child);
},
thread.visible ? 1 : 0
);
});
this.visibleCount = function() {
return visibleCount(thread());
};
this.topLevelThreadCount = function() {
return thread().totalChildren;
};
this.clearSelection = function() { this.clearSelection = function() {
let selectedTab = store.getState().selectedTab; let selectedTab = store.getState().selectedTab;
if ( if (
......
...@@ -4,33 +4,138 @@ const angular = require('angular'); ...@@ -4,33 +4,138 @@ const angular = require('angular');
const util = require('../../directive/test/util'); const util = require('../../directive/test/util');
describe('searchStatusBar', function() { describe('searchStatusBar', () => {
before(function() { before(() => {
angular angular
.module('app', []) .module('app', [])
.component('searchStatusBar', require('../search-status-bar')); .component('searchStatusBar', require('../search-status-bar'));
}); });
beforeEach(function() { let fakeRootThread;
angular.mock.module('app'); let fakeStore;
beforeEach(() => {
fakeRootThread = {
thread: sinon.stub(),
};
fakeStore = {
getState: sinon.stub(),
selectTab: sinon.stub(),
clearSelectedAnnotations: sinon.stub(),
clearDirectLinkedGroupFetchFailed: sinon.stub(),
clearDirectLinkedIds: sinon.stub(),
};
angular.mock.module('app', {
store: fakeStore,
rootThread: fakeRootThread,
});
});
describe('filterMatchCount', () => {
it('returns the total number of visible annotations or replies', () => {
fakeRootThread.thread.returns({
children: [
{
id: '1',
visible: true,
children: [{ id: '3', visible: true, children: [] }],
},
{
id: '2',
visible: false,
children: [],
},
],
}); });
context('when there is a filter', function() {
it('should display the filter count', function() {
const elem = util.createDirective(document, 'searchStatusBar', { const elem = util.createDirective(document, 'searchStatusBar', {
filterActive: true, filterActive: true,
filterMatchCount: 5,
}); });
assert.include(elem[0].textContent, '5 search results'); const ctrl = elem.ctrl;
assert.equal(ctrl.filterMatchCount(), 2);
});
});
describe('areAllAnnotationsVisible', () => {
it('returns true if the direct-linked group fetch failed', () => {
fakeStore.getState.returns({ directLinkedGroupFetchFailed: true });
const elem = util.createDirective(document, 'searchStatusBar', {});
const ctrl = elem.ctrl;
assert.isTrue(ctrl.areAllAnnotationsVisible());
});
it('returns true if there are annotations selected', () => {
fakeStore.getState.returns({
directLinkedGroupFetchFailed: false,
selectedAnnotationMap: { ann: true },
}); });
const elem = util.createDirective(document, 'searchStatusBar', {});
const ctrl = elem.ctrl;
assert.isTrue(ctrl.areAllAnnotationsVisible());
}); });
context('when there is a selection', function() { it('returns false if there are no annotations selected', () => {
it('should display the "Show all annotations (2)" message when there are 2 annotations', function() { fakeStore.getState.returns({
directLinkedGroupFetchFailed: false,
selectedAnnotationMap: {},
});
const elem = util.createDirective(document, 'searchStatusBar', {});
const ctrl = elem.ctrl;
assert.isFalse(ctrl.areAllAnnotationsVisible());
});
it('returns false if the `selectedAnnotationMap` is null', () => {
fakeStore.getState.returns({
directLinkedGroupFetchFailed: false,
selectedAnnotationMap: null,
});
const elem = util.createDirective(document, 'searchStatusBar', {});
const ctrl = elem.ctrl;
assert.isFalse(ctrl.areAllAnnotationsVisible());
});
});
context('when there is a filter', () => {
it('should display the filter count', () => {
fakeRootThread.thread.returns({
children: [
{
id: '1',
visible: true,
children: [{ id: '3', visible: true, children: [] }],
},
{
id: '2',
visible: false,
children: [],
},
],
});
const elem = util.createDirective(document, 'searchStatusBar', {
filterActive: true,
});
assert.include(elem[0].textContent, '2 search results');
});
});
context('when there is a selection', () => {
it('should display the "Show all annotations (2)" message when there are 2 annotations', () => {
const msg = 'Show all annotations'; const msg = 'Show all annotations';
const msgCount = '(2)'; const msgCount = '(2)';
fakeStore.getState.returns({
selectedAnnotationMap: { ann1: true },
});
const elem = util.createDirective(document, 'searchStatusBar', { const elem = util.createDirective(document, 'searchStatusBar', {
areAllAnnotationsVisible: true,
totalAnnotations: 2, totalAnnotations: 2,
selectedTab: 'annotation', selectedTab: 'annotation',
}); });
...@@ -39,11 +144,13 @@ describe('searchStatusBar', function() { ...@@ -39,11 +144,13 @@ describe('searchStatusBar', function() {
assert.include(clearBtn.textContent, msgCount); assert.include(clearBtn.textContent, msgCount);
}); });
it('should display the "Show all notes (3)" message when there are 3 notes', function() { it('should display the "Show all notes (3)" message when there are 3 notes', () => {
const msg = 'Show all notes'; const msg = 'Show all notes';
const msgCount = '(3)'; const msgCount = '(3)';
fakeStore.getState.returns({
selectedAnnotationMap: { ann1: true },
});
const elem = util.createDirective(document, 'searchStatusBar', { const elem = util.createDirective(document, 'searchStatusBar', {
areAllAnnotationsVisible: true,
totalNotes: 3, totalNotes: 3,
selectedTab: 'note', selectedTab: 'note',
}); });
......
...@@ -363,10 +363,6 @@ describe('sidebar.components.sidebar-content', function() { ...@@ -363,10 +363,6 @@ describe('sidebar.components.sidebar-content', function() {
}); });
}); });
it('areAllAnnotationsVisible returns true since there is an error message', () => {
assert.isTrue(ctrl.areAllAnnotationsVisible());
});
it('selectedGroupUnavailable returns true', () => { it('selectedGroupUnavailable returns true', () => {
assert.isTrue(ctrl.selectedGroupUnavailable()); assert.isTrue(ctrl.selectedGroupUnavailable());
}); });
...@@ -382,10 +378,6 @@ describe('sidebar.components.sidebar-content', function() { ...@@ -382,10 +378,6 @@ describe('sidebar.components.sidebar-content', function() {
$scope.$digest(); $scope.$digest();
}); });
it('areAllAnnotationsVisible returns false since group has no annotations', () => {
assert.isFalse(ctrl.areAllAnnotationsVisible());
});
it('selectedGroupUnavailable returns false', () => { it('selectedGroupUnavailable returns false', () => {
assert.isFalse(ctrl.selectedGroupUnavailable()); assert.isFalse(ctrl.selectedGroupUnavailable());
}); });
...@@ -408,10 +400,6 @@ describe('sidebar.components.sidebar-content', function() { ...@@ -408,10 +400,6 @@ describe('sidebar.components.sidebar-content', function() {
$scope.$digest(); $scope.$digest();
}); });
it('areAllAnnotationsVisible is true', function() {
assert.isTrue(ctrl.areAllAnnotationsVisible());
});
it("switches to the selected annotation's group", function() { it("switches to the selected annotation's group", function() {
assert.calledWith(fakeGroups.focus, '__world__'); assert.calledWith(fakeGroups.focus, '__world__');
assert.calledOnce(fakeAnnotationMapper.loadAnnotations); assert.calledOnce(fakeAnnotationMapper.loadAnnotations);
...@@ -438,10 +426,6 @@ describe('sidebar.components.sidebar-content', function() { ...@@ -438,10 +426,6 @@ describe('sidebar.components.sidebar-content', function() {
$scope.$digest(); $scope.$digest();
}); });
it('areAllAnnotationsVisible is false', function() {
assert.isFalse(ctrl.areAllAnnotationsVisible());
});
it('fetches annotations for the current group', function() { it('fetches annotations for the current group', function() {
assert.calledWith(searchClients[0].get, { assert.calledWith(searchClients[0].get, {
uri: [uri], uri: [uri],
...@@ -716,25 +700,4 @@ describe('sidebar.components.sidebar-content', function() { ...@@ -716,25 +700,4 @@ describe('sidebar.components.sidebar-content', function() {
}); });
}); });
}); });
describe('#visibleCount', function() {
it('returns the total number of visible annotations or replies', function() {
fakeRootThread.thread.returns({
children: [
{
id: '1',
visible: true,
children: [{ id: '3', visible: true, children: [] }],
},
{
id: '2',
visible: false,
children: [],
},
],
});
$scope.$digest();
assert.equal(ctrl.visibleCount(), 2);
});
});
}); });
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
<i class="primary-action-btn__icon h-icon-close"></i> Clear search <i class="primary-action-btn__icon h-icon-close"></i> Clear search
</button> </button>
<span ng-pluralize <span ng-pluralize
count="vm.filterMatchCount" count="vm.filterMatchCount()"
when="{'0': 'No results for “{{vm.searchQuery}}”', when="{'0': 'No results for “{{vm.searchQuery}}”',
'one': '1 search result', 'one': '1 search result',
'other': '{} search results'}"></span> 'other': '{} search results'}"></span>
</div> </div>
<div class="search-status-bar" ng-if="!vm.filterActive && vm.areAllAnnotationsVisible"> <div class="search-status-bar" ng-if="!vm.filterActive && vm.areAllAnnotationsVisible()">
<button class="primary-action-btn primary-action-btn--short" <button class="primary-action-btn primary-action-btn--short"
ng-click="vm.onClearSelection()" ng-click="vm.onClearSelection()"
title="Clear the selection and show all annotations"> title="Clear the selection and show all annotations">
......
...@@ -11,11 +11,8 @@ ...@@ -11,11 +11,8 @@
<search-status-bar <search-status-bar
ng-show="!vm.isLoading()" ng-show="!vm.isLoading()"
filter-active="!!vm.search.query()" filter-active="!!vm.search.query()"
filter-match-count="vm.visibleCount()"
on-clear-selection="vm.clearSelection()" on-clear-selection="vm.clearSelection()"
search-query="vm.search.query()" search-query="vm.search.query()"
are-all-annotations-visible="vm.areAllAnnotationsVisible()"
total-count="vm.topLevelThreadCount()"
selected-tab="vm.selectedTab" selected-tab="vm.selectedTab"
total-annotations="vm.totalAnnotations" total-annotations="vm.totalAnnotations"
total-notes="vm.totalNotes"> total-notes="vm.totalNotes">
......
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