summaryrefslogtreecommitdiff
path: root/annotator/plugins/store.js
blob: 3b5c91695a7efd581ff96ee3c5569ccf6d5bacf2 (plain)
  1. var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  2. __hasProp = Object.prototype.hasOwnProperty,
  3. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; },
  4. __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
  5. Annotator.Plugin.Store = (function(_super) {
  6. __extends(Store, _super);
  7. Store.prototype.events = {
  8. 'annotationCreated': 'annotationCreated',
  9. 'annotationDeleted': 'annotationDeleted',
  10. 'annotationUpdated': 'annotationUpdated'
  11. };
  12. Store.prototype.options = {
  13. prefix: '/api',
  14. autoFetch: true,
  15. annotationData: {},
  16. loadFromSearch: false,
  17. urls: {
  18. create: '/annotations',
  19. read: '/annotations/:id',
  20. update: '/annotations/:id',
  21. destroy: '/annotations/:id',
  22. search: '/search'
  23. }
  24. };
  25. function Store(element, options) {
  26. this._onError = __bind(this._onError, this);
  27. this._onLoadAnnotationsFromSearch = __bind(this._onLoadAnnotationsFromSearch, this);
  28. this._onLoadAnnotations = __bind(this._onLoadAnnotations, this);
  29. this._getAnnotations = __bind(this._getAnnotations, this); Store.__super__.constructor.apply(this, arguments);
  30. this.annotations = [];
  31. }
  32. Store.prototype.pluginInit = function() {
  33. if (!Annotator.supported()) return;
  34. if (this.annotator.plugins.Auth) {
  35. return this.annotator.plugins.Auth.withToken(this._getAnnotations);
  36. } else {
  37. return this._getAnnotations();
  38. }
  39. };
  40. Store.prototype._getAnnotations = function() {
  41. if (this.options.loadFromSearch) {
  42. return this.loadAnnotationsFromSearch(this.options.loadFromSearch);
  43. } else {
  44. return this.loadAnnotations();
  45. }
  46. };
  47. Store.prototype.annotationCreated = function(annotation) {
  48. var _this = this;
  49. if (__indexOf.call(this.annotations, annotation) < 0) {
  50. this.registerAnnotation(annotation);
  51. return this._apiRequest('create', annotation, function(data) {
  52. if (!(data.id != null)) {
  53. console.warn(Annotator._t("Warning: No ID returned from server for annotation "), annotation);
  54. }
  55. return _this.updateAnnotation(annotation, data);
  56. });
  57. } else {
  58. return this.updateAnnotation(annotation, {});
  59. }
  60. };
  61. Store.prototype.annotationUpdated = function(annotation) {
  62. var _this = this;
  63. if (__indexOf.call(this.annotations, annotation) >= 0) {
  64. return this._apiRequest('update', annotation, (function(data) {
  65. return _this.updateAnnotation(annotation, data);
  66. }));
  67. }
  68. };
  69. Store.prototype.annotationDeleted = function(annotation) {
  70. var _this = this;
  71. if (__indexOf.call(this.annotations, annotation) >= 0) {
  72. return this._apiRequest('destroy', annotation, (function() {
  73. return _this.unregisterAnnotation(annotation);
  74. }));
  75. }
  76. };
  77. Store.prototype.registerAnnotation = function(annotation) {
  78. return this.annotations.push(annotation);
  79. };
  80. Store.prototype.unregisterAnnotation = function(annotation) {
  81. return this.annotations.splice(this.annotations.indexOf(annotation), 1);
  82. };
  83. Store.prototype.updateAnnotation = function(annotation, data) {
  84. if (__indexOf.call(this.annotations, annotation) < 0) {
  85. console.error(Annotator._t("Trying to update unregistered annotation!"));
  86. } else {
  87. $.extend(annotation, data);
  88. }
  89. return $(annotation.highlights).data('annotation', annotation);
  90. };
  91. Store.prototype.loadAnnotations = function() {
  92. return this._apiRequest('read', null, this._onLoadAnnotations);
  93. };
  94. Store.prototype._onLoadAnnotations = function(data) {
  95. if (data == null) data = [];
  96. this.annotations = data;
  97. return this.annotator.loadAnnotations(data.slice());
  98. };
  99. Store.prototype.loadAnnotationsFromSearch = function(searchOptions) {
  100. return this._apiRequest('search', searchOptions, this._onLoadAnnotationsFromSearch);
  101. };
  102. Store.prototype._onLoadAnnotationsFromSearch = function(data) {
  103. if (data == null) data = {};
  104. return this._onLoadAnnotations(data.rows || []);
  105. };
  106. Store.prototype.dumpAnnotations = function() {
  107. var ann, _i, _len, _ref, _results;
  108. _ref = this.annotations;
  109. _results = [];
  110. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  111. ann = _ref[_i];
  112. _results.push(JSON.parse(this._dataFor(ann)));
  113. }
  114. return _results;
  115. };
  116. Store.prototype._apiRequest = function(action, obj, onSuccess) {
  117. var id, options, request, url;
  118. id = obj && obj.id;
  119. url = this._urlFor(action, id);
  120. options = this._apiRequestOptions(action, obj, onSuccess);
  121. request = $.ajax(url, options);
  122. request._id = id;
  123. request._action = action;
  124. return request;
  125. };
  126. Store.prototype._apiRequestOptions = function(action, obj, onSuccess) {
  127. var opts;
  128. opts = {
  129. type: this._methodFor(action),
  130. headers: this.element.data('annotator:headers'),
  131. dataType: "json",
  132. success: onSuccess || function() {},
  133. error: this._onError
  134. };
  135. if (action === "search") {
  136. opts = $.extend(opts, {
  137. data: obj
  138. });
  139. } else {
  140. opts = $.extend(opts, {
  141. data: obj && this._dataFor(obj),
  142. contentType: "application/json; charset=utf-8"
  143. });
  144. }
  145. return opts;
  146. };
  147. Store.prototype._urlFor = function(action, id) {
  148. var replaceWith, url;
  149. replaceWith = id != null ? '/' + id : '';
  150. url = this.options.prefix || '/';
  151. url += this.options.urls[action];
  152. url = url.replace(/\/:id/, replaceWith);
  153. return url;
  154. };
  155. Store.prototype._methodFor = function(action) {
  156. var table;
  157. table = {
  158. 'create': 'POST',
  159. 'read': 'GET',
  160. 'update': 'PUT',
  161. 'destroy': 'DELETE',
  162. 'search': 'GET'
  163. };
  164. return table[action];
  165. };
  166. Store.prototype._dataFor = function(annotation) {
  167. var data, highlights;
  168. highlights = annotation.highlights;
  169. delete annotation.highlights;
  170. $.extend(annotation, this.options.annotationData);
  171. data = JSON.stringify(annotation);
  172. if (highlights) annotation.highlights = highlights;
  173. return data;
  174. };
  175. Store.prototype._onError = function(xhr) {
  176. var action, message;
  177. action = xhr._action;
  178. message = Annotator._t("Sorry we could not ") + action + Annotator._t(" this annotation");
  179. if (xhr._action === 'search') {
  180. message = Annotator._t("Sorry we could not search the store for annotations");
  181. } else if (xhr._action === 'read' && !xhr._id) {
  182. message = Annotator._t("Sorry we could not ") + action + Annotator._t(" the annotations from the store");
  183. }
  184. switch (xhr.status) {
  185. case 401:
  186. message = Annotator._t("Sorry you are not allowed to ") + action + Annotator._t(" this annotation");
  187. break;
  188. case 404:
  189. message = Annotator._t("Sorry we could not connect to the annotations store");
  190. break;
  191. case 500:
  192. message = Annotator._t("Sorry something went wrong with the annotation store");
  193. }
  194. Annotator.showNotification(message, Annotator.Notification.ERROR);
  195. return console.error(Annotator._t("API request failed:") + (" '" + xhr.status + "'"));
  196. };
  197. return Store;
  198. })(Annotator.Plugin);