Commit 6c7533d8 authored by Sean Hammond's avatar Sean Hammond Committed by GitHub

Merge pull request #3526 from hypothesis/gh3523-non-text-selection-fix

Fix adder breaking after making a selection containing no text
parents 979b83c4 64740e76
...@@ -359,6 +359,14 @@ module.exports = class Guest extends Annotator ...@@ -359,6 +359,14 @@ module.exports = class Guest extends Annotator
@crossframe?.call('focusAnnotations', tags) @crossframe?.call('focusAnnotations', tags)
_onSelection: (range) -> _onSelection: (range) ->
selection = Annotator.Util.getGlobal().getSelection()
isBackwards = rangeUtil.isSelectionBackwards(selection)
focusRect = rangeUtil.selectionFocusRect(selection)
if !focusRect
# The selected range does not contain any text
this._onClearSelection()
return
@selectedRanges = [range] @selectedRanges = [range]
Annotator.$('.annotator-toolbar .h-icon-note') Annotator.$('.annotator-toolbar .h-icon-note')
...@@ -366,9 +374,6 @@ module.exports = class Guest extends Annotator ...@@ -366,9 +374,6 @@ module.exports = class Guest extends Annotator
.removeClass('h-icon-note') .removeClass('h-icon-note')
.addClass('h-icon-annotate'); .addClass('h-icon-annotate');
selection = Annotator.Util.getGlobal().getSelection()
isBackwards = rangeUtil.isSelectionBackwards(selection)
focusRect = rangeUtil.selectionFocusRect(selection)
{left, top, arrowDirection} = this.adderCtrl.target(focusRect, isBackwards) {left, top, arrowDirection} = this.adderCtrl.target(focusRect, isBackwards)
this.adderCtrl.showAt(left, top, arrowDirection) this.adderCtrl.showAt(left, top, arrowDirection)
......
Annotator = require('annotator') Annotator = require('annotator')
proxyquire = require('proxyquire')
adder = require('../adder')
Observable = require('../../util/observable').Observable
$ = Annotator.$ $ = Annotator.$
Annotator['@noCallThru'] = true; Annotator['@noCallThru'] = true;
highlighter = {} Guest = null
anchoring = {} anchoring = {}
highlighter = {}
rangeUtil = null
selections = null
raf = sinon.stub().yields() raf = sinon.stub().yields()
raf['@noCallThru'] = true raf['@noCallThru'] = true
...@@ -11,14 +19,15 @@ raf['@noCallThru'] = true ...@@ -11,14 +19,15 @@ raf['@noCallThru'] = true
scrollIntoView = sinon.stub() scrollIntoView = sinon.stub()
scrollIntoView['@noCallThru'] = true scrollIntoView['@noCallThru'] = true
proxyquire = require('proxyquire') class FakeAdder
Guest = proxyquire('../guest', { instance: null
'./highlighter': highlighter,
'./anchoring/html': anchoring, constructor: ->
'annotator': Annotator, FakeAdder::instance = this
'raf': raf,
'scroll-into-view': scrollIntoView, this.hide = sinon.stub()
}) this.showAt = sinon.stub()
this.target = sinon.stub()
# A little helper which returns a promise that resolves after a timeout # A little helper which returns a promise that resolves after a timeout
timeoutPromise = (millis = 0) -> timeoutPromise = (millis = 0) ->
...@@ -34,6 +43,28 @@ describe 'Guest', -> ...@@ -34,6 +43,28 @@ describe 'Guest', ->
return new Guest(element, options || {}) return new Guest(element, options || {})
beforeEach -> beforeEach ->
FakeAdder::instance = null
rangeUtil = {
isSelectionBackwards: sinon.stub()
selectionFocusRect: sinon.stub()
}
selections = null
Guest = proxyquire('../guest', {
'./adder': {Adder: FakeAdder},
'./anchoring/html': anchoring,
'./highlighter': highlighter,
'./range-util': rangeUtil,
'./selections': (document) ->
new Observable((obs) ->
selections = obs
return () ->
)
'annotator': Annotator,
'raf': raf,
'scroll-into-view': scrollIntoView,
})
fakeCrossFrame = { fakeCrossFrame = {
onConnect: sinon.stub() onConnect: sinon.stub()
on: sinon.stub() on: sinon.stub()
...@@ -206,7 +237,29 @@ describe 'Guest', -> ...@@ -206,7 +237,29 @@ describe 'Guest', ->
emitGuestEvent('getDocumentInfo', assertComplete) emitGuestEvent('getDocumentInfo', assertComplete)
describe 'getDocumentInfo()', -> describe 'when the selection changes', ->
it 'shows the adder if the selection contains text', ->
guest = createGuest()
rangeUtil.selectionFocusRect.returns({left: 0, top: 0, width: 5, height: 5})
FakeAdder::instance.target.returns({
left: 0, top: 0, arrowDirection: adder.ARROW_POINTING_UP
})
selections.next({})
assert.called FakeAdder::instance.showAt
it 'hides the adder if the selection does not contain text', ->
guest = createGuest()
rangeUtil.selectionFocusRect.returns(null)
selections.next({})
assert.called FakeAdder::instance.hide
assert.notCalled FakeAdder::instance.showAt
it 'hides the adder if the selection is empty', ->
guest = createGuest()
selections.next(null)
assert.called FakeAdder::instance.hide
describe '#getDocumentInfo()', ->
guest = null guest = null
beforeEach -> beforeEach ->
...@@ -228,7 +281,7 @@ describe 'Guest', -> ...@@ -228,7 +281,7 @@ describe 'Guest', ->
return guest.getDocumentInfo().then ({uri}) -> return guest.getDocumentInfo().then ({uri}) ->
assert.equal uri, 'urn:x-pdf:aabbcc' assert.equal uri, 'urn:x-pdf:aabbcc'
describe 'onAdderMouseUp', -> describe '#onAdderMouseUp()', ->
it 'it prevents the default browser action when triggered', () -> it 'it prevents the default browser action when triggered', () ->
event = jQuery.Event('mouseup') event = jQuery.Event('mouseup')
guest = createGuest() guest = createGuest()
...@@ -241,7 +294,7 @@ describe 'Guest', -> ...@@ -241,7 +294,7 @@ describe 'Guest', ->
guest.onAdderMouseup(event) guest.onAdderMouseup(event)
assert.isTrue(event.isPropagationStopped()) assert.isTrue(event.isPropagationStopped())
describe 'createAnnotation()', -> describe '#createAnnotation()', ->
it 'adds metadata to the annotation object', -> it 'adds metadata to the annotation object', ->
guest = createGuest() guest = createGuest()
sinon.stub(guest, 'getDocumentInfo').returns(Promise.resolve({ sinon.stub(guest, 'getDocumentInfo').returns(Promise.resolve({
...@@ -269,7 +322,7 @@ describe 'Guest', -> ...@@ -269,7 +322,7 @@ describe 'Guest', ->
guest.createAnnotation() guest.createAnnotation()
describe 'createComment()', -> describe '#createComment()', ->
it 'adds metadata to the annotation object', -> it 'adds metadata to the annotation object', ->
guest = createGuest() guest = createGuest()
sinon.stub(guest, 'getDocumentInfo').returns(Promise.resolve({ sinon.stub(guest, 'getDocumentInfo').returns(Promise.resolve({
...@@ -303,7 +356,7 @@ describe 'Guest', -> ...@@ -303,7 +356,7 @@ describe 'Guest', ->
guest.createComment() guest.createComment()
describe 'anchor()', -> describe '#anchor()', ->
el = null el = null
range = null range = null
...@@ -478,7 +531,7 @@ describe 'Guest', -> ...@@ -478,7 +531,7 @@ describe 'Guest', ->
assert.calledOnce(stub) assert.calledOnce(stub)
.then(done, done) .then(done, done)
describe 'detach()', -> describe '#detach()', ->
it 'removes the anchors from the "anchors" instance variable', -> it 'removes the anchors from the "anchors" instance variable', ->
guest = createGuest() guest = createGuest()
annotation = {} annotation = {}
......
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