Commit c1d03a03 authored by Nick Stenning's avatar Nick Stenning

Load API URL from a settings object, not a <link> tag

The approach of embedding a link tag in the app.html doesn't really give
us a great deal of flexibility. URLs within the application, perhaps as
a result, tend to be created either from baseURI or from the API URL,
called `serviceUrl` in the code.

This commit leaves the <base> tag alone, but:

- replaces the serviceUrl <link> tag with a settings object,
  `window.hypothesis.settings` which is inlined into app.html.
- replaces the serviceUrl angular service with a generic settings
  service.
- renames serviceUrl to apiUrl, to make its purpose more obvious.
parent a3f7a2cc
...@@ -162,7 +162,7 @@ module.exports = angular.module('h', [ ...@@ -162,7 +162,7 @@ module.exports = angular.module('h', [
.service('unicode', require('./unicode')) .service('unicode', require('./unicode'))
.service('viewFilter', require('./view-filter')) .service('viewFilter', require('./view-filter'))
.factory('serviceUrl', require('./service-url')) .factory('settings', require('./settings'))
.value('AnnotationSync', require('./annotation-sync')) .value('AnnotationSync', require('./annotation-sync'))
.value('AnnotationUISync', require('./annotation-ui-sync')) .value('AnnotationUISync', require('./annotation-ui-sync'))
......
...@@ -7,8 +7,8 @@ var currentToken = null; ...@@ -7,8 +7,8 @@ var currentToken = null;
// @ngInject // @ngInject
function fetchToken($http, $q, jwtHelper, serviceUrl, session) { function fetchToken($http, $q, jwtHelper, session, settings) {
var tokenUrl = new URL('token', serviceUrl).href; var tokenUrl = new URL('token', settings.apiUrl).href;
if (currentToken === null || jwtHelper.isTokenExpired(currentToken)) { if (currentToken === null || jwtHelper.isTokenExpired(currentToken)) {
if (tokenPromise === null) { if (tokenPromise === null) {
...@@ -47,13 +47,13 @@ function fetchToken($http, $q, jwtHelper, serviceUrl, session) { ...@@ -47,13 +47,13 @@ function fetchToken($http, $q, jwtHelper, serviceUrl, session) {
// @ngInject // @ngInject
function tokenGetter($injector, config, serviceUrl) { function tokenGetter($injector, config, settings) {
var requestUrl = config.url; var requestUrl = config.url;
// Only send the token on requests to the annotation storage service // Only send the token on requests to the annotation storage service
// and only if it is not the token request itself. // and only if it is not the token request itself.
if (requestUrl !== serviceUrl) { if (requestUrl !== settings.apiUrl) {
if (requestUrl.slice(0, serviceUrl.length) === serviceUrl) { if (requestUrl.slice(0, settings.apiUrl.length) === settings.apiUrl) {
return authPromise return authPromise
.then(function () { .then(function () {
return $injector.invoke(fetchToken); return $injector.invoke(fetchToken);
......
/**
* @ngdoc service
* @name serviceUrl
*
* @description
* The 'serviceUrl' exposes the base URL of the API backend.
*/
// @ngInject
function serviceUrl($document) {
return $document
.find('link')
.filter(function () {
return (this.rel === 'service' &&
this.type === 'application/annotatorsvc+json');
})
.filter(function () {
return this.href;
})
.prop('href');
}
module.exports = serviceUrl;
'use strict';
var angular = require('angular');
/**
* @ngdoc factory
* @name settings
*
* @description
* The 'settings' factory exposes shared application settings, read from the
* global variable 'hypothesis.settings' in the app page.
*/
// @ngInject
function settings($window) {
var data = {};
if ($window.hypothesis && $window.hypothesis.settings) {
angular.copy($window.hypothesis.settings, data);
}
return data;
}
module.exports = settings;
...@@ -10,16 +10,15 @@ ...@@ -10,16 +10,15 @@
# store.SearchResource(). # store.SearchResource().
### ###
module.exports = [ module.exports = [
'$http', '$resource', 'serviceUrl' '$http', '$resource', 'settings'
($http, $resource, serviceUrl) -> ($http, $resource, settings) ->
camelize = (string) -> camelize = (string) ->
string.replace /(?:^|_)([a-z])/g, (_, char) -> char.toUpperCase() string.replace /(?:^|_)([a-z])/g, (_, char) -> char.toUpperCase()
store = store =
$resolved: false $resolved: false
# We call the service_url and the backend api gives back # We call the API root and it gives back the actions it provides.
# the actions and urls it provides. $promise: $http.get(settings.apiUrl)
$promise: $http.get(serviceUrl)
.finally -> store.$resolved = true .finally -> store.$resolved = true
.then (response) -> .then (response) ->
for name, actions of response.data.links for name, actions of response.data.links
...@@ -27,6 +26,6 @@ module.exports = [ ...@@ -27,6 +26,6 @@ module.exports = [
# For the search resource, one URL is given for all actions. # For the search resource, one URL is given for all actions.
# For the annotations, each action has its own URL. # For the annotations, each action has its own URL.
prop = "#{camelize(name)}Resource" prop = "#{camelize(name)}Resource"
store[prop] = $resource(actions.url or serviceUrl, {}, actions) store[prop] = $resource(actions.url or settings.apiUrl, {}, actions)
store store
] ]
...@@ -13,7 +13,7 @@ describe 'store', -> ...@@ -13,7 +13,7 @@ describe 'store', ->
beforeEach module ($provide) -> beforeEach module ($provide) ->
sandbox = sinon.sandbox.create() sandbox = sinon.sandbox.create()
$provide.value 'serviceUrl', 'http://example.com/api' $provide.value 'settings', {apiUrl: 'http://example.com/api'}
return return
afterEach -> afterEach ->
......
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