From 41f1479cbc5e88db4b956fd493dd4b342b4a492a Mon Sep 17 00:00:00 2001 From: Matteo Pompili Date: Wed, 16 Dec 2015 15:25:27 +0100 Subject: [PATCH] Enabled client-side image resize --- bootstrap.php | 2 + composer.json | 2 +- js/admin/dist/extension.js | 25 ++- .../components/ImgurUploadSettingsModal.js | 16 +- js/forum/dist/extension.js | 151 +++++++++++------- js/forum/src/main.js | 151 +++++++++++------- locale/en.yml | 3 + locale/it.yml | 5 +- 8 files changed, 230 insertions(+), 125 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 63ab8d3..2eb0d14 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -56,6 +56,8 @@ public function subscribe(Dispatcher $events) { public function prepareApiAttributes(PrepareApiAttributes $event) { if ($event->isSerializer(ForumSerializer::class)) { $event->attributes['imgurClientID'] = $this->settings->get('matpompili.imgur-upload.clientID'); + $event->attributes['maxImageWidth'] = $this->settings->get('matpompili.imgur-upload.maxImageWidth'); + $event->attributes['maxImageHeight'] = $this->settings->get('matpompili.imgur-upload.maxImageHeight'); } } } diff --git a/composer.json b/composer.json index 70a0da3..2f75be3 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "matpompili/imgur-upload", "description": "Enable the upload of images to imgur directly from the composer", - "version": "v1.0.0-beta.4", + "version": "v1.0.0-beta.5", "type": "flarum-extension", "license": "MIT", "authors": [ diff --git a/js/admin/dist/extension.js b/js/admin/dist/extension.js index 76c8325..af1aa8a 100644 --- a/js/admin/dist/extension.js +++ b/js/admin/dist/extension.js @@ -48,10 +48,33 @@ System.register('matpompili/imgur-upload/components/ImgurUploadSettingsModal', [ m( 'a', { href: 'https://api.imgur.com/oauth2/addclient' }, - app.translator.trans('matpompili-imgur-upload.admin.get-id') + m( + 'small', + null, + app.translator.trans('matpompili-imgur-upload.admin.get-id') + ) ) ), m('input', { className: 'FormControl', bidi: this.setting('matpompili.imgur-upload.clientID') }) + ), m( + 'p', + null, + app.translator.trans('matpompili-imgur-upload.admin.leaveEmpty') + ), m( + 'div', + { className: 'Form-group' }, + m( + 'label', + null, + app.translator.trans('matpompili-imgur-upload.admin.maxImageWidth') + ), + m('input', { className: 'FormControl', bidi: this.setting('matpompili.imgur-upload.maxImageWidth') }), + m( + 'label', + null, + app.translator.trans('matpompili-imgur-upload.admin.maxImageHeight') + ), + m('input', { className: 'FormControl', bidi: this.setting('matpompili.imgur-upload.maxImageHeight') }) )]; } }]); diff --git a/js/admin/src/components/ImgurUploadSettingsModal.js b/js/admin/src/components/ImgurUploadSettingsModal.js index 574fe55..7a7a5a3 100644 --- a/js/admin/src/components/ImgurUploadSettingsModal.js +++ b/js/admin/src/components/ImgurUploadSettingsModal.js @@ -19,10 +19,18 @@ export default class ImageUploadSettingsModal extends SettingsModal { form() { return [ -
- - -
+
+ + +
, +

{app.translator.trans('matpompili-imgur-upload.admin.leaveEmpty')}

, +
+ + + + +
]; } } diff --git a/js/forum/dist/extension.js b/js/forum/dist/extension.js index c8b877c..d4ec7ba 100644 --- a/js/forum/dist/extension.js +++ b/js/forum/dist/extension.js @@ -10,6 +10,10 @@ System.register('matpompili/imgur-upload/main', ['flarum/extend', 'flarum/compon 'use strict'; var extend, TextEditor, Button; + + function isNumber(x) { + return !isNaN && x == ''; + } return { setters: [function (_flarumExtend) { extend = _flarumExtend.extend; @@ -62,66 +66,95 @@ System.register('matpompili/imgur-upload/main', ['flarum/extend', 'flarum/compon $("#composer").on("change", "#imgur-upload-input", function () { var reader = new FileReader(); reader.onload = function (e) { - //This formats the file for base64 upload - var data = e.target.result.substr(e.target.result.indexOf(",") + 1, e.target.result.length); - //Get the elements with jQuery to act on them later - var icon = $(".imgur-upload-button > i"); - var buttonText = $(".imgur-upload-button > span.Button-label"); - var submitButton = $(".item-submit > button"); - //Show a loading icon and a loading text - icon.removeClass('fa-paperclip').addClass('fa-spin fa-circle-o-notch'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loading')[0]); - //Disable the submit button until the upload is completed - submitButton.attr("disabled", true); - //Actually upload the image - $.ajax({ - url: 'https://api.imgur.com/3/image', - headers: { - 'Authorization': 'Client-ID ' + app.forum.attribute('imgurClientID') - }, - type: 'POST', - data: { - 'image': data, - 'type': 'base64' - }, - success: function success(response) { - //Remove the loading icon and text, and show the success - icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-check green'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loaded')[0]); - //Get the link to the uploaded image and put https instead of http - var linkString = '\n![alt text](' + response.data.link.replace('http:', 'https:') + ')\n'; - //Place the Markdown image link in the Composer - textAreaObj.insertAtCursor(linkString); - $("#imgur-upload-input").val(""); - //If we are not starting a new discussion, the variable is defined - if (typeof textAreaObj.props.preview !== 'undefined') { - // Show what we just uploaded - textAreaObj.props.preview(); - } - //After 1sec - setTimeout(function () { - //Enable the submit button - submitButton.attr("disabled", false); - //Restore the Attach button and text for a new upload - icon.removeClass('fa-check green').addClass('fa-paperclip'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); - }, 1000); - }, error: function error(response) { - //Remove the loading icon and text, and show the error - icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-times red'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.error')[0]); - //Output the error to the console, for debug purposes - console.log(response); - //After 1sec - setTimeout(function () { - //Enable the submit button - submitButton.attr("disabled", false); - //Restore the Attach button and text for a new upload - icon.removeClass('fa-times red').addClass('fa-paperclip'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); - }, 1000); + + // create an off-screen canvas and an Image object + var canvas = document.createElement('canvas'), + ctx = canvas.getContext('2d'), + img = new Image(); + + var maxWidth = app.forum.attribute('maxImageWidth'), + maxHeight = app.forum.attribute('maxImageHeight'); + + img.onload = function () { + // evaluate the scaling factor + var scale = 1; + if (isNumber(maxWidth) && isNumber(maxHeight)) { + scale = Math.min(maxWidth / img.width, maxHeight / img.height); + scale = Math.max(scale, 1); } - }); + // set canvas' dimension to target size + canvas.width = img.width * scale; + canvas.height = img.height * scale; + + // draw source image into the off-screen canvas: + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + // encode image to data-uri with base64 version of compressed image + var resizedImage = canvas.toDataURL(); + + //This formats the file for base64 upload + var data = resizedImage.substr(resizedImage.indexOf(",") + 1, resizedImage.length); + //Get the elements with jQuery to act on them later + var icon = $(".imgur-upload-button > i"); + var buttonText = $(".imgur-upload-button > span.Button-label"); + var submitButton = $(".item-submit > button"); + //Show a loading icon and a loading text + icon.removeClass('fa-paperclip').addClass('fa-spin fa-circle-o-notch'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loading')[0]); + //Disable the submit button until the upload is completed + submitButton.attr("disabled", true); + //Actually upload the image + $.ajax({ + url: 'https://api.imgur.com/3/image', + headers: { + 'Authorization': 'Client-ID ' + app.forum.attribute('imgurClientID') + }, + type: 'POST', + data: { + 'image': data, + 'type': 'base64' + }, + success: function success(response) { + //Remove the loading icon and text, and show the success + icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-check green'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loaded')[0]); + //Get the link to the uploaded image and put https instead of http + var linkString = '\n![alt text](' + response.data.link.replace('http:', 'https:') + ')\n'; + //Place the Markdown image link in the Composer + textAreaObj.insertAtCursor(linkString); + $("#imgur-upload-input").val(""); + //If we are not starting a new discussion, the variable is defined + if (typeof textAreaObj.props.preview !== 'undefined') { + // Show what we just uploaded + textAreaObj.props.preview(); + } + //After 1sec + setTimeout(function () { + //Enable the submit button + submitButton.attr("disabled", false); + //Restore the Attach button and text for a new upload + icon.removeClass('fa-check green').addClass('fa-paperclip'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); + }, 1000); + }, error: function error(response) { + //Remove the loading icon and text, and show the error + icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-times red'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.error')[0]); + //Output the error to the console, for debug purposes + console.log(response); + //After 1sec + setTimeout(function () { + //Enable the submit button + submitButton.attr("disabled", false); + //Restore the Attach button and text for a new upload + icon.removeClass('fa-times red').addClass('fa-paperclip'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); + }, 1000); + } + }); + }; + //Load the file in the image Object + img.src = e.target.result; }; //Actually run everything on the file that's been selected reader.readAsDataURL($("#imgur-upload-input")[0].files[0]); diff --git a/js/forum/src/main.js b/js/forum/src/main.js index 524e25d..42e8487 100644 --- a/js/forum/src/main.js +++ b/js/forum/src/main.js @@ -49,69 +49,102 @@ app.initializers.add('matpompili-imgur-upload', function() { $("#composer").on("change", "#imgur-upload-input", function() { var reader = new FileReader(); reader.onload = function(e) { - //This formats the file for base64 upload - var data = e.target.result.substr(e.target.result.indexOf(",") + 1, e.target.result.length); - //Get the elements with jQuery to act on them later - var icon = $(".imgur-upload-button > i"); - var buttonText = $(".imgur-upload-button > span.Button-label"); - var submitButton = $(".item-submit > button"); - //Show a loading icon and a loading text - icon.removeClass('fa-paperclip').addClass('fa-spin fa-circle-o-notch'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loading')[0]); - //Disable the submit button until the upload is completed - submitButton.attr("disabled", true); - //Actually upload the image - $.ajax({ - url: 'https://api.imgur.com/3/image', - headers: { - 'Authorization': 'Client-ID '+ app.forum.attribute('imgurClientID') - }, - type: 'POST', - data: { - 'image': data, - 'type': 'base64' - }, - success: function(response) { - //Remove the loading icon and text, and show the success - icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-check green'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loaded')[0]); - //Get the link to the uploaded image and put https instead of http - var linkString = '\n![alt text]('+response.data.link.replace('http:', 'https:')+')\n'; - //Place the Markdown image link in the Composer - textAreaObj.insertAtCursor(linkString); - $("#imgur-upload-input").val(""); - //If we are not starting a new discussion, the variable is defined - if (typeof textAreaObj.props.preview !== 'undefined') { - // Show what we just uploaded - textAreaObj.props.preview(); - } - //After 1sec - setTimeout(function(){ - //Enable the submit button - submitButton.attr("disabled", false); - //Restore the Attach button and text for a new upload - icon.removeClass('fa-check green').addClass('fa-paperclip'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); - },1000); - }, error: function(response) { - //Remove the loading icon and text, and show the error - icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-times red'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.error')[0]); - //Output the error to the console, for debug purposes - console.log(response); - //After 1sec - setTimeout(function(){ - //Enable the submit button - submitButton.attr("disabled", false); - //Restore the Attach button and text for a new upload - icon.removeClass('fa-times red').addClass('fa-paperclip'); - buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); - },1000); + + // create an off-screen canvas and an Image object + var canvas = document.createElement('canvas'), + ctx = canvas.getContext('2d'), + img = new Image; + + var maxWidth = app.forum.attribute('maxImageWidth'), + maxHeight = app.forum.attribute('maxImageHeight'); + + img.onload = function () { + // evaluate the scaling factor + var scale = 1; + if(isNumber(maxWidth) && isNumber(maxHeight)){ + scale=Math.min((maxWidth/img.width),(maxHeight/img.height)); + scale=Math.max(scale,1); } - }); + // set canvas' dimension to target size + canvas.width = img.width*scale; + canvas.height = img.height*scale; + + // draw source image into the off-screen canvas: + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + // encode image to data-uri with base64 version of compressed image + var resizedImage = canvas.toDataURL(); + + //This formats the file for base64 upload + var data = resizedImage.substr(resizedImage.indexOf(",") + 1, resizedImage.length); + //Get the elements with jQuery to act on them later + var icon = $(".imgur-upload-button > i"); + var buttonText = $(".imgur-upload-button > span.Button-label"); + var submitButton = $(".item-submit > button"); + //Show a loading icon and a loading text + icon.removeClass('fa-paperclip').addClass('fa-spin fa-circle-o-notch'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loading')[0]); + //Disable the submit button until the upload is completed + submitButton.attr("disabled", true); + //Actually upload the image + $.ajax({ + url: 'https://api.imgur.com/3/image', + headers: { + 'Authorization': 'Client-ID '+ app.forum.attribute('imgurClientID') + }, + type: 'POST', + data: { + 'image': data, + 'type': 'base64' + }, + success: function(response) { + //Remove the loading icon and text, and show the success + icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-check green'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.loaded')[0]); + //Get the link to the uploaded image and put https instead of http + var linkString = '\n![alt text]('+response.data.link.replace('http:', 'https:')+')\n'; + //Place the Markdown image link in the Composer + textAreaObj.insertAtCursor(linkString); + $("#imgur-upload-input").val(""); + //If we are not starting a new discussion, the variable is defined + if (typeof textAreaObj.props.preview !== 'undefined') { + // Show what we just uploaded + textAreaObj.props.preview(); + } + //After 1sec + setTimeout(function(){ + //Enable the submit button + submitButton.attr("disabled", false); + //Restore the Attach button and text for a new upload + icon.removeClass('fa-check green').addClass('fa-paperclip'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); + },1000); + }, error: function(response) { + //Remove the loading icon and text, and show the error + icon.removeClass('fa-spin fa-circle-o-notch').addClass('fa-times red'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.error')[0]); + //Output the error to the console, for debug purposes + console.log(response); + //After 1sec + setTimeout(function(){ + //Enable the submit button + submitButton.attr("disabled", false); + //Restore the Attach button and text for a new upload + icon.removeClass('fa-times red').addClass('fa-paperclip'); + buttonText.text(app.translator.trans('matpompili-imgur-upload.forum.attach')[0]); + },1000); + } + }); + }; + //Load the file in the image Object + img.src = e.target.result; }; //Actually run everything on the file that's been selected reader.readAsDataURL($("#imgur-upload-input")[0].files[0]); }); }); }); + +function isNumber(x) { + return (!isNaN && (x == '')); +} diff --git a/locale/en.yml b/locale/en.yml index bb9a1a6..04693fa 100644 --- a/locale/en.yml +++ b/locale/en.yml @@ -2,6 +2,9 @@ matpompili-imgur-upload: admin: get-id: Get one here without: without + leaveEmpty: Leave the following fields empty to disable image resizing + maxImageWidth: Max image width + maxImageHeight: Max image height forum: attach: Attach loading: Uploading... diff --git a/locale/it.yml b/locale/it.yml index 0f6aeb6..6c3ba07 100644 --- a/locale/it.yml +++ b/locale/it.yml @@ -1,7 +1,10 @@ matpompili-imgur-upload: - admin: + admin: get-id: Creane uno qui without: senza + leaveEmpty: Lascia i seguenti campi vuoti per disattivare il ridimensionamento delle immagini + maxImageWidth: Larghezza massima delle immagini + maxImageHeight: Altezza massima delle immagini forum: attach: Allega loading: Caricando...