Commit 2998e577 authored by chdorner's avatar chdorner

Search for PDF fingerprint and non-file URL for annotations

This will allow us to switch back to using the URL for the
`target.source` when creating annotations, which will then allow us to
link back to the exact document where the annotation was created.
parent 7b4fc59d
......@@ -46,11 +46,20 @@ module.exports = class CrossFrame
if err
channel.destroy()
else
searchUris = [info.uri]
documentFingerprint = null
if info.metadata and info.metadata.documentFingerprint
documentFingerprint = info.metadata.documentFingerprint
searchUris = info.metadata.link.map((link) -> link.href)
$rootScope.$apply =>
@frames.push({channel: channel, uri: info.uri, documentFingerprint: documentFingerprint})
@frames.push({
channel: channel,
uri: info.uri,
searchUris: searchUris,
documentFingerprint: documentFingerprint
})
this.connect = ->
discovery = createDiscovery()
......
......@@ -72,5 +72,23 @@ describe 'CrossFrame', ->
fakeBridge.onConnect.yields(channel)
crossframe.connect()
assert.deepEqual(crossframe.frames, [
{channel: channel, uri: uri, documentFingerprint: null}
{channel: channel, uri: uri, searchUris: [uri], documentFingerprint: null}
])
it 'updates the frames array with multiple search uris when the document is a PDF', ->
uri = 'http://example.com/test.pdf'
fingerprint = 'urn:x-pdf:fingerprint'
channel = {
call: sandbox.stub().yields(null, {
uri: uri,
metadata: {
link: [{href: uri}, {href: fingerprint}],
documentFingerprint: fingerprint,
},
})
}
fakeBridge.onConnect.yields(channel)
crossframe.connect()
assert.deepEqual(crossframe.frames, [
{channel: channel, uri: uri, searchUris: [uri, fingerprint], documentFingerprint: fingerprint}
])
......@@ -19,8 +19,12 @@ function FakeSearchClient(resource, opts) {
this.get = sinon.spy(function (query) {
assert.ok(query.uri);
this.emit('results', [{id: query.uri + '123', group: '__world__'}]);
this.emit('results', [{id: query.uri + '456', group: 'private-group'}]);
for (var i = 0; i < query.uri.length; i++) {
var uri = query.uri[i];
this.emit('results', [{id: uri + '123', group: '__world__'}]);
this.emit('results', [{id: uri + '456', group: 'private-group'}]);
}
this.emit('end');
});
}
......@@ -143,10 +147,12 @@ describe('WidgetController', function () {
// When new clients connect, all existing annotations should be unloaded
// before reloading annotations for each currently-connected client
annotationUI.addAnnotations([{id: '123'}]);
fakeCrossFrame.frames.push({uri: 'http://example.com/page-a'});
var uri1 = 'http://example.com/page-a';
fakeCrossFrame.frames.push({uri: uri1, searchUris: [uri1]});
$scope.$digest();
fakeAnnotationMapper.unloadAnnotations = sandbox.spy();
fakeCrossFrame.frames.push({uri: 'http://example.com/page-b'});
var uri2 = 'http://example.com/page-b';
fakeCrossFrame.frames.push({uri: uri2, searchUris: [uri2]});
$scope.$digest();
assert.calledWith(fakeAnnotationMapper.unloadAnnotations,
annotationUI.getState().annotations);
......@@ -154,17 +160,29 @@ describe('WidgetController', function () {
it('loads all annotations for a frame', function () {
var uri = 'http://example.com';
fakeCrossFrame.frames.push({uri: uri});
fakeCrossFrame.frames.push({uri: uri, searchUris: [uri]});
$scope.$digest();
var loadSpy = fakeAnnotationMapper.loadAnnotations;
assert.calledWith(loadSpy, [sinon.match({id: uri + '123'})]);
assert.calledWith(loadSpy, [sinon.match({id: uri + '456'})]);
});
it('loads all annotations for a frame with multiple urls', function () {
var uri = 'http://example.com/test.pdf';
var fingerprint = 'urn:x-pdf:fingerprint';
fakeCrossFrame.frames.push({uri: uri, searchUris: [uri, fingerprint]});
$scope.$digest();
var loadSpy = fakeAnnotationMapper.loadAnnotations;
assert.calledWith(loadSpy, [sinon.match({id: uri + '123'})]);
assert.calledWith(loadSpy, [sinon.match({id: fingerprint + '123'})]);
assert.calledWith(loadSpy, [sinon.match({id: uri + '456'})]);
assert.calledWith(loadSpy, [sinon.match({id: fingerprint + '456'})]);
});
it('loads all annotations for all frames', function () {
var uris = ['http://example.com', 'http://foobar.com'];
fakeCrossFrame.frames = uris.map(function (uri) {
return {uri: uri};
return {uri: uri, searchUris: [uri]};
});
$scope.$digest();
var loadSpy = fakeAnnotationMapper.loadAnnotations;
......@@ -179,7 +197,7 @@ describe('WidgetController', function () {
var id = uri + '123';
beforeEach(function () {
fakeCrossFrame.frames = [{uri: uri}];
fakeCrossFrame.frames = [{uri: uri, searchUris: [uri]}];
annotationUI.selectAnnotations([id]);
$scope.$digest();
});
......@@ -197,7 +215,7 @@ describe('WidgetController', function () {
});
it('fetches annotations for all groups', function () {
assert.calledWith(searchClients[0].get, {uri: uri, group: null});
assert.calledWith(searchClients[0].get, {uri: [uri], group: null});
});
it('loads annotations in one batch', function () {
......@@ -209,7 +227,7 @@ describe('WidgetController', function () {
var uri = 'http://example.com';
beforeEach(function () {
fakeCrossFrame.frames = [{uri: uri}];
fakeCrossFrame.frames = [{uri: uri, searchUris: [uri]}];
fakeGroups.focused = function () { return { id: 'a-group' }; };
$scope.$digest();
});
......@@ -219,7 +237,7 @@ describe('WidgetController', function () {
});
it('fetches annotations for the current group', function () {
assert.calledWith(searchClients[0].get, {uri: uri, group: 'a-group'});
assert.calledWith(searchClients[0].get, {uri: [uri], group: 'a-group'});
});
it('loads annotations in batches', function () {
......@@ -232,7 +250,7 @@ describe('WidgetController', function () {
var id = uri + 'does-not-exist';
beforeEach(function () {
fakeCrossFrame.frames = [{uri: uri}];
fakeCrossFrame.frames = [{uri: uri, searchUris: [uri]}];
annotationUI.selectAnnotations([id]);
fakeGroups.focused = function () { return { id: 'private-group' }; };
$scope.$digest();
......@@ -250,7 +268,7 @@ describe('WidgetController', function () {
it('focuses and scrolls to the annotation if already selected', function () {
var uri = 'http://example.com';
annotationUI.selectAnnotations(['123']);
fakeCrossFrame.frames.push({uri: uri});
fakeCrossFrame.frames.push({uri: uri, searchUris: [uri]});
var annot = {
$$tag: 'atag',
id: '123',
......@@ -272,7 +290,7 @@ describe('WidgetController', function () {
fakeDrafts.unsaved.returns([{id: uri + '123'}, {id: uri + '456'}]);
fakeCrossFrame.frames.push({uri: uri});
fakeCrossFrame.frames.push({uri: uri, searchUris: [uri]});
var loadSpy = fakeAnnotationMapper.loadAnnotations;
$scope.$broadcast(events.GROUP_FOCUSED);
......
......@@ -143,7 +143,7 @@ module.exports = function WidgetController(
annotationUI.addAnnotations(drafts.unsaved());
}
function _loadAnnotationsFor(uri, group) {
function _loadAnnotationsFor(uris, group) {
var searchClient = new SearchClient(store.SearchResource, {
// If no group is specified, we are fetching annotations from
// all groups in order to find out which group contains the selected
......@@ -177,7 +177,7 @@ module.exports = function WidgetController(
// Remove client from list of active search clients
searchClients.splice(searchClients.indexOf(searchClient), 1);
});
searchClient.get({uri: uri, group: group});
searchClient.get({uri: uris, group: group});
}
function isLoading() {
......@@ -197,12 +197,14 @@ module.exports = function WidgetController(
client.cancel();
});
var urls = frames.reduce(function (urls, frame) {
if (urls.indexOf(frame.uri) !== -1) {
return urls;
} else {
return urls.concat(frame.uri);
var searchUris = frames.reduce(function (uris, frame) {
for (var i = 0; i < frame.searchUris.length; i++) {
var uri = frame.searchUris[i];
if (uris.indexOf(uri) === -1) {
uris.push(uri);
}
}
return uris;
}, []);
// If there is no selection, load annotations only for the focused group.
......@@ -219,12 +221,10 @@ module.exports = function WidgetController(
var group = annotationUI.hasSelectedAnnotations() ?
null : groups.focused().id;
for (var i=0; i < urls.length; i++) {
_loadAnnotationsFor(urls[i], group);
}
if (searchUris.length > 0) {
_loadAnnotationsFor(searchUris, group);
if (urls.length > 0) {
streamFilter.resetFilter().addClause('/uri', 'one_of', urls);
streamFilter.resetFilter().addClause('/uri', 'one_of', searchUris);
streamer.setConfig('filter', {filter: streamFilter.getFilter()});
}
}
......
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