brat-client
Version:
Client from brat rapid annotation tool
239 lines (204 loc) • 7.17 kB
JavaScript
// -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; -*-
// vim:set ft=javascript ts=2 sw=2 sts=2 cindent:
var URLMonitor = (function($, window, undefined) {
var URLMonitor = function(dispatcher) {
var that = this;
var reloadData = true;
var changed = false;
var newIntArgs = {};
that.url_hash = new URLHash();
// Thanks to:
// http://kilianvalkhof.com/2010/javascript/the-case-of-the-disappearing-favicon/
var setFavicon = function() {
var link = $('link[type="image/x-icon"]').remove().attr("href");
$('<link href="'+ link +'" rel="shortcut icon" type="image/x-icon" />').appendTo('head');
}
var updateURL = function() {
var new_hash = that.url_hash.getHash();
changed = false;
window.location.hash = new_hash;
setFavicon();
dispatcher.post('hideForm');
};
var setArguments = function(args, force) {
var oldArgs = that.url_hash.arguments;
var argSplit = URLHash.splitArgs(args);
if (!Util.isEqual(that.url_hash.extArguments, argSplit[1])) {
changed = true;
that.url_hash.setArguments(args);
dispatcher.post('argsChanged', [args, oldArgs]);
}
if (changed) {
// hashchange event will trigger
newIntArgs = argSplit[0];
updateURL();
} else if (force || !Util.isEqual(that.url_hash.intArguments, argSplit[0])) {
// hash is same, but internal arguments differ
that.url_hash.setArguments(args);
// hashchange event won't trigger, but internal args have
// changed, so we have to do updateState's job
dispatcher.post('hideForm');
dispatcher.post('argsChanged', [args, oldArgs]);
dispatcher.post('current', [that.url_hash.collection,
that.url_hash.document, that.url_hash.arguments, reloadData]);
reloadData = true;
}
};
var setDocument = function(doc, args) {
var oldDoc = that.url_hash.document;
if (oldDoc !== doc) {
changed = true;
that.url_hash.setDocument(doc);
dispatcher.post('docChanged', [doc, oldDoc]);
}
setArguments(args || null);
};
var setCollection = function(coll, doc, args) {
var oldColl = that.url_hash.collection;
if (oldColl !== coll) {
changed = true;
that.url_hash.setCollection(coll);
// keep "blind" down while loading new collection
$('#waiter').dialog('open');
dispatcher.post('ajax', [{
action: 'getCollectionInformation',
collection: coll
}, 'collectionLoaded', {
collection: coll,
keep: true
}]);
dispatcher.post('collectionChanged', [coll, oldColl]);
}
setDocument(doc || '', args);
}
var updateState = function() {
dispatcher.post('makeAjaxObsolete');
if (!changed) {
var new_url_hash = URLHash.parse(window.location.hash);
setCollection(new_url_hash.collection, new_url_hash.document,
$.extend(new_url_hash.arguments, newIntArgs));
that.url_hash = new_url_hash;
newIntArgs = {};
}
dispatcher.post('current', [that.url_hash.collection,
that.url_hash.document, that.url_hash.arguments, reloadData]);
reloadData = true;
};
var forceUpdate = function() {
$(window).trigger('hashchange');
};
var preventReloadByURL = function() {
reloadData = false;
}
var allowReloadByURL = function() {
reloadData = true;
}
var init = function() {
$(window).bind('hashchange', updateState);
forceUpdate();
}
dispatcher.
on('forceUpdate', forceUpdate).
on('setArguments', setArguments).
on('setDocument', setDocument).
on('setCollection', setCollection).
on('preventReloadByURL', preventReloadByURL).
on('allowReloadByURL', allowReloadByURL).
on('init', init);
};
return URLMonitor;
})(jQuery, window);
var URLHash = (function($, window, undefined) {
var URLHash = function(collection, _document, _arguments) {
var that = this;
that.collection = collection;
that.document = _document || '';
that.arguments = _arguments || {};
that.calcArgs();
}
URLHash.prototype = {
calcArgs: function() {
var args = URLHash.splitArgs(this.arguments);
this.intArguments = args[0];
this.extArguments = args[1];
},
setArgument: function(argument, value) {
if (!this.arguments) {
this.arguments = {};
}
this.arguments[argument] = value;
this.calcArgs();
return this;
},
setArguments: function(_arguments) {
// the $.extend here basically takes a copy; raw assignment
// would allow changes of the args to alter original, which
// could be e.g. the "args" of search results
this.arguments = $.extend({}, _arguments || {});
this.calcArgs();
return this;
},
setDocument: function(_document) {
this.document = _document;
return this;
},
setCollection: function(collection) {
this.collection = collection;
return this;
},
getHash: function() {
var url_hash = this.collection + this.document;
var url_args = Util.param(this.extArguments);
if (url_args.length) {
url_hash += '?' + url_args;
}
if (url_hash.length) {
url_hash = '#' + url_hash;
}
return url_hash;
},
};
// arguments that do not appear in the URL
var INT_ARGS = ['match', 'matchfocus', 'edited'];
URLHash.splitArgs = function(args) {
var intArgs = {};
var extArgs = $.extend({}, args);
var intArgNameLen = INT_ARGS.length;
for (var i = 0; i < intArgNameLen; i++) {
intArgs[INT_ARGS[i]] = extArgs[INT_ARGS[i]];
delete extArgs[INT_ARGS[i]];
}
return [intArgs, extArgs];
};
// TODO: Document and conform variables to the rest of the object
URLHash.parse = function(hash) {
if (hash.length) {
// Remove the leading hash (#)
hash = hash.substr(1);
}
var pathAndArgs = hash.split('?');
var path = pathAndArgs[0] || '';
var argsStr = pathAndArgs[1] || '';
var coll;
var slashPos = path.lastIndexOf('/');
if (slashPos === -1) {
coll = '/';
} else {
coll = path.substr(0, slashPos + 1);
if (coll[coll.length - 1] !== '/') {
coll += '/';
}
if (coll[0] !== '/') {
coll = '/' + coll;
}
}
var doc = path.substr(slashPos + 1);
var args = Util.deparam(argsStr);
return new URLHash(coll, doc, args);
};
return URLHash;
})(jQuery, window)
module.exports = {
URLMonitor: URLMonitor,
URLHash: URLHash
};