Commit 25b2516d authored by Robert Knight's avatar Robert Knight

Make '#annotations' fragment parsing more robust

When parsing the '#annotations' fragment, ignore any extra content
outside of the url-safe-base64 character set for annotation IDs.

This helps in cases where extra content has been appended to the URL
fragment after '#annotations:<ID>', before the client loads. This
happens at one point during loading of Medium.com pages for example.
parent 82d1ea97
'use strict';
var annotationIDs = require('../util/annotation-ids');
var docs = 'https://h.readthedocs.org/en/latest/hacking/customized-embedding.html';
/**
......@@ -13,6 +15,18 @@ function config(window_) {
document.querySelector('link[type="application/annotator+html"]').href,
};
// Parse config from `<meta name="hypothesis-config" content="<JSON>">` tags
var configElement = window_.document
.querySelector('meta[name="hypothesis-config"]');
if (configElement) {
try {
Object.assign(options, JSON.parse(configElement.content));
} catch (err) {
console.warn('Could not parse Hypothesis config from', configElement);
}
}
// Parse config from `window.hypothesisConfig` function
if (window_.hasOwnProperty('hypothesisConfig')) {
if (typeof window_.hypothesisConfig === 'function') {
Object.assign(options, window_.hypothesisConfig());
......@@ -21,9 +35,9 @@ function config(window_) {
}
}
var annotFragmentMatch = window_.location.hash.match(/^#annotations:(.*)/);
if (annotFragmentMatch) {
options.annotations = annotFragmentMatch[1];
var directLinkedID = annotationIDs.extractIDFromURL(window_.location.href);
if (directLinkedID) {
options.annotations = directLinkedID;
}
return options;
}
......
......@@ -3,13 +3,28 @@
var config = require('../config');
describe('annotator configuration', function () {
var fakeMetaConfig;
var fakeWindowBase = {
document: {
querySelector: sinon.stub().returns({href: 'app.html'}),
querySelector: sinon.spy(function (selector) {
if (selector === 'link[type="application/annotator+html"]') {
return {href: 'app.html'};
} else if (selector === 'meta[name="hypothesis-config"]' &&
fakeMetaConfig) {
return {content:fakeMetaConfig};
} else {
return null;
}
}),
},
location: {hash: ''},
};
beforeEach(function () {
fakeMetaConfig = '';
});
it('reads the app src from the link tag', function () {
var linkEl = document.createElement('link');
linkEl.type = 'application/annotator+html';
......@@ -23,7 +38,7 @@ describe('annotator configuration', function () {
it('reads the #annotation query fragment', function () {
var fakeWindow = Object.assign({}, fakeWindowBase, {
location: {hash:'#annotations:456'},
location: {href:'https://foo.com/#annotations:456'},
});
assert.deepEqual(config(fakeWindow), {
app: 'app.html',
......@@ -42,4 +57,12 @@ describe('annotator configuration', function () {
firstRun: true,
});
});
it('merges the config from the "hypothesis-config" meta tag', function () {
fakeMetaConfig = '{"annotations":"456"}';
assert.deepEqual(config(fakeWindowBase), {
app: 'app.html',
annotations: '456',
});
});
});
'use strict';
function extractIDFromURL(url) {
try {
var annotFragmentMatch = url.match(/#annotations:([A-Za-z0-9_-]+)$/);
if (annotFragmentMatch) {
return annotFragmentMatch[1];
} else {
return null;
}
} catch (err) {
return null;
}
}
module.exports = {
extractIDFromURL: extractIDFromURL,
};
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