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

This commit is contained in:
Sam X. Chen 2019-08-10 21:21:42 -04:00
parent 77b5244723
commit 67d23ff8ae
5 changed files with 91 additions and 40 deletions

View file

@ -53,16 +53,21 @@
"prettier-eslint": "^8.8.2" "prettier-eslint": "^8.8.2"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.1.2", "@babel/runtime": "^7.5.4",
"ajv": "^5.0.0",
"babel-runtime": "^6.26.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", "es6-promise": "^4.2.4",
"hoek": "^5.0.4", "gridfs-stream": "^0.5.3",
"ldapjs": "^1.0.2",
"meteor-node-stubs": "^0.4.1", "meteor-node-stubs": "^0.4.1",
"mongodb": "^2.2.19",
"os": "^0.1.1", "os": "^0.1.1",
"page": "^1.8.6", "page": "^1.8.6",
"qs": "^6.5.2", "qs": "^6.5.2",
"source-map-support": "^0.5.9", "source-map-support": "^0.5.12",
"xss": "^1.0.6" "xss": "^1.0.6"
} }
} }

View file

@ -55,27 +55,12 @@ Template.cardAttachmentsPopup.events({
'change .js-attach-file'(event) { 'change .js-attach-file'(event) {
const card = this; const card = this;
const processFile = f => { const processFile = f => {
const file = new FS.File(f); Utils.processUploadedAttachment(card, f, attachment => {
if (card.isLinkedCard()) { if (attachment && attachment._id && attachment.isImage()) {
file.boardId = Cards.findOne(card.linkedId).boardId; card.setCover(attachment._id);
file.cardId = card.linkedId; }
} else { Popup.close();
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();
}; };
FS.Utility.eachFile(event, f => { FS.Utility.eachFile(event, f => {

View file

@ -176,36 +176,71 @@ Template.editor.onRendered(() => {
const $summernote = getSummernote(this); const $summernote = getSummernote(this);
if (files && files.length > 0) { if (files && files.length > 0) {
const image = files[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 MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO; const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
const processData = function(dataURL) { const insertImage = src => {
const img = document.createElement('img'); const img = document.createElement('img');
img.src = dataURL; img.src = src;
img.setAttribute('width', '100%'); img.setAttribute('width', '100%');
$summernote.summernote('insertNode', img); $summernote.summernote('insertNode', img);
}; };
reader.onload = function(e) { const processData = function(fileObj) {
const dataurl = e && e.target && e.target.result; Utils.processUploadedAttachment(
if (dataurl !== undefined) { currentCard,
if (MAX_IMAGE_PIXEL) { 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 // need to shrink image
Utils.shrinkImage({ Utils.shrinkImage({
dataurl, dataurl,
maxSize: MAX_IMAGE_PIXEL, maxSize: MAX_IMAGE_PIXEL,
ratio: COMPRESS_RATIO, ratio: COMPRESS_RATIO,
callback(changed) { toBlob: true,
if (changed !== false && !!changed) { callback(blob) {
processData(changed); if (blob !== false) {
blob.name = image.name;
processData(blob);
} }
}, },
}); });
} else {
processData(dataurl);
} }
} };
}; reader.readAsDataURL(image);
reader.readAsDataURL(image); } else {
processData(image);
}
} }
}, },
onPaste() { onPaste() {

View file

@ -26,6 +26,31 @@ Utils = {
MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL, MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO, 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) { shrinkImage(options) {
// shrink image to certain size // shrink image to certain size
const dataurl = options.dataurl, const dataurl = options.dataurl,

View file

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