From eaf2afb44cb9de64b1ed13cb795efd0f44c541ec Mon Sep 17 00:00:00 2001 From: floatinghotpot Date: Fri, 13 Nov 2015 11:13:54 +0800 Subject: add preview attached image, allow upload image from clipboard and drag & drp --- client/components/cards/attachments.jade | 12 ++++- client/components/cards/attachments.js | 79 +++++++++++++++++++++++++++++++- client/components/cards/attachments.styl | 11 +++++ client/lib/dropImage.js | 62 +++++++++++++++++++++++++ client/lib/pasteImage.js | 57 +++++++++++++++++++++++ i18n/en.i18n.json | 6 +++ 6 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 client/lib/dropImage.js create mode 100644 client/lib/pasteImage.js diff --git a/client/components/cards/attachments.jade b/client/components/cards/attachments.jade index 168fc2c8..79511ac9 100644 --- a/client/components/cards/attachments.jade +++ b/client/components/cards/attachments.jade @@ -3,6 +3,16 @@ template(name="cardAttachmentsPopup") li input.js-attach-file.hide(type="file" name="file" multiple) a.js-computer-upload {{_ 'computer'}} + li + a.js-upload-clipboard-image {{_ 'clipboard'}} + +template(name="previewClipboardImagePopup") + p {{_ "paste-or-dragdrop"}} + img.preview-clipboard-image() + button.primary.js-upload-pasted-image {{_ 'upload'}} + +template(name="previewAttachedImagePopup") + img.preview-large-image.js-large-image-clicked(src="{{pathFor url}}") template(name="attachmentDeletePopup") p {{_ "attachment-delete-pop"}} @@ -15,7 +25,7 @@ template(name="attachmentsGalery") .attachment-thumbnail if isUploaded if isImage - img.attachment-thumbnail-img(src="{{pathFor url}}") + img.attachment-thumbnail-img.js-preview-image(src="{{pathFor url}}") else span.attachment-thumbnail-ext= extension else diff --git a/client/components/cards/attachments.js b/client/components/cards/attachments.js index ea621a74..1e5aa03b 100644 --- a/client/components/cards/attachments.js +++ b/client/components/cards/attachments.js @@ -20,6 +20,39 @@ Template.attachmentsGalery.events({ 'click .js-remove-cover'() { Cards.findOne(this.cardId).unsetCover(); }, + 'click .js-preview-image'(evt) { + Popup.open('previewAttachedImage').call(this, evt); + // when multiple thumbnails, if click one then another very fast, + // we might get a wrong width from previous img. + // when popup reused, onRendered() won't be called, so we cannot get there. + // here make sure to get correct size when this img fully loaded. + const img = $('img.preview-large-image')[0]; + if (!img) return; + const rePosPopup = () => { + const w = img.width; + const h = img.height; + // if the image is too large, we resize & center the popup. + if (w > 300) { + $('div.pop-over').css({ + width: (w + 20), + position: 'absolute', + left: (window.innerWidth - w)/2, + top: (window.innerHeight - h)/2, + }); + } + }; + const url = $(evt.currentTarget).attr('src'); + if (img.src === url && img.complete) + rePosPopup(); + else + img.onload = rePosPopup; + }, +}); + +Template.previewAttachedImagePopup.events({ + 'click .js-large-image-clicked'(){ + Popup.close(); + }, }); Template.cardAttachmentsPopup.events({ @@ -28,7 +61,7 @@ Template.cardAttachmentsPopup.events({ FS.Utility.eachFile(evt, (f) => { const file = new FS.File(f); file.boardId = card.boardId; - file.cardId = card._id; + file.cardId = card._id; Attachments.insert(file); Popup.close(); @@ -38,4 +71,48 @@ Template.cardAttachmentsPopup.events({ tpl.find('.js-attach-file').click(); evt.preventDefault(); }, + 'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'), +}); + +let pastedResults = null; + +Template.previewClipboardImagePopup.onRendered(() => { + // we can paste image from clipboard + $(document.body).pasteImageReader((results) => { + if (results.dataURL.startsWith('data:image/')) { + $('img.preview-clipboard-image').attr('src', results.dataURL); + pastedResults = results; + } + }); + + // we can also drag & drop image file to it + $(document.body).dropImageReader((results) => { + if (results.dataURL.startsWith('data:image/')) { + $('img.preview-clipboard-image').attr('src', results.dataURL); + pastedResults = results; + } + }); +}); + +Template.previewClipboardImagePopup.events({ + 'click .js-upload-pasted-image'() { + const results = pastedResults; + if (results && results.file) { + const card = this; + const file = new FS.File(results.file); + if (!results.name) { + // if no filename, it's from clipboard. then we give it a name, with ext name from MIME type + if (typeof results.file.type === 'string') { + file.name(results.file.type.replace('image/', 'clipboard.')); + } + } + file.updatedAt(new Date()); + file.boardId = card.boardId; + file.cardId = card._id; + Attachments.insert(file); + pastedResults = null; + $(document.body).pasteImageReader(() => {}); + Popup.close(); + } + }, }); diff --git a/client/components/cards/attachments.styl b/client/components/cards/attachments.styl index 5cdf7386..a582f3af 100644 --- a/client/components/cards/attachments.styl +++ b/client/components/cards/attachments.styl @@ -45,3 +45,14 @@ display: block box-shadow: 0 1px 2px rgba(0,0,0,.2) +.preview-large-image + max-width: 1000px + display: block + box-shadow: 0 1px 2px rgba(0,0,0,.2) + +.preview-clipboard-image + width: 280px + height: 200px + display: block + border: 1px solid black + box-shadow: 0 1px 2px rgba(0,0,0,.2) diff --git a/client/lib/dropImage.js b/client/lib/dropImage.js new file mode 100644 index 00000000..592d5c8f --- /dev/null +++ b/client/lib/dropImage.js @@ -0,0 +1,62 @@ +/* eslint-disable */ + +// ------------------------------------------------------------------------ +// Created by STRd6 +// MIT License +// https://github.com/distri/jquery-image_reader/blob/master/drop.coffee.md +// +// Raymond re-write it to javascript + +(function($) { + $.event.fix = (function(originalFix) { + return function(event) { + event = originalFix.apply(this, arguments); + if (event.type.indexOf('drag') === 0 || event.type.indexOf('drop') === 0) { + event.dataTransfer = event.originalEvent.dataTransfer; + } + return event; + }; + })($.event.fix); + + const defaults = { + callback: $.noop, + matchType: /image.*/, + }; + + return $.fn.dropImageReader = function(options) { + if (typeof options === 'function') { + options = { + callback: options, + }; + } + options = $.extend({}, defaults, options); + const stopFn = function(event) { + event.stopPropagation(); + return event.preventDefault(); + }; + return this.each(function() { + const element = this; + $(element).bind('dragenter dragover dragleave', stopFn); + return $(element).bind('drop', function(event) { + stopFn(event); + const files = event.dataTransfer.files; + for(let i=0; ilogging in.", "page-not-found": "Page not found.", "password": "Password", + "paste-or-dragdrop": "Ctrl-V to paste, or drag & drop image file to it (image only)", + "preview": "Preview", + "previewClipboardImagePopup-title": "Preview", + "previewAttachedImagePopup-title": "Preview", "private": "Private", "private-desc": "This board is private. Only people added to the board can view and edit it.", "profile": "Profile", @@ -222,6 +227,7 @@ "title": "Title", "unassign-member": "Unassign member", "unsaved-description": "You have an unsaved description.", + "upload": "Upload", "upload-avatar": "Upload an avatar", "uploaded-avatar": "Uploaded an avatar", "username": "Username", -- cgit v1.2.3-1-g7c22 From 5763714d22c4533f173d1d34a1210acf548c4d58 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Sun, 15 Nov 2015 15:39:11 -0800 Subject: Enphasize keyboard shortcuts with a dedicated style Also add release notes related to the #387 merge. -- Fluctuat nec mergitur --- History.md | 9 +++++---- client/components/cards/attachments.jade | 2 +- client/components/main/keyboardShortcuts.styl | 5 ----- client/components/main/layouts.styl | 9 +++++++++ i18n/en.i18n.json | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/History.md b/History.md index 505be881..6b622699 100644 --- a/History.md +++ b/History.md @@ -4,12 +4,13 @@ This release features: * Card import from Trello * Autocompletion in the minicard editor. Start with @ to start the - a board member autocompletion, or # for a label. + a board member autocompletion, or # for a label; * Accelerate the initial page rendering by sending the data on the intial HTTP - response instead of waiting for the DDP connection to open. + response instead of waiting for the DDP connection to open; +* Support images attachments copy pasting. -Thanks to GitHub users AlexanderS, fisle, FuzzyWuzzie, ndarilek, and -xavierpriour for their contributions. +Thanks to GitHub users AlexanderS, fisle, floatinghotpot, FuzzyWuzzie, ndarilek, +and xavierpriour for their contributions. # v0.9 diff --git a/client/components/cards/attachments.jade b/client/components/cards/attachments.jade index 79511ac9..2cb3bb85 100644 --- a/client/components/cards/attachments.jade +++ b/client/components/cards/attachments.jade @@ -7,7 +7,7 @@ template(name="cardAttachmentsPopup") a.js-upload-clipboard-image {{_ 'clipboard'}} template(name="previewClipboardImagePopup") - p {{_ "paste-or-dragdrop"}} + p Ctrl+V {{_ "paste-or-dragdrop"}} img.preview-clipboard-image() button.primary.js-upload-pasted-image {{_ 'upload'}} diff --git a/client/components/main/keyboardShortcuts.styl b/client/components/main/keyboardShortcuts.styl index 42e0637b..f77d387f 100644 --- a/client/components/main/keyboardShortcuts.styl +++ b/client/components/main/keyboardShortcuts.styl @@ -14,11 +14,6 @@ padding: 5px 8px margin: 5px font-size: 18px - font-weight: bold - background: white - border-radius: 3px - border: 1px solid darken(white, 10%) - box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15) .shortcuts-list-item-action font-size: 1.4em diff --git a/client/components/main/layouts.styl b/client/components/main/layouts.styl index 1dbefc20..fcc94251 100644 --- a/client/components/main/layouts.styl +++ b/client/components/main/layouts.styl @@ -172,6 +172,15 @@ dl, dt dd margin: 0 0 16px 24px +kbd + padding: 1px 3px + margin: 3px + font-weight: bold + background: darken(white, 2%) + border-radius: 3px + border: 1px solid darken(white, 10%) + box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.15) + .clear clear: both diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index a6439fa5..66bd0155 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -184,7 +184,7 @@ "page-maybe-private": "This page may be private. You may be able to view it by logging in.", "page-not-found": "Page not found.", "password": "Password", - "paste-or-dragdrop": "Ctrl-V to paste, or drag & drop image file to it (image only)", + "paste-or-dragdrop": "to paste, or drag & drop image file to it (image only)", "preview": "Preview", "previewClipboardImagePopup-title": "Preview", "previewAttachedImagePopup-title": "Preview", -- cgit v1.2.3-1-g7c22 From 41aa2f63b59afbdd65c01e708472b3c71d909c40 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 21 Nov 2015 11:29:37 -0500 Subject: Add MAIL_FROM environment variable Otherwise the mail comes from no-reply@meteor.com, which will fail a lot of spam tests. Closes #407 --- History.md | 2 +- config/accounts.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 3e4ae42c..fce84bf4 100644 --- a/History.md +++ b/History.md @@ -11,7 +11,7 @@ This release features: * Support images attachments copy pasting. Thanks to GitHub users AlexanderS, fisle, floatinghotpot, FuzzyWuzzie, ndarilek, -and xavierpriour for their contributions. +SirCmpwn, and xavierpriour for their contributions. # v0.9 diff --git a/config/accounts.js b/config/accounts.js index d475e6b2..b1a4a177 100644 --- a/config/accounts.js +++ b/config/accounts.js @@ -46,3 +46,9 @@ AccountsTemplates.configureRoute('changePwd', { Popup.back(); }, }); + +if (Meteor.isServer) { + if (process.env.MAIL_FROM) { + Accounts.emailTemplates.from = process.env.MAIL_FROM; + } +} -- cgit v1.2.3-1-g7c22 From 643eb8a7e17df4e0088a44c631cf295f6f08f1db Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Wed, 25 Nov 2015 21:55:22 -0800 Subject: Fix #409 Credits goes to @floatinghotpot, thanks! --- .meteor/versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.meteor/versions b/.meteor/versions index a16f56bd..29f77214 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -95,7 +95,7 @@ mquandalle:jade@0.4.5 mquandalle:jade-compiler@0.4.5 mquandalle:jquery-textcomplete@0.8.0_1 mquandalle:jquery-ui-drag-drop-sort@0.1.0 -mquandalle:moment@1.0.0 +mquandalle:moment@1.0.1 mquandalle:mousetrap-bindglobal@0.0.1 mquandalle:perfect-scrollbar@0.6.5_2 mquandalle:stylus@1.1.1 -- cgit v1.2.3-1-g7c22 From 1a4ff826804665f27fc49c015c1a40ee49902f21 Mon Sep 17 00:00:00 2001 From: floatinghotpot Date: Fri, 27 Nov 2015 11:55:29 +0800 Subject: bugfix: template. does not accept dom elements, but jquery can --- client/components/boards/boardBody.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js index 5a74e61b..a601bc2e 100644 --- a/client/components/boards/boardBody.js +++ b/client/components/boards/boardBody.js @@ -134,7 +134,7 @@ Template.boardBody.onRendered(function() { if (!Meteor.user() || !Meteor.user().isBoardMember()) return; - self.$(self.listsDom).sortable({ + $(self.listsDom).sortable({ tolerance: 'pointer', helper: 'clone', handle: '.js-list-header', @@ -146,7 +146,7 @@ Template.boardBody.onRendered(function() { Popup.close(); }, stop() { - self.$('.js-lists').find('.js-list:not(.js-list-composer)').each( + $(self.listsDom).find('.js-list:not(.js-list-composer)').each( (i, list) => { const data = Blaze.getData(list); Lists.update(data._id, { @@ -161,7 +161,7 @@ Template.boardBody.onRendered(function() { // Disable drag-dropping while in multi-selection mode self.autorun(() => { - self.$(self.listsDom).sortable('option', 'disabled', + $(self.listsDom).sortable('option', 'disabled', MultiSelection.isActive()); }); -- cgit v1.2.3-1-g7c22 From 827663f2550ba691067535b317dd9f0b0bec12ba Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Wed, 25 Nov 2015 21:53:58 -0800 Subject: Sync Sandstorm URL and page title with the inner Wekan grain The page title synchronization required implementing reactivity in the kadira:dochead package, see https://github.com/kadirahq/meteor-dochead/pull/25 Closes #403. --- .meteor/versions | 2 +- History.md | 4 ++-- sandstorm.js | 20 ++++++++++++++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.meteor/versions b/.meteor/versions index 29f77214..fb3f61f3 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -63,7 +63,7 @@ id-map@1.0.4 idmontie:migrations@1.0.1 jquery@1.11.4 kadira:blaze-layout@2.2.0 -kadira:dochead@1.3.2 +kadira:dochead@1.4.0 kadira:flow-router@2.9.0 kenton:accounts-sandstorm@0.1.8 launch-screen@1.0.4 diff --git a/History.md b/History.md index fce84bf4..4391df3b 100644 --- a/History.md +++ b/History.md @@ -10,8 +10,8 @@ This release features: response instead of waiting for the DDP connection to open; * Support images attachments copy pasting. -Thanks to GitHub users AlexanderS, fisle, floatinghotpot, FuzzyWuzzie, ndarilek, -SirCmpwn, and xavierpriour for their contributions. +Thanks to GitHub users AlexanderS, fisle, floatinghotpot, FuzzyWuzzie, mnutt, +ndarilek, SirCmpwn, and xavierpriour for their contributions. # v0.9 diff --git a/sandstorm.js b/sandstorm.js index 997aed46..a711a960 100644 --- a/sandstorm.js +++ b/sandstorm.js @@ -54,10 +54,10 @@ if (isSandstorm && Meteor.isServer) { // XXX If this routing scheme changes, this will break. We should generate // the location URL using the router, but at the time of writing, the // it is only accessible on the client. - const path = `/boards/${sandstormBoard._id}/${sandstormBoard.slug}`; + const boardPath = `/b/${sandstormBoard._id}/${sandstormBoard.slug}`; res.writeHead(301, { - Location: base + path, + Location: base + boardPath, }); res.end(); @@ -126,6 +126,22 @@ if (isSandstorm && Meteor.isServer) { } if (isSandstorm && Meteor.isClient) { + // Since the Sandstorm grain is displayed in an iframe of the Sandstorm shell, + // we need to explicitly expose meta data like the page title or the URL path + // so that they could appear in the browser window. + // See https://docs.sandstorm.io/en/latest/developing/path/ + function updateSandstormMetaData(msg) { + return window.parent.postMessage(msg, '*'); + } + + FlowRouter.triggers.enter([({ path }) => { + updateSandstormMetaData({ setPath: path }); + }]); + + Tracker.autorun(() => { + updateSandstormMetaData({ setTitle: DocHead.getTitle() }); + }); + // XXX Hack. `Meteor.absoluteUrl` doesn't work in Sandstorm, since every // session has a different URL whereas Meteor computes absoluteUrl based on // the ROOT_URL environment variable. So we overwrite this function on a -- cgit v1.2.3-1-g7c22