UNPKG

wise-web-client

Version:

Based on Spine MVC framework

863 lines (724 loc) 26 kB
/* * HTML 5 Image upload script * by STBeets * bought on CodeCanyon: http://codecanyon.net/item/html-5-upload-image-ratio-with-drag-and-drop/8712634 * * Version: 1.3.5 * */ (function(window, $, undefined) { "use strict"; $.html5imageupload = function html5imageupload(options, element) { this.element = element; this.options = $.extend(true, {}, $.html5imageupload.defaults, options, $(this.element).data()); this.input = $(this.element).find('input[type=file]'); var $window = $(window); var _self = this; this.interval = null; this.drag = false; //buttons this.button = {} this.button.edit = '<div class="btn btn-xs btn-info btn-edit"><i class="glyphicon glyphicon-pencil"></i></div>' this.button.saving = '<div class="btn btn-xs btn-warning saving">' + (this.options.saveLabel || 'Saving...') + ' <i class="glyphicon glyphicon-time"></i></div>'; this.button.zoomin = '<div class="btn btn-xs btn-default btn-zoom-in"><i class="glyphicon glyphicon-resize-full"></i></div>'; this.button.zoomout = '<div class="btn btn-xs btn-default btn-zoom-out"><i class="glyphicon glyphicon-resize-small"></i></div>'; this.button.zoomreset = '<div class="btn btn-xs btn-default btn-zoom-reset"><i class="glyphicon glyphicon-fullscreen"></i></div>'; this.button.cancel = '<div class="btn btn-xs btn-danger btn-cancel"><i class="glyphicon glyphicon-remove"></i></div>'; this.button.done = '<div class="btn btn-xs btn-success btn-ok"><i class="glyphicon glyphicon-ok"></i></div>'; this.button.del = '<div class="btn btn-xs btn-danger btn-del"><i class="glyphicon glyphicon-trash"></i></div>'; //this.imageExtensions = {png: 'png', bmp: 'bmp', gif: 'gif', jpg: ['jpg','jpeg'], tiff: 'tiff'}; this.imageMimes = { png: 'image/png', bmp: 'image/bmp', gif: 'image/gif', jpg: 'image/jpeg', jpeg: 'image/jpeg', tiff: 'image/tiff' }; _self._init(); } $.html5imageupload.defaults = { width: null, height: null, image: null, ghost: true, originalsize: true, url: false, removeurl: null, data: {}, canvas: true, ajax: true, dimensionsonly: false, editstart: false, saveOriginal: false, onAfterZoomImage: null, onAfterInitImage: null, onAfterMoveImage: null, onAfterProcessImage: null, onAfterResetImage: null, onAfterCancel: null, onAfterRemoveImage: null, onAfterSelectImage: null, } $.html5imageupload.prototype = { _init: function() { var _self = this; var options = _self.options; var element = _self.element var input = _self.input; if (empty($(element))) { return false; } else { $(element).children().css({ position: 'absolute' }) } //the engine of this script if (!(window.FormData && ("upload" in ($.ajaxSettings.xhr())))) { $(element).empty().attr('class', '').addClass('alert alert-danger').html('HTML5 Upload Image: Sadly.. this browser does not support the plugin, update your browser today!'); return false; } if (!empty(options.width) && empty(options.height) && $(element).innerHeight() <= 0) { $(element).empty().attr('class', '').addClass('alert alert-danger').html('HTML5 Upload Image: Image height is not set and can not be calculated...'); return false; } if (!empty(options.height) && empty(options.width) && $(element).innerWidth() <= 0) { $(element).empty().attr('class', '').addClass('alert alert-danger').html('HTML5 Upload Image: Image width is not set and can not be calculated...'); return false; } if (!empty(options.height) && !empty(options.width) && !empty($(element).innerHeight() && !empty($(element).innerWidth()))) { //all sizes are filled in if ((options.width / options.height) != ($(element).outerWidth() / $(element).outerHeight())) { $(element).empty().attr('class', '').addClass('alert alert-danger').html('HTML5 Upload Image: The ratio of all sizes (CSS and image) are not the same...'); return false; } } //check sizes var width, height, imageWidth, imageHeight; options.width = imageWidth = options.width || $(element).outerWidth(); options.height = imageHeight = options.height || $(element).outerHeight(); if ($(element).innerWidth() > 0) { width = $(element).outerWidth(); } else if ($(element).innerHeight() > 0) { width = null } else if (!empty(options.width)) { width = options.width; } if ($(element).innerHeight() > 0) { height = $(element).outerHeight(); } else if ($(element).innerWidth() > 0) { height = null } else if (!empty(options.height)) { height = options.height; } height = height || width / (imageWidth / imageHeight); width = width || height / (imageHeight / imageWidth); $(element).css({ height: height, width: width }); _self._bind(); if (options.required || $(input).prop('required')) { _self.options.required = true; $(input).prop('required', true) } if (!options.ajax) { _self._formValidation(); } if (!empty(options.image) && options.editstart == false) { $(element).data('name', options.image).append($('<img />').addClass('preview').attr('src', options.image)); var tools = $('<div class="preview tools"></div>'); var del = $('' + this.button.del + ''); $(del).click(function(e) { e.preventDefault(); _self.reset(); }) if (options.buttonDel != false) { $(tools).append(del) } $(element).append(tools); } else if (!empty(options.image)) { _self.readImage(options.image, options.image, options.image, _self.imageMimes[options.image.split('.').pop()]); //$(img).attr('src'),) } if (_self.options.onAfterInitImage) _self.options.onAfterInitImage.call(_self); }, _bind: function() { var _self = this; var element = _self.element; var input = _self.input; //bind the events $(element).unbind('dragover').unbind('drop').unbind('mouseout').on({ dragover: function(event) { _self.handleDrag(event) }, drop: function(event) { _self.handleFile(event, $(this)) }, mouseout: function() { _self.imageUnhandle(); // } }); $(input).unbind('change').change(function(event) { _self.drag = false; _self.handleFile(event, $(element)) }); }, handleFile: function(event, element) { event.stopPropagation(); event.preventDefault(); var _self = this; var options = this.options; var files = (_self.drag == false) ? event.originalEvent.target.files : event.originalEvent.dataTransfer.files; // FileList object. _self.drag = false; // _self.reset(); if (options.removeurl != null && !empty($(element).data('name'))) { $.ajax({ type: 'POST', url: options.removeurl, data: { image: $(element).data('name') }, success: function(response) { if (_self.options.onAfterRemoveImage) _self.options.onAfterRemoveImage.call(_self, response); } }) } $(element).removeClass('notAnImage').addClass('loading'); //.unbind('dragover').unbind('drop'); for (var i = 0, f; f = files[i]; i++) { if (!f.type.match('image.*')) { $(element).addClass('notAnImage'); continue; } var reader = new FileReader(); reader.onload = (function(theFile) { //console.log(theFile); return function(e) { $(element).find('img').remove(); _self.readImage(reader.result, e.target.result, theFile.name, theFile.type); }; })(f); reader.readAsDataURL(f); } if (_self.options.onAfterSelectImage) _self.options.onAfterSelectImage.call(_self, response); }, readImage: function(image, src, name, mimeType) { var _self = this; var options = this.options; var element = this.element; _self.drag = false; var img = new Image; img.onload = function(tmp) { //console.log(tmp); var imgElement = $('<img src="' + src + '" name="' + name + '" />'); var width, height, useWidth, useHeight, ratio, elementRatio; width = useWidth = img.width; height = useHeight = img.height; ratio = width / height; elementRatio = $(element).outerWidth() / $(element).outerHeight(); //resize image if (options.originalsize == false) { useWidth = $(element).outerWidth() + 40; useHeight = useWidth / ratio; if (useHeight < $(element).outerHeight()) { useHeight = $(element).outerHeight() + 40; useWidth = useHeight * ratio; } } else if (useWidth < $(element).outerWidth() || useHeight < $(element).outerHeight()) { if (ratio < elementRatio) { useWidth = $(element).outerWidth(); useHeight = useWidth / ratio; } else { useHeight = $(element).outerHeight(); useWidth = useHeight * ratio; } } var left = parseFloat(($(element).outerWidth() - useWidth) / 2) // * -1; var top = parseFloat(($(element).outerHeight() - useHeight) / 2) // * -1; imgElement.css({ left: left, top: top, width: useWidth, height: useHeight }) _self.image = $(imgElement).clone().data({ mime: mimeType, width: width, height: height, ratio: ratio, left: left, top: top, useWidth: useWidth, useHeight: useHeight }).addClass('main').mousedown(function(event) { _self.imageHandle(event) }); _self.imageGhost = (options.ghost) ? $(imgElement).addClass('ghost') : null; //place the images $(element).append($('<div class="cropWrapper"></div>').append($(_self.image))); if (!empty(_self.imageGhost)) { $(element).append(_self.imageGhost); } //$(element).unbind('dragover').unbind('drop'); _self._tools(); //clean up $(element).removeClass('loading'); } img.src = image; }, handleDrag: function(event) { var _self = this; _self.drag = true; event.stopPropagation(); event.preventDefault(); event.originalEvent.dataTransfer.dropEffect = 'copy'; }, imageHandle: function(e) { e.preventDefault(); // disable selection var _self = this; var element = this.element; var image = this.image; var height = image.outerHeight(), width = image.outerWidth(), cursor_y = image.offset().top + height - e.pageY, cursor_x = image.offset().left + width - e.pageX; image.on({ mousemove: function(e) { var imgTop = e.pageY + cursor_y - height, imgLeft = e.pageX + cursor_x - width; var hasBorder = ($(element).outerWidth() != $(element).innerWidth()); if (parseInt(imgTop - $(element).offset().top) > 0) { imgTop = $(element).offset().top + ((hasBorder) ? 1 : 0); } else if (imgTop + height < $(element).offset().top + $(element).outerHeight()) { imgTop = $(element).offset().top + $(element).outerHeight() - height + ((hasBorder) ? 1 : 0); } if (parseInt(imgLeft - $(element).offset().left) > 0) { imgLeft = $(element).offset().left + ((hasBorder) ? 1 : 0);; } else if (imgLeft + width < $(element).offset().left + $(element).outerWidth()) { imgLeft = $(element).offset().left + $(element).outerWidth() - width + ((hasBorder) ? 1 : 0);; } image.offset({ top: imgTop, left: imgLeft }) _self._ghost(); }, mouseup: function() { _self.imageUnhandle(); } }) }, imageUnhandle: function() { var _self = this; var image = _self.image; $(image).unbind('mousemove'); if (_self.options.onAfterMoveImage) _self.options.onAfterMoveImage.call(_self); }, imageZoom: function(x) { var _self = this; var element = _self.element; var image = _self.image; if (empty(image)) { _self._clearTimers(); return false; } var ratio = image.data('ratio'); var newWidth = image.outerWidth() + x; var newHeight = newWidth / ratio; //smaller then element? if (newWidth < $(element).outerWidth()) { newWidth = $(element).outerWidth(); newHeight = newWidth / ratio; x = $(image).outerWidth() - newWidth; } if (newHeight < $(element).outerHeight()) { newHeight = $(element).outerHeight(); newWidth = newHeight * ratio; x = $(image).outerWidth() - newWidth; } var newTop = Math.round(parseFloat(image.css('top')) - parseFloat(newHeight - image.outerHeight()) / 2); var newLeft = parseInt(image.css('left')) - x / 2; if ($(element).offset().left - newLeft < $(element).offset().left) { newLeft = 0; } else if ($(element).outerWidth() > newLeft + $(image).outerWidth() && x <= 0) { newLeft = $(element).outerWidth() - newWidth; } if ($(element).offset().top - newTop < $(element).offset().top) { newTop = 0; } else if ($(element).outerHeight() > newTop + $(image).outerHeight() && x <= 0) { newTop = $(element).outerHeight() - newHeight; } image.css({ width: newWidth, height: newHeight, top: newTop, left: newLeft }) _self._ghost(); }, imageCrop: function() { var _self = this; var element = _self.element; var image = _self.image; var input = _self.input; var options = _self.options; var factor = (options.width != $(element).outerWidth()) ? options.width / $(element).outerWidth() : 1; var finalWidth, finalHeight, finalTop, finalLeft, imageWidth, imageHeight, imageOriginalWidth, imageOriginalHeight; finalWidth = options.width; finalHeight = options.height; finalTop = parseInt(Math.round(parseInt($(image).css('top')) * factor)) * -1 finalLeft = parseInt(Math.round(parseInt($(image).css('left')) * factor)) * -1 imageWidth = parseInt(Math.round($(image).width() * factor)); imageHeight = parseInt(Math.round($(image).height() * factor)); imageOriginalWidth = $(image).data('width'); imageOriginalHeight = $(image).data('height'); finalTop = finalTop || 0; finalLeft = finalLeft || 0; var obj = { name: $(image).attr('name'), imageOriginalWidth: imageOriginalWidth, imageOriginalHeight: imageOriginalHeight, imageWidth: imageWidth, imageHeight: imageHeight, width: finalWidth, height: finalHeight, left: finalLeft, top: finalTop } $(element).find('.tools').children().toggle(); $(element).find('.tools').append($(_self.button.saving)); if (options.canvas == true) { var canvas = $('<canvas class="final" id="canvas_' + $(input).attr('name') + '" width="' + finalWidth + '" height="' + finalHeight + '" style="position:absolute; top: 0; bottom: 0; left: 0; right: 0; z-index:100; width: 100%; height: 100%;"></canvas>'); $(element).append(canvas); var canvasContext = $(canvas)[0].getContext('2d'); var imageObj = new Image(); imageObj.onload = function() { var canvasTmp = $('<canvas width="' + imageWidth + '" height="' + imageHeight + '"></canvas>'); var canvasTmpContext = $(canvasTmp)[0].getContext('2d'); var tmpImage = $('<img src="" />'); canvasTmpContext.drawImage(imageObj, 0, 0, imageWidth, imageHeight); var tmpObj = new Image(); tmpObj.onload = function() { canvasContext.drawImage(tmpObj, finalLeft, finalTop, finalWidth, finalHeight, 0, 0, finalWidth, finalHeight); if (options.ajax == true) { _self._ajax($.extend({ data: $(canvas)[0].toDataURL(image.data('mime')) }, obj)); } else { var json = JSON.stringify($.extend({ data: $(canvas)[0].toDataURL(image.data('mime')) }, obj)); $(input).after($('<input type="text" name="' + $(input).attr('name') + '_values" class="final" />').val(json)); $(input).data('required', $(input).prop('required')); $(input).prop('required', false); $(input).wrap('<form>').parent('form').trigger('reset'); $(input).unwrap(); $(element).find('.tools .saving').remove(); $(element).find('.tools').children().toggle(); _self.imageFinal(); } } tmpObj.src = $(canvasTmp)[0].toDataURL(image.data('mime')); }; imageObj.src = $(image).attr('src'); if (options.saveOriginal === true) { //console.log($(image).attr('src')); obj = $.extend({ original: $(image).attr('src') }, obj); } } else { if (options.ajax == true) { _self._ajax($.extend({ data: $(image).attr('src'), saveOriginal: options.saveOriginal }, obj)); } else { var finalImage = $(element).find('.cropWrapper').clone(); $(finalImage).addClass('final').show().unbind().children().unbind() $(element).append($(finalImage)); _self.imageFinal(); var json = JSON.stringify(obj); $(input).after($('<input type="text" name="' + $(input).attr('name') + '_values" class="final" />').val(json)); } } }, _ajax: function(obj) { var _self = this; var element = _self.element; var image = _self.image; var options = _self.options; if (options.dimensionsonly == true) { delete obj.data; } $.ajax({ type: 'POST', url: options.url, data: $.extend(obj, options.data), success: function(response) { if (response.status == "success") { var file = response.url.split('?'); $(element).find('.tools .saving').remove(); $(element).find('.tools').children().toggle(); $(element).data('name', file[0]) if (options.canvas != true) { $(element).append($('<img src="' + file[0] + '" class="final" style="width: 100%" />')); } _self.imageFinal(response); } else { $(element).find('.tools .saving').remove(); $(element).find('.tools').children().toggle(); $(element).append($('<div class="alert alert-danger">' + response.error + '</div>').css({ bottom: '10px', left: '10px', right: '10px', position: 'absolute', zIndex: 99 })); setTimeout(function() { _self.responseReset(); }, 2000); } }, error: function(response, status) { $(element).find('.tools .saving').remove(); $(element).find('.tools').children().toggle(); $(element).append($('<div class="alert alert-danger"><strong>' + response.status + '</strong> ' + response.statusText + '</div>').css({ bottom: '10px', left: '10px', right: '10px', position: 'absolute', zIndex: 99 })); setTimeout(function() { _self.responseReset(); }, 2000); } }) }, imageReset: function() { var _self = this; var image = _self.image; var element = _self.element; $(image).css({ width: image.data('useWidth'), height: image.data('useHeight'), top: image.data('top'), left: image.data('left') }) _self._ghost(); if (_self.options.onAfterResetImage) _self.options.onAfterResetImage.call(_self); }, imageFinal: function(response) { var _self = this; var element = _self.element; var input = _self.input; var options = _self.options; //remove all children except final $(element).addClass('done'); $(element).children().not('.final').hide(); //create tools element var tools = $('<div class="tools final">'); //edit option after crop if (options.buttonEdit != false) { $(tools).append($(_self.button.edit).click(function() { $(element).children().show(); $(element).find('.final').remove(); $(input).data('valid', false); })); } //delete option after crop if (options.buttonDel != false) { $(tools).append($(_self.button.del).click(function(e) { _self.reset(); })) } //append tools to element $(element).append(tools); $(element).unbind(); //set input to valid for form upload $(input).unbind().data('valid', true); //custom function after process image; if (_self.options.onAfterProcessImage) _self.options.onAfterProcessImage.call(_self, response); }, responseReset: function() { var _self = this; var element = _self.element; //remove responds from ajax event $(element).find('.alert').remove(); }, reset: function() { var _self = this; var element = _self.element; var input = _self.input; var options = _self.options; _self.image = null; $(element).find('.preview').remove(); $(element).removeClass('loading done').children().show().not('input[type=file]').remove(); $(input).wrap('<form>').parent('form').trigger('reset'); $(input).unwrap(); $(input).prop('required', $(input).data('required') || options.required || false).data('valid', false); _self._bind(); if (options.removeurl != null && !empty($(element).data('name'))) { $.ajax({ type: 'POST', url: options.removeurl, data: { image: $(element).data('name') }, success: function(response) { if (_self.options.onAfterRemoveImage) _self.options.onAfterRemoveImage.call(_self, response); } }) } $(element).data('name', null); if (_self.imageGhost) { $(_self.imageGhost).remove(); _self.imageGhost = null; } if (_self.options.onAfterCancel) _self.options.onAfterCancel.call(_self); }, _ghost: function() { var _self = this; var options = _self.options; var image = _self.image; var ghost = _self.imageGhost; //if set to true, mirror all drag events //function in one place, much needed if (options.ghost == true && !empty(ghost)) { $(ghost).css({ width: image.css('width'), height: image.css('height'), top: image.css('top'), left: image.css('left') }) } }, _tools: function() { var _self = this; var element = _self.element; var tools = $('<div class="tools"></div>'); var options = _self.options; //zoomin button if (options.buttonZoomin != false) { $(tools).append($(_self.button.zoomin).on({ mousedown: function(e) { _self.interval = window.setInterval(function() { _self.imageZoom(2); }, 1); }, mouseup: function(e) { window.clearInterval(_self.interval); if (_self.options.onAfterZoomImage) _self.options.onAfterZoomImage.call(_self); }, mouseleave: function(e) { window.clearInterval(_self.interval); if (_self.options.onAfterZoomImage) _self.options.onAfterZoomImage.call(_self); } })); } //zoomreset button (set the image to the "original" size, same size as when selecting the image if (options.buttonZoomreset != false) { $(tools).append($(_self.button.zoomreset).on({ click: function(e) { _self.imageReset(); } })); } //zoomout button if (options.buttonZoomout != false) { $(tools).append($(_self.button.zoomout).on({ mousedown: function(e) { _self.interval = window.setInterval(function() { _self.imageZoom(-2); }, 1); }, mouseup: function(e) { window.clearInterval(_self.interval); if (_self.options.onAfterZoomImage) _self.options.onAfterZoomImage.call(_self); }, mouseleave: function(e) { window.clearInterval(_self.interval); if (_self.options.onAfterZoomImage) _self.options.onAfterZoomImage.call(_self); } })); } //cancel button (removes the image and resets it to the original init event if (options.buttonCancel != false) { $(tools).append($(_self.button.cancel).on({ click: function(e) { _self.reset() } })); } //done button (crop the image!) if (options.buttonDone != false) { $(tools).append($(_self.button.done).on({ click: function(e) { _self.imageCrop() } })); } $(element).append($(tools)); }, _clearTimers: function() { //function to clear all timers, just to be sure! var interval_id = window.setInterval("", 9999); for (var i = 1; i < interval_id; i++) window.clearInterval(i); }, _formValidation: function() { var _self = this; var element = _self.element; var input = _self.input; $(element).closest('form').submit(function(e) { //e.stopPropagation(); $(this).find('input[type=file]').each(function(i, el) { if ($(el).prop('required')) { if ($(el).data('valid') !== true) { e.preventDefault(); return false; } } }) return true; }) } } $.fn.html5imageupload = function(options) { if ($.data(this, "html5imageupload")) return; return $(this).each(function() { new $.html5imageupload(options, this); $.data(this, "html5imageupload"); }) } })(window, jQuery); function empty(mixed_var) { //discuss at: http://phpjs.org/functions/empty/ // original by: Philippe Baumann // input by: Onno Marsman // input by: LH // input by: Stoyan Kyosev (http://www.svest.org/) // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // improved by: Onno Marsman // improved by: Francesco // improved by: Marc Jansen // improved by: Rafal Kukawski var undef, key, i, len; var emptyValues = [undef, null, false, 0, '', '0']; for (i = 0, len = emptyValues.length; i < len; i++) { if (mixed_var === emptyValues[i]) { return true; } } if (typeof mixed_var === 'object') { for (key in mixed_var) { return false; } return true; } return false; }