Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
90bcfb11
Unverified
Commit
90bcfb11
authored
Mar 28, 2019
by
Robert Knight
Committed by
GitHub
Mar 28, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1018 from hypothesis/refactor-group-sections
Refactor new groups menu
parents
3f1f9c33
92b9aae3
Changes
22
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
850 additions
and
326 deletions
+850
-326
group-list-item-out-of-scope.js
src/sidebar/components/group-list-item-out-of-scope.js
+37
-0
group-list-item.js
src/sidebar/components/group-list-item.js
+35
-0
group-list-section.js
src/sidebar/components/group-list-section.js
+23
-0
group-list.js
src/sidebar/components/group-list.js
+0
-20
group-list-item-out-of-scope-test.js
...ebar/components/test/group-list-item-out-of-scope-test.js
+106
-0
group-list-item-test.js
src/sidebar/components/test/group-list-item-test.js
+111
-0
group-list-section-test.js
src/sidebar/components/test/group-list-section-test.js
+71
-0
group-list-test.js
src/sidebar/components/test/group-list-test.js
+16
-88
index.js
src/sidebar/index.js
+6
-0
group-list-item-out-of-scope.html
src/sidebar/templates/group-list-item-out-of-scope.html
+64
-0
group-list-item.html
src/sidebar/templates/group-list-item.html
+25
-0
group-list-section.html
src/sidebar/templates/group-list-section.html
+23
-0
group-list.html
src/sidebar/templates/group-list.html
+135
-162
group-list-item-common.js
src/sidebar/util/group-list-item-common.js
+14
-0
group-list-item-common-test.js
src/sidebar/util/test/group-list-item-common-test.js
+37
-0
common.scss
src/styles/sidebar/common.scss
+4
-0
group-list-item-out-of-scope.scss
...yles/sidebar/components/group-list-item-out-of-scope.scss
+50
-0
group-list-item.scss
src/styles/sidebar/components/group-list-item.scss
+73
-0
group-list-section.scss
src/styles/sidebar/components/group-list-section.scss
+14
-0
group-list.scss
src/styles/sidebar/components/group-list.scss
+2
-56
sidebar.scss
src/styles/sidebar/sidebar.scss
+3
-0
variables.scss
src/styles/variables.scss
+1
-0
No files found.
src/sidebar/components/group-list-item-out-of-scope.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
{
orgName
,
trackViewGroupActivity
,
}
=
require
(
'../util/group-list-item-common'
);
// @ngInject
function
GroupListItemOutOfScopeController
(
analytics
)
{
// Track whether the group details are expanded.
this
.
isDetailsExpanded
=
false
;
/**
* Toggle the expanded setting on un-selectable groups.
*/
this
.
toggleGroupDetails
=
function
(
event
)
{
event
.
stopPropagation
();
this
.
isDetailsExpanded
=
!
this
.
isDetailsExpanded
;
};
this
.
orgName
=
function
()
{
return
orgName
(
this
.
group
);
};
this
.
trackViewGroupActivity
=
function
()
{
trackViewGroupActivity
(
analytics
);
};
}
module
.
exports
=
{
controller
:
GroupListItemOutOfScopeController
,
controllerAs
:
'vm'
,
bindings
:
{
group
:
'<'
,
},
template
:
require
(
'../templates/group-list-item-out-of-scope.html'
),
};
src/sidebar/components/group-list-item.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
{
orgName
,
trackViewGroupActivity
,
}
=
require
(
'../util/group-list-item-common'
);
// @ngInject
function
GroupListItemController
(
analytics
,
store
)
{
this
.
focusGroup
=
function
()
{
analytics
.
track
(
analytics
.
events
.
GROUP_SWITCH
);
store
.
focusGroup
(
this
.
group
.
id
);
};
this
.
isSelected
=
function
()
{
return
this
.
group
.
id
===
store
.
focusedGroupId
();
};
this
.
orgName
=
function
()
{
return
orgName
(
this
.
group
);
};
this
.
trackViewGroupActivity
=
function
()
{
trackViewGroupActivity
(
analytics
);
};
}
module
.
exports
=
{
controller
:
GroupListItemController
,
controllerAs
:
'vm'
,
bindings
:
{
group
:
'<'
,
},
template
:
require
(
'../templates/group-list-item.html'
),
};
src/sidebar/components/group-list-section.js
0 → 100644
View file @
90bcfb11
'use strict'
;
// @ngInject
function
GroupListSectionController
()
{
this
.
isSelectable
=
function
(
groupId
)
{
const
group
=
this
.
sectionGroups
.
find
(
g
=>
g
.
id
===
groupId
);
return
!
this
.
disableOosGroupSelection
||
group
.
isScopedToUri
;
};
}
module
.
exports
=
{
controller
:
GroupListSectionController
,
controllerAs
:
'vm'
,
bindings
:
{
/* The list of groups to be displayed in the group list section. */
sectionGroups
:
'<'
,
/* The string name of the group list section. */
heading
:
'<'
,
/* A boolean indicating whether out of scope group selection should be disabled. */
disableOosGroupSelection
:
'<'
,
},
template
:
require
(
'../templates/group-list-section.html'
),
};
src/sidebar/components/group-list.js
View file @
90bcfb11
...
...
@@ -26,9 +26,6 @@ function GroupListController(
)
{
this
.
groups
=
groups
;
// Track which non-selectable groups have their group details expanded.
this
.
groupDetailsExpanded
=
{};
this
.
createNewGroup
=
function
()
{
$window
.
open
(
serviceUrl
(
'groups.new'
),
'_blank'
);
};
...
...
@@ -90,23 +87,6 @@ function GroupListController(
groups
.
focus
(
groupId
);
};
this
.
isGroupDetailsExpanded
=
function
(
groupId
)
{
if
(
!
(
groupId
in
this
.
groupDetailsExpanded
))
{
this
.
groupDetailsExpanded
[
groupId
]
=
false
;
}
return
this
.
groupDetailsExpanded
[
groupId
];
};
/**
* Toggle the expanded setting on un-selectable groups.
*/
this
.
toggleGroupDetails
=
function
(
event
,
groupId
)
{
event
.
stopPropagation
();
// Call the isGroupDetailsExpanded method so that if the groupId doesn't exist,
// it gets added before toggling it.
this
.
groupDetailsExpanded
[
groupId
]
=
!
this
.
isGroupDetailsExpanded
(
groupId
);
};
/**
* Show the share link for the group if it is not a third-party group
* AND if the URL needed is present in the group object. We should be able
...
...
src/sidebar/components/test/group-list-item-out-of-scope-test.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
angular
=
require
(
'angular'
);
const
proxyquire
=
require
(
'proxyquire'
);
const
util
=
require
(
'../../directive/test/util'
);
const
{
events
}
=
require
(
'../../services/analytics'
);
describe
(
'groupListItemOutOfScope'
,
()
=>
{
let
fakeAnalytics
;
let
fakeGroupListItemCommon
;
before
(()
=>
{
fakeGroupListItemCommon
=
{
orgName
:
sinon
.
stub
(),
trackViewGroupActivity
:
sinon
.
stub
(),
};
// Return groupListItemOutOfScope with groupListItemCommon stubbed out.
const
groupListItemOutOfScope
=
proxyquire
(
'../group-list-item-out-of-scope'
,
{
'../util/group-list-item-common'
:
fakeGroupListItemCommon
,
'@noCallThru'
:
true
,
}
);
angular
.
module
(
'app'
,
[])
.
component
(
'groupListItemOutOfScope'
,
groupListItemOutOfScope
);
});
beforeEach
(()
=>
{
fakeAnalytics
=
{
track
:
sinon
.
stub
(),
events
,
};
angular
.
mock
.
module
(
'app'
,
{
analytics
:
fakeAnalytics
});
});
const
createGroupListItemOutOfScope
=
fakeGroup
=>
{
return
util
.
createDirective
(
document
,
'groupListItemOutOfScope'
,
{
group
:
fakeGroup
,
});
};
it
(
'calls groupListItemCommon.trackViewGroupActivity when trackViewGroupActivity is called'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItemOutOfScope
(
fakeGroup
);
element
.
ctrl
.
trackViewGroupActivity
();
assert
.
calledWith
(
fakeGroupListItemCommon
.
trackViewGroupActivity
,
fakeAnalytics
);
});
it
(
'returns groupListItemCommon.orgName when orgName is called'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
,
organization
:
{
name
:
'org'
}
};
fakeGroupListItemCommon
.
orgName
.
withArgs
(
fakeGroup
)
.
returns
(
fakeGroup
.
organization
.
name
);
const
element
=
createGroupListItemOutOfScope
(
fakeGroup
);
const
orgName
=
element
.
ctrl
.
orgName
();
assert
.
calledWith
(
fakeGroupListItemCommon
.
orgName
,
fakeGroup
);
assert
.
equal
(
orgName
,
fakeGroup
.
organization
.
name
);
});
describe
(
'toggleGroupDetails'
,
()
=>
{
it
(
'sets the default expanded value to false'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItemOutOfScope
(
fakeGroup
);
assert
.
isFalse
(
element
.
ctrl
.
isDetailsExpanded
);
});
it
(
'toggles the expanded value'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItemOutOfScope
(
fakeGroup
);
const
fakeEvent
=
{
stopPropagation
:
sinon
.
stub
()
};
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
);
assert
.
isTrue
(
element
.
ctrl
.
isDetailsExpanded
);
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
);
assert
.
isFalse
(
element
.
ctrl
.
isDetailsExpanded
);
});
it
(
'stops the event from propagating when toggling'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItemOutOfScope
(
fakeGroup
);
const
fakeEvent
=
{
stopPropagation
:
sinon
.
spy
()
};
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
);
sinon
.
assert
.
called
(
fakeEvent
.
stopPropagation
);
});
});
});
src/sidebar/components/test/group-list-item-test.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
angular
=
require
(
'angular'
);
const
proxyquire
=
require
(
'proxyquire'
);
const
util
=
require
(
'../../directive/test/util'
);
const
{
events
}
=
require
(
'../../services/analytics'
);
describe
(
'groupListItem'
,
()
=>
{
let
fakeAnalytics
;
let
fakeStore
;
let
fakeGroupListItemCommon
;
before
(()
=>
{
fakeGroupListItemCommon
=
{
orgName
:
sinon
.
stub
(),
trackViewGroupActivity
:
sinon
.
stub
(),
};
// Return groupListItem with groupListItemCommon stubbed out.
const
groupListItem
=
proxyquire
(
'../group-list-item'
,
{
'../util/group-list-item-common'
:
fakeGroupListItemCommon
,
'@noCallThru'
:
true
,
});
angular
.
module
(
'app'
,
[]).
component
(
'groupListItem'
,
groupListItem
);
});
beforeEach
(()
=>
{
fakeStore
=
{
focusGroup
:
sinon
.
stub
(),
focusedGroupId
:
sinon
.
stub
().
returns
(
'groupid'
),
};
fakeAnalytics
=
{
track
:
sinon
.
stub
(),
events
,
};
angular
.
mock
.
module
(
'app'
,
{
analytics
:
fakeAnalytics
,
store
:
fakeStore
,
});
});
const
createGroupListItem
=
fakeGroup
=>
{
return
util
.
createDirective
(
document
,
'groupListItem'
,
{
group
:
fakeGroup
,
});
};
it
(
'changes the focused group when group is clicked'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItem
(
fakeGroup
);
const
group
=
element
.
find
(
'.group-list-item__item'
);
group
[
0
].
click
();
assert
.
calledWith
(
fakeStore
.
focusGroup
,
fakeGroup
.
id
);
assert
.
calledWith
(
fakeAnalytics
.
track
,
fakeAnalytics
.
events
.
GROUP_SWITCH
);
});
it
(
'calls groupListItemCommon.trackViewGroupActivity when trackViewGroupActivity is called'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItem
(
fakeGroup
);
element
.
ctrl
.
trackViewGroupActivity
();
assert
.
calledWith
(
fakeGroupListItemCommon
.
trackViewGroupActivity
,
fakeAnalytics
);
});
it
(
'returns groupListItemCommon.orgName when orgName is called'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
,
organization
:
{
name
:
'org'
}
};
fakeGroupListItemCommon
.
orgName
.
withArgs
(
fakeGroup
)
.
returns
(
fakeGroup
.
organization
.
name
);
const
element
=
createGroupListItem
(
fakeGroup
);
const
orgName
=
element
.
ctrl
.
orgName
();
assert
.
equal
(
orgName
,
fakeGroup
.
organization
.
name
);
});
describe
(
'isSelected'
,
()
=>
{
[
{
description
:
'returns true if group is the focused group'
,
focusedGroupId
:
'groupid'
,
expectedIsSelected
:
true
,
},
{
description
:
'returns false if group is not the focused group'
,
focusedGroupId
:
'other'
,
expectedIsSelected
:
false
,
},
].
forEach
(({
description
,
focusedGroupId
,
expectedIsSelected
})
=>
{
it
(
description
,
()
=>
{
fakeStore
.
focusedGroupId
.
returns
(
focusedGroupId
);
const
fakeGroup
=
{
id
:
'groupid'
};
const
element
=
createGroupListItem
(
fakeGroup
);
assert
.
equal
(
element
.
ctrl
.
isSelected
(),
expectedIsSelected
);
});
});
});
});
src/sidebar/components/test/group-list-section-test.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
angular
=
require
(
'angular'
);
const
groupListSection
=
require
(
'../group-list-section'
);
const
util
=
require
(
'../../directive/test/util'
);
describe
(
'groupListSection'
,
()
=>
{
before
(()
=>
{
angular
.
module
(
'app'
,
[]).
component
(
'groupListSection'
,
groupListSection
);
});
beforeEach
(()
=>
{
angular
.
mock
.
module
(
'app'
,
{});
});
const
createGroupListSection
=
(
fakeSectionGroups
,
fakeDisableOosGroupSelection
)
=>
{
const
config
=
{
sectionGroups
:
fakeSectionGroups
,
};
if
(
fakeDisableOosGroupSelection
!==
undefined
)
{
config
.
disableOosGroupSelection
=
fakeDisableOosGroupSelection
;
}
return
util
.
createDirective
(
document
,
'groupListSection'
,
config
);
};
describe
(
'isSelectable'
,
()
=>
{
[
{
description
:
'always returns true if disableOosGroupSelection is false'
,
fakeDisableOosGroupSelection
:
false
,
expectedIsSelectable
:
[
true
,
true
],
},
{
description
:
'always returns true if disableOosGroupSelection is undefined'
,
fakeDisableOosGroupSelection
:
undefined
,
expectedIsSelectable
:
[
true
,
true
],
},
{
description
:
'returns false if disableOosGroupSelection is true and group is out of scope'
,
fakeDisableOosGroupSelection
:
true
,
expectedIsSelectable
:
[
true
,
false
],
},
].
forEach
(
({
description
,
fakeDisableOosGroupSelection
,
expectedIsSelectable
})
=>
{
it
(
description
,
()
=>
{
const
fakeSectionGroups
=
[
{
isScopedToUri
:
true
,
id
:
0
},
{
isScopedToUri
:
false
,
id
:
1
},
];
const
element
=
createGroupListSection
(
fakeSectionGroups
,
fakeDisableOosGroupSelection
);
fakeSectionGroups
.
forEach
(
g
=>
assert
.
equal
(
element
.
ctrl
.
isSelectable
(
g
.
id
),
expectedIsSelectable
[
g
.
id
]
)
);
});
}
);
});
});
src/sidebar/components/test/group-list-test.js
View file @
90bcfb11
...
...
@@ -3,6 +3,7 @@
const
angular
=
require
(
'angular'
);
const
immutable
=
require
(
'seamless-immutable'
);
const
{
events
}
=
require
(
'../../services/analytics'
);
const
groupList
=
require
(
'../group-list'
);
const
util
=
require
(
'../../directive/test/util'
);
...
...
@@ -33,17 +34,6 @@ describe('groupList', function() {
isScopedToUri
:
true
,
});
const
restrictedOutOfScopeGroup
=
immutable
({
id
:
'restrictedoos'
,
links
:
{
html
:
'https://hypothes.is/groups/restricto'
,
},
name
:
'Restricted'
,
organization
:
groupFixtures
.
defaultOrganization
(),
type
:
'restricted'
,
isScopedToUri
:
false
,
});
const
publicGroup
=
immutable
({
id
:
'__world__'
,
links
:
{
...
...
@@ -85,11 +75,7 @@ describe('groupList', function() {
fakeAnalytics
=
{
track
:
sinon
.
stub
(),
events
:
{
GROUP_LEAVE
:
'groupLeave'
,
GROUP_SWITCH
:
'groupSwitch'
,
GROUP_VIEW_ACTIVITY
:
'groupViewActivity'
,
},
events
,
};
fakeServiceUrl
=
sinon
.
stub
();
...
...
@@ -385,6 +371,7 @@ describe('groupList', function() {
'_blank'
);
});
describe
(
'group section visibility'
,
()
=>
{
[
{
...
...
@@ -393,7 +380,7 @@ describe('groupList', function() {
currentlyViewingGroups
:
[
publicGroup
],
featuredGroups
:
[
restrictedGroup
],
myGroups
:
[],
expectedSections
:
[
'Currently Viewing'
,
'Featured Groups'
],
expectedSections
:
[
"'Currently Viewing'"
,
"'Featured Groups'"
],
},
{
description
:
...
...
@@ -401,14 +388,14 @@ describe('groupList', function() {
currentlyViewingGroups
:
[],
featuredGroups
:
[
restrictedGroup
],
myGroups
:
[
publicGroup
],
expectedSections
:
[
'Featured Groups'
,
'My Groups'
],
expectedSections
:
[
"'Featured Groups'"
,
"'My Groups'"
],
},
{
description
:
'shows My Groups section when there are my groups'
,
currentlyViewingGroups
:
[],
featuredGroups
:
[],
myGroups
:
[
publicGroup
,
privateGroup
],
expectedSections
:
[
'My Groups'
],
expectedSections
:
[
"'My Groups'"
],
},
].
forEach
(
({
...
...
@@ -433,76 +420,21 @@ describe('groupList', function() {
const
showGroupsMenu
=
element
.
ctrl
.
showGroupsMenu
();
const
dropdownToggle
=
element
.
find
(
'.dropdown-toggle'
);
const
arrowIcon
=
element
.
find
(
'.h-icon-arrow-drop-down'
);
const
sectionHeader
=
element
.
find
(
'.dropdown-menu__section-heading'
);
const
section
=
element
.
find
(
'.dropdown-menu__section'
);
const
dropdownOptions
=
element
.
find
(
'.dropdown-community-groups-menu__row'
);
const
groupListSection
=
element
.
find
(
'group-list-section'
);
assert
.
isTrue
(
showGroupsMenu
);
assert
.
lengthOf
(
dropdownToggle
,
1
);
assert
.
lengthOf
(
arrowIcon
,
1
);
sectionHeader
.
each
(
function
()
{
assert
.
isTrue
(
expectedSections
.
includes
(
this
.
textContent
));
assert
.
lengthOf
(
groupListSection
,
expectedSections
.
length
);
groupListSection
.
each
(
function
()
{
assert
.
isTrue
(
expectedSections
.
includes
(
this
.
getAttribute
(
'heading'
))
);
});
// Plus one for the create private group section.
assert
.
lengthOf
(
section
,
expectedSections
.
length
+
1
);
assert
.
lengthOf
(
dropdownOptions
,
3
);
});
}
);
});
describe
(
'group details expanded on out of scope groups'
,
()
=>
{
it
(
'sets the default for the given groupid to false and returns it'
,
()
=>
{
const
element
=
createGroupList
();
const
expanded
=
element
.
ctrl
.
isGroupDetailsExpanded
(
'groupid'
);
assert
.
isFalse
(
expanded
);
assert
.
isFalse
(
element
.
ctrl
.
groupDetailsExpanded
.
groupid
);
});
it
(
'gets expanded value for the given groupid if already present'
,
()
=>
{
const
element
=
createGroupList
();
element
.
ctrl
.
groupDetailsExpanded
=
{
groupid
:
true
};
const
expanded
=
element
.
ctrl
.
isGroupDetailsExpanded
(
'groupid'
);
assert
.
isTrue
(
expanded
);
});
it
(
'toggles the expanded value for the given groupid'
,
()
=>
{
const
element
=
createGroupList
();
let
fakeEvent
=
{
stopPropagation
:
sinon
.
stub
()
};
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
,
'groupid'
);
assert
.
isTrue
(
element
.
ctrl
.
groupDetailsExpanded
.
groupid
);
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
,
'groupid'
);
assert
.
isFalse
(
element
.
ctrl
.
groupDetailsExpanded
.
groupid
);
});
it
(
'stops the event from propogating when toggling'
,
()
=>
{
const
element
=
createGroupList
();
let
fakeEvent
=
{
stopPropagation
:
sinon
.
spy
()
};
element
.
ctrl
.
toggleGroupDetails
(
fakeEvent
,
'groupid'
);
sinon
.
assert
.
called
(
fakeEvent
.
stopPropagation
);
});
});
it
(
'displays out of scope groups as non-selectable'
,
()
=>
{
fakeFeatures
.
flagEnabled
.
withArgs
(
'community_groups'
).
returns
(
true
);
// In order to show the group drop down there must be at least two groups.
groups
=
[
publicGroup
,
restrictedOutOfScopeGroup
];
fakeStore
.
getMyGroups
.
returns
(
groups
);
const
element
=
createGroupList
();
const
notSelectable
=
element
.
find
(
'.group-item--out-of-scope'
);
assert
.
lengthOf
(
notSelectable
,
1
);
});
describe
(
'group menu visibility'
,
()
=>
{
it
(
'is hidden when third party service and only one group'
,
function
()
{
...
...
@@ -585,14 +517,12 @@ describe('groupList', function() {
const
showGroupsMenu
=
element
.
ctrl
.
showGroupsMenu
();
const
dropdownToggle
=
element
.
find
(
'.dropdown-toggle'
);
const
arrowIcon
=
element
.
find
(
'.h-icon-arrow-drop-down'
);
const
dropdownOptions
=
element
.
find
(
'.dropdown-community-groups-menu__row'
);
const
groupListSection
=
element
.
find
(
'.group-list-section'
);
assert
.
isTrue
(
showGroupsMenu
);
assert
.
lengthOf
(
dropdownToggle
,
1
);
assert
.
lengthOf
(
arrowIcon
,
1
);
assert
.
lengthOf
(
dropdownOptions
,
3
);
assert
.
lengthOf
(
groupListSection
,
1
);
});
it
(
'is not shown when community_groups feature flag is on and there is only one group'
,
function
()
{
...
...
@@ -605,14 +535,12 @@ describe('groupList', function() {
const
showGroupsMenu
=
element
.
ctrl
.
showGroupsMenu
();
const
dropdownToggle
=
element
.
find
(
'.dropdown-toggle'
);
const
arrowIcon
=
element
.
find
(
'.h-icon-arrow-drop-down'
);
const
dropdownOptions
=
element
.
find
(
'.dropdown-community-groups-menu__row'
);
const
groupListSection
=
element
.
find
(
'.group-list-section'
);
assert
.
isFalse
(
showGroupsMenu
);
assert
.
lengthOf
(
dropdownToggle
,
0
);
assert
.
lengthOf
(
arrowIcon
,
0
);
assert
.
lengthOf
(
dropdownOptions
,
0
);
assert
.
lengthOf
(
groupListSection
,
0
);
});
});
...
...
src/sidebar/index.js
View file @
90bcfb11
...
...
@@ -151,6 +151,12 @@ function startAngularApp(config) {
.
component
(
'dropdownMenuBtn'
,
require
(
'./components/dropdown-menu-btn'
))
.
component
(
'excerpt'
,
require
(
'./components/excerpt'
))
.
component
(
'groupList'
,
require
(
'./components/group-list'
))
.
component
(
'groupListItem'
,
require
(
'./components/group-list-item'
))
.
component
(
'groupListItemOutOfScope'
,
require
(
'./components/group-list-item-out-of-scope'
)
)
.
component
(
'groupListSection'
,
require
(
'./components/group-list-section'
))
.
component
(
'helpLink'
,
require
(
'./components/help-link'
))
.
component
(
'helpPanel'
,
require
(
'./components/help-panel'
))
.
component
(
'loggedoutMessage'
,
require
(
'./components/loggedout-message'
))
...
...
src/sidebar/templates/group-list-item-out-of-scope.html
0 → 100644
View file @
90bcfb11
<div
class=
"group-list-item-out-of-scope__item"
ng-class=
"{'group-list-item__item': true, 'is-selected': false}"
ng-click=
"vm.toggleGroupDetails($event)"
tabindex=
"0"
>
<!-- the group icon !-->
<div
class=
"group-list-item__icon-container"
>
<img
class=
"group-list-item__icon group-list-item__icon--organization"
alt=
"{{ vm.orgName() }}"
ng-src=
"{{ vm.group.logo }}"
ng-if=
"vm.group.logo"
/>
</div>
<!-- the group name and share link !-->
<div
ng-class=
"{'group-list-item-out-of-scope__details': true, expanded: vm.isDetailsExpanded}"
>
<svg
class=
"svg-icon group-list-item-out-of-scope__icon--unavailable"
xmlns=
"http://www.w3.org/2000/svg"
width=
"100%"
height=
"100%"
viewBox=
"0 0 24 24"
>
<path
fill=
"none"
d=
"M0 0h24v24H0V0z"
/>
<path
d=
"M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"
/>
</svg>
<a
class=
"group-list-item__name-link"
href=
""
title=
"Group not annotatable on this domain."
>
{{vm.group.name}}
</a
><br
/>
<p
class=
"group-list-item-out-of-scope__details-toggle"
ng-if=
"!vm.isDetailsExpanded"
>
Why is this group unavailable?
</p>
<p
class=
"group-list-item-out-of-scope__details-unavailable-message"
ng-if=
"vm.isDetailsExpanded"
>
This group has been restricted to selected URLs by its administrators.
</p>
<p
class=
"group-list-item-out-of-scope__details-actions"
ng-if=
"vm.isDetailsExpanded"
>
<a
class=
"button button--text group-list-item-out-of-scope__details-group-page-link"
href=
"{{vm.group.links.html}}"
target=
"_blank"
ng-click=
"vm.trackViewGroupActivity()"
>
Go to group page
</a
>
</p>
</div>
</div>
src/sidebar/templates/group-list-item.html
0 → 100644
View file @
90bcfb11
<div
ng-class=
"{'group-list-item__item': true, 'is-selected': vm.isSelected()}"
ng-click=
"vm.focusGroup()"
tabindex=
"0"
>
<!-- the group icon !-->
<div
class=
"group-list-item__icon-container"
>
<img
class=
"group-list-item__icon group-list-item__icon--organization"
alt=
"{{ vm.orgName() }}"
ng-src=
"{{ vm.group.logo }}"
ng-if=
"vm.group.logo"
/>
</div>
<!-- the group name and share link -->
<div
class=
"group-list-item__details"
>
<a
class=
"group-list-item__name-link"
href=
""
title=
"{{ vm.group.type === 'private' ? 'Show and create annotations in ' + vm.group.name : 'Show public annotations' }}"
>
{{vm.group.name}}
</a>
</div>
</div>
src/sidebar/templates/group-list-section.html
0 → 100644
View file @
90bcfb11
<h2
class=
"group-list-section__heading"
>
{{ vm.heading }}
</h2>
<ul
class=
"group-list-section__content"
>
<li
class=
"dropdown-menu__row dropdown-menu__row--no-border dropdown-menu__row--unpadded"
ng-repeat=
"group in vm.sectionGroups track by group.id"
>
<group-list-item
class=
"group-list-item"
group=
"group"
ng-if=
"vm.isSelectable(group.id)"
>
</group-list-item>
<group-list-item-out-of-scope
class=
"group-list-item-out-of-scope"
group=
"group"
ng-if=
"!vm.isSelectable(group.id)"
>
</group-list-item-out-of-scope>
</li>
</ul>
src/sidebar/templates/group-list.html
View file @
90bcfb11
This diff is collapsed.
Click to expand it.
src/sidebar/util/group-list-item-common.js
0 → 100644
View file @
90bcfb11
'use strict'
;
function
orgName
(
group
)
{
return
group
.
organization
&&
group
.
organization
.
name
;
}
function
trackViewGroupActivity
(
analytics
)
{
analytics
.
track
(
analytics
.
events
.
GROUP_VIEW_ACTIVITY
);
}
module
.
exports
=
{
orgName
,
trackViewGroupActivity
,
};
src/sidebar/util/test/group-list-item-common-test.js
0 → 100644
View file @
90bcfb11
'use strict'
;
const
groupListItemCommon
=
require
(
'../group-list-item-common'
);
const
{
events
}
=
require
(
'../../services/analytics'
);
describe
(
'sidebar/util/groupListItemCommon'
,
()
=>
{
describe
(
'trackViewGroupActivity'
,
()
=>
{
it
(
'triggers the GROUP_VIEW_ACTIVITY event when called'
,
()
=>
{
const
fakeAnalytics
=
{
track
:
sinon
.
stub
(),
events
,
};
groupListItemCommon
.
trackViewGroupActivity
(
fakeAnalytics
);
assert
.
calledWith
(
fakeAnalytics
.
track
,
fakeAnalytics
.
events
.
GROUP_VIEW_ACTIVITY
);
});
});
describe
(
'orgName'
,
()
=>
{
it
(
'returns the organization name if it exists'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
,
organization
:
{
name
:
'org'
}
};
const
organizationName
=
groupListItemCommon
.
orgName
(
fakeGroup
);
assert
.
equal
(
organizationName
,
fakeGroup
.
organization
.
name
);
});
it
(
'returns undefined if group has no organization'
,
()
=>
{
const
fakeGroup
=
{
id
:
'groupid'
};
assert
.
isUndefined
(
groupListItemCommon
.
orgName
(
fakeGroup
));
});
});
});
src/styles/sidebar/common.scss
View file @
90bcfb11
...
...
@@ -260,6 +260,10 @@ html {
min-width
:
120px
;
}
.dropdown-menu__row--no-border
{
border
:
none
;
}
.dropdown-menu__row--unpadded
{
padding-left
:
0px
;
padding-right
:
0px
;
...
...
src/styles/sidebar/components/group-list-item-out-of-scope.scss
0 → 100644
View file @
90bcfb11
/* The group-list out of scope item. */
.group-list-item-out-of-scope
{
display
:
flex
;
flex-direction
:
row
;
flex-grow
:
1
;
}
.group-list-item-out-of-scope__item
{
background-color
:
$gray-lightest
;
color
:
$gray-light
;
}
.group-list-item-out-of-scope__icon--unavailable
{
fill
:
$gray-light
;
float
:
right
;
height
:
20px
;
width
:
auto
;
}
.group-list-item-out-of-scope__details
{
flex-grow
:
1
;
flex-shrink
:
1
;
font-weight
:
500
;
}
.group-list-item-out-of-scope__details-toggle
{
font-size
:
$body1-font-size
;
font-style
:
italic
;
margin
:
0
;
text-decoration
:
underline
;
}
.group-list-item-out-of-scope__details-unavailable-message
{
font-size
:
$body1-font-size
;
line-height
:
1
.5
;
white-space
:
normal
;
width
:
$group-list-width
-
60px
;
}
.group-list-item-out-of-scope__details-actions
{
text-align
:
right
;
}
.group-list-item-out-of-scope__details-group-page-link
{
color
:
inherit
;
font-size
:
$body1-font-size
;
text-decoration
:
underline
;
text-transform
:
uppercase
;
}
src/styles/sidebar/components/group-list-item.scss
0 → 100644
View file @
90bcfb11
/* The group. */
.group-list-item
{
display
:
flex
;
flex-direction
:
row
;
flex-grow
:
1
;
}
.group-list-item__item
{
border
:
solid
1px
transparent
;
display
:
flex
;
flex-direction
:
row
;
flex-grow
:
1
;
margin
:
1px
;
padding
:
10px
;
cursor
:
pointer
;
&
:focus
{
outline
:
none
;
@include
focus-outline
;
}
&
:hover
{
background
:
$gray-lightest
;
}
&
.is-selected
{
.name-link
{
font-size
:
$body2-font-size
;
font-weight
:
600
;
}
}
}
.group-list-item__icon-container
{
margin-right
:
10px
;
width
:
15px
;
height
:
15px
;
}
// the icon indicating the type of group currently selected at
// the top of the groups list
.group-list-item__icon
{
color
:
$color-gray
;
display
:
inline-block
;
margin-right
:
4px
;
position
:
relative
;
vertical-align
:
baseline
;
// align the base of the chat-heads icon for groups
// with the baseline of the group name label
transform
:
translateY
(
1px
);
}
.group-list-item__icon--organization
{
height
:
15px
;
width
:
15px
;
top
:
2px
;
}
// the name of a group in the groups drop-down list
// and 'Post to <Group>' button for saving annotations
.group-list-item__name-link
{
white-space
:
nowrap
;
color
:
inherit
;
}
.group-list-item__details
{
flex-grow
:
1
;
flex-shrink
:
1
;
font-weight
:
500
;
}
src/styles/sidebar/components/group-list-section.scss
0 → 100644
View file @
90bcfb11
/* The groups section. */
.group-list-section__content
{
border-bottom
:
solid
1px
rgba
(
0
,
0
,
0
,
0
.15
);
}
.group-list-section__heading
{
color
:
$gray-light
;
font-size
:
$body1-font-size
;
line-height
:
1
;
margin
:
1px
1px
0
;
padding
:
12px
10px
0
;
text-transform
:
uppercase
;
}
src/styles/sidebar/components/group-list.scss
View file @
90bcfb11
/* The groups dropdown list. */
$group-list-width
:
300px
;
$group-list-spacing-below
:
50px
;
.group-list
{
...
...
@@ -10,7 +9,7 @@ $group-list-spacing-below: 50px;
.dropdown-menu
{
width
:
$group-list-width
;
max-height
:
500px
;
// fallback for browsers lacking support for vh/calc
max-height
:
500px
;
// fallback for browsers lacking support for vh/calc
max-height
:
calc
(
100vh
-
#{
$top-bar-height
}
-
#{
$group-list-spacing-below
}
);
overflow-y
:
auto
;
...
...
@@ -22,26 +21,11 @@ $group-list-spacing-below: 50px;
}
.dropdown-menu__section--no-header
{
border-top
:
solid
1px
rgba
(
0
,
0
,
0
,
0
.15
);
.group-details
{
font-weight
:
400
;
}
}
.dropdown-menu__section-heading
{
color
:
$gray-light
;
font-size
:
12px
;
line-height
:
1
;
margin
:
1px
1px
0
;
padding
:
12px
10px
0
;
text-transform
:
uppercase
;
&
:not
(
:first-child
)
{
border-top
:
solid
1px
rgba
(
0
,
0
,
0
,
0
.15
);
}
}
.group-item
{
display
:
flex
;
flex-direction
:
row
;
...
...
@@ -91,11 +75,6 @@ $group-list-spacing-below: 50px;
}
}
.group-item--out-of-scope
{
background-color
:
$gray-lightest
;
color
:
$gray-light
;
}
.group-icon-container
{
margin-right
:
10px
;
}
...
...
@@ -114,13 +93,6 @@ $group-list-spacing-below: 50px;
margin-right
:
2px
;
}
.group__icon--unavailable
{
fill
:
$gray-light
;
float
:
right
;
height
:
20px
;
width
:
auto
;
}
.group-details
{
flex-grow
:
1
;
flex-shrink
:
1
;
...
...
@@ -147,31 +119,6 @@ $group-list-spacing-below: 50px;
}
}
.group-details__toggle
{
font-size
:
$body1-font-size
;
font-style
:
italic
;
margin
:
0
;
text-decoration
:
underline
;
}
.group-details__unavailable-message
{
font-size
:
$body1-font-size
;
line-height
:
1
.5
;
white-space
:
normal
;
width
:
$group-list-width
-
60px
;
}
.group-details__actions
{
text-align
:
right
;
}
.group-details__group-page-link
{
color
:
inherit
;
font-size
:
$body1-font-size
;
text-decoration
:
underline
;
text-transform
:
uppercase
;
}
.new-group-btn
{
background-color
:
$gray-lightest
;
...
...
@@ -210,7 +157,7 @@ $group-list-spacing-below: 50px;
// the drop-down list when clicked
.group-list-label__label
{
font-size
:
$body2-font-size
;
font-weight
:bold
;
font-weight
:
bold
;
display
:
inline-block
;
}
...
...
@@ -226,7 +173,6 @@ $group-list-spacing-below: 50px;
color
:
inherit
;
}
.open
{
&
>
.group-list__toggle
{
background
:
$gray-lighter
;
...
...
src/styles/sidebar/sidebar.scss
View file @
90bcfb11
...
...
@@ -15,6 +15,9 @@ $base-line-height: 20px;
@import
'./components/dropdown-menu-btn'
;
@import
'./components/excerpt'
;
@import
'./components/group-list'
;
@import
'./components/group-list-item'
;
@import
'./components/group-list-item-out-of-scope'
;
@import
'./components/group-list-section'
;
@import
'./components/help-panel'
;
@import
'./components/loggedout-message'
;
@import
'./components/login-control'
;
...
...
src/styles/variables.scss
View file @
90bcfb11
...
...
@@ -126,6 +126,7 @@ $highlight-color-second: rgba(206, 206, 60, 0.4);
$highlight-color-third
:
rgba
(
192
,
192
,
49
,
0
.4
);
$highlight-color-focus
:
rgba
(
156
,
230
,
255
,
0
.5
);
$top-bar-height
:
40px
;
$group-list-width
:
300px
;
// Mixins
// ------
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment