mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-04 15:09:16 +02:00
Added several usage examples, fixed bugs, turned off restore by default
This commit is contained in:
parent
0e08b734ec
commit
416f7ab6a0
112 changed files with 23903 additions and 3348 deletions
178
libs/annotator/lib/spec/plugin/annotateitpermissions_spec.js
Normal file
178
libs/annotator/lib/spec/plugin/annotateitpermissions_spec.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe('Annotator.Plugin.AnnotateItPermissions', function() {
|
||||
var el, permissions;
|
||||
el = null;
|
||||
permissions = null;
|
||||
beforeEach(function() {
|
||||
el = $("<div class='annotator-viewer'></div>").appendTo('body')[0];
|
||||
return permissions = new Annotator.Plugin.AnnotateItPermissions(el);
|
||||
});
|
||||
afterEach(function() {
|
||||
return $(el).remove();
|
||||
});
|
||||
it("it should set user for newly created annotations on beforeAnnotationCreated", function() {
|
||||
var ann;
|
||||
ann = {};
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'fookey'
|
||||
});
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
return assert.equal(ann.user, 'alice');
|
||||
});
|
||||
it("it should set consumer for newly created annotations on beforeAnnotationCreated", function() {
|
||||
var ann;
|
||||
ann = {};
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'fookey'
|
||||
});
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
return assert.equal(ann.consumer, 'fookey');
|
||||
});
|
||||
return describe('authorize', function() {
|
||||
var annotations;
|
||||
annotations = null;
|
||||
beforeEach(function() {
|
||||
return annotations = [
|
||||
{}, {
|
||||
user: 'alice'
|
||||
}, {
|
||||
user: 'alice',
|
||||
consumer: 'annotateit'
|
||||
}, {
|
||||
permissions: {}
|
||||
}, {
|
||||
permissions: {
|
||||
'read': ['group:__world__']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['group:__authenticated__']
|
||||
}
|
||||
}, {
|
||||
consumer: 'annotateit',
|
||||
permissions: {
|
||||
'read': ['group:__consumer__']
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
it('should NOT allow any action for an annotation with no owner info and no permissions', function() {
|
||||
var a;
|
||||
a = annotations[0];
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
assert.isFalse(permissions.authorize('foo', a));
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
return assert.isFalse(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should NOT allow any action if an annotation has only user set (but no consumer)', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
assert.isFalse(permissions.authorize('foo', a));
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
return assert.isFalse(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should allow any action if the current auth info identifies the owner of the annotation', function() {
|
||||
var a;
|
||||
a = annotations[2];
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
return assert.isTrue(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should NOT allow any action for an annotation with no owner info and empty permissions field', function() {
|
||||
var a;
|
||||
a = annotations[3];
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
assert.isFalse(permissions.authorize('foo', a));
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
return assert.isFalse(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should allow an action when the action field contains the world group', function() {
|
||||
var a;
|
||||
a = annotations[4];
|
||||
assert.isTrue(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'alice',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('read', a));
|
||||
});
|
||||
it('should allow an action when the action field contains the authenticated group and the plugin has auth info', function() {
|
||||
var a;
|
||||
a = annotations[5];
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'anywhere'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
it('should allow an action when the action field contains the consumer group and the plugin has auth info with a matching consumer', function() {
|
||||
var a;
|
||||
a = annotations[6];
|
||||
assert.isFalse(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'anywhere'
|
||||
});
|
||||
assert.isFalse(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('read', a));
|
||||
});
|
||||
it('should allow an action when the action field contains the consumer group and the plugin has auth info with a matching consumer', function() {
|
||||
var a;
|
||||
a = annotations[6];
|
||||
assert.isFalse(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'anywhere'
|
||||
});
|
||||
assert.isFalse(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'annotateit'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('read', a));
|
||||
});
|
||||
return it('should allow an action when the user is an admin of the annotation\'s consumer', function() {
|
||||
var a;
|
||||
a = annotations[2];
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'anywhere',
|
||||
admin: true
|
||||
});
|
||||
assert.isFalse(permissions.authorize('read', a));
|
||||
permissions.setUser({
|
||||
userId: 'anyone',
|
||||
consumerKey: 'annotateit',
|
||||
admin: true
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('read', a));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=annotateitpermissions_spec.map
|
||||
*/
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "annotateitpermissions_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/annotateitpermissions_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA,CAAS,CAA0C,CAAA,KAAnD,CAAmD,+BAAnD;CACE,KAAA,SAAA;CAAA,CAAA,CAAK,CAAL;CAAA,CACA,CAAc,CADd,OACA;CADA,CAGA,CAAW,MAAA,CAAX;CACE,CAAA,CAAK,CAAL,EAAK,EAAA,8BAAA;CACuB,CAAV,CAAA,CAAA,EAAgB,GAAP,EAA3B,UAAkB;CAFpB,EAAW;CAHX,CAOA,CAAU,MAAV;CAAa,CAAA,IAAA,KAAA;CAAb,EAAU;CAPV,CASA,CAAkF,MAAA,oEAAlF;CACE,EAAA,KAAA;CAAA,CAAA,CAAA,CAAA;CAAA,GACA,GAAA,IAAW;CAAS,CAAS,IAAR,CAAD;CAAA,CAA+B,IAAb,EAAlB,GAAkB;CADtC,KACA;CADA,CAEA,CAAyC,CAAzC,GAAA,kBAAA;CACO,CAAgB,CAAP,CAAhB,CAAA,CAAM,CAAN,IAAA;CAJF,EAAkF;CATlF,CAeA,CAAsF,MAAA,wEAAtF;CACE,EAAA,KAAA;CAAA,CAAA,CAAA,CAAA;CAAA,GACA,GAAA,IAAW;CAAS,CAAS,IAAR,CAAD;CAAA,CAA+B,IAAb,EAAlB,GAAkB;CADtC,KACA;CADA,CAEA,CAAyC,CAAzC,GAAA,kBAAA;CACO,CAAoB,CAAX,EAAhB,CAAM,EAAN,GAAA;CAJF,EAAsF;CAM7E,CAAa,CAAA,KAAtB,CAAA,EAAA;CACE,OAAA,GAAA;CAAA,EAAc,CAAd,OAAA;CAAA,EAEW,CAAX,KAAW,CAAX;GACgB,QAAd,EAAA;EAAc,OACZ;CACA,CAAQ,EAAN,GAAF,GAAE;EACF,QAHY;CAGZ,CAAQ,EAAN,GAAF,GAAE;CAAF,CAA2B,MAAV,EAAA,EAAjB;EACA,QAJY;CAIZ,CAAe,QAAb,CAAA;EACF,QALY;CAKZ,CACe,QAAb,CAAA;CAAa,CACH,IAAR,MAAA,KAAQ;YAFZ;EAKA,QAVY;CAUZ,CACe,QAAb,CAAA;CAAa,CACH,MAAV,IAAA,aAAU;YAFZ;EAKA,QAfY;CAeZ,CACY,MAAV,EAAA,EADF;CAAA,CAEe,QAAb,CAAA;CAAa,CACH,IAAR,MAAA,QAAQ;YAHZ;UAfY;CADL;CAAX,IAAW;CAFX,CA0BA,CAA0F,CAA1F,KAA0F,4EAA1F;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CAD1B,CAE4C,GAA7B,CAAf,CAAA,EAAe,EAAW;CAF1B,KAGA,CAAA,IAAW;CAAS,CAAS,IAAR,CAAD,CAAC;CAAD,CAA+B,MAAb,GAAA,CAAlB;CAHpB,OAGA;CAHA,CAI4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CACnB,CAAqC,GAA7B,CAAT,CAAN,EAAe,EAAW,EAA1B;CANF,IAA0F;CA1B1F,CAkCA,CAAuF,CAAvF,KAAuF,yEAAvF;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CAD1B,CAE4C,GAA7B,CAAf,CAAA,EAAe,EAAW;CAF1B,KAGA,CAAA,IAAW;CAAS,CAAS,IAAR,CAAD,CAAC;CAAD,CAA+B,MAAb,GAAA,CAAlB;CAHpB,OAGA;CAHA,CAI4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CACnB,CAAqC,GAA7B,CAAT,CAAN,EAAe,EAAW,EAA1B;CANF,IAAuF;CAlCvF,CA0CA,CAA8F,CAA9F,KAA8F,gFAA9F;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,KACA,CAAA,IAAW;CAAS,CAAS,IAAR,CAAD,CAAC;CAAD,CAA+B,MAAb,GAAA,CAAlB;CADpB,OACA;CADA,CAE2C,EAA7B,EAAd,GAAc,EAAW;CAClB,CAAoC,GAA7B,CAAR,GAAQ,EAAW,EAAzB;CAJF,IAA8F;CA1C9F,CAgDA,CAAmG,CAAnG,KAAmG,qFAAnG;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CAD1B,CAE4C,GAA7B,CAAf,CAAA,EAAe,EAAW;CAF1B,KAGA,CAAA,IAAW;CAAS,CAAS,IAAR,CAAD,CAAC;CAAD,CAA+B,MAAb,GAAA,CAAlB;CAHpB,OAGA;CAHA,CAI4C,EAA7B,EAAf,CAAA,EAAe,EAAW;CACnB,CAAqC,GAA7B,CAAT,CAAN,EAAe,EAAW,EAA1B;CANF,IAAmG;CAhDnG,CAwDA,CAA4E,CAA5E,KAA4E,8DAA5E;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC4C,IAA5C,GAAc,EAAW;CADzB,KAEA,CAAA,IAAW;CAAS,CAAS,IAAR,CAAD,CAAC;CAAD,CAA+B,MAAb,GAAA,CAAlB;CAFpB,OAEA;CACO,CAAqC,IAAtC,GAAQ,EAAW,EAAzB;CAJF,IAA4E;CAxD5E,CA8DA,CAAiH,CAAjH,KAAiH,mGAAjH;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC+C,IAA/C,CAAA,CAAe,CAAA,EAAW;CAD1B,KAEA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,EAAnB,CAAmB;CAFvC,OAEA;CACO,CAAuC,IAAxC,EAAQ,CAAA,EAAW,EAAzB;CAJF,IAAiH;CA9DjH,CAoEA,CAAqI,CAArI,KAAqI,uHAArI;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC6C,IAA7C,CAAA,EAAe,EAAW;CAD1B,KAEA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,EAAnB,CAAmB;CAFvC,OAEA;CAFA,CAG6C,IAA7C,CAAA,EAAe,EAAW;CAH1B,KAIA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,GAAA,CAAnB;CAJpB,OAIA;CACO,CAAqC,IAAtC,GAAQ,EAAW,EAAzB;CANF,IAAqI;CApErI,CA4EA,CAAqI,CAArI,KAAqI,uHAArI;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,CAC6C,IAA7C,CAAA,EAAe,EAAW;CAD1B,KAEA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,EAAnB,CAAmB;CAFvC,OAEA;CAFA,CAG6C,IAA7C,CAAA,EAAe,EAAW;CAH1B,KAIA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,GAAA,CAAnB;CAJpB,OAIA;CACO,CAAqC,IAAtC,GAAQ,EAAW,EAAzB;CANF,IAAqI;CAQlI,CAAH,CAAqF,MAAA,EAArF,qEAAA;CACE,SAAA;CAAA,EAAI,GAAJ,KAAgB;CAAhB,KACA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,EAAnB,CAAmB;CAAnB,CAAmD,EAAnD,CAA4C,GAAA;CADhE,OACA;CADA,CAE6C,IAA7C,CAAA,EAAe,EAAW;CAF1B,KAGA,CAAA,IAAW;CAAS,CAAS,IAAR,EAAA;CAAD,CAAgC,MAAb,GAAA,CAAnB;CAAA,CAAqD,EAArD,CAA8C,GAAA;CAHlE,OAGA;CACO,CAAqC,IAAtC,GAAQ,EAAW,EAAzB;CALF,IAAqF;CArFvF,EAAsB;CAtB2B"
|
||||
}
|
131
libs/annotator/lib/spec/plugin/auth_spec.js
Normal file
131
libs/annotator/lib/spec/plugin/auth_spec.js
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
var B64, base64Encode, base64UrlEncode, makeToken;
|
||||
|
||||
Date.prototype.toISO8601String = DateToISO8601String;
|
||||
|
||||
B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
base64Encode = function(data) {
|
||||
var ac, bits, enc, h1, h2, h3, h4, i, o1, o2, o3, r, tmp_arr;
|
||||
if (typeof btoa !== "undefined" && btoa !== null) {
|
||||
return btoa(data);
|
||||
} else {
|
||||
i = 0;
|
||||
ac = 0;
|
||||
enc = "";
|
||||
tmp_arr = [];
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
data += '';
|
||||
while (i < data.length) {
|
||||
o1 = data.charCodeAt(i++);
|
||||
o2 = data.charCodeAt(i++);
|
||||
o3 = data.charCodeAt(i++);
|
||||
bits = o1 << 16 | o2 << 8 | o3;
|
||||
h1 = bits >> 18 & 0x3f;
|
||||
h2 = bits >> 12 & 0x3f;
|
||||
h3 = bits >> 6 & 0x3f;
|
||||
h4 = bits & 0x3f;
|
||||
tmp_arr[ac++] = B64.charAt(h1) + B64.charAt(h2) + B64.charAt(h3) + B64.charAt(h4);
|
||||
}
|
||||
enc = tmp_arr.join('');
|
||||
r = data.length % 3;
|
||||
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
|
||||
}
|
||||
};
|
||||
|
||||
base64UrlEncode = function(data) {
|
||||
var chop;
|
||||
data = base64Encode(data);
|
||||
chop = data.indexOf('=');
|
||||
if (chop !== -1) {
|
||||
data = data.slice(0, chop);
|
||||
}
|
||||
data = data.replace(/\+/g, '-');
|
||||
data = data.replace(/\//g, '_');
|
||||
return data;
|
||||
};
|
||||
|
||||
makeToken = function() {
|
||||
var rawToken;
|
||||
rawToken = {
|
||||
consumerKey: "key",
|
||||
issuedAt: new Date().toISO8601String(),
|
||||
ttl: 300,
|
||||
userId: "testUser"
|
||||
};
|
||||
return {
|
||||
rawToken: rawToken,
|
||||
encodedToken: 'header.' + base64UrlEncode(JSON.stringify(rawToken)) + '.signature'
|
||||
};
|
||||
};
|
||||
|
||||
describe('Annotator.Plugin.Auth', function() {
|
||||
var encodedToken, mock, mockAuth, rawToken;
|
||||
mock = null;
|
||||
rawToken = null;
|
||||
encodedToken = null;
|
||||
mockAuth = function(options) {
|
||||
var a, el;
|
||||
el = $('<div></div>')[0];
|
||||
a = new Annotator.Plugin.Auth(el, options);
|
||||
return {
|
||||
elem: el,
|
||||
auth: a
|
||||
};
|
||||
};
|
||||
beforeEach(function() {
|
||||
var _ref;
|
||||
_ref = makeToken(), rawToken = _ref.rawToken, encodedToken = _ref.encodedToken;
|
||||
return mock = mockAuth({
|
||||
token: encodedToken,
|
||||
autoFetch: false
|
||||
});
|
||||
});
|
||||
it("uses token supplied in options by default", function() {
|
||||
return assert.equal(mock.auth.token, encodedToken);
|
||||
});
|
||||
xit("makes an ajax request to tokenUrl to retrieve token otherwise");
|
||||
it("sets annotator:headers data on its element with token data", function() {
|
||||
var data;
|
||||
data = $(mock.elem).data('annotator:headers');
|
||||
assert.isNotNull(data);
|
||||
return assert.equal(data['x-annotator-auth-token'], encodedToken);
|
||||
});
|
||||
it("should call callbacks given to #withToken immediately if it has a valid token", function() {
|
||||
var callback;
|
||||
callback = sinon.spy();
|
||||
mock.auth.withToken(callback);
|
||||
return assert.isTrue(callback.calledWith(rawToken));
|
||||
});
|
||||
xit("should call callbacks given to #withToken after retrieving a token");
|
||||
return describe("#haveValidToken", function() {
|
||||
it("returns true when the current token is valid", function() {
|
||||
return assert.isTrue(mock.auth.haveValidToken());
|
||||
});
|
||||
it("returns false when the current token is missing a consumerKey", function() {
|
||||
delete mock.auth._unsafeToken.consumerKey;
|
||||
return assert.isFalse(mock.auth.haveValidToken());
|
||||
});
|
||||
it("returns false when the current token is missing an issuedAt", function() {
|
||||
delete mock.auth._unsafeToken.issuedAt;
|
||||
return assert.isFalse(mock.auth.haveValidToken());
|
||||
});
|
||||
it("returns false when the current token is missing a ttl", function() {
|
||||
delete mock.auth._unsafeToken.ttl;
|
||||
return assert.isFalse(mock.auth.haveValidToken());
|
||||
});
|
||||
return it("returns false when the current token expires in the past", function() {
|
||||
mock.auth._unsafeToken.ttl = 0;
|
||||
assert.isFalse(mock.auth.haveValidToken());
|
||||
mock.auth._unsafeToken.ttl = 86400;
|
||||
mock.auth._unsafeToken.issuedAt = "1970-01-01T00:00";
|
||||
return assert.isFalse(mock.auth.haveValidToken());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=auth_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/auth_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/auth_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "auth_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/auth_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA,IAAA,yCAAA;;AAAA,CAAA,EAAwB,CAApB,KAAE,MAAN,IAAA;;AAEA,CAFA,EAEA,gEAFA;;AAIA,CAJA,EAIe,CAAA,KAAC,GAAhB;CACE,KAAA,kDAAA;CAAA,CAAA,EAAG,wCAAH;CAEO,GAAL,OAAA;IAFF,EAAA;CAME,EAAI,CAAJ;CAAA,CACA,CAAK,CAAL;CADA,CAAA,CAEA,CAAA;CAFA,CAAA,CAGU,CAAV,GAAA;AAEO,CAAP,GAAA;CACE,GAAA,SAAO;MANT;CAAA,CAAA,EAQA;CAEA,EAAU,CAAI,EAAd,KAAM;AAEiB,CAArB,CAAA,CAAK,CAAI,EAAT,IAAK;AACgB,CADrB,CACA,CAAK,CAAI,EAAT,IAAK;AACgB,CAFrB,CAEA,CAAK,CAAI,EAAT,IAAK;CAFL,CAIO,CAAA,CAAP,EAAA;CAJA,CAMA,CAAK,CAAA,EAAL;CANA,CAOA,CAAK,CAAA,EAAL;CAPA,CAQA,CAAK,CAAA,EAAL;CARA,CASA,CAAK,CAAA,EAAL;AAGQ,CAZR,CAYQ,CAAQ,GAAhB,CAAQ;CAxBV,IAUA;CAVA,CA0BM,CAAN,CAAA,GAAa;CA1Bb,EA4BI,CAAJ,EAAI;CACJ,CAA+B,CAAb,CAAiD,CAAjD,MAAX;IApCI;CAAA;;AAsCf,CA1CA,EA0CkB,CAAA,KAAC,MAAnB;CACE,GAAA,EAAA;CAAA,CAAA,CAAO,CAAP,QAAO;CAAP,CACA,CAAO,CAAP,GAAO;AAC4B,CAAnC,CAAA,EAAwB,CAAU;CAAlC,EAAO,CAAP,WAAA;IAFA;CAAA,CAGA,CAAO,CAAP,CAAO,EAAA;CAHP,CAIA,CAAO,CAAP,CAAO,EAAA;CALS,QAMhB;CANgB;;AAQlB,CAlDA,EAkDY,MAAZ;CACE,KAAA,EAAA;CAAA,CAAA,CAAW,KAAX;CAAW,CACI,EAAb,CADS,MACT;CADS,CAEK,EAAd,IAAA,OAAc;CAFL,CAGJ,CAAL,CAAA;CAHS,CAID,EAAR,EAAA,IAJS;CAAX,GAAA;SAMA;CAAA,CACY,EAAV,IAAA;CADF,CAEgB,CAAY,CAA1B,IAA0C,CAA5B,GAAd,GAA0B;CATlB;CAAA;;AAYZ,CA9DA,CA8DkC,CAAA,KAAlC,CAAkC,cAAlC;CACE,KAAA,gCAAA;CAAA,CAAA,CAAO,CAAP;CAAA,CACA,CAAW,CADX,IACA;CADA,CAEA,CAAe,CAFf,QAEA;CAFA,CAIA,CAAW,IAAA,CAAX,CAAY;CACV,IAAA,GAAA;CAAA,CAAA,CAAK,CAAL,SAAK;CAAL,CACQ,CAAA,CAAR,EAAwB,CAAhB,EAAS;WAEjB;CAAA,CACQ,EAAN,EAAA;CADF,CAEQ,EAAN,EAAA;CANO;CAJX,EAIW;CAJX,CAaA,CAAW,MAAA,CAAX;CACE,GAAA,IAAA;CAAA,CAAC,EAAD,GAA2B,CAA3B,CAA2B,GAA3B;CACgB,EAAT,CAAP,IAAO,GAAP;CAAgB,CAAQ,GAAP,CAAA,MAAD;CAAA,CAAiC,GAAjC,CAAsB,GAAA;CAF7B,KAEF;CAFT,EAAW;CAbX,CAiBA,CAAgD,MAAA,kCAAhD;CACS,CAAuB,EAAb,CAAjB,CAAM,KAAN,CAAA;CADF,EAAgD;CAjBhD,CAoBA,CAAA,4DAAA;CApBA,CAsBA,CAAiE,MAAA,mDAAjE;CACE,GAAA,IAAA;CAAA,EAAO,CAAP,eAAO;CAAP,GACA,EAAM,GAAN;CACO,CAAsC,EAA3B,CAAlB,CAAM,KAAN,CAAA,YAAkB;CAHpB,EAAiE;CAtBjE,CA2BA,CAAoF,MAAA,sEAApF;CACE,OAAA;CAAA,EAAW,CAAX,CAAgB,GAAhB;CAAA,GACA,IAAA,CAAA;CACO,KAAD,EAAgB,EAAR,CAAd;CAHF,EAAoF;CA3BpF,CAgCA,CAAA,iEAAA;CAES,CAAmB,CAAA,KAA5B,CAAA,QAAA;CACE,CAAA,CAAmD,CAAnD,KAAmD,qCAAnD;CACS,GAAW,EAAZ,OAAN,CAAc;CADhB,IAAmD;CAAnD,CAGA,CAAoE,CAApE,KAAoE,sDAApE;AACE,CAAA,GAAW,EAAX,KAAA,CAA6B;CACtB,GAAY,EAAb,CAAN,MAAA,CAAe;CAFjB,IAAoE;CAHpE,CAOA,CAAkE,CAAlE,KAAkE,oDAAlE;AACE,CAAA,GAAW,EAAX,EAAA,IAA6B;CACtB,GAAY,EAAb,CAAN,MAAA,CAAe;CAFjB,IAAkE;CAPlE,CAWA,CAA4D,CAA5D,KAA4D,8CAA5D;AACE,CAAA,EAAA,CAAW,EAAX,MAA6B;CACtB,GAAY,EAAb,CAAN,MAAA,CAAe;CAFjB,IAA4D;CAIzD,CAAH,CAA+D,MAAA,EAA/D,+CAAA;CACE,EAAA,CAAI,EAAJ,MAAsB;CAAtB,GACmB,EAAnB,CAAA,OAAe;CADf,EAEA,CAAI,CAFJ,CAEA,MAAsB;CAFtB,EAGkC,CAA9B,EAAJ,EAAA,IAAsB,MAHtB;CAIO,GAAY,EAAb,CAAN,MAAA,CAAe;CALjB,IAA+D;CAhBjE,EAA4B;CAnCI"
|
||||
}
|
110
libs/annotator/lib/spec/plugin/document_spec.js
Normal file
110
libs/annotator/lib/spec/plugin/document_spec.js
Normal file
|
@ -0,0 +1,110 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe('Annotator.Plugin.Document', function() {
|
||||
var $fix, annotator;
|
||||
$fix = null;
|
||||
annotator = null;
|
||||
beforeEach(function() {
|
||||
annotator = new Annotator($('<div></div>')[0], {});
|
||||
return annotator.addPlugin('Document');
|
||||
});
|
||||
afterEach(function() {
|
||||
return $(document).unbind();
|
||||
});
|
||||
describe('has an annotator', function() {
|
||||
return it('should have an annotator', function() {
|
||||
return assert.ok(annotator);
|
||||
});
|
||||
});
|
||||
describe('has the plugin', function() {
|
||||
return it('should have Document plugin', function() {
|
||||
return assert.ok('Document' in annotator.plugins);
|
||||
});
|
||||
});
|
||||
return describe('annotation should have some metadata', function() {
|
||||
var annotation, head;
|
||||
head = $("head");
|
||||
head.append('<link rel="alternate" href="foo.pdf" type="application/pdf"></link>');
|
||||
head.append('<link rel="alternate" href="foo.doc" type="application/msword"></link>');
|
||||
head.append('<link rel="bookmark" href="http://example.com/bookmark"></link>');
|
||||
head.append('<meta name="citation_doi" content="10.1175/JCLI-D-11-00015.1">');
|
||||
head.append('<meta name="citation_title" content="Foo">');
|
||||
head.append('<meta name="citation_pdf_url" content="foo.pdf">');
|
||||
head.append('<meta name="dc.identifier" content="doi:10.1175/JCLI-D-11-00015.1">');
|
||||
head.append('<meta name="dc.identifier" content="isbn:123456789">');
|
||||
head.append('<meta name="DC.type" content="Article">');
|
||||
head.append('<meta property="og:url" content="http://example.com">');
|
||||
head.append('<meta name="twitter:site" content="@okfn">');
|
||||
head.append('<link rel="icon" href="http://example.com/images/icon.ico"></link>');
|
||||
head.append('<meta name="eprints.title" content="Computer Lib / Dream Machines">');
|
||||
head.append('<meta name="prism.title" content="Literary Machines">');
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
return annotation = annotator.createAnnotation();
|
||||
});
|
||||
it('can create annotation', function() {
|
||||
return assert.ok(annotation);
|
||||
});
|
||||
it('should have a document', function() {
|
||||
return assert.ok(annotation.document);
|
||||
});
|
||||
it('should have a title, derived from highwire metadata if possible', function() {
|
||||
return assert.equal(annotation.document.title, 'Foo');
|
||||
});
|
||||
it('should have links with absoulte hrefs and types', function() {
|
||||
assert.ok(annotation.document.link);
|
||||
assert.equal(annotation.document.link.length, 7);
|
||||
assert.match(annotation.document.link[0].href, /^.+runner.html(\?.*)?$/);
|
||||
assert.equal(annotation.document.link[1].rel, "alternate");
|
||||
assert.match(annotation.document.link[1].href, /^.+foo\.pdf$/);
|
||||
assert.equal(annotation.document.link[1].type, "application/pdf");
|
||||
assert.equal(annotation.document.link[2].rel, "alternate");
|
||||
assert.match(annotation.document.link[2].href, /^.+foo\.doc$/);
|
||||
assert.equal(annotation.document.link[2].type, "application/msword");
|
||||
assert.equal(annotation.document.link[3].rel, "bookmark");
|
||||
assert.equal(annotation.document.link[3].href, "http://example.com/bookmark");
|
||||
assert.equal(annotation.document.link[4].href, "doi:10.1175/JCLI-D-11-00015.1");
|
||||
assert.match(annotation.document.link[5].href, /.+foo\.pdf$/);
|
||||
assert.equal(annotation.document.link[5].type, "application/pdf");
|
||||
return assert.equal(annotation.document.link[6].href, "doi:10.1175/JCLI-D-11-00015.1");
|
||||
});
|
||||
it('should have highwire metadata', function() {
|
||||
assert.ok(annotation.document.highwire);
|
||||
assert.deepEqual(annotation.document.highwire.pdf_url, ['foo.pdf']);
|
||||
assert.deepEqual(annotation.document.highwire.doi, ['10.1175/JCLI-D-11-00015.1']);
|
||||
return assert.deepEqual(annotation.document.highwire.title, ['Foo']);
|
||||
});
|
||||
it('should have dublincore metadata', function() {
|
||||
assert.ok(annotation.document.dc);
|
||||
assert.deepEqual(annotation.document.dc.identifier, ["doi:10.1175/JCLI-D-11-00015.1", "isbn:123456789"]);
|
||||
return assert.deepEqual(annotation.document.dc.type, ["Article"]);
|
||||
});
|
||||
it('should have facebook metadata', function() {
|
||||
assert.ok(annotation.document.facebook);
|
||||
return assert.deepEqual(annotation.document.facebook.url, ["http://example.com"]);
|
||||
});
|
||||
it('should have eprints metadata', function() {
|
||||
assert.ok(annotation.document.eprints);
|
||||
return assert.deepEqual(annotation.document.eprints.title, ['Computer Lib / Dream Machines']);
|
||||
});
|
||||
it('should have prism metadata', function() {
|
||||
assert.ok(annotation.document.prism);
|
||||
return assert.deepEqual(annotation.document.prism.title, ['Literary Machines']);
|
||||
});
|
||||
it('should have twitter card metadata', function() {
|
||||
assert.ok(annotation.document.twitter);
|
||||
return assert.deepEqual(annotation.document.twitter.site, ['@okfn']);
|
||||
});
|
||||
it('should have unique uris', function() {
|
||||
var uris;
|
||||
uris = annotator.plugins.Document.uris();
|
||||
return assert.equal(uris.length, 5);
|
||||
});
|
||||
return it('should have a favicon', function() {
|
||||
return assert.equal(annotation.document.favicon, 'http://example.com/images/icon.ico');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=document_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/document_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/document_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "document_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/document_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
468
libs/annotator/lib/spec/plugin/filter_spec.js
Normal file
468
libs/annotator/lib/spec/plugin/filter_spec.js
Normal file
|
@ -0,0 +1,468 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe("Filter", function() {
|
||||
var element, plugin;
|
||||
plugin = null;
|
||||
element = null;
|
||||
beforeEach(function() {
|
||||
var annotator;
|
||||
element = $('<div />');
|
||||
annotator = {
|
||||
subscribe: sinon.spy(),
|
||||
element: {
|
||||
find: sinon.stub().returns($())
|
||||
}
|
||||
};
|
||||
plugin = new Annotator.Plugin.Filter(element[0]);
|
||||
return plugin.annotator = annotator;
|
||||
});
|
||||
afterEach(function() {
|
||||
return plugin.element.remove();
|
||||
});
|
||||
describe("events", function() {
|
||||
var filterElement;
|
||||
filterElement = null;
|
||||
beforeEach(function() {
|
||||
filterElement = $(plugin.html.filter);
|
||||
return plugin.element.append(filterElement);
|
||||
});
|
||||
afterEach(function() {
|
||||
return filterElement.remove();
|
||||
});
|
||||
it("should call Filter#_onFilterFocus when a filter input is focussed", function() {
|
||||
sinon.spy(plugin, '_onFilterFocus');
|
||||
filterElement.find('input').focus();
|
||||
return assert(plugin._onFilterFocus.calledOnce);
|
||||
});
|
||||
it("should call Filter#_onFilterBlur when a filter input is blurred", function() {
|
||||
sinon.spy(plugin, '_onFilterBlur');
|
||||
filterElement.find('input').blur();
|
||||
return assert(plugin._onFilterBlur.calledOnce);
|
||||
});
|
||||
return it("should call Filter#_onFilterKeyup when a key is pressed in an input", function() {
|
||||
sinon.spy(plugin, '_onFilterKeyup');
|
||||
filterElement.find('input').keyup();
|
||||
return assert(plugin._onFilterKeyup.calledOnce);
|
||||
});
|
||||
});
|
||||
describe("constructor", function() {
|
||||
it("should have an empty filters array", function() {
|
||||
return assert.deepEqual(plugin.filters, []);
|
||||
});
|
||||
it("should have an filter element wrapped in jQuery", function() {
|
||||
assert.isTrue(plugin.filter instanceof jQuery);
|
||||
return assert.lengthOf(plugin.filter, 1);
|
||||
});
|
||||
return it("should append the toolbar to the @options.appendTo selector", function() {
|
||||
var parent;
|
||||
assert.isTrue(plugin.element instanceof jQuery);
|
||||
assert.lengthOf(plugin.element, 1);
|
||||
parent = $(plugin.options.appendTo);
|
||||
return assert.equal(plugin.element.parent()[0], parent[0]);
|
||||
});
|
||||
});
|
||||
describe("pluginInit", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(plugin, 'updateHighlights');
|
||||
sinon.stub(plugin, '_setupListeners').returns(plugin);
|
||||
sinon.stub(plugin, '_insertSpacer').returns(plugin);
|
||||
return sinon.stub(plugin, 'addFilter');
|
||||
});
|
||||
it("should call Filter#updateHighlights()", function() {
|
||||
plugin.pluginInit();
|
||||
return assert(plugin.updateHighlights.calledOnce);
|
||||
});
|
||||
it("should call Filter#_setupListeners()", function() {
|
||||
plugin.pluginInit();
|
||||
return assert(plugin._setupListeners.calledOnce);
|
||||
});
|
||||
it("should call Filter#_insertSpacer()", function() {
|
||||
plugin.pluginInit();
|
||||
return assert(plugin._insertSpacer.calledOnce);
|
||||
});
|
||||
return it("should load any filters in the Filter#options.filters array", function() {
|
||||
var filter, filters, _i, _len, _results;
|
||||
filters = [
|
||||
{
|
||||
label: 'filter1'
|
||||
}, {
|
||||
label: 'filter2'
|
||||
}, {
|
||||
label: 'filter3'
|
||||
}
|
||||
];
|
||||
plugin.options.filters = filters;
|
||||
plugin.pluginInit();
|
||||
_results = [];
|
||||
for (_i = 0, _len = filters.length; _i < _len; _i++) {
|
||||
filter = filters[_i];
|
||||
_results.push(assert.isTrue(plugin.addFilter.calledWith(filter)));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
});
|
||||
describe("_setupListeners", function() {
|
||||
return it("should subscribe to all relevant events on the annotator", function() {
|
||||
var event, events, _i, _len, _results;
|
||||
plugin._setupListeners();
|
||||
events = ['annotationsLoaded', 'annotationCreated', 'annotationUpdated', 'annotationDeleted'];
|
||||
_results = [];
|
||||
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
||||
event = events[_i];
|
||||
_results.push(assert.isTrue(plugin.annotator.subscribe.calledWith(event, plugin.updateHighlights)));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
});
|
||||
describe("addFilter", function() {
|
||||
var filter;
|
||||
filter = null;
|
||||
beforeEach(function() {
|
||||
filter = {
|
||||
label: 'Tag',
|
||||
property: 'tags'
|
||||
};
|
||||
return plugin.addFilter(filter);
|
||||
});
|
||||
it("should add a filter object to Filter#plugins", function() {
|
||||
return assert.ok(plugin.filters[0]);
|
||||
});
|
||||
it("should append the html to Filter#toolbar", function() {
|
||||
filter = plugin.filters[0];
|
||||
return assert.equal(filter.element[0], plugin.element.find('#annotator-filter-tags').parent()[0]);
|
||||
});
|
||||
it("should store the filter in the elements data store under 'filter'", function() {
|
||||
filter = plugin.filters[0];
|
||||
return assert.equal(filter.element.data('filter'), filter);
|
||||
});
|
||||
return it("should not add a filter for a property that has already been loaded", function() {
|
||||
plugin.addFilter({
|
||||
label: 'Tag',
|
||||
property: 'tags'
|
||||
});
|
||||
return assert.lengthOf(plugin.filters, 1);
|
||||
});
|
||||
});
|
||||
describe("updateFilter", function() {
|
||||
var annotations, filter;
|
||||
filter = null;
|
||||
annotations = null;
|
||||
beforeEach(function() {
|
||||
filter = {
|
||||
id: 'text',
|
||||
label: 'Annotation',
|
||||
property: 'text',
|
||||
element: $('<span><input value="ca" /></span>'),
|
||||
annotations: [],
|
||||
isFiltered: function(value, text) {
|
||||
return text.indexOf('ca') !== -1;
|
||||
}
|
||||
};
|
||||
annotations = [
|
||||
{
|
||||
text: 'cat'
|
||||
}, {
|
||||
text: 'dog'
|
||||
}, {
|
||||
text: 'car'
|
||||
}
|
||||
];
|
||||
plugin.filters = {
|
||||
'text': filter
|
||||
};
|
||||
plugin.highlights = {
|
||||
map: function() {
|
||||
return annotations;
|
||||
}
|
||||
};
|
||||
sinon.stub(plugin, 'updateHighlights');
|
||||
sinon.stub(plugin, 'resetHighlights');
|
||||
return sinon.stub(plugin, 'filterHighlights');
|
||||
});
|
||||
it("should call Filter#updateHighlights()", function() {
|
||||
plugin.updateFilter(filter);
|
||||
return assert(plugin.updateHighlights.calledOnce);
|
||||
});
|
||||
it("should call Filter#resetHighlights()", function() {
|
||||
plugin.updateFilter(filter);
|
||||
return assert(plugin.resetHighlights.calledOnce);
|
||||
});
|
||||
it("should filter the cat and car annotations", function() {
|
||||
plugin.updateFilter(filter);
|
||||
return assert.deepEqual(filter.annotations, [annotations[0], annotations[2]]);
|
||||
});
|
||||
it("should call Filter#filterHighlights()", function() {
|
||||
plugin.updateFilter(filter);
|
||||
return assert(plugin.filterHighlights.calledOnce);
|
||||
});
|
||||
return it("should NOT call Filter#filterHighlights() if there is no input", function() {
|
||||
filter.element.find('input').val('');
|
||||
plugin.updateFilter(filter);
|
||||
return assert.isFalse(plugin.filterHighlights.called);
|
||||
});
|
||||
});
|
||||
describe("updateHighlights", function() {
|
||||
beforeEach(function() {
|
||||
plugin.highlights = null;
|
||||
return plugin.updateHighlights();
|
||||
});
|
||||
it("should fetch the visible highlights from the Annotator#element", function() {
|
||||
return assert.isTrue(plugin.annotator.element.find.calledWith('.annotator-hl:visible'));
|
||||
});
|
||||
return it("should set the Filter#highlights property", function() {
|
||||
return assert.ok(plugin.highlights);
|
||||
});
|
||||
});
|
||||
describe("filterHighlights", function() {
|
||||
var div;
|
||||
div = null;
|
||||
beforeEach(function() {
|
||||
var match;
|
||||
plugin.highlights = $('<span /><span /><span /><span /><span />');
|
||||
match = {
|
||||
highlights: [plugin.highlights[1]]
|
||||
};
|
||||
plugin.filters = [
|
||||
{
|
||||
annotations: [
|
||||
{
|
||||
highlights: [plugin.highlights[0]]
|
||||
}, match
|
||||
]
|
||||
}, {
|
||||
annotations: [
|
||||
{
|
||||
highlights: [plugin.highlights[4]]
|
||||
}, match, {
|
||||
highlights: [plugin.highlights[2]]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
return div = $('<div>').append(plugin.highlights);
|
||||
});
|
||||
it("should hide all highlights not whitelisted by _every_ filter", function() {
|
||||
plugin.filterHighlights();
|
||||
return assert.lengthOf(div.find('.' + plugin.classes.hl.hide), 4);
|
||||
});
|
||||
it("should hide all highlights not whitelisted by _every_ filter if every filter is active", function() {
|
||||
plugin.filters[1].annotations = [];
|
||||
plugin.filterHighlights();
|
||||
return assert.lengthOf(div.find('.' + plugin.classes.hl.hide), 3);
|
||||
});
|
||||
return it("should hide all highlights not whitelisted if only one filter", function() {
|
||||
plugin.filters = plugin.filters.slice(0, 1);
|
||||
plugin.filterHighlights();
|
||||
return assert.lengthOf(div.find('.' + plugin.classes.hl.hide), 3);
|
||||
});
|
||||
});
|
||||
describe("resetHighlights", function() {
|
||||
return it("should remove the filter-hide class from all highlights", function() {
|
||||
plugin.highlights = $('<span /><span /><span />').addClass(plugin.classes.hl.hide);
|
||||
plugin.resetHighlights();
|
||||
return assert.lengthOf(plugin.highlights.filter('.' + plugin.classes.hl.hide), 0);
|
||||
});
|
||||
});
|
||||
return describe("group: filter input actions", function() {
|
||||
var filterElement;
|
||||
filterElement = null;
|
||||
beforeEach(function() {
|
||||
filterElement = $(plugin.html.filter);
|
||||
return plugin.element.append(filterElement);
|
||||
});
|
||||
describe("_onFilterFocus", function() {
|
||||
return it("should add an active class to the element", function() {
|
||||
plugin._onFilterFocus({
|
||||
target: filterElement.find('input')[0]
|
||||
});
|
||||
return assert.isTrue(filterElement.hasClass(plugin.classes.active));
|
||||
});
|
||||
});
|
||||
describe("_onFilterBlur", function() {
|
||||
it("should remove the active class from the element", function() {
|
||||
filterElement.addClass(plugin.classes.active);
|
||||
plugin._onFilterBlur({
|
||||
target: filterElement.find('input')[0]
|
||||
});
|
||||
return assert.isFalse(filterElement.hasClass(plugin.classes.active));
|
||||
});
|
||||
return it("should NOT remove the active class from the element if it has a value", function() {
|
||||
filterElement.addClass(plugin.classes.active);
|
||||
plugin._onFilterBlur({
|
||||
target: filterElement.find('input').val('filtered')[0]
|
||||
});
|
||||
return assert.isTrue(filterElement.hasClass(plugin.classes.active));
|
||||
});
|
||||
});
|
||||
describe("_onFilterKeyup", function() {
|
||||
beforeEach(function() {
|
||||
plugin.filters = [
|
||||
{
|
||||
label: 'My Filter'
|
||||
}
|
||||
];
|
||||
return sinon.stub(plugin, 'updateFilter');
|
||||
});
|
||||
it("should call Filter#updateFilter() with the relevant filter", function() {
|
||||
filterElement.data('filter', plugin.filters[0]);
|
||||
plugin._onFilterKeyup({
|
||||
target: filterElement.find('input')[0]
|
||||
});
|
||||
return assert.isTrue(plugin.updateFilter.calledWith(plugin.filters[0]));
|
||||
});
|
||||
return it("should NOT call Filter#updateFilter() if no filter is found", function() {
|
||||
plugin._onFilterKeyup({
|
||||
target: filterElement.find('input')[0]
|
||||
});
|
||||
return assert.isFalse(plugin.updateFilter.called);
|
||||
});
|
||||
});
|
||||
describe("navigation", function() {
|
||||
var annotation1, annotation2, annotation3, element1, element2, element3;
|
||||
element1 = null;
|
||||
element2 = null;
|
||||
element3 = null;
|
||||
annotation1 = null;
|
||||
annotation2 = null;
|
||||
annotation3 = null;
|
||||
beforeEach(function() {
|
||||
element1 = $('<span />');
|
||||
annotation1 = {
|
||||
text: 'annotation1',
|
||||
highlights: [element1[0]]
|
||||
};
|
||||
element1.data('annotation', annotation1);
|
||||
element2 = $('<span />');
|
||||
annotation2 = {
|
||||
text: 'annotation2',
|
||||
highlights: [element2[0]]
|
||||
};
|
||||
element2.data('annotation', annotation2);
|
||||
element3 = $('<span />');
|
||||
annotation3 = {
|
||||
text: 'annotation3',
|
||||
highlights: [element3[0]]
|
||||
};
|
||||
element3.data('annotation', annotation3);
|
||||
plugin.highlights = $([element1[0], element2[0], element3[0]]);
|
||||
return sinon.spy(plugin, '_scrollToHighlight');
|
||||
});
|
||||
describe("_onNextClick", function() {
|
||||
it("should advance to the next element", function() {
|
||||
element2.addClass(plugin.classes.hl.active);
|
||||
plugin._onNextClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element3[0]]));
|
||||
});
|
||||
it("should loop back to the start once it gets to the end", function() {
|
||||
element3.addClass(plugin.classes.hl.active);
|
||||
plugin._onNextClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element1[0]]));
|
||||
});
|
||||
it("should use the first element if there is no current element", function() {
|
||||
plugin._onNextClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element1[0]]));
|
||||
});
|
||||
it("should only navigate through non hidden elements", function() {
|
||||
element1.addClass(plugin.classes.hl.active);
|
||||
element2.addClass(plugin.classes.hl.hide);
|
||||
plugin._onNextClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element3[0]]));
|
||||
});
|
||||
return it("should do nothing if there are no annotations", function() {
|
||||
plugin.highlights = $();
|
||||
plugin._onNextClick();
|
||||
return assert.isFalse(plugin._scrollToHighlight.called);
|
||||
});
|
||||
});
|
||||
return describe("_onPreviousClick", function() {
|
||||
it("should advance to the previous element", function() {
|
||||
element3.addClass(plugin.classes.hl.active);
|
||||
plugin._onPreviousClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element2[0]]));
|
||||
});
|
||||
it("should loop to the end once it gets to the beginning", function() {
|
||||
element1.addClass(plugin.classes.hl.active);
|
||||
plugin._onPreviousClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element3[0]]));
|
||||
});
|
||||
it("should use the last element if there is no current element", function() {
|
||||
plugin._onPreviousClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element3[0]]));
|
||||
});
|
||||
it("should only navigate through non hidden elements", function() {
|
||||
element3.addClass(plugin.classes.hl.active);
|
||||
element2.addClass(plugin.classes.hl.hide);
|
||||
plugin._onPreviousClick();
|
||||
return assert.isTrue(plugin._scrollToHighlight.calledWith([element1[0]]));
|
||||
});
|
||||
return it("should do nothing if there are no annotations", function() {
|
||||
plugin.highlights = $();
|
||||
plugin._onPreviousClick();
|
||||
return assert.isFalse(plugin._scrollToHighlight.called);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("_scrollToHighlight", function() {
|
||||
var mockjQuery;
|
||||
mockjQuery = null;
|
||||
beforeEach(function() {
|
||||
plugin.highlights = $();
|
||||
mockjQuery = {
|
||||
addClass: sinon.spy(),
|
||||
animate: sinon.spy(),
|
||||
offset: sinon.stub().returns({
|
||||
top: 0
|
||||
})
|
||||
};
|
||||
sinon.spy(plugin.highlights, 'removeClass');
|
||||
return sinon.stub(jQuery.prototype, 'init').returns(mockjQuery);
|
||||
});
|
||||
afterEach(function() {
|
||||
return jQuery.prototype.init.restore();
|
||||
});
|
||||
it("should remove active class from currently active element", function() {
|
||||
plugin._scrollToHighlight({});
|
||||
return assert.isTrue(plugin.highlights.removeClass.calledWith(plugin.classes.hl.active));
|
||||
});
|
||||
it("should add active class to provided elements", function() {
|
||||
plugin._scrollToHighlight({});
|
||||
return assert.isTrue(mockjQuery.addClass.calledWith(plugin.classes.hl.active));
|
||||
});
|
||||
return it("should animate the scrollbar to the highlight offset", function() {
|
||||
plugin._scrollToHighlight({});
|
||||
assert(mockjQuery.offset.calledOnce);
|
||||
return assert(mockjQuery.animate.calledOnce);
|
||||
});
|
||||
});
|
||||
return describe("_onClearClick", function() {
|
||||
var mockjQuery;
|
||||
mockjQuery = null;
|
||||
beforeEach(function() {
|
||||
mockjQuery = {};
|
||||
mockjQuery.val = sinon.stub().returns(mockjQuery);
|
||||
mockjQuery.prev = sinon.stub().returns(mockjQuery);
|
||||
mockjQuery.keyup = sinon.stub().returns(mockjQuery);
|
||||
mockjQuery.blur = sinon.stub().returns(mockjQuery);
|
||||
sinon.stub(jQuery.prototype, 'init').returns(mockjQuery);
|
||||
return plugin._onClearClick({
|
||||
target: {}
|
||||
});
|
||||
});
|
||||
afterEach(function() {
|
||||
return jQuery.prototype.init.restore();
|
||||
});
|
||||
it("should clear the input", function() {
|
||||
return assert.isTrue(mockjQuery.val.calledWith(''));
|
||||
});
|
||||
it("should trigger the blur event", function() {
|
||||
return assert(mockjQuery.blur.calledOnce);
|
||||
});
|
||||
return it("should trigger the keyup event", function() {
|
||||
return assert(mockjQuery.keyup.calledOnce);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=filter_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/filter_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/filter_spec.map
Normal file
File diff suppressed because one or more lines are too long
150
libs/annotator/lib/spec/plugin/kitchensink_spec.js
Normal file
150
libs/annotator/lib/spec/plugin/kitchensink_spec.js
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
var MockPlugin,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
MockPlugin = (function() {
|
||||
function MockPlugin() {}
|
||||
|
||||
MockPlugin.prototype.pluginInit = function() {};
|
||||
|
||||
return MockPlugin;
|
||||
|
||||
})();
|
||||
|
||||
describe('Annotator::setupPlugins', function() {
|
||||
var $fix, annotator;
|
||||
annotator = null;
|
||||
$fix = null;
|
||||
beforeEach(function() {
|
||||
var p, _i, _len, _ref;
|
||||
_ref = ['AnnotateItPermissions', 'Auth', 'Markdown', 'Store', 'Tags', 'Unsupported'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
p = _ref[_i];
|
||||
Annotator.Plugin[p] = MockPlugin;
|
||||
}
|
||||
addFixture('kitchensink');
|
||||
return $fix = $(fix());
|
||||
});
|
||||
afterEach(function() {
|
||||
return clearFixtures();
|
||||
});
|
||||
it('should added to the Annotator prototype', function() {
|
||||
return assert.equal(typeof Annotator.prototype.setupPlugins, 'function');
|
||||
});
|
||||
it('should be callable via jQuery.fn.Annotator', function() {
|
||||
sinon.spy(Annotator.prototype, 'setupPlugins');
|
||||
$fix.annotator().annotator('setupPlugins', {}, {
|
||||
Filter: {
|
||||
appendTo: fix()
|
||||
}
|
||||
});
|
||||
return assert(Annotator.prototype.setupPlugins.calledOnce);
|
||||
});
|
||||
describe('called with no parameters', function() {
|
||||
var _Showdown;
|
||||
_Showdown = null;
|
||||
beforeEach(function() {
|
||||
_Showdown = window.Showdown;
|
||||
annotator = new Annotator(fix());
|
||||
return annotator.setupPlugins({}, {
|
||||
Filter: {
|
||||
appendTo: fix()
|
||||
}
|
||||
});
|
||||
});
|
||||
afterEach(function() {
|
||||
return window.Showdown = _Showdown;
|
||||
});
|
||||
describe('it includes the Unsupported plugin', function() {
|
||||
return it('should add the Unsupported plugin by default', function() {
|
||||
return assert.isDefined(annotator.plugins.Unsupported);
|
||||
});
|
||||
});
|
||||
describe('it includes the Tags plugin', function() {
|
||||
return it('should add the Tags plugin by default', function() {
|
||||
return assert.isDefined(annotator.plugins.Tags);
|
||||
});
|
||||
});
|
||||
describe('it includes the Filter plugin', function() {
|
||||
var filterPlugin;
|
||||
filterPlugin = null;
|
||||
beforeEach(function() {
|
||||
return filterPlugin = annotator.plugins.Filter;
|
||||
});
|
||||
it('should add the Filter plugin by default', function() {
|
||||
return assert.isDefined(filterPlugin);
|
||||
});
|
||||
return it('should have filters for annotations, tags and users', function() {
|
||||
var expectedFilters, f, filter, _i, _len, _results;
|
||||
expectedFilters = ['text', 'user', 'tags'];
|
||||
_results = [];
|
||||
for (_i = 0, _len = expectedFilters.length; _i < _len; _i++) {
|
||||
filter = expectedFilters[_i];
|
||||
_results.push(assert.isTrue(__indexOf.call((function() {
|
||||
var _j, _len1, _ref, _results1;
|
||||
_ref = filterPlugin.filters;
|
||||
_results1 = [];
|
||||
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
||||
f = _ref[_j];
|
||||
_results1.push(f.property);
|
||||
}
|
||||
return _results1;
|
||||
})(), filter) >= 0));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
});
|
||||
return describe('and with Showdown loaded in the page', function() {
|
||||
return it('should add the Markdown plugin', function() {
|
||||
return assert.isDefined(annotator.plugins.Markdown);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('called with AnnotateIt config', function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(Annotator.Plugin.Store.prototype, 'pluginInit');
|
||||
annotator = new Annotator(fix());
|
||||
return annotator.setupPlugins();
|
||||
});
|
||||
afterEach(function() {
|
||||
return Annotator.Plugin.Store.prototype.pluginInit.restore();
|
||||
});
|
||||
it('should add the Store plugin', function() {
|
||||
return assert.isDefined(annotator.plugins.Store);
|
||||
});
|
||||
it('should add the AnnotateItPermissions plugin', function() {
|
||||
return assert.isDefined(annotator.plugins.AnnotateItPermissions);
|
||||
});
|
||||
return it('should add the Auth plugin', function() {
|
||||
return assert.isDefined(annotator.plugins.Auth);
|
||||
});
|
||||
});
|
||||
return describe('called with plugin options', function() {
|
||||
beforeEach(function() {
|
||||
return annotator = new Annotator(fix());
|
||||
});
|
||||
it('should override default plugin options', function() {
|
||||
annotator.setupPlugins(null, {
|
||||
AnnotateItPermissions: false,
|
||||
Filter: {
|
||||
filters: null,
|
||||
addAnnotationFilter: false,
|
||||
appendTo: fix()
|
||||
}
|
||||
});
|
||||
return assert.lengthOf(annotator.plugins.Filter.filters, 0);
|
||||
});
|
||||
return it('should NOT load a plugin if its key is set to null OR false', function() {
|
||||
annotator.setupPlugins(null, {
|
||||
Filter: false,
|
||||
Tags: null
|
||||
});
|
||||
assert.isUndefined(annotator.plugins.Tags);
|
||||
return assert.isUndefined(annotator.plugins.Filter);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=kitchensink_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/kitchensink_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/kitchensink_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "kitchensink_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/kitchensink_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
72
libs/annotator/lib/spec/plugin/markdown_spec.js
Normal file
72
libs/annotator/lib/spec/plugin/markdown_spec.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe('Annotator.Plugin.Markdown', function() {
|
||||
var input, output, plugin;
|
||||
input = 'Is **this** [Markdown](http://daringfireball.com)?';
|
||||
output = '<p>Is <strong>this</strong> <a href="http://daringfireball.com">Markdown</a>?</p>';
|
||||
plugin = null;
|
||||
beforeEach(function() {
|
||||
return plugin = new Annotator.Plugin.Markdown($('<div />')[0]);
|
||||
});
|
||||
describe("events", function() {
|
||||
return it("should call Markdown#updateTextField() when annotationViewerTextField event is fired", function() {
|
||||
var annotation, field;
|
||||
field = $('<div />')[0];
|
||||
annotation = {
|
||||
text: 'test'
|
||||
};
|
||||
sinon.spy(plugin, 'updateTextField');
|
||||
plugin.publish('annotationViewerTextField', [field, annotation]);
|
||||
return assert.isTrue(plugin.updateTextField.calledWith(field, annotation));
|
||||
});
|
||||
});
|
||||
describe("constructor", function() {
|
||||
it("should create a new instance of Showdown", function() {
|
||||
return assert.ok(plugin.converter);
|
||||
});
|
||||
return it("should log an error if Showdown is not loaded", function() {
|
||||
var converter;
|
||||
sinon.stub(console, 'error');
|
||||
converter = Showdown.converter;
|
||||
Showdown.converter = null;
|
||||
plugin = new Annotator.Plugin.Markdown($('<div />')[0]);
|
||||
assert(console.error.calledOnce);
|
||||
Showdown.converter = converter;
|
||||
return console.error.restore();
|
||||
});
|
||||
});
|
||||
describe("updateTextField", function() {
|
||||
var annotation, field;
|
||||
field = null;
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
field = $('<div />')[0];
|
||||
annotation = {
|
||||
text: input
|
||||
};
|
||||
sinon.stub(plugin, 'convert').returns(output);
|
||||
sinon.stub(Annotator.Util, 'escape').returns(input);
|
||||
return plugin.updateTextField(field, annotation);
|
||||
});
|
||||
afterEach(function() {
|
||||
return Annotator.Util.escape.restore();
|
||||
});
|
||||
it('should process the annotation text as Markdown', function() {
|
||||
return assert.isTrue(plugin.convert.calledWith(input));
|
||||
});
|
||||
it('should update the content in the field', function() {
|
||||
return assert.equal($(field).html(), output);
|
||||
});
|
||||
return it("should escape any existing HTML to prevent XSS", function() {
|
||||
return assert.isTrue(Annotator.Util.escape.calledWith(input));
|
||||
});
|
||||
});
|
||||
return describe("convert", function() {
|
||||
return it("should convert the provided text into markdown", function() {
|
||||
return assert.equal(plugin.convert(input), output);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=markdown_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/markdown_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/markdown_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "markdown_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/markdown_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAAA,CAAS,CAA6B,CAAA,KAAtC,CAAsC,kBAAtC;CACE,KAAA,eAAA;CAAA,CAAA,CAAS,EAAT,+CAAA;CAAA,CACA,CAAS,GAAT,6EADA;CAAA,CAEA,CAAS,CAFT,EAEA;CAFA,CAKA,CAAW,MAAA,CAAX;CACyB,EAAV,CAAA,EAAb,EAAa,CAAS,EAAtB;CADF,EAAW;CALX,CAQA,CAAmB,KAAnB,CAAmB;CACd,CAAH,CAA2F,MAAA,EAA3F,2EAAA;CACE,SAAA,OAAA;CAAA,EAAQ,EAAR,CAAA,GAAQ;CAAR,EACa,GAAb,IAAA;CAAa,CAAO,EAAN,EAAD,EAAC;CADd,OAAA;CAAA,CAGkB,CAAlB,EAAK,CAAL,WAAA;CAHA,CAI4C,GAAA,CAA5C,CAAA,GAA4C,iBAA5C;CACO,CAAgD,GAAzC,CAAR,IAAQ,GAAd,EAAoC;CANtC,IAA2F;CAD7F,EAAmB;CARnB,CAiBA,CAAwB,KAAxB,CAAwB,IAAxB;CACE,CAAA,CAA+C,CAA/C,KAA+C,iCAA/C;CACS,CAAP,IAAM,GAAN,IAAA;CADF,IAA+C;CAG5C,CAAH,CAAoD,MAAA,EAApD,oCAAA;CACE,QAAA,CAAA;CAAA,CAAoB,EAApB,CAAK,CAAL,CAAA;CAAA,EAEY,GAAZ,EAAoB,CAApB;CAFA,EAGqB,CAHrB,EAGA,EAAQ,CAAR;CAHA,EAKa,CAAA,EAAb,EAAa,CAAS;CALtB,IAMoB,CAApB,CAAc,GAAd;CANA,EAQqB,GAArB,EAAQ,CAAR;CACQ,IAAK,EAAN,MAAP;CAVF,IAAoD;CAJtD,EAAwB;CAjBxB,CAiCA,CAA4B,KAA5B,CAA4B,QAA5B;CACE,OAAA,SAAA;CAAA,EAAa,CAAb,CAAA;CAAA,EACa,CAAb,MAAA;CADA,EAGW,CAAX,KAAW,CAAX;CACE,EAAQ,EAAR,CAAA,GAAQ;CAAR,EACa,GAAb,IAAA;CAAa,CAAO,EAAN,CAAD,GAAC;CADd,OAAA;CAAA,CAEmB,EAAnB,CAAK,CAAL,CAAA,EAAA;CAFA,CAG2B,EAA3B,CAAK,CAAL,CAAA,CAAA,CAAoB;CAEb,CAAuB,GAA9B,CAAM,IAAN,GAAA,EAAA;CANF,IAAW;CAHX,EAWU,CAAV,KAAA;CACY,GAAI,EAAO,CAArB,EAAS,IAAT;CADF,IAAU;CAXV,CAcA,CAAqD,CAArD,KAAqD,uCAArD;CACS,IAAO,CAAR,CAAsB,GAAd,GAAd;CADF,IAAqD;CAdrD,CAiBA,CAA6C,CAA7C,KAA6C,+BAA7C;CACS,CAAuB,EAAjB,CAAb,CAAM,OAAN;CADF,IAA6C;CAG1C,CAAH,CAAqD,MAAA,EAArD,qCAAA;CACS,GAAqB,CAAd,CAAR,GAAiB,CAAT,GAAd;CADF,IAAqD;CArBvD,EAA4B;CAwBnB,CAAW,CAAA,KAApB,CAAA;CACK,CAAH,CAAqD,MAAA,EAArD,qCAAA;CACS,CAA6B,GAApC,CAAM,CAAO,MAAb;CADF,IAAqD;CADvD,EAAoB;CA1DgB"
|
||||
}
|
456
libs/annotator/lib/spec/plugin/permissions_spec.js
Normal file
456
libs/annotator/lib/spec/plugin/permissions_spec.js
Normal file
|
@ -0,0 +1,456 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
var __slice = [].slice,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
describe('Annotator.Plugin.Permissions', function() {
|
||||
var el, permissions;
|
||||
el = null;
|
||||
permissions = null;
|
||||
beforeEach(function() {
|
||||
el = $("<div class='annotator-viewer'></div>").appendTo('body')[0];
|
||||
return permissions = new Annotator.Plugin.Permissions(el);
|
||||
});
|
||||
afterEach(function() {
|
||||
return $(el).remove();
|
||||
});
|
||||
it("it should add the current user object to newly created annotations on beforeAnnotationCreated", function() {
|
||||
var ann;
|
||||
ann = {};
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
assert.isUndefined(ann.user);
|
||||
ann = {};
|
||||
permissions.setUser('alice');
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
assert.equal(ann.user, 'alice');
|
||||
ann = {};
|
||||
permissions.setUser({
|
||||
id: 'alice'
|
||||
});
|
||||
permissions.options.userId = function(user) {
|
||||
return user.id;
|
||||
};
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
return assert.deepEqual(ann.user, {
|
||||
id: 'alice'
|
||||
});
|
||||
});
|
||||
it("it should add permissions to newly created annotations on beforeAnnotationCreated", function() {
|
||||
var ann;
|
||||
ann = {};
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
assert.ok(ann.permissions);
|
||||
ann = {};
|
||||
permissions.options.permissions = {};
|
||||
$(el).trigger('beforeAnnotationCreated', [ann]);
|
||||
return assert.deepEqual(ann.permissions, {});
|
||||
});
|
||||
describe('pluginInit', function() {
|
||||
beforeEach(function() {
|
||||
return permissions.annotator = {
|
||||
viewer: {
|
||||
addField: sinon.spy()
|
||||
},
|
||||
editor: {
|
||||
addField: sinon.spy()
|
||||
},
|
||||
plugins: {}
|
||||
};
|
||||
});
|
||||
it("should register a field with the Viewer", function() {
|
||||
permissions.pluginInit();
|
||||
return assert(permissions.annotator.viewer.addField.calledOnce);
|
||||
});
|
||||
it("should register an two checkbox fields with the Editor", function() {
|
||||
permissions.pluginInit();
|
||||
return assert.equal(permissions.annotator.editor.addField.callCount, 2);
|
||||
});
|
||||
it("should register an 'anyone can view' field with the Editor if showEditPermissionsCheckbox is true", function() {
|
||||
permissions.options.showViewPermissionsCheckbox = true;
|
||||
permissions.options.showEditPermissionsCheckbox = false;
|
||||
permissions.pluginInit();
|
||||
return assert.equal(permissions.annotator.editor.addField.callCount, 1);
|
||||
});
|
||||
it("should register an 'anyone can edit' field with the Editor if showViewPermissionsCheckbox is true", function() {
|
||||
permissions.options.showViewPermissionsCheckbox = false;
|
||||
permissions.options.showEditPermissionsCheckbox = true;
|
||||
permissions.pluginInit();
|
||||
return assert.equal(permissions.annotator.editor.addField.callCount, 1);
|
||||
});
|
||||
return it("should register a filter if the Filter plugin is loaded", function() {
|
||||
permissions.annotator.plugins.Filter = {
|
||||
addFilter: sinon.spy()
|
||||
};
|
||||
permissions.pluginInit();
|
||||
return assert(permissions.annotator.plugins.Filter.addFilter.calledOnce);
|
||||
});
|
||||
});
|
||||
describe('authorize', function() {
|
||||
var annotations;
|
||||
annotations = null;
|
||||
describe('Basic usage', function() {
|
||||
beforeEach(function() {
|
||||
return annotations = [
|
||||
{}, {
|
||||
user: 'alice'
|
||||
}, {
|
||||
permissions: {}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': []
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
it('should allow any action for an annotation with no authorisation info', function() {
|
||||
var a;
|
||||
a = annotations[0];
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
assert.isTrue(permissions.authorize('foo', a));
|
||||
permissions.setUser('alice');
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
return assert.isTrue(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should NOT allow any action if annotation.user and no @user is set', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
return assert.isFalse(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should allow any action if @options.userId(@user) == annotation.user', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
permissions.setUser('alice');
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
return assert.isTrue(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should NOT allow any action if @options.userId(@user) != annotation.user', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
permissions.setUser('bob');
|
||||
assert.isFalse(permissions.authorize(null, a));
|
||||
return assert.isFalse(permissions.authorize('foo', a));
|
||||
});
|
||||
it('should allow any action if annotation.permissions == {}', function() {
|
||||
var a;
|
||||
a = annotations[2];
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
assert.isTrue(permissions.authorize('foo', a));
|
||||
permissions.setUser('alice');
|
||||
assert.isTrue(permissions.authorize(null, a));
|
||||
return assert.isTrue(permissions.authorize('foo', a));
|
||||
});
|
||||
return it('should allow an action if annotation.permissions[action] == []', function() {
|
||||
var a;
|
||||
a = annotations[3];
|
||||
assert.isTrue(permissions.authorize('update', a));
|
||||
permissions.setUser('bob');
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
});
|
||||
return describe('Custom options.userAuthorize() callback', function() {
|
||||
beforeEach(function() {
|
||||
permissions.setUser(null);
|
||||
permissions.options.userAuthorize = function(action, annotation, user) {
|
||||
var token, tokenTest, tokens, userGroups, _i, _len;
|
||||
userGroups = function(user) {
|
||||
return (user != null ? user.groups : void 0) || ['public'];
|
||||
};
|
||||
tokenTest = function(token, user) {
|
||||
var groups, key, value, values, _ref;
|
||||
if (/^(?:group|user):/.test(token)) {
|
||||
_ref = token.split(':'), key = _ref[0], values = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
|
||||
value = values.join(':');
|
||||
if (key === 'group') {
|
||||
groups = userGroups(user);
|
||||
return __indexOf.call(groups, value) >= 0;
|
||||
} else if (user && key === 'user') {
|
||||
return value === user.id;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (annotation.permissions) {
|
||||
tokens = annotation.permissions[action] || [];
|
||||
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
|
||||
token = tokens[_i];
|
||||
if (tokenTest(token, user)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return annotations = [
|
||||
{
|
||||
permissions: {
|
||||
'update': ['group:public']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['user:alice']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['user:alice', 'user:bob']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['user:alice', 'user:bob', 'group:admin']
|
||||
}
|
||||
}
|
||||
];
|
||||
});
|
||||
afterEach(function() {
|
||||
return delete permissions.options.userAuthorize;
|
||||
});
|
||||
it('should (by default) allow an action if annotation.permissions[action] includes "group:public"', function() {
|
||||
var a;
|
||||
a = annotations[0];
|
||||
assert.isTrue(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'bob'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
it('should (by default) allow an action if annotation.permissions[action] includes "user:@user"', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'bob'
|
||||
});
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'alice'
|
||||
});
|
||||
assert.isTrue(permissions.authorize('update', a));
|
||||
a = annotations[2];
|
||||
permissions.setUser(null);
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'bob'
|
||||
});
|
||||
assert.isTrue(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'alice'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
it('should allow an action if annotation.permissions[action] includes "user:@options.userId(@user)"', function() {
|
||||
var a;
|
||||
a = annotations[1];
|
||||
permissions.options.userId = function(user) {
|
||||
return (user != null ? user.id : void 0) || null;
|
||||
};
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'alice'
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
return it('should allow an action if annotation.permissions[action] includes "user:@options.userId(@user)"', function() {
|
||||
var a;
|
||||
a = annotations[3];
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'foo',
|
||||
groups: ['other']
|
||||
});
|
||||
assert.isFalse(permissions.authorize('update', a));
|
||||
permissions.setUser({
|
||||
id: 'charlie',
|
||||
groups: ['admin']
|
||||
});
|
||||
return assert.isTrue(permissions.authorize('update', a));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('updateAnnotationPermissions', function() {
|
||||
var annotation, checkbox, field;
|
||||
field = null;
|
||||
checkbox = null;
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
checkbox = $('<input type="checkbox" />');
|
||||
field = $('<li />').append(checkbox)[0];
|
||||
return annotation = {
|
||||
permissions: {
|
||||
'update': ['Alice']
|
||||
}
|
||||
};
|
||||
});
|
||||
it("should NOT be world editable when 'Anyone can edit' checkbox is unchecked", function() {
|
||||
checkbox.removeAttr('checked');
|
||||
permissions.updateAnnotationPermissions('update', field, annotation);
|
||||
return assert.isFalse(permissions.authorize('update', annotation, null));
|
||||
});
|
||||
it("should be world editable when 'Anyone can edit' checkbox is checked", function() {
|
||||
checkbox.attr('checked', 'checked');
|
||||
permissions.updateAnnotationPermissions('update', field, annotation);
|
||||
return assert.isTrue(permissions.authorize('update', annotation, null));
|
||||
});
|
||||
return it("should NOT be world editable when 'Anyone can edit' checkbox is unchecked for a second time", function() {
|
||||
checkbox.attr('checked', 'checked');
|
||||
permissions.updateAnnotationPermissions('update', field, annotation);
|
||||
assert.isTrue(permissions.authorize('update', annotation, null));
|
||||
checkbox.removeAttr('checked');
|
||||
permissions.updateAnnotationPermissions('update', field, annotation);
|
||||
return assert.isFalse(permissions.authorize('update', annotation, null));
|
||||
});
|
||||
});
|
||||
describe('updatePermissionsField', function() {
|
||||
var annotations, checkbox, field;
|
||||
field = null;
|
||||
checkbox = null;
|
||||
annotations = [
|
||||
{}, {
|
||||
permissions: {
|
||||
'update': ['user:Alice']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['user:Alice']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['Alice'],
|
||||
'admin': ['Alice']
|
||||
}
|
||||
}, {
|
||||
permissions: {
|
||||
'update': ['Alice'],
|
||||
'admin': ['Bob']
|
||||
}
|
||||
}
|
||||
];
|
||||
beforeEach(function() {
|
||||
checkbox = $('<input type="checkbox" />');
|
||||
field = $('<li />').append(checkbox).appendTo(permissions.element);
|
||||
permissions.setUser('Alice');
|
||||
return permissions.updatePermissionsField('update', field, annotations.shift());
|
||||
});
|
||||
afterEach(function() {
|
||||
return field.remove();
|
||||
});
|
||||
it("should have a checked checkbox when there are no permissions", function() {
|
||||
return assert.isTrue(checkbox.is(':checked'));
|
||||
});
|
||||
it("should have an unchecked checkbox when there are permissions", function() {
|
||||
return assert.isFalse(checkbox.is(':checked'));
|
||||
});
|
||||
it("should enable the checkbox by default", function() {
|
||||
return assert.isTrue(checkbox.is(':enabled'));
|
||||
});
|
||||
it("should display the field if the current user has 'admin' permissions", function() {
|
||||
return assert.isTrue(field.is(':visible'));
|
||||
});
|
||||
return it("should NOT display the field if the current user does not have 'admin' permissions", function() {
|
||||
return assert.isFalse(field.is(':visible'));
|
||||
});
|
||||
});
|
||||
return describe('updateViewer', function() {
|
||||
var controls, field;
|
||||
controls = null;
|
||||
field = null;
|
||||
beforeEach(function() {
|
||||
field = $('<div />').appendTo('<div />')[0];
|
||||
return controls = {
|
||||
showEdit: sinon.spy(),
|
||||
hideEdit: sinon.spy(),
|
||||
showDelete: sinon.spy(),
|
||||
hideDelete: sinon.spy()
|
||||
};
|
||||
});
|
||||
describe('coarse grained updates based on user', function() {
|
||||
var annotations;
|
||||
annotations = null;
|
||||
beforeEach(function() {
|
||||
permissions.setUser('alice');
|
||||
return annotations = [
|
||||
{
|
||||
user: 'alice'
|
||||
}, {
|
||||
user: 'bob'
|
||||
}, {}
|
||||
];
|
||||
});
|
||||
it("it should display annotations' users in the viewer element", function() {
|
||||
permissions.updateViewer(field, annotations[0], controls);
|
||||
assert.equal($(field).html(), 'alice');
|
||||
return assert.lengthOf($(field).parent(), 1);
|
||||
});
|
||||
it("it should remove the field if annotation has no user", function() {
|
||||
permissions.updateViewer(field, {}, controls);
|
||||
return assert.lengthOf($(field).parent(), 0);
|
||||
});
|
||||
it("it should remove the field if annotation has no user string", function() {
|
||||
permissions.options.userString = function() {
|
||||
return null;
|
||||
};
|
||||
permissions.updateViewer(field, annotations[1], controls);
|
||||
return assert.lengthOf($(field).parent(), 0);
|
||||
});
|
||||
it("it should remove the field if annotation has empty user string", function() {
|
||||
permissions.options.userString = function() {
|
||||
return '';
|
||||
};
|
||||
permissions.updateViewer(field, annotations[1], controls);
|
||||
return assert.lengthOf($(field).parent(), 0);
|
||||
});
|
||||
it("should hide controls for users other than the current user", function() {
|
||||
permissions.updateViewer(field, annotations[0], controls);
|
||||
assert.isFalse(controls.hideEdit.called);
|
||||
assert.isFalse(controls.hideDelete.called);
|
||||
permissions.updateViewer(field, annotations[1], controls);
|
||||
assert(controls.hideEdit.calledOnce);
|
||||
return assert(controls.hideDelete.calledOnce);
|
||||
});
|
||||
return it("should show controls for annotations without a user", function() {
|
||||
permissions.updateViewer(field, annotations[2], controls);
|
||||
assert.isFalse(controls.hideEdit.called);
|
||||
return assert.isFalse(controls.hideDelete.called);
|
||||
});
|
||||
});
|
||||
return describe('fine-grained use (user and permissions)', function() {
|
||||
var annotations;
|
||||
annotations = null;
|
||||
beforeEach(function() {
|
||||
annotations = [
|
||||
{
|
||||
user: 'alice',
|
||||
permissions: {
|
||||
'update': ['alice'],
|
||||
'delete': ['alice']
|
||||
}
|
||||
}, {
|
||||
user: 'bob',
|
||||
permissions: {
|
||||
'update': ['bob'],
|
||||
'delete': ['bob']
|
||||
}
|
||||
}
|
||||
];
|
||||
return permissions.setUser('bob');
|
||||
});
|
||||
it("it should should hide edit button if user cannot update", function() {
|
||||
permissions.updateViewer(field, annotations[0], controls);
|
||||
return assert(controls.hideEdit.calledOnce);
|
||||
});
|
||||
it("it should should show edit button if user can update", function() {
|
||||
permissions.updateViewer(field, annotations[1], controls);
|
||||
return assert.isFalse(controls.hideEdit.called);
|
||||
});
|
||||
it("it should should hide delete button if user cannot delete", function() {
|
||||
permissions.updateViewer(field, annotations[0], controls);
|
||||
return assert(controls.hideDelete.calledOnce);
|
||||
});
|
||||
return it("it should should show delete button if user can delete", function() {
|
||||
permissions.updateViewer(field, annotations[1], controls);
|
||||
return assert.isFalse(controls.hideDelete.called);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=permissions_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/permissions_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/permissions_spec.map
Normal file
File diff suppressed because one or more lines are too long
640
libs/annotator/lib/spec/plugin/store_spec.js
Normal file
640
libs/annotator/lib/spec/plugin/store_spec.js
Normal file
|
@ -0,0 +1,640 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe("Annotator.Plugin.Store", function() {
|
||||
var store;
|
||||
store = null;
|
||||
beforeEach(function() {
|
||||
var element;
|
||||
element = $('<div></div>')[0];
|
||||
store = new Annotator.Plugin.Store(element, {
|
||||
autoFetch: false
|
||||
});
|
||||
return store.annotator = {
|
||||
plugins: {},
|
||||
loadAnnotations: sinon.spy()
|
||||
};
|
||||
});
|
||||
describe("events", function() {
|
||||
it("should call Store#annotationCreated when the annotationCreated is fired", function() {
|
||||
sinon.stub(store, 'annotationCreated');
|
||||
store.element.trigger('annotationCreated', ['annotation1']);
|
||||
return assert.isTrue(store.annotationCreated.calledWith('annotation1'));
|
||||
});
|
||||
it("should call Store#annotationUpdated when the annotationUpdated is fired", function() {
|
||||
sinon.stub(store, 'annotationUpdated');
|
||||
store.element.trigger('annotationUpdated', ['annotation1']);
|
||||
return assert.isTrue(store.annotationUpdated.calledWith('annotation1'));
|
||||
});
|
||||
return it("should call Store#annotationDeleted when the annotationDeleted is fired", function() {
|
||||
sinon.stub(store, 'annotationDeleted');
|
||||
store.element.trigger('annotationDeleted', ['annotation1']);
|
||||
return assert.isTrue(store.annotationDeleted.calledWith('annotation1'));
|
||||
});
|
||||
});
|
||||
describe("pluginInit", function() {
|
||||
it("should call Store#_getAnnotations() if no Auth plugin is loaded", function() {
|
||||
sinon.stub(store, '_getAnnotations');
|
||||
store.pluginInit();
|
||||
return assert(store._getAnnotations.calledOnce);
|
||||
});
|
||||
return it("should call Auth#withToken() if Auth plugin is loaded", function() {
|
||||
var authMock;
|
||||
authMock = {
|
||||
withToken: sinon.spy()
|
||||
};
|
||||
store.annotator.plugins.Auth = authMock;
|
||||
store.pluginInit();
|
||||
return assert.isTrue(authMock.withToken.calledWith(store._getAnnotations));
|
||||
});
|
||||
});
|
||||
describe("_getAnnotations", function() {
|
||||
it("should call Store#loadAnnotations() if @options.loadFromSearch is not present", function() {
|
||||
sinon.stub(store, 'loadAnnotations');
|
||||
store._getAnnotations();
|
||||
return assert(store.loadAnnotations.calledOnce);
|
||||
});
|
||||
return it("should call Store#loadAnnotationsFromSearch() if @options.loadFromSearch is present", function() {
|
||||
sinon.stub(store, 'loadAnnotationsFromSearch');
|
||||
store.options.loadFromSearch = {};
|
||||
store._getAnnotations();
|
||||
return assert.isTrue(store.loadAnnotationsFromSearch.calledWith(store.options.loadFromSearch));
|
||||
});
|
||||
});
|
||||
describe("annotationCreated", function() {
|
||||
var annotation;
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
annotation = {};
|
||||
sinon.stub(store, 'registerAnnotation');
|
||||
sinon.stub(store, 'updateAnnotation');
|
||||
return sinon.stub(store, '_apiRequest');
|
||||
});
|
||||
it("should call Store#registerAnnotation() with the new annotation", function() {
|
||||
store.annotationCreated(annotation);
|
||||
return assert.isTrue(store.registerAnnotation.calledWith(annotation));
|
||||
});
|
||||
it("should call Store#_apiRequest('create') with the new annotation", function() {
|
||||
var args;
|
||||
store.annotationCreated(annotation);
|
||||
args = store._apiRequest.lastCall.args;
|
||||
assert(store._apiRequest.calledOnce);
|
||||
assert.equal(args[0], 'create');
|
||||
return assert.equal(args[1], annotation);
|
||||
});
|
||||
return it("should call Store#updateAnnotation() if the annotation already exists in @annotations", function() {
|
||||
store.annotations = [annotation];
|
||||
store.annotationCreated(annotation);
|
||||
assert(store.updateAnnotation.calledOnce);
|
||||
return assert.equal(store.updateAnnotation.lastCall.args[0], annotation);
|
||||
});
|
||||
});
|
||||
describe("annotationUpdated", function() {
|
||||
var annotation;
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
annotation = {};
|
||||
return sinon.stub(store, '_apiRequest');
|
||||
});
|
||||
it("should call Store#_apiRequest('update') with the annotation and data", function() {
|
||||
var args, data;
|
||||
store.annotations = [annotation];
|
||||
store.annotationUpdated(annotation);
|
||||
args = store._apiRequest.lastCall.args;
|
||||
assert(store._apiRequest.calledOnce);
|
||||
assert.equal(args[0], 'update');
|
||||
assert.equal(args[1], annotation);
|
||||
assert.equal(typeof args[2], 'function');
|
||||
sinon.stub(store, 'updateAnnotation');
|
||||
data = {
|
||||
text: "Dummy response data"
|
||||
};
|
||||
args[2](data);
|
||||
return assert.isTrue(store.updateAnnotation.calledWith(annotation, data));
|
||||
});
|
||||
return it("should NOT call Store#_apiRequest() if the annotation is unregistered", function() {
|
||||
store.annotations = [];
|
||||
store.annotationUpdated(annotation);
|
||||
return assert.isFalse(store._apiRequest.called);
|
||||
});
|
||||
});
|
||||
describe("annotationDeleted", function() {
|
||||
var annotation;
|
||||
annotation = null;
|
||||
beforeEach(function() {
|
||||
annotation = {};
|
||||
return sinon.stub(store, '_apiRequest');
|
||||
});
|
||||
it("should call Store#_apiRequest('destroy') with the annotation and data", function() {
|
||||
var args;
|
||||
store.annotations = [annotation];
|
||||
store.annotationDeleted(annotation);
|
||||
args = store._apiRequest.lastCall.args;
|
||||
assert(store._apiRequest.calledOnce);
|
||||
assert.equal(args[0], 'destroy');
|
||||
return assert.equal(args[1], annotation);
|
||||
});
|
||||
return it("should NOT call Store#_apiRequest() if the annotation is unregistered", function() {
|
||||
store.annotations = [];
|
||||
store.annotationDeleted(annotation);
|
||||
return assert.isFalse(store._apiRequest.called);
|
||||
});
|
||||
});
|
||||
describe("registerAnnotation", function() {
|
||||
return it("should add the annotation to the @annotations array", function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
store.annotations = [];
|
||||
store.registerAnnotation(annotation);
|
||||
return assert.equal($.inArray(annotation, store.annotations), 0);
|
||||
});
|
||||
});
|
||||
describe("unregisterAnnotation", function() {
|
||||
return it("should remove the annotation from the @annotations array", function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
store.annotations = [annotation];
|
||||
store.unregisterAnnotation(annotation);
|
||||
return assert.equal($.inArray(annotation, store.annotations), -1);
|
||||
});
|
||||
});
|
||||
describe("updateAnnotation", function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
beforeEach(function() {
|
||||
sinon.stub(console, 'error');
|
||||
annotation = {
|
||||
text: "my annotation text",
|
||||
range: []
|
||||
};
|
||||
return store.annotations = [annotation];
|
||||
});
|
||||
afterEach(function() {
|
||||
return console.error.restore();
|
||||
});
|
||||
it("should extend the annotation with the data provided", function() {
|
||||
store.updateAnnotation(annotation, {
|
||||
id: "myid",
|
||||
text: "new text"
|
||||
});
|
||||
return assert.deepEqual(annotation, {
|
||||
id: "myid",
|
||||
text: "new text",
|
||||
range: []
|
||||
});
|
||||
});
|
||||
it("should NOT extend the annotation if it is not registered with the Store", function() {
|
||||
store.annotations = [];
|
||||
store.updateAnnotation(annotation, {
|
||||
id: "myid",
|
||||
text: "new text"
|
||||
});
|
||||
return assert.equal(annotation, annotation);
|
||||
});
|
||||
return it("should update the data stored on the annotation highlight", function() {
|
||||
var data;
|
||||
data = {};
|
||||
annotation.highlight = $('<span />').data('annotation', annotation);
|
||||
store.updateAnnotation(annotation, data);
|
||||
return assert.equal(annotation.highlight.data('annotation'), annotation);
|
||||
});
|
||||
});
|
||||
describe("loadAnnotations", function() {
|
||||
return it("should call Store#_apiRequest()", function() {
|
||||
sinon.stub(store, '_apiRequest');
|
||||
store.loadAnnotations();
|
||||
return assert.isTrue(store._apiRequest.calledWith('read', null, store._onLoadAnnotations));
|
||||
});
|
||||
});
|
||||
describe("loadAnnotationsFromSearch", function() {
|
||||
return it("should call Store#_apiRequest()", function() {
|
||||
var options;
|
||||
options = {};
|
||||
sinon.stub(store, '_apiRequest');
|
||||
store.loadAnnotationsFromSearch(options);
|
||||
return assert.isTrue(store._apiRequest.calledWith('search', options, store._onLoadAnnotationsFromSearch));
|
||||
});
|
||||
});
|
||||
describe("_onLoadAnnotations", function() {
|
||||
it("should set the Store#annotations property with received annotations", function() {
|
||||
var data;
|
||||
data = [1, 2, 3];
|
||||
store._onLoadAnnotations(data);
|
||||
return assert.deepEqual(store.annotations, data);
|
||||
});
|
||||
it("should default to an empty array if no data is provided", function() {
|
||||
store._onLoadAnnotations();
|
||||
return assert.deepEqual(store.annotations, []);
|
||||
});
|
||||
it("should call Annotator#loadAnnotations()", function() {
|
||||
store._onLoadAnnotations();
|
||||
return assert(store.annotator.loadAnnotations.calledOnce);
|
||||
});
|
||||
it("should call Annotator#loadAnnotations() with clone of provided data", function() {
|
||||
var data;
|
||||
data = [];
|
||||
store._onLoadAnnotations(data);
|
||||
assert.notStrictEqual(store.annotator.loadAnnotations.lastCall.args[0], data);
|
||||
return assert.deepEqual(store.annotator.loadAnnotations.lastCall.args[0], data);
|
||||
});
|
||||
return it("should add, dedupe and update annotations when called for the 2nd time", function() {
|
||||
var data1, data2, dataAll;
|
||||
data1 = [
|
||||
{
|
||||
id: 1
|
||||
}, {
|
||||
id: 2
|
||||
}
|
||||
];
|
||||
data2 = [
|
||||
{
|
||||
id: 1,
|
||||
foo: "bar"
|
||||
}, {
|
||||
id: 3
|
||||
}
|
||||
];
|
||||
dataAll = [
|
||||
{
|
||||
id: 1,
|
||||
foo: "bar"
|
||||
}, {
|
||||
id: 2
|
||||
}, {
|
||||
id: 3
|
||||
}
|
||||
];
|
||||
store._onLoadAnnotations(data1);
|
||||
store._onLoadAnnotations(data2);
|
||||
return assert.deepEqual(store.annotations, dataAll);
|
||||
});
|
||||
});
|
||||
describe("_onLoadAnnotationsFromSearch", function() {
|
||||
it("should call Store#_onLoadAnnotations() with data.rows", function() {
|
||||
var data;
|
||||
sinon.stub(store, '_onLoadAnnotations');
|
||||
data = {
|
||||
rows: [{}, {}, {}]
|
||||
};
|
||||
store._onLoadAnnotationsFromSearch(data);
|
||||
return assert.deepEqual(store._onLoadAnnotations.lastCall.args[0], data.rows);
|
||||
});
|
||||
return it("should default to an empty array if no data.rows are provided", function() {
|
||||
sinon.stub(store, '_onLoadAnnotations');
|
||||
store._onLoadAnnotationsFromSearch();
|
||||
return assert.deepEqual(store._onLoadAnnotations.lastCall.args[0], []);
|
||||
});
|
||||
});
|
||||
describe("dumpAnnotations", function() {
|
||||
it("returns a list of its annotations", function() {
|
||||
store.annotations = [
|
||||
{
|
||||
text: "Foobar"
|
||||
}, {
|
||||
user: "Bob"
|
||||
}
|
||||
];
|
||||
return assert.deepEqual(store.dumpAnnotations(), [
|
||||
{
|
||||
text: "Foobar"
|
||||
}, {
|
||||
user: "Bob"
|
||||
}
|
||||
]);
|
||||
});
|
||||
return it("removes the highlights properties from the annotations", function() {
|
||||
store.annotations = [
|
||||
{
|
||||
highlights: "abc"
|
||||
}, {
|
||||
highlights: [1, 2, 3]
|
||||
}
|
||||
];
|
||||
return assert.deepEqual(store.dumpAnnotations(), [{}, {}]);
|
||||
});
|
||||
});
|
||||
describe("_apiRequest", function() {
|
||||
var mockOptions, mockUri;
|
||||
mockUri = 'http://mock.com';
|
||||
mockOptions = {};
|
||||
beforeEach(function() {
|
||||
sinon.stub(store, '_urlFor').returns(mockUri);
|
||||
sinon.stub(store, '_apiRequestOptions').returns(mockOptions);
|
||||
return sinon.stub($, 'ajax').returns({});
|
||||
});
|
||||
afterEach(function() {
|
||||
return $.ajax.restore();
|
||||
});
|
||||
it("should call Store#_urlFor() with the action", function() {
|
||||
var action;
|
||||
action = 'read';
|
||||
store._apiRequest(action);
|
||||
return assert.isTrue(store._urlFor.calledWith(action, void 0));
|
||||
});
|
||||
it("should call Store#_urlFor() with the action and id extracted from the data", function() {
|
||||
var action, data;
|
||||
data = {
|
||||
id: 'myId'
|
||||
};
|
||||
action = 'read';
|
||||
store._apiRequest(action, data);
|
||||
return assert.isTrue(store._urlFor.calledWith(action, data.id));
|
||||
});
|
||||
it("should call Store#_apiRequestOptions() with the action, data and callback", function() {
|
||||
var action, callback, data;
|
||||
data = {
|
||||
id: 'myId'
|
||||
};
|
||||
action = 'read';
|
||||
callback = function() {};
|
||||
store._apiRequest(action, data, callback);
|
||||
return assert.isTrue(store._apiRequestOptions.calledWith(action, data, callback));
|
||||
});
|
||||
it("should call jQuery#ajax()", function() {
|
||||
store._apiRequest();
|
||||
return assert.isTrue($.ajax.calledWith(mockUri, mockOptions));
|
||||
});
|
||||
return it("should return the jQuery XHR object with action and id appended", function() {
|
||||
var action, data, request;
|
||||
data = {
|
||||
id: 'myId'
|
||||
};
|
||||
action = 'read';
|
||||
request = store._apiRequest(action, data);
|
||||
assert.equal(request._id, data.id);
|
||||
return assert.equal(request._action, action);
|
||||
});
|
||||
});
|
||||
describe("_apiRequestOptions", function() {
|
||||
beforeEach(function() {
|
||||
return sinon.stub(store, '_dataFor').returns('{}');
|
||||
});
|
||||
it("should call Store#_methodFor() with the action", function() {
|
||||
var action;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
action = 'read';
|
||||
store._apiRequestOptions(action);
|
||||
return assert.isTrue(store._methodFor.calledWith(action));
|
||||
});
|
||||
it("should return options for jQuery.ajax()", function() {
|
||||
var action, callback, data, options;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
action = 'read';
|
||||
data = {};
|
||||
callback = function() {};
|
||||
options = store._apiRequestOptions(action, data, callback);
|
||||
return assert.deepEqual(options, {
|
||||
type: 'GET',
|
||||
headers: void 0,
|
||||
dataType: "json",
|
||||
success: callback,
|
||||
error: store._onError,
|
||||
data: '{}',
|
||||
contentType: "application/json; charset=utf-8"
|
||||
});
|
||||
});
|
||||
it("should set custom headers from the data property 'annotator:headers'", function() {
|
||||
var action, data, options;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
sinon.stub(store.element, 'data').returns({
|
||||
'x-custom-header-one': 'mycustomheader',
|
||||
'x-custom-header-two': 'mycustomheadertwo',
|
||||
'x-custom-header-three': 'mycustomheaderthree'
|
||||
});
|
||||
action = 'read';
|
||||
data = {};
|
||||
options = store._apiRequestOptions(action, data);
|
||||
return assert.deepEqual(options.headers, {
|
||||
'x-custom-header-one': 'mycustomheader',
|
||||
'x-custom-header-two': 'mycustomheadertwo',
|
||||
'x-custom-header-three': 'mycustomheaderthree'
|
||||
});
|
||||
});
|
||||
it("should call Store#_dataFor() with the data if action is NOT search", function() {
|
||||
var action, data;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
action = 'read';
|
||||
data = {};
|
||||
store._apiRequestOptions(action, data);
|
||||
return assert.isTrue(store._dataFor.calledWith(data));
|
||||
});
|
||||
it("should NOT call Store#_dataFor() if action is search", function() {
|
||||
var action, data;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
action = 'search';
|
||||
data = {};
|
||||
store._apiRequestOptions(action, data);
|
||||
return assert.isFalse(store._dataFor.called);
|
||||
});
|
||||
it("should NOT add the contentType property if the action is search", function() {
|
||||
var action, data, options;
|
||||
sinon.stub(store, '_methodFor').returns('GET');
|
||||
action = 'search';
|
||||
data = {};
|
||||
options = store._apiRequestOptions(action, data);
|
||||
assert.isUndefined(options.contentType);
|
||||
return assert.equal(options.data, data);
|
||||
});
|
||||
it("should emulate new-fangled HTTP if emulateHTTP is true", function() {
|
||||
var options;
|
||||
sinon.stub(store, '_methodFor').returns('DELETE');
|
||||
store.options.emulateHTTP = true;
|
||||
options = store._apiRequestOptions('destroy', {
|
||||
id: 4
|
||||
});
|
||||
assert.equal(options.type, 'POST');
|
||||
return assert.deepEqual(options.headers, {
|
||||
'X-HTTP-Method-Override': 'DELETE'
|
||||
});
|
||||
});
|
||||
it("should emulate proper JSON handling if emulateJSON is true", function() {
|
||||
var options;
|
||||
sinon.stub(store, '_methodFor').returns('DELETE');
|
||||
store.options.emulateJSON = true;
|
||||
options = store._apiRequestOptions('destroy', {});
|
||||
assert.deepEqual(options.data, {
|
||||
json: '{}'
|
||||
});
|
||||
return assert.isUndefined(options.contentType);
|
||||
});
|
||||
return it("should append _method to the form data if emulateHTTP and emulateJSON are both true", function() {
|
||||
var options;
|
||||
sinon.stub(store, '_methodFor').returns('DELETE');
|
||||
store.options.emulateHTTP = true;
|
||||
store.options.emulateJSON = true;
|
||||
options = store._apiRequestOptions('destroy', {});
|
||||
return assert.deepEqual(options.data, {
|
||||
_method: 'DELETE',
|
||||
json: '{}'
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("_urlFor", function() {
|
||||
it("should generate RESTful URLs by default", function() {
|
||||
assert.equal(store._urlFor('create'), '/store/annotations');
|
||||
assert.equal(store._urlFor('read'), '/store/annotations');
|
||||
assert.equal(store._urlFor('read', 'foo'), '/store/annotations/foo');
|
||||
assert.equal(store._urlFor('update', 'bar'), '/store/annotations/bar');
|
||||
return assert.equal(store._urlFor('destroy', 'baz'), '/store/annotations/baz');
|
||||
});
|
||||
it("should generate URLs as specified by its options otherwise", function() {
|
||||
store.options.prefix = '/some/prefix';
|
||||
store.options.urls.create = '/createMe';
|
||||
store.options.urls.read = '/:id/readMe';
|
||||
store.options.urls.update = '/:id/updateMe';
|
||||
store.options.urls.destroy = '/:id/destroyMe';
|
||||
assert.equal(store._urlFor('create'), '/some/prefix/createMe');
|
||||
assert.equal(store._urlFor('read'), '/some/prefix/readMe');
|
||||
assert.equal(store._urlFor('read', 'foo'), '/some/prefix/foo/readMe');
|
||||
assert.equal(store._urlFor('update', 'bar'), '/some/prefix/bar/updateMe');
|
||||
return assert.equal(store._urlFor('destroy', 'baz'), '/some/prefix/baz/destroyMe');
|
||||
});
|
||||
it("should generate URLs correctly with an empty prefix", function() {
|
||||
store.options.prefix = '';
|
||||
store.options.urls.create = '/createMe';
|
||||
store.options.urls.read = '/:id/readMe';
|
||||
store.options.urls.update = '/:id/updateMe';
|
||||
store.options.urls.destroy = '/:id/destroyMe';
|
||||
assert.equal(store._urlFor('create'), '/createMe');
|
||||
assert.equal(store._urlFor('read'), '/readMe');
|
||||
assert.equal(store._urlFor('read', 'foo'), '/foo/readMe');
|
||||
assert.equal(store._urlFor('update', 'bar'), '/bar/updateMe');
|
||||
return assert.equal(store._urlFor('destroy', 'baz'), '/baz/destroyMe');
|
||||
});
|
||||
return it("should generate URLs with substitution markers in query strings", function() {
|
||||
store.options.prefix = '/some/prefix';
|
||||
store.options.urls.read = '/read?id=:id';
|
||||
store.options.urls.update = '/update?foo&id=:id';
|
||||
store.options.urls.destroy = '/delete?id=:id&foo';
|
||||
assert.equal(store._urlFor('read'), '/some/prefix/read?id=');
|
||||
assert.equal(store._urlFor('read', 'foo'), '/some/prefix/read?id=foo');
|
||||
assert.equal(store._urlFor('update', 'bar'), '/some/prefix/update?foo&id=bar');
|
||||
return assert.equal(store._urlFor('destroy', 'baz'), '/some/prefix/delete?id=baz&foo');
|
||||
});
|
||||
});
|
||||
describe("_methodFor", function() {
|
||||
return it("should return the appropriate method for the action", function() {
|
||||
var action, method, table, _i, _len, _results;
|
||||
table = {
|
||||
'create': 'POST',
|
||||
'read': 'GET',
|
||||
'update': 'PUT',
|
||||
'destroy': 'DELETE',
|
||||
'search': 'GET'
|
||||
};
|
||||
_results = [];
|
||||
for (method = _i = 0, _len = table.length; _i < _len; method = ++_i) {
|
||||
action = table[method];
|
||||
_results.push(assert.equal(store._methodFor(action, method)));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
});
|
||||
describe("_dataFor", function() {
|
||||
it("should stringify the annotation into JSON", function() {
|
||||
var annotation, data;
|
||||
annotation = {
|
||||
id: 'bill'
|
||||
};
|
||||
data = store._dataFor(annotation);
|
||||
return assert.equal(data, '{"id":"bill"}');
|
||||
});
|
||||
it("should NOT stringify the highlights property", function() {
|
||||
var annotation, data;
|
||||
annotation = {
|
||||
id: 'bill',
|
||||
highlights: {}
|
||||
};
|
||||
data = store._dataFor(annotation);
|
||||
return assert.equal(data, '{"id":"bill"}');
|
||||
});
|
||||
it("should NOT append a highlights property if the annotation does not have one", function() {
|
||||
var annotation;
|
||||
annotation = {
|
||||
id: 'bill'
|
||||
};
|
||||
store._dataFor(annotation);
|
||||
return assert.isFalse(annotation.hasOwnProperty('highlights'));
|
||||
});
|
||||
return it("should extend the annotation with @options.annotationData", function() {
|
||||
var annotation, data;
|
||||
annotation = {
|
||||
id: "cat"
|
||||
};
|
||||
store.options.annotationData = {
|
||||
custom: 'value',
|
||||
customArray: []
|
||||
};
|
||||
data = store._dataFor(annotation);
|
||||
assert.equal(data, '{"id":"cat","custom":"value","customArray":[]}');
|
||||
return assert.deepEqual(annotation, {
|
||||
"id": "cat",
|
||||
"custom": "value",
|
||||
"customArray": []
|
||||
});
|
||||
});
|
||||
});
|
||||
return describe("_onError", function() {
|
||||
var message, requests;
|
||||
message = null;
|
||||
requests = [
|
||||
{}, {}, {
|
||||
_action: 'read',
|
||||
_id: 'jim'
|
||||
}, {
|
||||
_action: 'search'
|
||||
}, {
|
||||
_action: 'read'
|
||||
}, {
|
||||
status: 401,
|
||||
_action: 'delete',
|
||||
'_id': 'cake'
|
||||
}, {
|
||||
status: 404,
|
||||
_action: 'delete',
|
||||
'_id': 'cake'
|
||||
}, {
|
||||
status: 500,
|
||||
_action: 'delete',
|
||||
'_id': 'cake'
|
||||
}
|
||||
];
|
||||
beforeEach(function() {
|
||||
sinon.stub(Annotator, 'showNotification');
|
||||
sinon.stub(console, 'error');
|
||||
store._onError(requests.shift());
|
||||
return message = Annotator.showNotification.lastCall.args[0];
|
||||
});
|
||||
afterEach(function() {
|
||||
Annotator.showNotification.restore();
|
||||
return console.error.restore();
|
||||
});
|
||||
it("should call call Annotator.showNotification() with a message and error style", function() {
|
||||
assert(Annotator.showNotification.calledOnce);
|
||||
return assert.equal(Annotator.showNotification.lastCall.args[1], Annotator.Notification.ERROR);
|
||||
});
|
||||
it("should call console.error with a message", function() {
|
||||
return assert(console.error.calledOnce);
|
||||
});
|
||||
it("should give a default message if xhr.status id not provided", function() {
|
||||
return assert.equal(message, "Sorry we could not read this annotation");
|
||||
});
|
||||
it("should give a default specific message if xhr._action is 'search'", function() {
|
||||
return assert.equal(message, "Sorry we could not search the store for annotations");
|
||||
});
|
||||
it("should give a default specific message if xhr._action is 'read' and there is no xhr._id", function() {
|
||||
return assert.equal(message, "Sorry we could not read the annotations from the store");
|
||||
});
|
||||
it("should give a specific message if xhr.status == 401", function() {
|
||||
return assert.equal(message, "Sorry you are not allowed to delete this annotation");
|
||||
});
|
||||
it("should give a specific message if xhr.status == 404", function() {
|
||||
return assert.equal(message, "Sorry we could not connect to the annotations store");
|
||||
});
|
||||
return it("should give a specific message if xhr.status == 500", function() {
|
||||
return assert.equal(message, "Sorry something went wrong with the annotation store");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=store_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/store_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/store_spec.map
Normal file
File diff suppressed because one or more lines are too long
108
libs/annotator/lib/spec/plugin/tags_spec.js
Normal file
108
libs/annotator/lib/spec/plugin/tags_spec.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
describe('Annotator.Plugin.Tags', function() {
|
||||
var annotator, plugin;
|
||||
annotator = null;
|
||||
plugin = null;
|
||||
beforeEach(function() {
|
||||
var el;
|
||||
el = $("<div><div class='annotator-editor-controls'></div></div>")[0];
|
||||
annotator = new Annotator($('<div/>')[0]);
|
||||
plugin = new Annotator.Plugin.Tags(el);
|
||||
plugin.annotator = annotator;
|
||||
return plugin.pluginInit();
|
||||
});
|
||||
it("should parse whitespace-delimited tags into an array", function() {
|
||||
var str;
|
||||
str = 'one two three\tfourFive';
|
||||
return assert.deepEqual(plugin.parseTags(str), ['one', 'two', 'three', 'fourFive']);
|
||||
});
|
||||
it("should stringify a tags array into a space-delimited string", function() {
|
||||
var ary;
|
||||
ary = ['one', 'two', 'three'];
|
||||
return assert.equal(plugin.stringifyTags(ary), "one two three");
|
||||
});
|
||||
describe("pluginInit", function() {
|
||||
it("should add a field to the editor", function() {
|
||||
sinon.spy(annotator.editor, 'addField');
|
||||
plugin.pluginInit();
|
||||
return assert(annotator.editor.addField.calledOnce);
|
||||
});
|
||||
return it("should register a filter if the Filter plugin is loaded", function() {
|
||||
plugin.annotator.plugins.Filter = {
|
||||
addFilter: sinon.spy()
|
||||
};
|
||||
plugin.pluginInit();
|
||||
return assert(plugin.annotator.plugins.Filter.addFilter.calledOnce);
|
||||
});
|
||||
});
|
||||
describe("updateField", function() {
|
||||
it("should set the value of the input", function() {
|
||||
var annotation;
|
||||
annotation = {
|
||||
tags: ['apples', 'oranges', 'pears']
|
||||
};
|
||||
plugin.updateField(plugin.field, annotation);
|
||||
return assert.equal(plugin.input.val(), 'apples oranges pears');
|
||||
});
|
||||
return it("should set the clear the value of the input if there are no tags", function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
plugin.input.val('apples pears oranges');
|
||||
plugin.updateField(plugin.field, annotation);
|
||||
return assert.equal(plugin.input.val(), '');
|
||||
});
|
||||
});
|
||||
describe("setAnnotationTags", function() {
|
||||
return it("should set the annotation's tags", function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
plugin.input.val('apples oranges pears');
|
||||
plugin.setAnnotationTags(plugin.field, annotation);
|
||||
return assert.deepEqual(annotation.tags, ['apples', 'oranges', 'pears']);
|
||||
});
|
||||
});
|
||||
return describe("updateViewer", function() {
|
||||
it("should insert the tags into the field", function() {
|
||||
var annotation, field;
|
||||
annotation = {
|
||||
tags: ['foo', 'bar', 'baz']
|
||||
};
|
||||
field = $('<div />')[0];
|
||||
plugin.updateViewer(field, annotation);
|
||||
return assert.deepEqual($(field).html(), ['<span class="annotator-tag">foo</span>', '<span class="annotator-tag">bar</span>', '<span class="annotator-tag">baz</span>'].join(' '));
|
||||
});
|
||||
return it("should remove the field if there are no tags", function() {
|
||||
var annotation, field;
|
||||
annotation = {
|
||||
tags: []
|
||||
};
|
||||
field = $('<div />')[0];
|
||||
plugin.updateViewer(field, annotation);
|
||||
assert.lengthOf($(field).parent(), 0);
|
||||
annotation = {};
|
||||
field = $('<div />')[0];
|
||||
plugin.updateViewer(field, annotation);
|
||||
return assert.lengthOf($(field).parent(), 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Annotator.Plugin.Tags.filterCallback', function() {
|
||||
var filter;
|
||||
filter = null;
|
||||
beforeEach(function() {
|
||||
return filter = Annotator.Plugin.Tags.filterCallback;
|
||||
});
|
||||
it('should return true if all tags are matched by keywords', function() {
|
||||
assert.isTrue(filter('cat dog mouse', ['cat', 'dog', 'mouse']));
|
||||
return assert.isTrue(filter('cat dog', ['cat', 'dog', 'mouse']));
|
||||
});
|
||||
return it('should NOT return true if all tags are NOT matched by keywords', function() {
|
||||
assert.isFalse(filter('cat dog', ['cat']));
|
||||
return assert.isFalse(filter('cat dog', []));
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=tags_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/tags_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/tags_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "tags_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/tags_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
6
libs/annotator/lib/spec/plugin/unsupported_spec.js
Normal file
6
libs/annotator/lib/spec/plugin/unsupported_spec.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
|
||||
|
||||
/*
|
||||
//@ sourceMappingURL=unsupported_spec.map
|
||||
*/
|
10
libs/annotator/lib/spec/plugin/unsupported_spec.map
Normal file
10
libs/annotator/lib/spec/plugin/unsupported_spec.map
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "unsupported_spec.js",
|
||||
"sourceRoot": "../../..",
|
||||
"sources": [
|
||||
"test/spec/plugin/unsupported_spec.coffee"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": ";AAwFyC"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue