attachments.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. Template.attachmentsGalery.events({
  2. 'click .js-add-attachment': Popup.open('cardAttachments'),
  3. // If we let this event bubble, FlowRouter will handle it and empty the page
  4. // content, see #101.
  5. 'click .js-download'(event) {
  6. event.stopPropagation();
  7. },
  8. 'click .js-open-attachment-menu': Popup.open('attachmentActions'),
  9. });
  10. Template.attachmentsGalery.helpers({
  11. isBoardAdmin() {
  12. return Meteor.user().isBoardAdmin();
  13. },
  14. fileSize(size) {
  15. return Math.round(size / 1024);
  16. },
  17. });
  18. Template.cardAttachmentsPopup.events({
  19. 'change .js-attach-file'(event) {
  20. const card = this;
  21. if (event.currentTarget.files && event.currentTarget.files[0]) {
  22. const fileId = Random.id();
  23. const config = {
  24. file: event.currentTarget.files[0],
  25. fileId: fileId,
  26. meta: Utils.getCommonAttachmentMetaFrom(card),
  27. chunkSize: 'dynamic',
  28. };
  29. config.meta.fileId = fileId;
  30. const uploader = Attachments.insert(
  31. config,
  32. false,
  33. );
  34. uploader.on('uploaded', (error, fileRef) => {
  35. if (!error) {
  36. if (fileRef.isImage) {
  37. card.setCover(fileRef._id);
  38. }
  39. }
  40. });
  41. uploader.on('end', (error, fileRef) => {
  42. Popup.back();
  43. });
  44. uploader.start();
  45. }
  46. },
  47. 'click .js-computer-upload'(event, templateInstance) {
  48. templateInstance.find('.js-attach-file').click();
  49. event.preventDefault();
  50. },
  51. 'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
  52. });
  53. const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
  54. const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
  55. let pastedResults = null;
  56. Template.previewClipboardImagePopup.onRendered(() => {
  57. // we can paste image from clipboard
  58. const handle = results => {
  59. if (results.dataURL.startsWith('data:image/')) {
  60. const direct = results => {
  61. $('img.preview-clipboard-image').attr('src', results.dataURL);
  62. pastedResults = results;
  63. };
  64. if (MAX_IMAGE_PIXEL) {
  65. // if has size limitation on image we shrink it before uploading
  66. Utils.shrinkImage({
  67. dataurl: results.dataURL,
  68. maxSize: MAX_IMAGE_PIXEL,
  69. ratio: COMPRESS_RATIO,
  70. callback(changed) {
  71. if (changed !== false && !!changed) {
  72. results.dataURL = changed;
  73. }
  74. direct(results);
  75. },
  76. });
  77. } else {
  78. direct(results);
  79. }
  80. }
  81. };
  82. $(document.body).pasteImageReader(handle);
  83. // we can also drag & drop image file to it
  84. $(document.body).dropImageReader(handle);
  85. });
  86. Template.previewClipboardImagePopup.events({
  87. 'click .js-upload-pasted-image'() {
  88. const card = this;
  89. if (pastedResults && pastedResults.file) {
  90. const file = pastedResults.file;
  91. window.oPasted = pastedResults;
  92. const fileId = Random.id();
  93. const config = {
  94. file,
  95. fileId: fileId,
  96. meta: Utils.getCommonAttachmentMetaFrom(card),
  97. fileName: file.name || file.type.replace('image/', 'clipboard.'),
  98. chunkSize: 'dynamic',
  99. };
  100. config.meta.fileId = fileId;
  101. const uploader = Attachments.insert(
  102. config,
  103. false,
  104. );
  105. uploader.on('uploaded', (error, fileRef) => {
  106. if (!error) {
  107. if (fileRef.isImage) {
  108. card.setCover(fileRef._id);
  109. }
  110. }
  111. });
  112. uploader.on('end', (error, fileRef) => {
  113. pastedResults = null;
  114. $(document.body).pasteImageReader(() => {});
  115. Popup.back();
  116. });
  117. uploader.start();
  118. }
  119. },
  120. });
  121. BlazeComponent.extendComponent({
  122. isCover() {
  123. const ret = Cards.findOne(this.data().meta.cardId).coverId == this.data()._id;
  124. return ret;
  125. },
  126. events() {
  127. return [
  128. {
  129. 'click .js-rename': Popup.open('attachmentRename'),
  130. 'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete', function() {
  131. Attachments.remove(this._id);
  132. Popup.back(2);
  133. }),
  134. 'click .js-add-cover'() {
  135. Cards.findOne(this.data().meta.cardId).setCover(this.data()._id);
  136. Popup.back();
  137. },
  138. 'click .js-remove-cover'() {
  139. Cards.findOne(this.data().meta.cardId).unsetCover();
  140. Popup.back();
  141. },
  142. 'click .js-move-storage-fs'() {
  143. Meteor.call('moveAttachmentToStorage', this.data()._id, "fs");
  144. Popup.back();
  145. },
  146. 'click .js-move-storage-gridfs'() {
  147. Meteor.call('moveAttachmentToStorage', this.data()._id, "gridfs");
  148. Popup.back();
  149. },
  150. }
  151. ]
  152. }
  153. }).register('attachmentActionsPopup');
  154. BlazeComponent.extendComponent({
  155. getNameWithoutExtension() {
  156. const ret = this.data().name.replace(new RegExp("\." + this.data().extension + "$"), "");
  157. return ret;
  158. },
  159. events() {
  160. return [
  161. {
  162. 'keydown input.js-edit-attachment-name'(evt) {
  163. // enter = save
  164. if (evt.keyCode === 13) {
  165. this.find('button[type=submit]').click();
  166. }
  167. },
  168. 'click button.js-submit-edit-attachment-name'(event) {
  169. // save button pressed
  170. event.preventDefault();
  171. const name = this.$('.js-edit-attachment-name')[0]
  172. .value
  173. .trim() + this.data().extensionWithDot;
  174. Meteor.call('renameAttachment', this.data()._id, name);
  175. Popup.back(2);
  176. },
  177. }
  178. ]
  179. }
  180. }).register('attachmentRenamePopup');