Guest User

Untitled

a guest
Jun 21st, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.13 KB | None | 0 0
  1. // Document Model
  2.  
  3. dc.model.Document = Backbone.Model.extend({
  4.  
  5. constructor : function(attrs, options) {
  6. attrs.selected = false;
  7. attrs.selectable = true;
  8. if (attrs.annotation_count == null) attrs.annotation_count = 0;
  9. Backbone.Model.call(this, attrs, options);
  10. var id = this.id;
  11. this.notes = new dc.model.NoteSet();
  12. this.notes.url = function() {
  13. return 'documents/' + id + '/annotations';
  14. };
  15. this.pageEntities = new dc.model.EntitySet();
  16. },
  17.  
  18. // If this document does not belong to a collection, it still has a URL.
  19. url : function() {
  20. if (!this.collection) return '/documents/' + this.id;
  21. return Backbone.Model.prototype.url.call(this);
  22. },
  23.  
  24. // Generate the canonical URL for opening this document, over SSL if we're
  25. // currently secured.
  26. viewerUrl : function() {
  27. var base = this.get('document_viewer_url').replace(/^http:/, '');
  28. return window.location.protocol + base;
  29. },
  30.  
  31. // Generate the published URL for opening this document.
  32. publishedUrl : function() {
  33. return this.get('remote_url') || this.get('detected_remote_url');
  34. },
  35.  
  36. // Generate the canonical id for this document.
  37. canonicalId : function() {
  38. return this.id + '-' + this.get('slug');
  39. },
  40.  
  41. formatDay : DateUtils.create('%b %e, %Y'),
  42.  
  43. formatTime : DateUtils.create('%l:%M %P'),
  44.  
  45. // Generate the date object for this Document's `publish_at`.
  46. publishAtDate : function() {
  47. var date = this.get('publish_at');
  48. return date && DateUtils.parseRfc(date);
  49. },
  50.  
  51. // Standard display of `publish_at`.
  52. formattedPublishAtDate : function() {
  53. var date = this.publishAtDate();
  54. return date && (this.formatDay(date) + ' at ' + this.formatTime(date));
  55. },
  56.  
  57. reprocessText : function(forceOCR) {
  58. var params = {};
  59. if (forceOCR) params.ocr = true;
  60. $.ajax({url : this.url() + '/reprocess_text', data: params, type : 'POST', dataType : 'json', success : _.bind(function(resp) {
  61. this.set({access : dc.access.PENDING});
  62. }, this)});
  63. },
  64.  
  65. openViewer : function() {
  66. if (this.checkBusy()) return;
  67. window.open(this.viewerUrl());
  68. },
  69.  
  70. openPublishedViewer : function() {
  71. if (this.checkBusy()) return;
  72. if (!this.isPublished()) return dc.ui.Dialog.alert('"' + this.get('title') + '" is not published.');
  73. window.open(this.publishedUrl());
  74. },
  75.  
  76. openText : function() {
  77. if (this.checkBusy()) return;
  78. window.open(this.get('full_text_url'));
  79. },
  80.  
  81. openPDF : function() {
  82. if (this.checkBusy()) return;
  83. window.open(this.get('pdf_url'));
  84. },
  85.  
  86. pageThumbnailURL : function(page) {
  87. return this.get('page_image_url').replace('{size}', 'thumbnail').replace('{page}', page);
  88. },
  89.  
  90. allowedToEdit : function() {
  91. var current = Accounts.current();
  92. return current && Accounts.current().checkAllowedToEdit(this);
  93. },
  94.  
  95. // Is the document editable by the current account?
  96. checkAllowedToEdit : function(message) {
  97. message = message || "You don't have permission to edit \"" + this.get('title') + "\".";
  98. if (this.allowedToEdit()) return true;
  99. dc.ui.Dialog.alert(message);
  100. return false;
  101. },
  102.  
  103. checkBusy : function() {
  104. if (!(this.get('access') == dc.access.PENDING)) return false;
  105. dc.ui.Dialog.alert('"' + this.get('title') + '" is still being processed. Please wait for it to finish.');
  106. return true;
  107. },
  108.  
  109. uniquePageEntityValues : function() {
  110. return _.uniq(this.pageEntities.map(function(m){ return m.get('value'); }));
  111. },
  112.  
  113. isPending : function() {
  114. return this.get('access') == dc.access.PENDING;
  115. },
  116.  
  117. isPublic : function() {
  118. return this.get('access') == dc.access.PUBLIC;
  119. },
  120.  
  121. isPublished : function() {
  122. return this.isPublic() && this.publishedUrl();
  123. },
  124.  
  125. decrementNotes : function() {
  126. var count = this.get('annotation_count');
  127. if (count <= 0) return false;
  128. this.set({annotation_count : count - 1});
  129. },
  130.  
  131. removePages : function(pages) {
  132. Documents.removePages(this, pages);
  133. },
  134.  
  135. reorderPages : function(pageOrder) {
  136. Documents.reorderPages(this, pageOrder);
  137. },
  138.  
  139. // Inspect.
  140. toString : function() {
  141. return 'Document ' + this.id + ' "' + this.get('title') + '"';
  142. }
  143.  
  144. });
  145.  
  146.  
  147. // Document Set
  148.  
  149. dc.model.DocumentSet = Backbone.Collection.extend({
  150.  
  151. model : dc.model.Document,
  152.  
  153. EMBED_FORBIDDEN : "At this stage in the beta, you may only embed documents you've uploaded yourself.",
  154.  
  155. POLL_INTERVAL : 5 * 1000, // 5 seconds.
  156.  
  157. url : '/documents',
  158.  
  159. constructor : function(options) {
  160. Backbone.Collection.call(this, options);
  161. this._polling = false;
  162. _.bindAll(this, 'poll', 'downloadViewers', 'downloadSelectedPDF', 'downloadSelectedFullText', '_onModelChanged');
  163. this.bind('change', this._onModelChanged);
  164. },
  165.  
  166. comparator : function(doc) {
  167. return doc.get('index');
  168. },
  169.  
  170. pending : function() {
  171. return this.select(function(doc){ return doc.isPending(); });
  172. },
  173.  
  174. subtitle : function(count) {
  175. return count > 1 ? count + ' Documents' : '';
  176. },
  177.  
  178. // Given a list of documents and an attribute, return the value of the
  179. // attribute if identical, or null if divergent.
  180. sharedAttribute : function(docs, attr) {
  181. var attrs = _.uniq(_.map(docs, function(doc){ return doc.get(attr); }));
  182. return attrs.length > 1 ? false : attrs[0];
  183. },
  184.  
  185. selectedPublicCount : function() {
  186. return _.reduce(this.selected(), function(memo, doc){
  187. return memo + doc.isPublic() ? 1 : 0;
  188. }, 0);
  189. },
  190.  
  191. allowedToEdit : function(docs, message) {
  192. return !_.any(docs, function(doc) { return !doc.checkAllowedToEdit(message); });
  193. },
  194.  
  195. // Given a clicked document, and the current selected set, determine which
  196. // documents are chosen.
  197. chosen : function(doc) {
  198. var docs = this.selected();
  199. docs = !doc || _.include(docs, doc) ? docs : [doc];
  200. if (_.any(docs, function(doc){ return doc.checkBusy(); })) return [];
  201. return docs;
  202. },
  203.  
  204. downloadViewers : function(docs) {
  205. var ids = _.map(docs, function(doc){ return doc.id; });
  206. var dialog = dc.ui.Dialog.progress('Preparing ' + Inflector.pluralize('document', ids.length) + ' for download...');
  207. dc.app.download('/download/' + ids.join('/') + '/document_viewer.zip', function() {
  208. dialog.close();
  209. });
  210. },
  211.  
  212. downloadSelectedPDF : function() {
  213. if (this.selectedCount <= 1) return this.selected()[0].openPDF();
  214. dc.app.download('/download/' + this.selectedIds().join('/') + '/document_pdfs.zip');
  215. },
  216.  
  217. downloadSelectedFullText : function() {
  218. if (this.selectedCount <= 1) return this.selected()[0].openText();
  219. dc.app.download('/download/' + this.selectedIds().join('/') + '/document_text.zip');
  220. },
  221.  
  222. startPolling : function() {
  223. this._polling = setInterval(this.poll, this.POLL_INTERVAL);
  224. },
  225.  
  226. stopPolling : function() {
  227. clearInterval(this._polling);
  228. this._polling = null;
  229. },
  230.  
  231. poll : function() {
  232. var ids = _.pluck(this.pending(), 'id');
  233. $.get('/documents/status.json', {'ids[]' : ids}, _.bind(function(resp) {
  234. _.each(resp.documents, function(json) {
  235. var doc = Documents.get(json.id);
  236. if (doc && doc.get('access') != json.access) doc.set(json);
  237. });
  238. if (!this.pending().length) this.stopPolling();
  239. }, this), 'json');
  240. },
  241.  
  242. // Destroy the currently selected documents, after asking for confirmation.
  243. verifyDestroy : function(docs) {
  244. if (!this.allowedToEdit(docs)) return;
  245. var message = 'Really delete ' + docs.length + ' ' + Inflector.pluralize('document', docs.length) + '?';
  246. dc.ui.Dialog.confirm(message, _.bind(function() {
  247. var counter = docs.length;
  248. var progress = dc.ui.Dialog.progress('Deleting Documents&hellip;');
  249. _(docs).each(function(doc){ doc.destroy({success : function() {
  250. if (!--counter) progress.close();
  251. }}); });
  252. Projects.removeDocuments(docs);
  253. return true;
  254. }, this));
  255. },
  256.  
  257. // Removes an array of pages from a document. Forces a reprocessing of
  258. // the entire document, which can be expensive.
  259. removePages : function(model, pages, options) {
  260. options = options || {};
  261.  
  262. $.ajax({
  263. url : '/' + this.resource + '/' + model.id + '/remove_pages',
  264. type : 'POST',
  265. data : { pages : pages },
  266. dataType : 'json',
  267. success : function(resp) {
  268. model.set(resp);
  269. if (options.success) options.success(model, resp);
  270. },
  271. error : _.bind(function(resp) {
  272. this._handleError(model, options.error, null, resp);
  273. }, this)
  274. });
  275. },
  276.  
  277. // Reorders an array of pages from a document. Forces a reprocessing of
  278. // the entire document, which can be expensive.
  279. reorderPages : function(model, pageOrder, options) {
  280. options = options || {};
  281.  
  282. $.ajax({
  283. url : '/' + this.resource + '/' + model.id + '/reorder_pages',
  284. type : 'POST',
  285. data : { page_order : pageOrder },
  286. dataType : 'json',
  287. success : function(resp) {
  288. model.set(resp);
  289. if (options.success) options.success(model, resp);
  290. },
  291. error : _.bind(function(resp) {
  292. this._handleError(model, options.error, null, resp);
  293. }, this)
  294. });
  295. },
  296.  
  297. editAccess : function(docs) {
  298. var options = {information: this.subtitle(docs.length)};
  299. if (!this.allowedToEdit(docs)) return;
  300. var current = this.sharedAttribute(docs, 'access') || dc.access.PRIVATE;
  301. dc.ui.Dialog.choose('Access Level', [
  302. {text : 'Public Access', description : 'Anyone on the internet can search for and view the document.', value : dc.access.PUBLIC, selected : current == dc.access.PUBLIC},
  303. {text : 'Private Access', description : 'Only people explicitly granted permission (via collaboration) may access.', value : dc.access.PRIVATE, selected : current == dc.access.PRIVATE},
  304. {text : 'Private to ' + dc.account.organization.name, description : 'Only the people in your organization may view the document.', value : dc.access.ORGANIZATION, selected : current == dc.access.ORGANIZATION}
  305. ], function(access) {
  306. _.each(docs, function(doc) { doc.save({access : parseInt(access, 10)}); });
  307. var notification = 'Access updated for ' + docs.length + ' ' + Inflector.pluralize('document', docs.length);
  308. dc.ui.notifier.show({mode : 'info', text : notification});
  309. return true;
  310. }, options);
  311. },
  312.  
  313. // We override `add` to listen for uploading documents, and to start polling
  314. // for changes.
  315. add : function(model, options) {
  316. Backbone.Collection.prototype.add.call(this, model, options);
  317. this._checkForPending();
  318. },
  319.  
  320. // We override `refresh` to cancel the polling action if the current set
  321. // has no pending documents.
  322. refresh : function(models, options) {
  323. this._resetSelection();
  324. if (!this.pending().length) this.stopPolling();
  325. Backbone.Collection.prototype.refresh.call(this, models, options);
  326. },
  327.  
  328. // When one of our models has changed, if it has changed its access level
  329. // to pending, start polling.
  330. _onModelChanged : function(doc) {
  331. if (doc.hasChanged('access') && doc.isPending()) this._checkForPending();
  332. },
  333.  
  334. _checkForPending : function() {
  335. if (this._polling) return false;
  336. if (!this.pending().length) return false;
  337. this.startPolling();
  338. }
  339.  
  340. });
  341.  
  342. _.extend(dc.model.DocumentSet.prototype, dc.model.Selectable);
  343.  
  344. // The main set of Documents.
  345. window.Documents = new dc.model.DocumentSet();
Add Comment
Please, Sign In to add comment