Commit e32aa63c authored by Nick Stenning's avatar Nick Stenning

Merge pull request #3085 from hypothesis/open-sidebar-when-annot-fragment-present

(1/3) Open sidebar and set selection when '#annotations' URL fragment is present
parents 76478213 7f69532e
......@@ -2,12 +2,20 @@
function value(selection) {
if (Object.keys(selection).length) {
return selection;
return Object.freeze(selection);
} else {
return null;
}
}
function initialSelection(settings) {
var selection = {};
if (settings.annotations) {
selection[settings.annotations] = true;
}
return value(selection);
}
/**
* Stores the UI state of the annotator in connected clients.
*
......@@ -17,7 +25,9 @@ function value(selection) {
* - The state of the bucket bar
*
*/
module.exports = function () {
// @ngInject
module.exports = function (settings) {
return {
visibleHighlights: false,
......@@ -25,7 +35,7 @@ module.exports = function () {
focusedAnnotationMap: null,
// Contains a map of annotation id:true pairs.
selectedAnnotationMap: null,
selectedAnnotationMap: initialSelection(settings),
/**
* @ngdoc method
......@@ -62,17 +72,19 @@ module.exports = function () {
},
/**
* @ngdoc method
* @name annotationUI.selectAnnotations
* @returns nothing
* @description Takes an array of annotation objects and uses them to
* set the selectedAnnotationMap property.
* Set the currently selected annotation IDs.
*
* @param {Array<string|{id:string}>} annotations - Annotations or IDs
* of annotations to select.
*/
selectAnnotations: function (annotations) {
var selection = {};
for (var i = 0, annotation; i < annotations.length; i++) {
annotation = annotations[i];
selection[annotation.id] = true;
for (var i = 0; i < annotations.length; i++) {
if (typeof annotations[i] === 'string') {
selection[annotations[i]] = true;
} else {
selection[annotations[i].id] = true;
}
}
this.selectedAnnotationMap = value(selection);
},
......
'use strict';
var docs = 'https://h.readthedocs.org/en/latest/hacking/customized-embedding.html';
/**
* Reads the Hypothesis configuration from the environment.
*
* @param {Window} window_ - The Window object to read config from.
*/
function config(window_) {
var options = {
app: window_.
document.querySelector('link[type="application/annotator+html"]').href,
};
if (window_.hasOwnProperty('hypothesisConfig')) {
if (typeof window_.hypothesisConfig === 'function') {
Object.assign(options, window_.hypothesisConfig());
} else {
throw new TypeError('hypothesisConfig must be a function, see: ' + docs);
}
}
var annotFragmentMatch = window_.location.hash.match(/^#annotations:(.*)/);
if (annotFragmentMatch) {
options.annotations = annotFragmentMatch[1];
}
return options;
}
module.exports = config;
Annotator = require('annotator')
queryString = require('query-string')
$ = Annotator.$
Guest = require('./guest')
module.exports = class Host extends Guest
constructor: (element, options) ->
if options.firstRun
options.app += (if '?' in options.app then '&' else '?') + 'firstrun'
appOpts = queryString.stringify(
Object.assign({}, options, {app: undefined})
)
options.app += (if '?' in options.app then '&' else '?') + appOpts
# Create the iframe
app = $('<iframe></iframe>')
......
'use strict';
require('../polyfills');
var extend = require('extend');
var Annotator = require('annotator');
// Polyfills
......@@ -32,23 +33,11 @@ Annotator.Plugin.CrossFrame.AnnotationSync = require('../annotation-sync');
Annotator.Plugin.CrossFrame.Bridge = require('../bridge');
Annotator.Plugin.CrossFrame.Discovery = require('../discovery');
var docs = 'https://h.readthedocs.org/en/latest/hacking/customized-embedding.html';
var appLinkEl =
document.querySelector('link[type="application/annotator+html"]');
var options = {
app: appLinkEl.href,
};
if (window.hasOwnProperty('hypothesisConfig')) {
if (typeof window.hypothesisConfig === 'function') {
extend(options, window.hypothesisConfig());
} else {
throw new TypeError('hypothesisConfig must be a function, see: ' + docs);
}
}
var options = require('./config')(window);
Annotator.noConflict().$.noConflict(true)(function() {
'use strict';
var Klass = window.PDFViewerApplication ?
Annotator.PdfSidebar :
Annotator.Sidebar;
......
......@@ -24,7 +24,7 @@ module.exports = class Sidebar extends Host
super
this.hide()
if options.firstRun
if options.firstRun || options.annotations
this.on 'panelReady', => this.show()
if @plugins.BucketBar?
......
'use strict';
var config = require('../config');
describe('annotator configuration', function () {
var fakeWindowBase = {
document: {
querySelector: sinon.stub().returns({href: 'app.html'}),
},
location: {hash: ''},
};
it('reads the app src from the link tag', function () {
var linkEl = document.createElement('link');
linkEl.type = 'application/annotator+html';
linkEl.href = 'https://test.hypothes.is/app.html';
document.head.appendChild(linkEl);
assert.deepEqual(config(window), {
app: linkEl.href,
});
document.head.removeChild(linkEl);
});
it('reads the #annotation query fragment', function () {
var fakeWindow = Object.assign({}, fakeWindowBase, {
location: {hash:'#annotations:456'},
});
assert.deepEqual(config(fakeWindow), {
app: 'app.html',
annotations: '456',
});
});
it('merges the config from hypothesisConfig()', function () {
var fakeWindow = Object.assign({}, fakeWindowBase, {
hypothesisConfig: function () {
return {firstRun: true};
},
});
assert.deepEqual(config(fakeWindow), {
app: 'app.html',
firstRun: true,
});
});
});
......@@ -84,3 +84,11 @@ describe 'Host', ->
assert.isTrue(host.visibleHighlights)
done()
host.publish('panelReady')
it 'passes options to the sidebar iframe', ->
appURL = 'http://localhost:1000/app.html'
host = createHost({
app: appURL,
annotations: '1234'
})
assert.equal(host.frame[0].children[0].src, appURL + '?annotations=1234')
......@@ -24,7 +24,7 @@ function authStateFromUserID(userid) {
module.exports = function AppController(
$controller, $document, $location, $rootScope, $route, $scope,
$window, annotationUI, auth, drafts, features, groups,
session
session, settings
) {
$controller('AnnotationUIController', {$scope: $scope});
......@@ -42,8 +42,6 @@ module.exports = function AppController(
// Allow all child scopes access to the session
$scope.session = session;
var isFirstRun = $location.search().hasOwnProperty('firstrun');
// App dialogs
$scope.accountDialog = {visible: false};
$scope.shareDialog = {visible: false};
......@@ -73,7 +71,7 @@ module.exports = function AppController(
// update the auth info in the top bar and show the login form
// after first install of the extension.
$scope.auth = authStateFromUserID(state.userid);
if (!state.userid && isFirstRun) {
if (!state.userid && settings.firstRun) {
$scope.login();
}
});
......
'use strict';
require('./polyfills');
var queryString = require('query-string');
// Initialize Raven. This is required at the top of this file
// so that it happens early in the app's startup flow
var settings = require('./settings')(document);
Object.assign(settings, queryString.parse(window.location.search));
if (settings.raven) {
var raven = require('./raven');
raven.init(settings.raven);
......
'use strict';
var annotationUIFactory = require('../annotation-ui');
describe('annotationUI', function () {
var annotationUI;
beforeEach(function () {
annotationUI = require('../annotation-ui')();
annotationUI = annotationUIFactory({});
});
describe('initialization', function () {
it('does not set a selection when settings.annotations is null', function () {
assert.isFalse(annotationUI.hasSelectedAnnotations());
});
it('sets the selection when settings.annotations is set', function () {
annotationUI = annotationUIFactory({annotations: 'testid'});
assert.deepEqual(annotationUI.selectedAnnotationMap, {
testid: true,
});
});
});
describe('.focusAnnotations()', function () {
......
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