Browse Source

Add Feature: Richer Editor insert picture as attachment instead of b64 string

Sam X. Chen 5 years ago
parent
commit
67d23ff8ae

+ 9 - 4
.meteor-1.6-snap/package.json

@@ -53,16 +53,21 @@
     "prettier-eslint": "^8.8.2"
   },
   "dependencies": {
-    "@babel/runtime": "^7.1.2",
+    "@babel/runtime": "^7.5.4",
+    "ajv": "^5.0.0",
     "babel-runtime": "^6.26.0",
-    "bson-ext": "^2.0.0",
+    "bcrypt": "^3.0.2",
+    "bson": "^4.0.0",
+    "bunyan": "^1.8.12",
     "es6-promise": "^4.2.4",
-    "hoek": "^5.0.4",
+    "gridfs-stream": "^0.5.3",
+    "ldapjs": "^1.0.2",
     "meteor-node-stubs": "^0.4.1",
+    "mongodb": "^2.2.19",
     "os": "^0.1.1",
     "page": "^1.8.6",
     "qs": "^6.5.2",
-    "source-map-support": "^0.5.9",
+    "source-map-support": "^0.5.12",
     "xss": "^1.0.6"
   }
 }

+ 6 - 21
client/components/cards/attachments.js

@@ -55,27 +55,12 @@ Template.cardAttachmentsPopup.events({
   'change .js-attach-file'(event) {
     const card = this;
     const processFile = f => {
-      const file = new FS.File(f);
-      if (card.isLinkedCard()) {
-        file.boardId = Cards.findOne(card.linkedId).boardId;
-        file.cardId = card.linkedId;
-      } else {
-        file.boardId = card.boardId;
-        file.swimlaneId = card.swimlaneId;
-        file.listId = card.listId;
-        file.cardId = card._id;
-      }
-      file.userId = Meteor.userId();
-      if (file.original) {
-        file.original.name = f.name;
-      }
-      const attachment = Attachments.insert(file);
-
-      if (attachment && attachment._id && attachment.isImage()) {
-        card.setCover(attachment._id);
-      }
-
-      Popup.close();
+      Utils.processUploadedAttachment(card, f, attachment => {
+        if (attachment && attachment._id && attachment.isImage()) {
+          card.setCover(attachment._id);
+        }
+        Popup.close();
+      });
     };
 
     FS.Utility.eachFile(event, f => {

+ 50 - 15
client/components/main/editor.js

@@ -176,36 +176,71 @@ Template.editor.onRendered(() => {
               const $summernote = getSummernote(this);
               if (files && files.length > 0) {
                 const image = files[0];
-                const reader = new FileReader();
+                const currentCard = Cards.findOne(Session.get('currentCard'));
                 const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
                 const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
-                const processData = function(dataURL) {
+                const insertImage = src => {
                   const img = document.createElement('img');
-                  img.src = dataURL;
+                  img.src = src;
                   img.setAttribute('width', '100%');
                   $summernote.summernote('insertNode', img);
                 };
-                reader.onload = function(e) {
-                  const dataurl = e && e.target && e.target.result;
-                  if (dataurl !== undefined) {
-                    if (MAX_IMAGE_PIXEL) {
+                const processData = function(fileObj) {
+                  Utils.processUploadedAttachment(
+                    currentCard,
+                    fileObj,
+                    attachment => {
+                      if (
+                        attachment &&
+                        attachment._id &&
+                        attachment.isImage()
+                      ) {
+                        attachment.one('uploaded', function() {
+                          const maxTry = 3;
+                          const checkItvl = 500;
+                          let retry = 0;
+                          const checkUrl = function() {
+                            // even though uploaded event fired, attachment.url() is still null somehow //TODO
+                            const url = attachment.url();
+                            if (url) {
+                              insertImage(url);
+                            } else {
+                              retry++;
+                              if (retry < maxTry) {
+                                setTimeout(checkUrl, checkItvl);
+                              }
+                            }
+                          };
+                          checkUrl();
+                        });
+                      }
+                    },
+                  );
+                };
+                if (MAX_IMAGE_PIXEL) {
+                  const reader = new FileReader();
+                  reader.onload = function(e) {
+                    const dataurl = e && e.target && e.target.result;
+                    if (dataurl !== undefined) {
                       // need to shrink image
                       Utils.shrinkImage({
                         dataurl,
                         maxSize: MAX_IMAGE_PIXEL,
                         ratio: COMPRESS_RATIO,
-                        callback(changed) {
-                          if (changed !== false && !!changed) {
-                            processData(changed);
+                        toBlob: true,
+                        callback(blob) {
+                          if (blob !== false) {
+                            blob.name = image.name;
+                            processData(blob);
                           }
                         },
                       });
-                    } else {
-                      processData(dataurl);
                     }
-                  }
-                };
-                reader.readAsDataURL(image);
+                  };
+                  reader.readAsDataURL(image);
+                } else {
+                  processData(image);
+                }
               }
             },
             onPaste() {

+ 25 - 0
client/lib/utils.js

@@ -26,6 +26,31 @@ Utils = {
 
   MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
   COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO,
+  processUploadedAttachment(card, fileObj, callback) {
+    const next = attachment => {
+      if (typeof callback === 'function') {
+        callback(attachment);
+      }
+    };
+    if (!card) {
+      return next();
+    }
+    const file = new FS.File(fileObj);
+    if (card.isLinkedCard()) {
+      file.boardId = Cards.findOne(card.linkedId).boardId;
+      file.cardId = card.linkedId;
+    } else {
+      file.boardId = card.boardId;
+      file.swimlaneId = card.swimlaneId;
+      file.listId = card.listId;
+      file.cardId = card._id;
+    }
+    file.userId = Meteor.userId();
+    if (file.original) {
+      file.original.name = fileObj.name;
+    }
+    return next(Attachments.insert(file));
+  },
   shrinkImage(options) {
     // shrink image to certain size
     const dataurl = options.dataurl,

+ 1 - 0
package.json

@@ -55,6 +55,7 @@
   "dependencies": {
     "@babel/runtime": "^7.5.4",
     "ajv": "^5.0.0",
+    "babel-runtime": "^6.26.0",
     "bcrypt": "^3.0.2",
     "bson": "^4.0.0",
     "bunyan": "^1.8.12",