UNPKG

image-uploader-crop

Version:

cropper and uploader of images that uses another libraries

725 lines (603 loc) 19.9 kB
// image-uploader-crop v0.1.1 for jQuery that uses fine-uploader, jcrop // (c) 2017, MIT licensed. http://tuproyecto.com // ==================================================================== // Dependencies: jQuery, fine-uploader, jcrop // Author: TuProyecto.com // Developer: @krobing // Created: 04/03/2016 // Website: http://tuproyecto.com // Description: cropper and uploader of images that uses another libraries !(function (factory) { 'use strict' if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else if (typeof module === 'object' && module.exports) { // Node/CommonJS module.exports = factory(require('jquery')); } else { // Browser globals factory(jQuery); } }(function ($) { 'use strict'; var slice = Array.prototype.slice; // save ref to original slice() var splice = Array.prototype.splice; // save ref to original slice() // default options var defaults = { formCrop: null, btnToCrop: null, imgCrop: null, previewImg: null, uploaderImg: null, templateImgUploader: '', configImg: { maxWidthImg : 0, // 646 * 2 maxHeightImg : 0, // 374 * 2 minWidthImg : 0, minHeightImg : 0, allowedExtensions: ['jpeg', 'jpg', 'png'], sizeLimit: 0, // 50 kB = 50 * 1024 bytes, sendOriginal: true, // send images original in true defaultQuality: 100 // quality of the image, range( 1 - 100 ) }, uploadding: { inputName: 'file', endpoint: '', params: {} }, cropping: { endpoint: '', params: {} }, extraDropzones: [$('#wrapper-image-crop')], // Events handlers callbacks: { onCropping: function (jcrop_img) {}, onCropComplete: function (jcrop_img, resp, jqXHR) {}, onCropError: function (jcrop_img, jqXHR, error) {}, onLoadImg: function ($uploaderImg, id, name) {}, onCompleteLoad: function ($uploaderImg, id, name, res) {} }, messages: {}, showMessage: function (message) { return alertify.alert(message); }, showConfirm: function (message) { var promise = new qq.Promise(); alertify.confirm(message, function(result) { if (result) { return promise.success(result); } else { return promise.failure(); } }); return promise; }, showPrompt: function (message, defaultValue) { var promise = new qq.Promise(); alertify.prompt(message, function(result, inStr) { if (result) { return promise.success(inStr); } else { return promise.failure(inStr); } }, defaultValue); return promise; } }; // ============== // helpers method // ============== /** * Serialize form into json format * @param { string } name class or id of the html element to embed the loader * @return { object } form into json */ function formToJson ( selector ){ var o = {}, a = []; if( $.prototype.isPrototypeOf(selector) ){ a = selector.serializeArray(); } else{ a = $(selector).serializeArray(); } $.each( a, function() { if ( o[ this.name ] !== undefined ) { if ( ! o[this.name].push ) { o[ this.name ] = [ o[ this.name ] ]; } o[ this.name ].push( this.value || '' ); } else { o[ this.name ] = this.value || ''; } }); return o; } /** * Set select on image crop * @param Number imgWidth * @param Number imgHeight */ function setSquare (imgWidth, imgHeight) { var minDim = Math.min(imgWidth, imgHeight); if( imgWidth == imgHeight ){ return [imgWidth, imgHeight]; } return [minDim, minDim]; } // check out if exits jQuery plugin fineuploader function existUploaderPlugin () { if( ({}).hasOwnProperty.call($.fn, 'fineUploader') ){ return true; }else { return false; } } // check out if exits jQuery plugin jcrop function existCropPlugin () { if( ({}).hasOwnProperty.call($.fn, 'Jcrop') ){ return true; }else { return false; } } /** * privates methods */ var methods = { /** * reassign events and another things */ reassignActions: function() { this.settings.uploaderImg.off('complete'); this.settings.uploaderImg.on('complete', methods.onCompleteLoadImg.bind(this)); // if was defined a button to execute action to crop if(this.settings.btnToCrop) { this.settings.btnToCrop.unbind().off('click', methods.submitCropImage.bind(this)); this.settings.btnToCrop.on('click', methods.submitCropImage.bind(this)); } else { this.settings.formCrop.off('submit', methods.submitCropImage.bind(this)); this.settings.formCrop.on('submit', methods.submitCropImage.bind(this)); } }, /** * destroy plugin */ destroy: function () { // destroy jcrop if( this.settings.imgCrop.data('Jcrop') !== undefined ){ this.jcrop_img.destroy(); } // undelegate events // this.settings.uploaderImg.off('upload'); this.settings.uploaderImg.off('complete'); this.settings.formCrop.off('submit'); // remove object plugin in data this.$element.removeData('imageUploaderCrop'); }, /** * set image * @param {String} urlImage * @param {Function} callback */ setImage: function (urlImage, callback) { urlImage || (urlImage = this.settings.imgCrop.attr('src')) || (urlImage = ''); try { if( !this.settings.imgCrop ) { throw "The imgCrop element have not went assign"; } }catch(err) { console.error('Error: '+ err + "."); } var _this = this; // validate if already or not was created the crop image if( this.settings.imgCrop.data('Jcrop') !== undefined ){ this.jcrop_img = this.settings.imgCrop.data('Jcrop'); // set image crop this.jcrop_img.setImage(urlImage, function () { var dimImg = []; // image crop settings if( this.settings.configImg.minWidthImg && this.settings.configImg.minHeightImg ) { dimImg = [this.settings.configImg.minWidthImg, this.settings.configImg.minHeightImg]; }else { dimImg = this.jcrop_img.getBounds(); } methods.changeOptsCrop.call(_this, { imgSet: urlImage, minWidth: _this.settings.configImg.minWidthImg, minHeight: _this.settings.configImg.minHeightImg, imgWidth: dimImg[0], imgHeight: dimImg[1] }); // add values to the crop form _this.settings.formCrop.find('input#crop_type').val( 'url' ); _this.settings.formCrop.find('input#file_name').val( urlImage ); _this.settings.formCrop.find('input#file_type').val( urlImage.split('.').slice(-1) ); }); }else { this.settings.imgCrop.attr('src', urlImage); // create crop whether does not exist methods.renderImageCrop.call(this, this.settings.imgCrop, function () { var dimImg = []; // settings image crop if( this.settings.configImg.minWidthImg && this.settings.configImg.minHeightImg ) { dimImg = [this.settings.configImg.minWidthImg, this.settings.configImg.minHeightImg]; }else { dimImg = this.jcrop_img.getBounds(); } methods.changeOptsCrop.call(this, { imgSet: urlImage, minWidth: this.settings.configImg.minWidthImg, minHeight: this.settings.configImg.minHeightImg, imgWidth: dimImg[0], imgHeight: dimImg[1] }); // Add values to the crop form this.settings.formCrop.find('input#crop_type').val( 'url' ); this.settings.formCrop.find('input#file_name').val( urlImage ); this.settings.formCrop.find('input#file_type').val( urlImage.split('.').slice(-1) ); }.bind(this)); } // call callback if( $.isFunction(callback) ) callback.call(); }, /** * Render FineUploader plugin for user product image * @param {Element jQuery} $uploaderImg */ renderUploaderImg: function ($uploaderImg) { if( !existUploaderPlugin() ) { console.error('Error: The imageUploaderCrop jQuery library do need of the fine-uploader jQuery library.'); return false; } var _this = this; $uploaderImg.fineUploader({ debug: false, template: this.settings.templateImgUploader, request: this.settings.uploadding, thumbnails: { placeholders: { waitingPath: 'img/waiting-generic.png', notAvailablePath: 'img/not_available-generic.png' } }, autoUpload: true, multiple: false, validation: { image: { // minWidth: this.settings.configImg.minWidthImg || defaults.configImg.minWidthImg, // minHeight: this.settings.configImg.minHeightImg || defaults.configImg.minHeightImg, maxWidth: this.settings.configImg.maxWidthImg || defaults.configImg.maxWidthImg, maxHeight: this.settings.configImg.maxHeightImg || defaults.configImg.maxHeightImg }, allowedExtensions: this.settings.configImg.allowedExtensions || defaults.configImg.allowedExtensions, sizeLimit: this.settings.configImg.sizeLimit || defaults.configImg.sizeLimit, stopOnFirstInvalidFile: false, itemLimit: 0 }, scaling: { sendOriginal: this.settings.configImg.sendOriginal || defaults.configImg.sendOriginal, defaultQuality: this.settings.configImg.defaultQuality || defaults.configImg.defaultQuality }, // Events handlers callbacks: { onUpload: methods.onLoadImg.bind(this) }, messages: $.extend({}, this.settings.messages), dragAndDrop: { extraDropzones: this.settings.extraDropzones }, showMessage: this.settings.showMessage, showConfirm: this.settings.showConfirm, showPrompt: this.settings.showPrompt }); }, /** * set image crop plugin * @param {Element jQuery} $imgCrop * @param {Function} callback */ renderImageCrop: function ($imgCrop, callback) { if( !existCropPlugin() ) { console.error('Error: The imageUploaderCrop jQuery library needs of the jcrop jQuery library.'); return false; } //images crop var _this = this; $imgCrop.Jcrop({ onSelect: methods.setCoords.bind(this), onChange: methods.setCoords.bind(this), onRelease: function () { }, // minSize: [this.settings.configImg.minWidthImg, this.settings.configImg.minHeightImg], // maxSize: [this.settings.configImg.maxWidthImg, this.settings.configImg.maxHeightImg], bgColor: 'black', bgOpacity: 0.4, setSelect: [ 0, 0, this.settings.configImg.minWidthImg, this.settings.configImg.minHeightImg ], aspectRatio: this.settings.configImg.minWidthImg / this.settings.configImg.minHeightImg, boxWidth: $imgCrop.parent().width(), boxHeight: 0, allowSelect: false, allowResize: true },function(){ _this.jcrop_img = this; var dimDefault = _this.jcrop_img.getBounds(); methods.changeOptsCrop.call(_this, { imgSet: $imgCrop.attr('src'), minWidth: _this.settings.configImg.minWidthImg, minHeight: _this.settings.configImg.minHeightImg, imgWidth: dimDefault[0], imgHeight: dimDefault[1] }); if (typeof callback == 'function'){ callback.call(); } }); }, /** * Set select on image crop * @param Number imgWidth * @param Number imgHeight */ changeOptsCrop: function (options, callback) { var settings = { imgSet: '', minWidth: 0, minHeight: 0, imgWidth: 0, imgHeight: 0, dimSelect: [0,0], ix: 0, iy: 0 }; $.extend(settings, options); // set properties settings.dimSelect = setSquare(settings.imgWidth, settings.imgHeight); settings.ix = (settings.imgWidth - settings.dimSelect[0])/2; // refresh options crop this.jcrop_img.setOptions({ trueSize: [ Math.floor(settings.imgWidth), Math.floor(settings.imgHeight) ] // outerImage: settings.imgSet }); this.settings.previewImg.attr('src', settings.imgSet); this.jcrop_img.setSelect( [settings.ix, settings.iy, settings.dimSelect[0], settings.dimSelect[1]] ); //run callback if (typeof callback == 'function') { callback.call(); } }, /** * submit event for image crop */ submitCropImage: function(e) { e.preventDefault(); var _this = this; var data = formToJson( this.settings.formCrop ); data.targ_w = this.settings.configImg.minWidthImg; data.targ_h = this.settings.configImg.minHeightImg; $.extend(data, this.settings.cropping.params); // emit callback if( $.isFunction(this.settings.callbacks['onCropping']) ) this.settings.callbacks['onCropping'].call(this, this.jcrop_img); this.settings.formCrop.find(':submit').addClass('disabled'); $.post(this.settings.cropping.endpoint, data, methods.onSuccessCrop.bind(this)) .fail(methods.onErrorCrop.bind(this)); }, // -------------- // events handler // -------------- /** * handler for set to coords of image crop * @param Object coords */ setCoords: function (coords){ var ratioLesser = this.settings.configImg.minHeightImg / this.settings.configImg.minWidthImg; var dimImg = this.jcrop_img !== null ? this.jcrop_img.getBounds() : false, rx = $(this.settings.previewImg.parent()[0]).width() / coords.w, ry = (ratioLesser * $(this.settings.previewImg.parent()[0]).width()) / coords.h; // set content height of content preview if( this.settings.previewImg.attr('src') ) { $(this.settings.previewImg.parent()[0]).height( ratioLesser * $(this.settings.previewImg.parent()[0]).width() ); } this.settings.formCrop.find('input.crop-x').val( coords.x ); this.settings.formCrop.find('input.crop-y').val( coords.y ); this.settings.formCrop.find('input.crop-w').val( coords.w ); this.settings.formCrop.find('input.crop-h').val( coords.h ); // set preview image if( dimImg ){ this.settings.previewImg.css({ width: Math.round(rx * dimImg[0]) + 'px', height: Math.round(ry * dimImg[1]) + 'px', minWidth: Math.round(rx * dimImg[0]) + 'px', minHeight: Math.round(ry * dimImg[1]) + 'px', marginLeft: '-' + Math.round(rx * coords.x) + 'px', marginTop: '-' + Math.round(ry * coords.y) + 'px' }); } }, /** * will upload image * @param Number id * @param String name */ onLoadImg: function (id, name) { var $areaDrop = this.settings.uploaderImg.fineUploader('getDropTarget', id); // when the image was loaded with a drop zone if( $areaDrop !== undefined && $areaDrop.length ){ if( $areaDrop.hasClass('image-area-drop') || $areaDrop.hasClass('wrapper-image-crop') ){ methods.reassignActions.call(this); methods.setImage.call(this); } } if( $.isFunction(this.settings.callbacks['onLoadImg']) ) { this.settings.callbacks['onLoadImg'].call(this, this.settings.uploaderImg, id, name); } }, /** * complete event for upload image * @param Number id * @param String name * @param Object res * @param Object xhr */ onCompleteLoadImg: function (event, id, name, res) { var _this = this; if( !res.success ) return; // settings image crop if( this.settings.imgCrop.data('Jcrop') !== undefined ) { this.jcrop_img.setImage(res.file_path, function () { var dimImg = [res.file_width, res.file_height]; methods.changeOptsCrop.call(this, { imgSet: res.file_path, minWidth: this.settings.configImg.minWidthImg, minHeight: this.settings.configImg.minHeightImg, imgWidth: res.file_width, imgHeight: res.file_height }, function () { // emit callback if( $.isFunction(this.settings.callbacks['onCompleteLoad']) ) this.settings.callbacks['onCompleteLoad'].call(this, this.settings.uploaderImg, id, name, res); }.bind(this)); }.bind(this)); }else { this.settings.imgCrop.attr('src', res.file_path); methods.renderImageCrop.call(this, this.settings.imgCrop, function () { methods.changeOptsCrop.call(this, { imgSet: res.file_path, minWidth: this.settings.configImg.minWidthImg, minHeight: this.settings.configImg.minHeightImg, imgWidth: res.file_width, imgHeight: res.file_height }, function () { // emit callback if( $.isFunction(this.settings.callbacks['onCompleteLoad']) ) { this.settings.callbacks['onCompleteLoad'].call(this, this.settings.uploaderImg, id, name, res); } }.bind(this)); }.bind(this)); } // Add values to the crop form this.settings.formCrop.find('input#crop_type').val( 'name' ); this.settings.formCrop.find('input#file_name').val( res.file_name ); this.settings.formCrop.find('input#file_type').val( res.file_type ); }, /** * success event for crop image * @param Object res * @param String status * @param Object jqXHR */ onSuccessCrop: function (resp, status, jqXHR) { this.settings.formCrop.find(':submit').removeClass('disabled'); // call crop complete if( $.isFunction(this.settings.callbacks['onCropComplete']) ) { this.settings.callbacks['onCropComplete'].call(this, this.jcrop_img, resp, jqXHR); } }, /** * error event for crop image * @param Object jqXHR * @param String status * @param String error */ onErrorCrop: function(jqXHR, status, error) { this.settings.formCrop.find(':submit').removeClass('disabled'); // call crop error if( $.isFunction(this.settings.callbacks['onCropError']) ) { this.settings.callbacks['onCropError'].call(this, this.jcrop_img, jqXHR, error); } } }; // plugin class // instance the plugin // ------------------- $.imageUploaderCrop = function (element, options) { options || (options = {}); // parameters var plugin = this; // set attributes this.jcrop_img = null; this.element = element; this.$element = $(element); // initialize plugin if( $.isFunction(plugin.init) ) plugin.init(element, options); }; // extends prototype of plugin $.imageUploaderCrop.prototype = { // plugin's settings settings : {}, /** * Constructor method */ init : function(element, options) { this.settings = $.extend({}, defaults, options); // check out if already was assigned the jcrop library if( this.settings.imgCrop && this.settings.imgCrop.data('Jcrop') !== undefined ) { this.jcrop_img = this.settings.imgCrop.data('Jcrop'); this.jcrop_img.destroy(); } // Init image uploader and actions methods.reassignActions.call(this); methods.renderUploaderImg.call(this, this.settings.uploaderImg); methods.renderImageCrop.call(this, this.settings.imgCrop); }, /** * ----------- * Api methods * ----------- */ /** * change Image * @param String urlImage * @param Function callback */ changeImage : function(urlImage, callback) { methods.reassignActions.call(this); methods.setImage.call(this, urlImage, callback); }, /** * get image crop element */ getImgCrop : function () { return this.settings.imgCrop; }, /** * get form crop element */ getFormCrop : function () { return this.settings.formCrop; }, /** * get uploader image element */ getUploaderImg : function () { return this.settings.uploaderImg; }, /** * get image preview element */ getPreviewImg : function () { return this.settings.previewImg; }, /** * destroy object plugin */ destroy : function () { methods.destroy.call(this); } }; $.fn.imageUploaderCrop = function(optsOrCmd) { var self = this, selfArgs = arguments, retVals = []; if ( $(this).data('imageUploaderCrop') !== undefined && $.isFunction($(this).data('imageUploaderCrop')[optsOrCmd]) ) { var plug = $(this).data('imageUploaderCrop'); return plug[optsOrCmd].apply(plug, slice.call(selfArgs, 1)); } else if (typeof optsOrCmd === 'object' || !optsOrCmd) { return this.each(function(index, el) { var plugin = new $.imageUploaderCrop(this, optsOrCmd); $(this).data('imageUploaderCrop', plugin); }); } else { $.error( 'Method "' + optsOrCmd + '" does not exist in imageUploaderCrop - (krobing) plugin!'); } }; }));