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

Merge pull request #825 from hypothesis/fix-bucket-bar-selection

Fix selection of annotations when bucket bar indicators are clicked
parents 85904fb3 3c7e9ddd
......@@ -76,6 +76,8 @@ module.exports = class BucketBar extends Plugin
else
$(element).append @element
@highlighter = options.highlighter ? highlighter # Test seam.
pluginInit: ->
$(window).on 'resize scroll', @update
......@@ -113,7 +115,7 @@ module.exports = class BucketBar extends Plugin
unless anchor.highlights?.length
return points
rect = highlighter.getBoundingClientRect(anchor.highlights)
rect = @highlighter.getBoundingClientRect(anchor.highlights)
x = rect.top
h = rect.bottom - rect.top
......@@ -251,7 +253,7 @@ module.exports = class BucketBar extends Plugin
scrollToClosest(@buckets[bucket], 'down')
else
annotations = (anchor.annotation for anchor in @buckets[bucket])
annotator.selectAnnotations annotations,
@annotator.selectAnnotations annotations,
(event.ctrlKey or event.metaKey),
this._buildTabs(@tabs, @buckets)
......
BucketBar = require('../bucket-bar')
# Return DOM elements for non-empty bucket indicators in a `BucketBar`.
nonEmptyBuckets = (bucketBar) ->
buckets = bucketBar.element[0].querySelectorAll('.annotator-bucket-indicator')
Array.from(buckets)
.filter((bucket) ->
label = bucket.querySelector('.label')
parseInt(label.textContent) > 0
)
createMouseEvent = (type, { ctrlKey, metaKey } = {}) ->
# In a modern browser we could use `new MouseEvent` constructor and pass
# `ctrlKey` and `metaKey` via the init object.
event = new Event(type)
event.ctrlKey = Boolean(ctrlKey)
event.metaKey = Boolean(metaKey)
event
describe 'BucketBar', ->
createBucketBar = (options) ->
element = document.createElement('div')
new BucketBar(element, options || {})
# Create a fake anchor, which is a combination of annotation object and
# associated highlight elements.
createAnchor = ->
annotation: { $tag: 'ann1' },
highlights: [document.createElement('span')]
context 'when a bucket is clicked', ->
bucketBar = null
fakeHighlighter = null
fakeAnnotator = null
beforeEach ->
fakeHighlighter =
getBoundingClientRect: -> { left: 0, top: 200, right: 200, bottom: 250 }
bucketBar = createBucketBar(highlighter: fakeHighlighter)
# This setup is done by `Guest#addPlugin` in the actual app.
bucketBar.annotator = {
anchors: [],
selectAnnotations: sinon.stub(),
}
# Create fake anchors and render buckets.
anchors = [createAnchor()]
bucketBar.annotator.anchors = anchors
bucketBar._update()
it 'selects the annotations', ->
# Click on the indicator for the non-empty bucket.
bucketEls = nonEmptyBuckets(bucketBar)
assert.equal(bucketEls.length, 1)
bucketEls[0].dispatchEvent(createMouseEvent('click'))
anns = bucketBar.annotator.anchors.map((anchor) -> anchor.annotation)
assert.calledWith(bucketBar.annotator.selectAnnotations, anns, false)
[
{ ctrlKey: true, metaKey: false },
{ ctrlKey: false, metaKey: true },
].forEach(({ ctrlKey, metaKey }) ->
it 'toggles selection of the annotations if Ctrl or Alt is pressed', ->
# Click on the indicator for the non-empty bucket.
bucketEls = nonEmptyBuckets(bucketBar)
assert.equal(bucketEls.length, 1)
bucketEls[0].dispatchEvent(
createMouseEvent('click', ctrlKey: ctrlKey, metaKey: metaKey)
)
anns = bucketBar.annotator.anchors.map((anchor) -> anchor.annotation)
assert.calledWith(bucketBar.annotator.selectAnnotations, anns, true)
)
# Yes this is testing a private method. Yes this is bad practice, but I'd
# rather test this functionality in a private method than not test it at all.
#
# Note: This could be tested using only the public APIs of the `BucketBar`
# class using the approach of the "when a bucket is clicked" tests above.
describe '_buildTabs', ->
setup = (tabs) ->
bucketBar = createBucketBar()
......
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