├── .gitignore ├── Gruntfile.js ├── Jcrop.gif ├── README.md ├── dist ├── css │ ├── mr-uploader.css │ └── mr-uploader.min.css └── js │ ├── mr-uploader.all.js │ ├── mr-uploader.all.min.js │ └── mr-uploader.js ├── examples ├── aspect-ratio │ └── index.html ├── simple │ └── index.html └── upload.php ├── package.json ├── src ├── style.css └── uploader.coffee └── vendors ├── jquery.Jcrop.min.css └── jquery.Jcrop.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* global module:false */ 2 | module.exports = function(grunt) { 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | // Metadata. 7 | meta: { 8 | version: '0.1.0' 9 | }, 10 | banner: '/*! MrUploader - v<%= meta.version %> - ' + 11 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 12 | '* http://github.com/vinelab/mr-uploader\n' + 13 | '* Copyright (c) <%= grunt.template.today("yyyy") %> ' + 14 | 'Vinelab; Licensed MIT */\n' 15 | }); 16 | 17 | // Task configuration. 18 | grunt.loadNpmTasks('grunt-contrib-concat'); 19 | grunt.config('concat', { 20 | options: { 21 | banner: '<%= banner %>', 22 | stripBanners: true 23 | }, 24 | dist: { 25 | src: ['vendors/jquery.Jcrop.min.js', 'dist/js/mr-uploader.js'], 26 | dest: 'dist/js/mr-uploader.all.js' 27 | }, 28 | css: { 29 | src: ['src/style.css', 'vendors/jquery.Jcrop.min.css'], 30 | dest: 'dist/css/mr-uploader.css' 31 | } 32 | }); 33 | 34 | grunt.loadNpmTasks('grunt-contrib-uglify'); 35 | grunt.config('uglify', { 36 | options: { 37 | banner: '<%= banner %>', 38 | mangle: false 39 | }, 40 | all: { 41 | src: '<%= concat.dist.dest %>', 42 | dest: 'dist/js/mr-uploader.all.min.js' 43 | } 44 | }); 45 | 46 | grunt.loadNpmTasks('grunt-contrib-coffee'); 47 | grunt.config('coffee', { 48 | compile: { 49 | options: {bare: true}, 50 | files: {'dist/js/mr-uploader.js': 'src/uploader.coffee'} 51 | } 52 | }); 53 | 54 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 55 | grunt.config('cssmin', { 56 | style: { 57 | files: [{ 58 | expand: true, 59 | cwd: 'dist/css', 60 | src: ['*.css'], 61 | dest: 'dist/css', 62 | ext: '.min.css' 63 | }] 64 | } 65 | }); 66 | 67 | grunt.loadNpmTasks('grunt-contrib-watch'); 68 | grunt.config('watch', { 69 | coffee: { 70 | files: ['src/**/*'], 71 | tasks: ['clean', 'coffee', 'concat', 'uglify', 'cssmin'] 72 | } 73 | }); 74 | 75 | grunt.loadNpmTasks('grunt-contrib-clean'); 76 | grunt.config('clean', { 77 | css: { 78 | src: ['dist/css'] 79 | } 80 | }); 81 | 82 | }; 83 | -------------------------------------------------------------------------------- /Jcrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vinelab/mr-uploader/31a36024cdb3836fad3733e51b430755c77ab62d/Jcrop.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mr. Uploader 2 | jQuery plugin for simplified photo cropping and uploading. 3 | 4 | ## Installation 5 | 6 | - jQuery is a requirement and must be loaded before the js file of this package. 7 | - Clone this repo 8 | - Copy the files from the `dist/` directory into the directory where you'll be serving your static assets 9 | 10 | ## Usage 11 | 12 | - Use `upload = $('selector').mrUploader({uploadUrl: '/upload'});` to start using this package. 13 | 14 | - Here's full snippet: 15 | 16 | ```html 17 | 18 | 19 | 20 | Mr. Uploader 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | ``` 36 | 37 | - The `upload` variable will now be a `MrUploader` instance 38 | - Access the photos uploaded using the `uploads` key on the instance 39 | - A sample of an `upload` is the following: 40 | 41 | ```javascript 42 | { 43 | "response": {}, // The upload response from the server 44 | "$image", // A jQuery image object representing the uploaded image 45 | "meta": { 46 | "width": 1920, // Original image width 47 | "height": 1080, // Original image height 48 | "size": 140210, // Original image size in bytes 49 | "type": 'image/png', // Image MIME type 50 | "name": 'my-image.png' // Original image file name on client's disk 51 | }, 52 | "crop": { 53 | "width": 123, // Crop width 54 | "height": 456, // Crop height 55 | "x": 834, // Crop X 56 | "x2": 747, // Crop X2 57 | "y": 773, // Crop Y 58 | "y2": 836 // Crop Y2 59 | } 60 | } 61 | ``` 62 | 63 | For more examples please check the `example` folder of this package. 64 | 65 | ## Event Handlers 66 | You may attach handlers to events to be notified when they occur. 67 | 68 | ### Events 69 | 70 | #### upload 71 | This event will be called when an upload is **successfully** completed 72 | 73 | ```javascript 74 | upload = $('element').mrUploader(); 75 | upload.on('upload', function (event, data) { 76 | // e is the jQuery event 77 | // data is the upload data 78 | }); 79 | ``` 80 | -------------------------------------------------------------------------------- /dist/css/mr-uploader.css: -------------------------------------------------------------------------------- 1 | /*! MrUploader - v0.1.0 - 2015-03-18 2 | * http://github.com/vinelab/mr-uploader 3 | * Copyright (c) 2015 Vinelab; Licensed MIT */ 4 | .mr-uploader-fullscreen-mode { 5 | top: 0; 6 | left: 0; 7 | width: 100%; 8 | height: 100%; 9 | z-index: 99999; 10 | position: fixed; 11 | overflow: scroll; 12 | font-family: Arial; 13 | border: 0!important; 14 | padding: 15px 30px 15px; 15 | color: #272727; 16 | background: #FAFAFB!important; 17 | } 18 | 19 | .mr-uploader-fullscreen-close { 20 | float:left; 21 | font-size: 28px; 22 | cursor: pointer; 23 | font-color: #ededed; 24 | text-decoration: none; 25 | } 26 | 27 | #mr-uploader-file-input { 28 | margin: 0 auto; 29 | padding-bottom: 10px; 30 | } 31 | 32 | #mr-uploader-images { 33 | min-height: 200px; 34 | } 35 | 36 | #mr-uploader-images .jcrop-holder { 37 | text-align: : center; 38 | margin: 0 auto; 39 | } 40 | 41 | .mr-uploader-preview { 42 | position: relative; 43 | float: left; 44 | font-size: 30px; 45 | margin-left: 10px; 46 | overflow: hidden; 47 | background-color: transparent; 48 | box-shadow: 0px 0px 5px 1px #888; 49 | -moz-box-shadow: inset 0px 0px 5px 1px #888; 50 | -webkit-box-shadow: inset 0px 0px 5px 1px #888; 51 | } 52 | 53 | .mr-uploader-ar-landscape { 54 | width: 300px; 55 | height: 200px; 56 | } 57 | 58 | .mr-uploader-ar-portrait { 59 | width: 200px; 60 | height: 300px; 61 | } 62 | 63 | .mr-uploader-ar-square { 64 | width: 200px; 65 | height: 200px; 66 | } 67 | 68 | .mr-uploader-preview-overlay { 69 | position: absolute; 70 | width: 100%; 71 | height: 100%; 72 | opacity: 0.8; 73 | text-align: center; 74 | text-decoration: bold; 75 | color: green; 76 | vertical-align: middle; 77 | line-height: 200px; 78 | text-decoration: bold; 79 | background-color: #ededed; 80 | } 81 | 82 | .mr-uploader-preview .error { 83 | color: red; 84 | font-size: 22px; 85 | } 86 | 87 | .mr-uploader-spinner { 88 | margin: 0 auto; 89 | width: 70px; 90 | text-align: center; 91 | } 92 | 93 | .mr-uploader-spinner > div { 94 | width: 18px; 95 | height: 18px; 96 | background-color: #333; 97 | 98 | border-radius: 100%; 99 | display: inline-block; 100 | -webkit-animation: bouncedelay 0.8s infinite ease-in-out; 101 | animation: bouncedelay 0.8s infinite ease-in-out; 102 | /* Prevent first frame from flickering when animation starts */ 103 | -webkit-animation-fill-mode: both; 104 | animation-fill-mode: both; 105 | } 106 | 107 | .mr-uploader-spinner-bounce1 { 108 | -webkit-animation-delay: -0.32s; 109 | animation-delay: -0.32s; 110 | } 111 | 112 | .mr-uploader-spinner-bounce2 { 113 | -webkit-animation-delay: -0.16s; 114 | animation-delay: -0.16s; 115 | } 116 | 117 | @-webkit-keyframes bouncedelay { 118 | 0%, 80%, 100% { -webkit-transform: scale(0.0) } 119 | 40% { -webkit-transform: scale(1.0) } 120 | } 121 | 122 | @keyframes bouncedelay { 123 | 0%, 80%, 100% { 124 | transform: scale(0.0); 125 | -webkit-transform: scale(0.0); 126 | } 40% { 127 | transform: scale(1.0); 128 | -webkit-transform: scale(1.0); 129 | } 130 | } 131 | 132 | .mr-uploader-ratio-options { 133 | margin: 30px 0px 30px 0px; 134 | } 135 | 136 | .jcrop-holder{direction:ltr;text-align:left;} 137 | .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;} 138 | .jcrop-vline{height:100%;width:1px!important;} 139 | .jcrop-vline.right{right:0;} 140 | .jcrop-hline{height:1px!important;width:100%;} 141 | .jcrop-hline.bottom{bottom:0;} 142 | .jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;} 143 | .jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;} 144 | .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;} 145 | .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;} 146 | .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;} 147 | .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;} 148 | .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;} 149 | .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;} 150 | .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;} 151 | .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;} 152 | .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;} 153 | .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;} 154 | .jcrop-dragbar.ord-n{margin-top:-4px;} 155 | .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;} 156 | .jcrop-dragbar.ord-e{margin-right:-4px;right:0;} 157 | .jcrop-dragbar.ord-w{margin-left:-4px;} 158 | .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;} 159 | .jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;} 160 | .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;} 161 | .jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;} 162 | .solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;} 163 | .jcrop-holder img,img.jcrop-preview{max-width:none;} 164 | -------------------------------------------------------------------------------- /dist/css/mr-uploader.min.css: -------------------------------------------------------------------------------- 1 | /*! MrUploader - v0.1.0 - 2015-03-18 2 | * http://github.com/vinelab/mr-uploader 3 | * Copyright (c) 2015 Vinelab; Licensed MIT */.mr-uploader-fullscreen-mode{top:0;left:0;width:100%;height:100%;z-index:99999;position:fixed;overflow:scroll;font-family:Arial;border:0!important;padding:15px 30px;color:#272727;background:#FAFAFB!important}.mr-uploader-fullscreen-close{float:left;font-size:28px;cursor:pointer;font-color:#ededed;text-decoration:none}#mr-uploader-file-input{margin:0 auto;padding-bottom:10px}#mr-uploader-images{min-height:200px}#mr-uploader-images .jcrop-holder{text-align:center;margin:0 auto}.mr-uploader-preview{position:relative;float:left;font-size:30px;margin-left:10px;overflow:hidden;background-color:transparent;box-shadow:0 0 5px 1px #888;-moz-box-shadow:inset 0 0 5px 1px #888;-webkit-box-shadow:inset 0 0 5px 1px #888}.mr-uploader-ar-landscape{width:300px;height:200px}.mr-uploader-ar-portrait{width:200px;height:300px}.mr-uploader-ar-square{width:200px;height:200px}.mr-uploader-preview-overlay{position:absolute;width:100%;height:100%;opacity:.8;text-align:center;color:green;vertical-align:middle;line-height:200px;text-decoration:bold;background-color:#ededed}.mr-uploader-preview .error{color:red;font-size:22px}.mr-uploader-spinner{margin:0 auto;width:70px;text-align:center}.mr-uploader-spinner>div{width:18px;height:18px;background-color:#333;border-radius:100%;display:inline-block;-webkit-animation:bouncedelay .8s infinite ease-in-out;animation:bouncedelay .8s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.mr-uploader-spinner-bounce1{-webkit-animation-delay:-.32s;animation-delay:-.32s}.mr-uploader-spinner-bounce2{-webkit-animation-delay:-.16s;animation-delay:-.16s}@-webkit-keyframes bouncedelay{0%,100%,80%{-webkit-transform:scale(0)}40%{-webkit-transform:scale(1)}}@keyframes bouncedelay{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.mr-uploader-ratio-options{margin:30px 0}.jcrop-holder{direction:ltr;text-align:left}.jcrop-hline,.jcrop-vline{background:url(Jcrop.gif) #FFF;font-size:0;position:absolute}.jcrop-vline{height:100%;width:1px!important}.jcrop-vline.right{right:0}.jcrop-hline{height:1px!important;width:100%}.jcrop-hline.bottom{bottom:0}.jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%}.jcrop-handle{background-color:#333;border:1px solid #EEE;font-size:1px;height:7px;width:7px}.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0}.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px}.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%}.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%}.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0}.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0}.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0}.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px}.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%}.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px}.jcrop-dragbar.ord-n{margin-top:-4px}.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px}.jcrop-dragbar.ord-e{margin-right:-4px;right:0}.jcrop-dragbar.ord-w{margin-left:-4px}.jcrop-light .jcrop-hline,.jcrop-light .jcrop-vline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.7!important}.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px}.jcrop-dark .jcrop-hline,.jcrop-dark .jcrop-vline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important}.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px}.solid-line .jcrop-hline,.solid-line .jcrop-vline{background:#FFF}.jcrop-holder img,img.jcrop-preview{max-width:none} -------------------------------------------------------------------------------- /dist/js/mr-uploader.all.js: -------------------------------------------------------------------------------- 1 | /*! MrUploader - v0.1.0 - 2015-03-18 2 | * http://github.com/vinelab/mr-uploader 3 | * Copyright (c) 2015 Vinelab; Licensed MIT */ 4 | (function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys 5 | (),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring 6 | (0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("
").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2], 7 | a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb 8 | .setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id"). 9 | css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("
").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("
"),I=a("
").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("
").width("100%").height("100%").css("zIndex",320),K=a("
").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart" 10 | ,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;da+f&&(f-=f+a),0>b+g&&(g-=g+b),FE&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-ah&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):rh&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return cP&&(c=d>0?a+P:a-P),Q&&Math.abs 12 | (f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)0?b+S/U:b-S/U),R/T&&Math.abs(d)0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("
").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb. 13 | isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("
").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("
").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("
").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++ 14 | ).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("
").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if( 18 | b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges 19 | :!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery); 20 | 21 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 22 | __slice = [].slice; 23 | 24 | (function($, window) { 25 | var MrUploader; 26 | MrUploader = (function() { 27 | MrUploader.prototype.defaults = { 28 | multiple: true, 29 | cropping: true, 30 | onClick: true, 31 | uploadUrl: '/upload.php', 32 | aspectRatio: 'landscape', 33 | crop: { 34 | boxWidth: 800, 35 | aspectRatio: 3 / 2, 36 | keySupport: false, 37 | allowSelect: false, 38 | minSize: [300, 200], 39 | setSelect: [0, 0, 600, 400] 40 | } 41 | }; 42 | 43 | function MrUploader(el, options) { 44 | this.hideFullscreen = __bind(this.hideFullscreen, this); 45 | this.setAspectRatio = __bind(this.setAspectRatio, this); 46 | this.setLandscapeAspectRatio = __bind(this.setLandscapeAspectRatio, this); 47 | this.setPortraitAspectRatio = __bind(this.setPortraitAspectRatio, this); 48 | this.setSquareAspectRatio = __bind(this.setSquareAspectRatio, this); 49 | this.show = __bind(this.show, this); 50 | this.showFullscreen = __bind(this.showFullscreen, this); 51 | this.onCloseClick = __bind(this.onCloseClick, this); 52 | this.getStagedFileMeta = __bind(this.getStagedFileMeta, this); 53 | this.changePreview = __bind(this.changePreview, this); 54 | this.getPreviewHeight = __bind(this.getPreviewHeight, this); 55 | this.getPreviewWidth = __bind(this.getPreviewWidth, this); 56 | this.onReaderLoad = __bind(this.onReaderLoad, this); 57 | this.onUploaderFileChanged = __bind(this.onUploaderFileChanged, this); 58 | this.onUploadClick = __bind(this.onUploadClick, this); 59 | this.onCancelClick = __bind(this.onCancelClick, this); 60 | this.resetCroppingArea = __bind(this.resetCroppingArea, this); 61 | this.setStaged = __bind(this.setStaged, this); 62 | this.onCroppingSelected = __bind(this.onCroppingSelected, this); 63 | this.showPhotoActionElements = __bind(this.showPhotoActionElements, this); 64 | this.hidePhotoActionElements = __bind(this.hidePhotoActionElements, this); 65 | this.getCroppingAreaContent = __bind(this.getCroppingAreaContent, this); 66 | this.getRatioOptions = __bind(this.getRatioOptions, this); 67 | this.getHeaderContent = __bind(this.getHeaderContent, this); 68 | this.onElementClick = __bind(this.onElementClick, this); 69 | this.on = __bind(this.on, this); 70 | this.$el = $(el); 71 | this.$options = $.extend(true, {}, this.defaults, options); 72 | this.photoActionsElements = []; 73 | this.addContent(); 74 | if (this.$options.onClick === true) { 75 | this.$el.click(this.onElementClick); 76 | } 77 | this.setStaged(null); 78 | this.uploads = []; 79 | } 80 | 81 | MrUploader.prototype.on = function(event, callback) { 82 | return $(this).on(event, callback); 83 | }; 84 | 85 | MrUploader.prototype.onElementClick = function(e) { 86 | e.preventDefault(); 87 | return this.showFullscreen(); 88 | }; 89 | 90 | MrUploader.prototype.getHeaderContent = function() { 91 | var close, header, ratioOptions, title; 92 | header = $('
'); 93 | close = $('

×

'); 94 | close.click(this.onCloseClick); 95 | title = $('

').text('Choose & Crop'); 96 | ratioOptions = this.getRatioOptions(); 97 | this.photoActionsElements.push(ratioOptions); 98 | header.append(close, title, ratioOptions); 99 | return header; 100 | }; 101 | 102 | MrUploader.prototype.getRatioOptions = function() { 103 | var landscape, landscapeLabel, portrait, portraitLabel, square, squareLabel; 104 | squareLabel = $(' '); 105 | this.squareInput = $(' '); 106 | this.squareInput.click((function(_this) { 107 | return function() { 108 | return _this.setSquareAspectRatio(); 109 | }; 110 | })(this)); 111 | if (this.$options.aspectRatio === 'square') { 112 | this.squareInput.attr('checked', true); 113 | } 114 | square = $('
').append(squareLabel, this.squareInput); 115 | portraitLabel = $(' '); 116 | this.portraitInput = $(' '); 117 | if (this.$options.aspectRatio === 'portrait') { 118 | this.portraitInput.attr('checked', true); 119 | } 120 | this.portraitInput.click((function(_this) { 121 | return function() { 122 | return _this.setPortraitAspectRatio(); 123 | }; 124 | })(this)); 125 | portrait = $('
').append(portraitLabel, this.portraitInput); 126 | landscapeLabel = $(' '); 127 | this.landscapeInput = $(' '); 128 | if (this.$options.aspectRatio === 'landscape') { 129 | this.landscapeInput.attr('checked', true); 130 | } 131 | this.landscapeInput.click((function(_this) { 132 | return function() { 133 | return _this.setLandscapeAspectRatio(); 134 | }; 135 | })(this)); 136 | landscape = $('
').append(landscapeLabel, this.landscapeInput); 137 | return $('
').append(square).append(portrait).append(landscape); 138 | }; 139 | 140 | MrUploader.prototype.getCroppingAreaContent = function() { 141 | var cancel, crop, upload; 142 | crop = $('
'); 143 | this.$input = $(''); 144 | this.$input.change(this.onUploaderFileChanged); 145 | crop.append(this.$input); 146 | this.$photos = $('
 
'); 147 | crop.append(this.$photos); 148 | upload = $(''); 149 | upload.click(this.onUploadClick); 150 | cancel = $(''); 151 | cancel.click(this.onCancelClick); 152 | this.photoActionsElements.push(upload, cancel); 153 | crop.append(upload); 154 | crop.append(cancel); 155 | return crop; 156 | }; 157 | 158 | MrUploader.prototype.addContent = function() { 159 | this.$container = $('
').hide().addClass('mr-uploader-fullscreen-mode').css('text-align', 'center'); 160 | this.$container.append(this.getHeaderContent()); 161 | this.$croppingArea = this.getCroppingAreaContent(); 162 | this.$container.append(this.$croppingArea); 163 | this.$container.append('
'); 164 | this.$previews = $('
'); 165 | this.$container.append(this.$previews); 166 | this.hidePhotoActionElements(); 167 | return $('body').append(this.$container); 168 | }; 169 | 170 | MrUploader.prototype.hidePhotoActionElements = function() { 171 | var element, _i, _len, _ref, _results; 172 | _ref = this.photoActionsElements; 173 | _results = []; 174 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 175 | element = _ref[_i]; 176 | _results.push(element.hide()); 177 | } 178 | return _results; 179 | }; 180 | 181 | MrUploader.prototype.showPhotoActionElements = function() { 182 | var element, _i, _len, _ref, _results; 183 | _ref = this.photoActionsElements; 184 | _results = []; 185 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 186 | element = _ref[_i]; 187 | _results.push(element.show()); 188 | } 189 | return _results; 190 | }; 191 | 192 | MrUploader.prototype.onCroppingSelected = function(crop, image, meta) { 193 | crop = { 194 | x: Math.round(crop.x), 195 | y: Math.round(crop.y), 196 | x2: Math.round(crop.x2), 197 | y2: Math.round(crop.y2), 198 | width: Math.round(crop.w), 199 | height: Math.round(crop.h) 200 | }; 201 | meta.width = image.width(); 202 | meta.height = image.height(); 203 | return this.setStaged({ 204 | $image: image, 205 | meta: meta, 206 | crop: crop 207 | }); 208 | }; 209 | 210 | MrUploader.prototype.setStaged = function(staged) { 211 | this.staged = staged; 212 | }; 213 | 214 | MrUploader.prototype.resetCroppingArea = function() { 215 | this.$croppingArea.html(this.getCroppingAreaContent()); 216 | return this.hidePhotoActionElements(); 217 | }; 218 | 219 | MrUploader.prototype.onCancelClick = function(e) { 220 | this.resetCroppingArea(); 221 | this.setStaged(null); 222 | return this.$preview.remove(); 223 | }; 224 | 225 | MrUploader.prototype.onUploadClick = function(e) { 226 | var $overlay, crop, meta, photo, request, url; 227 | e.preventDefault(); 228 | if (this.staged == null) { 229 | return alert('Please choose a photo to upload'); 230 | } 231 | url = this.$options.uploadUrl; 232 | photo = this.staged.$image.attr('src'); 233 | meta = this.staged.meta; 234 | crop = this.staged.crop; 235 | $overlay = this.getPreviewOverlay(); 236 | request = $.ajax({ 237 | type: 'POST', 238 | url: url, 239 | cache: false, 240 | dataType: 'json', 241 | data: { 242 | photo: photo, 243 | meta: meta, 244 | crop: crop 245 | }, 246 | beforeSend: (function(_this) { 247 | return function(xhr, settings) { 248 | _this.$preview.find('.mr-uploader-preview-overlay').each(function() { 249 | return this.remove(); 250 | }); 251 | _this.$preview.prepend($overlay); 252 | return _this.Jcrop.disable(); 253 | }; 254 | })(this) 255 | }); 256 | request.done((function(_this) { 257 | return function(response, status, xhr) { 258 | _this.staged.response = response; 259 | _this.uploads.push(_this.staged); 260 | _this.resetCroppingArea(); 261 | $overlay.html('✓'); 262 | $(_this).trigger('upload', _this.staged); 263 | return _this.setStaged(null); 264 | }; 265 | })(this)); 266 | return request.fail((function(_this) { 267 | return function(xhr, status, error) { 268 | return $overlay.addClass('error').html('× Upload failed, please retry'); 269 | }; 270 | })(this)); 271 | }; 272 | 273 | MrUploader.prototype.getPreviewOverlay = function() { 274 | return $('
').append('
'); 275 | }; 276 | 277 | MrUploader.prototype.onUploaderFileChanged = function(e) { 278 | var file, input, reader, _i, _len, _ref; 279 | input = this.$input[0]; 280 | if ((input.files != null) && input.files.length > 0) { 281 | reader = new FileReader(); 282 | reader.onload = this.onReaderLoad; 283 | _ref = input.files; 284 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 285 | file = _ref[_i]; 286 | reader.readAsDataURL(file); 287 | } 288 | this.$input.hide(); 289 | return this.showPhotoActionElements(); 290 | } 291 | }; 292 | 293 | MrUploader.prototype.onReaderLoad = function(e) { 294 | var crop, img, meta, previewImage, self; 295 | img = $(''); 296 | crop = this.$options.crop; 297 | meta = this.getStagedFileMeta(); 298 | this.$preview = $('
'); 299 | previewImage = $('').attr('src', e.target.result); 300 | this.$preview.html(previewImage); 301 | this.$previews.prepend(this.$preview); 302 | crop.onSelect = (function(_this) { 303 | return function(crop) { 304 | return _this.onCroppingSelected(crop, img, meta); 305 | }; 306 | })(this); 307 | crop.onChange = (function(_this) { 308 | return function(crop) { 309 | return _this.changePreview(crop, previewImage); 310 | }; 311 | })(this); 312 | this.$photos.html(img); 313 | self = this; 314 | return img.Jcrop(crop, function() { 315 | return self.Jcrop = this; 316 | }); 317 | }; 318 | 319 | MrUploader.prototype.getPreviewWidth = function() { 320 | switch (this.$options.aspectRatio) { 321 | case 'square': 322 | case 'portrait': 323 | return 200; 324 | case 'landscape': 325 | return 300; 326 | } 327 | }; 328 | 329 | MrUploader.prototype.getPreviewHeight = function() { 330 | switch (this.$options.aspectRatio) { 331 | case 'square': 332 | case 'landscape': 333 | return 200; 334 | case 'portrait': 335 | return 300; 336 | } 337 | }; 338 | 339 | MrUploader.prototype.changePreview = function(crop, $thumbnail) { 340 | var height, rx, ry, width; 341 | if (this.staged != null) { 342 | width = this.getPreviewWidth(); 343 | height = this.getPreviewHeight(); 344 | rx = width / crop.w; 345 | ry = height / crop.h; 346 | return $thumbnail.css({ 347 | marginTop: '-' + Math.round(ry * crop.y) + 'px', 348 | marginLeft: '-' + Math.round(rx * crop.x) + 'px', 349 | width: Math.round(rx * this.staged.meta.width) + 'px', 350 | height: Math.round(ry * this.staged.meta.height) + 'px' 351 | }); 352 | } 353 | }; 354 | 355 | MrUploader.prototype.getStagedFileMeta = function() { 356 | var file, input; 357 | input = this.$input[0]; 358 | file = input.files[0]; 359 | return { 360 | name: file.name, 361 | size: file.size, 362 | type: file.type 363 | }; 364 | }; 365 | 366 | MrUploader.prototype.onCloseClick = function() { 367 | return this.hideFullscreen(); 368 | }; 369 | 370 | MrUploader.prototype.showFullscreen = function() { 371 | return this.$container.fadeIn(); 372 | }; 373 | 374 | MrUploader.prototype.show = function() { 375 | return this.showFullscreen(); 376 | }; 377 | 378 | MrUploader.prototype.setSquareAspectRatio = function() { 379 | var _ref, _ref1, _ref2, _ref3; 380 | if (this.$options.aspectRatio !== 'square') { 381 | if ((_ref = this.$preview) != null) { 382 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 383 | } 384 | this.$options.aspectRatio = 'square'; 385 | this.$options.crop.aspectRatio = 2 / 2; 386 | this.$options.crop.minSize = [200, 200]; 387 | if ((_ref1 = this.Jcrop) != null) { 388 | _ref1.setOptions(this.$options.crop); 389 | } 390 | if ((_ref2 = this.$preview) != null) { 391 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 392 | } 393 | return (_ref3 = this.squareInput) != null ? _ref3.attr('checked', true) : void 0; 394 | } 395 | }; 396 | 397 | MrUploader.prototype.setPortraitAspectRatio = function() { 398 | var _ref, _ref1, _ref2, _ref3; 399 | if (this.$options.aspectRatio !== 'portrait') { 400 | if ((_ref = this.$preview) != null) { 401 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 402 | } 403 | this.$options.aspectRatio = 'portrait'; 404 | this.$options.crop.aspectRatio = 2 / 3; 405 | this.$options.crop.minSize = [200, 300]; 406 | if ((_ref1 = this.Jcrop) != null) { 407 | _ref1.setOptions(this.$options.crop); 408 | } 409 | if ((_ref2 = this.$preview) != null) { 410 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 411 | } 412 | return (_ref3 = this.portraitInput) != null ? _ref3.attr('checked', true) : void 0; 413 | } 414 | }; 415 | 416 | MrUploader.prototype.setLandscapeAspectRatio = function() { 417 | var _ref, _ref1, _ref2, _ref3; 418 | if (this.$options.aspectRatio !== 'landscape') { 419 | if ((_ref = this.$preview) != null) { 420 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 421 | } 422 | this.$options.aspectRatio = 'landscape'; 423 | this.$options.crop.aspectRatio = 3 / 2; 424 | this.$options.crop.minSize = [300, 200]; 425 | if ((_ref1 = this.Jcrop) != null) { 426 | _ref1.setOptions(this.$options.crop); 427 | } 428 | if ((_ref2 = this.$preview) != null) { 429 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 430 | } 431 | return (_ref3 = this.landscapeInput) != null ? _ref3.attr('checked', true) : void 0; 432 | } 433 | }; 434 | 435 | MrUploader.prototype.setAspectRatio = function(aspectRatio) { 436 | switch (aspectRatio) { 437 | case 'square': 438 | return this.setSquareAspectRatio(); 439 | case 'portrait': 440 | return this.setPortraitAspectRatio(); 441 | case 'landscape': 442 | return this.setLandscapeAspectRatio(); 443 | } 444 | }; 445 | 446 | MrUploader.prototype.hideFullscreen = function() { 447 | return this.$container.fadeOut(); 448 | }; 449 | 450 | return MrUploader; 451 | 452 | })(); 453 | return $.fn.extend({ 454 | mrUploader: function() { 455 | var $this, args, data, option, upload; 456 | option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 457 | $this = this.first(); 458 | data = $this.data('mrUploader'); 459 | if (!data) { 460 | upload = new MrUploader(this, option); 461 | $this.data('mrUploader', (data = upload)); 462 | return upload; 463 | } 464 | if (typeof option === 'string') { 465 | return data[optiokn].apply(data, args); 466 | } 467 | } 468 | }); 469 | })(window.jQuery, window); 470 | -------------------------------------------------------------------------------- /dist/js/mr-uploader.all.min.js: -------------------------------------------------------------------------------- 1 | /*! MrUploader - v0.1.0 - 2015-03-18 2 | * http://github.com/vinelab/mr-uploader 3 | * Copyright (c) 2015 Vinelab; Licensed MIT */ 4 | !function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){"object"!=typeof b&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){"function"!=typeof d[b]&&(d[b]=function(){})})}function o(a,b,c){if(e=l(D),bc.setCursor("move"===a?a:a+"-resize"),"move"===a)return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(d.aspectRatio)switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}else switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys(),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:"move"!==a||d.allowMove?(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1):!1}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,"touch"===a.type.substring(0,5)),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("
").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(!X){var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),100>q?(bh(k),t()):(bb.done(),bb.animMode(!1),"function"==typeof b&&b.call(bs))}}();t()}}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2],a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+2*L).height(F+2*L),G.width(E).height(F),ba.resize(E,F),bm(),"function"==typeof b&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb.setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var e,d=a.extend({},a.Jcrop.defaults),f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);"object"!=typeof b&&(b=a(b)[0]),"object"!=typeof c&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if("IMG"==b.tagName){if(0!=A[0].width&&0!=A[0].height)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id").css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,null===d.shade&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("
").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("
"),I=a("
").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("
").width("100%").height("100%").css("zIndex",320),K=a("
").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var P,Q,R,S,T,U,W,X,Y,L=d.boundary,M=y().width(E+2*L).height(F+2*L).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity;e=l(D);var Z=function(){function a(){var d,a={},b=["touchstart","touchmove","touchend"],c=document.createElement("div");try{for(d=0;da+f&&(f-=f+a),0>b+g&&(g-=g+b),e+g>F&&(g+=F-(e+g)),c+f>E&&(f+=E-(c+f)),a+=f,c+=f,b+=g,e+=g}function l(a){var b=m();switch(a){case"ne":return[b.x2,b.y];case"nw":return[b.x,b.y];case"se":return[b.x2,b.y2];case"sw":return[b.x,b.y2]}}function m(){if(!d.aspectRatio)return p();var r,s,t,u,f=d.aspectRatio,g=d.minSize[0]/T,h=d.maxSize[0]/T,i=d.maxSize[1]/U,j=c-a,k=e-b,l=Math.abs(j),m=Math.abs(k),n=l/m;return 0===h&&(h=10*E),0===i&&(i=10*F),f>n?(s=e,t=m*f,r=0>j?a-t:t+a,0>r?(r=0,u=Math.abs((r-a)/f),s=0>k?b-u:u+b):r>E&&(r=E,u=Math.abs((r-a)/f),s=0>k?b-u:u+b)):(r=c,u=l/f,s=0>k?b-u:b+u,0>s?(s=0,t=Math.abs((s-b)*f),r=0>j?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=0>j?a-t:t+a)),r>a?(g>r-a?r=a+g:r-a>h&&(r=a+h),s=s>b?b+(r-a)/f:b-(r-a)/f):a>r&&(g>a-r?r=a-g:a-r>h&&(r=a-h),s=s>b?b+(a-r)/f:b-(a-r)/f),0>r?(a-=r,r=0):r>E&&(a-=r-E,r=E),0>s?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return a>c&&(e=c,f=a),b>d&&(g=d,h=b),[e,g,f,h]}function p(){var g,d=c-a,f=e-b;return P&&Math.abs(d)>P&&(c=d>0?a+P:a-P),Q&&Math.abs(f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)0?b+S/U:b-S/U),R/T&&Math.abs(d)0?a+R/T:a-R/T),0>a&&(c-=a,a-=a),0>b&&(e-=b,b-=b),0>c&&(a-=c,c-=c),0>e&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var f,g,a=0,b=0,c=0,e=0;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("
").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb.isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("
").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("
").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("
").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("
").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if("api"===b)return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else"IMG"==this.tagName?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges:!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}}(jQuery);var __bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__slice=[].slice;!function($){var MrUploader;return MrUploader=function(){function MrUploader(el,options){this.hideFullscreen=__bind(this.hideFullscreen,this),this.setAspectRatio=__bind(this.setAspectRatio,this),this.setLandscapeAspectRatio=__bind(this.setLandscapeAspectRatio,this),this.setPortraitAspectRatio=__bind(this.setPortraitAspectRatio,this),this.setSquareAspectRatio=__bind(this.setSquareAspectRatio,this),this.show=__bind(this.show,this),this.showFullscreen=__bind(this.showFullscreen,this),this.onCloseClick=__bind(this.onCloseClick,this),this.getStagedFileMeta=__bind(this.getStagedFileMeta,this),this.changePreview=__bind(this.changePreview,this),this.getPreviewHeight=__bind(this.getPreviewHeight,this),this.getPreviewWidth=__bind(this.getPreviewWidth,this),this.onReaderLoad=__bind(this.onReaderLoad,this),this.onUploaderFileChanged=__bind(this.onUploaderFileChanged,this),this.onUploadClick=__bind(this.onUploadClick,this),this.onCancelClick=__bind(this.onCancelClick,this),this.resetCroppingArea=__bind(this.resetCroppingArea,this),this.setStaged=__bind(this.setStaged,this),this.onCroppingSelected=__bind(this.onCroppingSelected,this),this.showPhotoActionElements=__bind(this.showPhotoActionElements,this),this.hidePhotoActionElements=__bind(this.hidePhotoActionElements,this),this.getCroppingAreaContent=__bind(this.getCroppingAreaContent,this),this.getRatioOptions=__bind(this.getRatioOptions,this),this.getHeaderContent=__bind(this.getHeaderContent,this),this.onElementClick=__bind(this.onElementClick,this),this.on=__bind(this.on,this),this.$el=$(el),this.$options=$.extend(!0,{},this.defaults,options),this.photoActionsElements=[],this.addContent(),this.$options.onClick===!0&&this.$el.click(this.onElementClick),this.setStaged(null),this.uploads=[]}return MrUploader.prototype.defaults={multiple:!0,cropping:!0,onClick:!0,uploadUrl:"/upload.php",aspectRatio:"landscape",crop:{boxWidth:800,aspectRatio:1.5,keySupport:!1,allowSelect:!1,minSize:[300,200],setSelect:[0,0,600,400]}},MrUploader.prototype.on=function(event,callback){return $(this).on(event,callback)},MrUploader.prototype.onElementClick=function(e){return e.preventDefault(),this.showFullscreen()},MrUploader.prototype.getHeaderContent=function(){var close,header,ratioOptions,title;return header=$("
"),close=$('

×

'),close.click(this.onCloseClick),title=$("

").text("Choose & Crop"),ratioOptions=this.getRatioOptions(),this.photoActionsElements.push(ratioOptions),header.append(close,title,ratioOptions),header},MrUploader.prototype.getRatioOptions=function(){var landscape,landscapeLabel,portrait,portraitLabel,square,squareLabel;return squareLabel=$(' '),this.squareInput=$(' '),this.squareInput.click(function(_this){return function(){return _this.setSquareAspectRatio()}}(this)),"square"===this.$options.aspectRatio&&this.squareInput.attr("checked",!0),square=$("
").append(squareLabel,this.squareInput),portraitLabel=$(' '),this.portraitInput=$(' '),"portrait"===this.$options.aspectRatio&&this.portraitInput.attr("checked",!0),this.portraitInput.click(function(_this){return function(){return _this.setPortraitAspectRatio()}}(this)),portrait=$("
").append(portraitLabel,this.portraitInput),landscapeLabel=$(' '),this.landscapeInput=$(' '),"landscape"===this.$options.aspectRatio&&this.landscapeInput.attr("checked",!0),this.landscapeInput.click(function(_this){return function(){return _this.setLandscapeAspectRatio()}}(this)),landscape=$("
").append(landscapeLabel,this.landscapeInput),$('
').append(square).append(portrait).append(landscape)},MrUploader.prototype.getCroppingAreaContent=function(){var cancel,crop,upload;return crop=$("
"),this.$input=$(''),this.$input.change(this.onUploaderFileChanged),crop.append(this.$input),this.$photos=$('
 
'),crop.append(this.$photos),upload=$(''),upload.click(this.onUploadClick),cancel=$(''),cancel.click(this.onCancelClick),this.photoActionsElements.push(upload,cancel),crop.append(upload),crop.append(cancel),crop},MrUploader.prototype.addContent=function(){return this.$container=$("
").hide().addClass("mr-uploader-fullscreen-mode").css("text-align","center"),this.$container.append(this.getHeaderContent()),this.$croppingArea=this.getCroppingAreaContent(),this.$container.append(this.$croppingArea),this.$container.append("
"),this.$previews=$("
"),this.$container.append(this.$previews),this.hidePhotoActionElements(),$("body").append(this.$container)},MrUploader.prototype.hidePhotoActionElements=function(){var element,_i,_len,_ref,_results;for(_ref=this.photoActionsElements,_results=[],_i=0,_len=_ref.length;_len>_i;_i++)element=_ref[_i],_results.push(element.hide());return _results},MrUploader.prototype.showPhotoActionElements=function(){var element,_i,_len,_ref,_results;for(_ref=this.photoActionsElements,_results=[],_i=0,_len=_ref.length;_len>_i;_i++)element=_ref[_i],_results.push(element.show());return _results},MrUploader.prototype.onCroppingSelected=function(crop,image,meta){return crop={x:Math.round(crop.x),y:Math.round(crop.y),x2:Math.round(crop.x2),y2:Math.round(crop.y2),width:Math.round(crop.w),height:Math.round(crop.h)},meta.width=image.width(),meta.height=image.height(),this.setStaged({$image:image,meta:meta,crop:crop})},MrUploader.prototype.setStaged=function(staged){this.staged=staged},MrUploader.prototype.resetCroppingArea=function(){return this.$croppingArea.html(this.getCroppingAreaContent()),this.hidePhotoActionElements()},MrUploader.prototype.onCancelClick=function(){return this.resetCroppingArea(),this.setStaged(null),this.$preview.remove()},MrUploader.prototype.onUploadClick=function(e){var $overlay,crop,meta,photo,request,url;return e.preventDefault(),null==this.staged?alert("Please choose a photo to upload"):(url=this.$options.uploadUrl,photo=this.staged.$image.attr("src"),meta=this.staged.meta,crop=this.staged.crop,$overlay=this.getPreviewOverlay(),request=$.ajax({type:"POST",url:url,cache:!1,dataType:"json",data:{photo:photo,meta:meta,crop:crop},beforeSend:function(_this){return function(){return _this.$preview.find(".mr-uploader-preview-overlay").each(function(){return this.remove()}),_this.$preview.prepend($overlay),_this.Jcrop.disable()}}(this)}),request.done(function(_this){return function(response){return _this.staged.response=response,_this.uploads.push(_this.staged),_this.resetCroppingArea(),$overlay.html("✓"),$(_this).trigger("upload",_this.staged),_this.setStaged(null)}}(this)),request.fail(function(){return function(){return $overlay.addClass("error").html("× Upload failed, please retry")}}(this)))},MrUploader.prototype.getPreviewOverlay=function(){return $('
').append('
')},MrUploader.prototype.onUploaderFileChanged=function(){var file,input,reader,_i,_len,_ref;if(input=this.$input[0],null!=input.files&&input.files.length>0){for(reader=new FileReader,reader.onload=this.onReaderLoad,_ref=input.files,_i=0,_len=_ref.length;_len>_i;_i++)file=_ref[_i],reader.readAsDataURL(file);return this.$input.hide(),this.showPhotoActionElements()}},MrUploader.prototype.onReaderLoad=function(e){var crop,img,meta,previewImage,self;return img=$(''),crop=this.$options.crop,meta=this.getStagedFileMeta(),this.$preview=$('
'),previewImage=$("").attr("src",e.target.result),this.$preview.html(previewImage),this.$previews.prepend(this.$preview),crop.onSelect=function(_this){return function(crop){return _this.onCroppingSelected(crop,img,meta)}}(this),crop.onChange=function(_this){return function(crop){return _this.changePreview(crop,previewImage)}}(this),this.$photos.html(img),self=this,img.Jcrop(crop,function(){return self.Jcrop=this})},MrUploader.prototype.getPreviewWidth=function(){switch(this.$options.aspectRatio){case"square":case"portrait":return 200;case"landscape":return 300}},MrUploader.prototype.getPreviewHeight=function(){switch(this.$options.aspectRatio){case"square":case"landscape":return 200;case"portrait":return 300}},MrUploader.prototype.changePreview=function(crop,$thumbnail){var height,rx,ry,width;return null!=this.staged?(width=this.getPreviewWidth(),height=this.getPreviewHeight(),rx=width/crop.w,ry=height/crop.h,$thumbnail.css({marginTop:"-"+Math.round(ry*crop.y)+"px",marginLeft:"-"+Math.round(rx*crop.x)+"px",width:Math.round(rx*this.staged.meta.width)+"px",height:Math.round(ry*this.staged.meta.height)+"px"})):void 0},MrUploader.prototype.getStagedFileMeta=function(){var file,input;return input=this.$input[0],file=input.files[0],{name:file.name,size:file.size,type:file.type}},MrUploader.prototype.onCloseClick=function(){return this.hideFullscreen()},MrUploader.prototype.showFullscreen=function(){return this.$container.fadeIn()},MrUploader.prototype.show=function(){return this.showFullscreen()},MrUploader.prototype.setSquareAspectRatio=function(){var _ref,_ref1,_ref2,_ref3;return"square"!==this.$options.aspectRatio?(null!=(_ref=this.$preview)&&_ref.removeClass("mr-uploader-ar-"+this.$options.aspectRatio),this.$options.aspectRatio="square",this.$options.crop.aspectRatio=1,this.$options.crop.minSize=[200,200],null!=(_ref1=this.Jcrop)&&_ref1.setOptions(this.$options.crop),null!=(_ref2=this.$preview)&&_ref2.addClass("mr-uploader-ar-"+this.$options.aspectRatio),null!=(_ref3=this.squareInput)?_ref3.attr("checked",!0):void 0):void 0},MrUploader.prototype.setPortraitAspectRatio=function(){var _ref,_ref1,_ref2,_ref3;return"portrait"!==this.$options.aspectRatio?(null!=(_ref=this.$preview)&&_ref.removeClass("mr-uploader-ar-"+this.$options.aspectRatio),this.$options.aspectRatio="portrait",this.$options.crop.aspectRatio=2/3,this.$options.crop.minSize=[200,300],null!=(_ref1=this.Jcrop)&&_ref1.setOptions(this.$options.crop),null!=(_ref2=this.$preview)&&_ref2.addClass("mr-uploader-ar-"+this.$options.aspectRatio),null!=(_ref3=this.portraitInput)?_ref3.attr("checked",!0):void 0):void 0},MrUploader.prototype.setLandscapeAspectRatio=function(){var _ref,_ref1,_ref2,_ref3;return"landscape"!==this.$options.aspectRatio?(null!=(_ref=this.$preview)&&_ref.removeClass("mr-uploader-ar-"+this.$options.aspectRatio),this.$options.aspectRatio="landscape",this.$options.crop.aspectRatio=1.5,this.$options.crop.minSize=[300,200],null!=(_ref1=this.Jcrop)&&_ref1.setOptions(this.$options.crop),null!=(_ref2=this.$preview)&&_ref2.addClass("mr-uploader-ar-"+this.$options.aspectRatio),null!=(_ref3=this.landscapeInput)?_ref3.attr("checked",!0):void 0):void 0},MrUploader.prototype.setAspectRatio=function(aspectRatio){switch(aspectRatio){case"square":return this.setSquareAspectRatio();case"portrait":return this.setPortraitAspectRatio();case"landscape":return this.setLandscapeAspectRatio()}},MrUploader.prototype.hideFullscreen=function(){return this.$container.fadeOut()},MrUploader}(),$.fn.extend({mrUploader:function(){var $this,args,data,option,upload;return option=arguments[0],args=2<=arguments.length?__slice.call(arguments,1):[],$this=this.first(),data=$this.data("mrUploader"),data?"string"==typeof option?data[optiokn].apply(data,args):void 0:(upload=new MrUploader(this,option),$this.data("mrUploader",data=upload),upload)}})}(window.jQuery,window); -------------------------------------------------------------------------------- /dist/js/mr-uploader.js: -------------------------------------------------------------------------------- 1 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 2 | __slice = [].slice; 3 | 4 | (function($, window) { 5 | var MrUploader; 6 | MrUploader = (function() { 7 | MrUploader.prototype.defaults = { 8 | multiple: true, 9 | cropping: true, 10 | onClick: true, 11 | uploadUrl: '/upload.php', 12 | aspectRatio: 'landscape', 13 | crop: { 14 | boxWidth: 800, 15 | aspectRatio: 3 / 2, 16 | keySupport: false, 17 | allowSelect: false, 18 | minSize: [300, 200], 19 | setSelect: [0, 0, 600, 400] 20 | } 21 | }; 22 | 23 | function MrUploader(el, options) { 24 | this.hideFullscreen = __bind(this.hideFullscreen, this); 25 | this.setAspectRatio = __bind(this.setAspectRatio, this); 26 | this.setLandscapeAspectRatio = __bind(this.setLandscapeAspectRatio, this); 27 | this.setPortraitAspectRatio = __bind(this.setPortraitAspectRatio, this); 28 | this.setSquareAspectRatio = __bind(this.setSquareAspectRatio, this); 29 | this.show = __bind(this.show, this); 30 | this.showFullscreen = __bind(this.showFullscreen, this); 31 | this.onCloseClick = __bind(this.onCloseClick, this); 32 | this.getStagedFileMeta = __bind(this.getStagedFileMeta, this); 33 | this.changePreview = __bind(this.changePreview, this); 34 | this.getPreviewHeight = __bind(this.getPreviewHeight, this); 35 | this.getPreviewWidth = __bind(this.getPreviewWidth, this); 36 | this.onReaderLoad = __bind(this.onReaderLoad, this); 37 | this.onUploaderFileChanged = __bind(this.onUploaderFileChanged, this); 38 | this.onUploadClick = __bind(this.onUploadClick, this); 39 | this.onCancelClick = __bind(this.onCancelClick, this); 40 | this.resetCroppingArea = __bind(this.resetCroppingArea, this); 41 | this.setStaged = __bind(this.setStaged, this); 42 | this.onCroppingSelected = __bind(this.onCroppingSelected, this); 43 | this.showPhotoActionElements = __bind(this.showPhotoActionElements, this); 44 | this.hidePhotoActionElements = __bind(this.hidePhotoActionElements, this); 45 | this.getCroppingAreaContent = __bind(this.getCroppingAreaContent, this); 46 | this.getRatioOptions = __bind(this.getRatioOptions, this); 47 | this.getHeaderContent = __bind(this.getHeaderContent, this); 48 | this.onElementClick = __bind(this.onElementClick, this); 49 | this.on = __bind(this.on, this); 50 | this.$el = $(el); 51 | this.$options = $.extend(true, {}, this.defaults, options); 52 | this.photoActionsElements = []; 53 | this.addContent(); 54 | if (this.$options.onClick === true) { 55 | this.$el.click(this.onElementClick); 56 | } 57 | this.setStaged(null); 58 | this.uploads = []; 59 | } 60 | 61 | MrUploader.prototype.on = function(event, callback) { 62 | return $(this).on(event, callback); 63 | }; 64 | 65 | MrUploader.prototype.onElementClick = function(e) { 66 | e.preventDefault(); 67 | return this.showFullscreen(); 68 | }; 69 | 70 | MrUploader.prototype.getHeaderContent = function() { 71 | var close, header, ratioOptions, title; 72 | header = $('
'); 73 | close = $('

×

'); 74 | close.click(this.onCloseClick); 75 | title = $('

').text('Choose & Crop'); 76 | ratioOptions = this.getRatioOptions(); 77 | this.photoActionsElements.push(ratioOptions); 78 | header.append(close, title, ratioOptions); 79 | return header; 80 | }; 81 | 82 | MrUploader.prototype.getRatioOptions = function() { 83 | var landscape, landscapeLabel, portrait, portraitLabel, square, squareLabel; 84 | squareLabel = $(' '); 85 | this.squareInput = $(' '); 86 | this.squareInput.click((function(_this) { 87 | return function() { 88 | return _this.setSquareAspectRatio(); 89 | }; 90 | })(this)); 91 | if (this.$options.aspectRatio === 'square') { 92 | this.squareInput.attr('checked', true); 93 | } 94 | square = $('
').append(squareLabel, this.squareInput); 95 | portraitLabel = $(' '); 96 | this.portraitInput = $(' '); 97 | if (this.$options.aspectRatio === 'portrait') { 98 | this.portraitInput.attr('checked', true); 99 | } 100 | this.portraitInput.click((function(_this) { 101 | return function() { 102 | return _this.setPortraitAspectRatio(); 103 | }; 104 | })(this)); 105 | portrait = $('
').append(portraitLabel, this.portraitInput); 106 | landscapeLabel = $(' '); 107 | this.landscapeInput = $(' '); 108 | if (this.$options.aspectRatio === 'landscape') { 109 | this.landscapeInput.attr('checked', true); 110 | } 111 | this.landscapeInput.click((function(_this) { 112 | return function() { 113 | return _this.setLandscapeAspectRatio(); 114 | }; 115 | })(this)); 116 | landscape = $('
').append(landscapeLabel, this.landscapeInput); 117 | return $('
').append(square).append(portrait).append(landscape); 118 | }; 119 | 120 | MrUploader.prototype.getCroppingAreaContent = function() { 121 | var cancel, crop, upload; 122 | crop = $('
'); 123 | this.$input = $(''); 124 | this.$input.change(this.onUploaderFileChanged); 125 | crop.append(this.$input); 126 | this.$photos = $('
 
'); 127 | crop.append(this.$photos); 128 | upload = $(''); 129 | upload.click(this.onUploadClick); 130 | cancel = $(''); 131 | cancel.click(this.onCancelClick); 132 | this.photoActionsElements.push(upload, cancel); 133 | crop.append(upload); 134 | crop.append(cancel); 135 | return crop; 136 | }; 137 | 138 | MrUploader.prototype.addContent = function() { 139 | this.$container = $('
').hide().addClass('mr-uploader-fullscreen-mode').css('text-align', 'center'); 140 | this.$container.append(this.getHeaderContent()); 141 | this.$croppingArea = this.getCroppingAreaContent(); 142 | this.$container.append(this.$croppingArea); 143 | this.$container.append('
'); 144 | this.$previews = $('
'); 145 | this.$container.append(this.$previews); 146 | this.hidePhotoActionElements(); 147 | return $('body').append(this.$container); 148 | }; 149 | 150 | MrUploader.prototype.hidePhotoActionElements = function() { 151 | var element, _i, _len, _ref, _results; 152 | _ref = this.photoActionsElements; 153 | _results = []; 154 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 155 | element = _ref[_i]; 156 | _results.push(element.hide()); 157 | } 158 | return _results; 159 | }; 160 | 161 | MrUploader.prototype.showPhotoActionElements = function() { 162 | var element, _i, _len, _ref, _results; 163 | _ref = this.photoActionsElements; 164 | _results = []; 165 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 166 | element = _ref[_i]; 167 | _results.push(element.show()); 168 | } 169 | return _results; 170 | }; 171 | 172 | MrUploader.prototype.onCroppingSelected = function(crop, image, meta) { 173 | crop = { 174 | x: Math.round(crop.x), 175 | y: Math.round(crop.y), 176 | x2: Math.round(crop.x2), 177 | y2: Math.round(crop.y2), 178 | width: Math.round(crop.w), 179 | height: Math.round(crop.h) 180 | }; 181 | meta.width = image.width(); 182 | meta.height = image.height(); 183 | return this.setStaged({ 184 | $image: image, 185 | meta: meta, 186 | crop: crop 187 | }); 188 | }; 189 | 190 | MrUploader.prototype.setStaged = function(staged) { 191 | this.staged = staged; 192 | }; 193 | 194 | MrUploader.prototype.resetCroppingArea = function() { 195 | this.$croppingArea.html(this.getCroppingAreaContent()); 196 | return this.hidePhotoActionElements(); 197 | }; 198 | 199 | MrUploader.prototype.onCancelClick = function(e) { 200 | this.resetCroppingArea(); 201 | this.setStaged(null); 202 | return this.$preview.remove(); 203 | }; 204 | 205 | MrUploader.prototype.onUploadClick = function(e) { 206 | var $overlay, crop, meta, photo, request, url; 207 | e.preventDefault(); 208 | if (this.staged == null) { 209 | return alert('Please choose a photo to upload'); 210 | } 211 | url = this.$options.uploadUrl; 212 | photo = this.staged.$image.attr('src'); 213 | meta = this.staged.meta; 214 | crop = this.staged.crop; 215 | $overlay = this.getPreviewOverlay(); 216 | request = $.ajax({ 217 | type: 'POST', 218 | url: url, 219 | cache: false, 220 | dataType: 'json', 221 | data: { 222 | photo: photo, 223 | meta: meta, 224 | crop: crop 225 | }, 226 | beforeSend: (function(_this) { 227 | return function(xhr, settings) { 228 | _this.$preview.find('.mr-uploader-preview-overlay').each(function() { 229 | return this.remove(); 230 | }); 231 | _this.$preview.prepend($overlay); 232 | return _this.Jcrop.disable(); 233 | }; 234 | })(this) 235 | }); 236 | request.done((function(_this) { 237 | return function(response, status, xhr) { 238 | _this.staged.response = response; 239 | _this.uploads.push(_this.staged); 240 | _this.resetCroppingArea(); 241 | $overlay.html('✓'); 242 | $(_this).trigger('upload', _this.staged); 243 | return _this.setStaged(null); 244 | }; 245 | })(this)); 246 | return request.fail((function(_this) { 247 | return function(xhr, status, error) { 248 | return $overlay.addClass('error').html('× Upload failed, please retry'); 249 | }; 250 | })(this)); 251 | }; 252 | 253 | MrUploader.prototype.getPreviewOverlay = function() { 254 | return $('
').append('
'); 255 | }; 256 | 257 | MrUploader.prototype.onUploaderFileChanged = function(e) { 258 | var file, input, reader, _i, _len, _ref; 259 | input = this.$input[0]; 260 | if ((input.files != null) && input.files.length > 0) { 261 | reader = new FileReader(); 262 | reader.onload = this.onReaderLoad; 263 | _ref = input.files; 264 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 265 | file = _ref[_i]; 266 | reader.readAsDataURL(file); 267 | } 268 | this.$input.hide(); 269 | return this.showPhotoActionElements(); 270 | } 271 | }; 272 | 273 | MrUploader.prototype.onReaderLoad = function(e) { 274 | var crop, img, meta, previewImage, self; 275 | img = $(''); 276 | crop = this.$options.crop; 277 | meta = this.getStagedFileMeta(); 278 | this.$preview = $('
'); 279 | previewImage = $('').attr('src', e.target.result); 280 | this.$preview.html(previewImage); 281 | this.$previews.prepend(this.$preview); 282 | crop.onSelect = (function(_this) { 283 | return function(crop) { 284 | return _this.onCroppingSelected(crop, img, meta); 285 | }; 286 | })(this); 287 | crop.onChange = (function(_this) { 288 | return function(crop) { 289 | return _this.changePreview(crop, previewImage); 290 | }; 291 | })(this); 292 | this.$photos.html(img); 293 | self = this; 294 | return img.Jcrop(crop, function() { 295 | return self.Jcrop = this; 296 | }); 297 | }; 298 | 299 | MrUploader.prototype.getPreviewWidth = function() { 300 | switch (this.$options.aspectRatio) { 301 | case 'square': 302 | case 'portrait': 303 | return 200; 304 | case 'landscape': 305 | return 300; 306 | } 307 | }; 308 | 309 | MrUploader.prototype.getPreviewHeight = function() { 310 | switch (this.$options.aspectRatio) { 311 | case 'square': 312 | case 'landscape': 313 | return 200; 314 | case 'portrait': 315 | return 300; 316 | } 317 | }; 318 | 319 | MrUploader.prototype.changePreview = function(crop, $thumbnail) { 320 | var height, rx, ry, width; 321 | if (this.staged != null) { 322 | width = this.getPreviewWidth(); 323 | height = this.getPreviewHeight(); 324 | rx = width / crop.w; 325 | ry = height / crop.h; 326 | return $thumbnail.css({ 327 | marginTop: '-' + Math.round(ry * crop.y) + 'px', 328 | marginLeft: '-' + Math.round(rx * crop.x) + 'px', 329 | width: Math.round(rx * this.staged.meta.width) + 'px', 330 | height: Math.round(ry * this.staged.meta.height) + 'px' 331 | }); 332 | } 333 | }; 334 | 335 | MrUploader.prototype.getStagedFileMeta = function() { 336 | var file, input; 337 | input = this.$input[0]; 338 | file = input.files[0]; 339 | return { 340 | name: file.name, 341 | size: file.size, 342 | type: file.type 343 | }; 344 | }; 345 | 346 | MrUploader.prototype.onCloseClick = function() { 347 | return this.hideFullscreen(); 348 | }; 349 | 350 | MrUploader.prototype.showFullscreen = function() { 351 | return this.$container.fadeIn(); 352 | }; 353 | 354 | MrUploader.prototype.show = function() { 355 | return this.showFullscreen(); 356 | }; 357 | 358 | MrUploader.prototype.setSquareAspectRatio = function() { 359 | var _ref, _ref1, _ref2, _ref3; 360 | if (this.$options.aspectRatio !== 'square') { 361 | if ((_ref = this.$preview) != null) { 362 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 363 | } 364 | this.$options.aspectRatio = 'square'; 365 | this.$options.crop.aspectRatio = 2 / 2; 366 | this.$options.crop.minSize = [200, 200]; 367 | if ((_ref1 = this.Jcrop) != null) { 368 | _ref1.setOptions(this.$options.crop); 369 | } 370 | if ((_ref2 = this.$preview) != null) { 371 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 372 | } 373 | return (_ref3 = this.squareInput) != null ? _ref3.attr('checked', true) : void 0; 374 | } 375 | }; 376 | 377 | MrUploader.prototype.setPortraitAspectRatio = function() { 378 | var _ref, _ref1, _ref2, _ref3; 379 | if (this.$options.aspectRatio !== 'portrait') { 380 | if ((_ref = this.$preview) != null) { 381 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 382 | } 383 | this.$options.aspectRatio = 'portrait'; 384 | this.$options.crop.aspectRatio = 2 / 3; 385 | this.$options.crop.minSize = [200, 300]; 386 | if ((_ref1 = this.Jcrop) != null) { 387 | _ref1.setOptions(this.$options.crop); 388 | } 389 | if ((_ref2 = this.$preview) != null) { 390 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 391 | } 392 | return (_ref3 = this.portraitInput) != null ? _ref3.attr('checked', true) : void 0; 393 | } 394 | }; 395 | 396 | MrUploader.prototype.setLandscapeAspectRatio = function() { 397 | var _ref, _ref1, _ref2, _ref3; 398 | if (this.$options.aspectRatio !== 'landscape') { 399 | if ((_ref = this.$preview) != null) { 400 | _ref.removeClass('mr-uploader-ar-' + this.$options.aspectRatio); 401 | } 402 | this.$options.aspectRatio = 'landscape'; 403 | this.$options.crop.aspectRatio = 3 / 2; 404 | this.$options.crop.minSize = [300, 200]; 405 | if ((_ref1 = this.Jcrop) != null) { 406 | _ref1.setOptions(this.$options.crop); 407 | } 408 | if ((_ref2 = this.$preview) != null) { 409 | _ref2.addClass('mr-uploader-ar-' + this.$options.aspectRatio); 410 | } 411 | return (_ref3 = this.landscapeInput) != null ? _ref3.attr('checked', true) : void 0; 412 | } 413 | }; 414 | 415 | MrUploader.prototype.setAspectRatio = function(aspectRatio) { 416 | switch (aspectRatio) { 417 | case 'square': 418 | return this.setSquareAspectRatio(); 419 | case 'portrait': 420 | return this.setPortraitAspectRatio(); 421 | case 'landscape': 422 | return this.setLandscapeAspectRatio(); 423 | } 424 | }; 425 | 426 | MrUploader.prototype.hideFullscreen = function() { 427 | return this.$container.fadeOut(); 428 | }; 429 | 430 | return MrUploader; 431 | 432 | })(); 433 | return $.fn.extend({ 434 | mrUploader: function() { 435 | var $this, args, data, option, upload; 436 | option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 437 | $this = this.first(); 438 | data = $this.data('mrUploader'); 439 | if (!data) { 440 | upload = new MrUploader(this, option); 441 | $this.data('mrUploader', (data = upload)); 442 | return upload; 443 | } 444 | if (typeof option === 'string') { 445 | return data[optiokn].apply(data, args); 446 | } 447 | } 448 | }); 449 | })(window.jQuery, window); 450 | -------------------------------------------------------------------------------- /examples/aspect-ratio/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mr. Uploader 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 35 | 36 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mr. Uploader 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/upload.php: -------------------------------------------------------------------------------- 1 | $file, 'url' => "http://$_SERVER[HTTP_HOST]/$file"]); 20 | 21 | return true; 22 | } 23 | 24 | http_response_code(400); 25 | echo 'FAILED to upload'; 26 | 27 | return false; 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mr-uploader", 3 | "version": "1.0.0", 4 | "description": "Photo cropping and upload made easy", 5 | "main": "Gruntfile.js", 6 | "dependencies": { 7 | "grunt": "^0.4.5" 8 | }, 9 | "devDependencies": { 10 | "grunt-contrib-clean": "^0.6.0", 11 | "grunt-contrib-coffee": "^0.12.0", 12 | "grunt-contrib-concat": "^0.5.0", 13 | "grunt-contrib-cssmin": "^0.11.0", 14 | "grunt-contrib-uglify": "^0.7.0", 15 | "grunt-contrib-watch": "^0.6.1" 16 | }, 17 | "scripts": { 18 | "test": "test" 19 | }, 20 | "author": "Abed Halawi ", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | .mr-uploader-fullscreen-mode { 2 | top: 0; 3 | left: 0; 4 | width: 100%; 5 | height: 100%; 6 | z-index: 99999; 7 | position: fixed; 8 | overflow: scroll; 9 | font-family: Arial; 10 | border: 0!important; 11 | padding: 15px 30px 15px; 12 | color: #272727; 13 | background: #FAFAFB!important; 14 | } 15 | 16 | .mr-uploader-fullscreen-close { 17 | float:left; 18 | font-size: 28px; 19 | cursor: pointer; 20 | font-color: #ededed; 21 | text-decoration: none; 22 | } 23 | 24 | #mr-uploader-file-input { 25 | margin: 0 auto; 26 | padding-bottom: 10px; 27 | } 28 | 29 | #mr-uploader-images { 30 | min-height: 200px; 31 | } 32 | 33 | #mr-uploader-images .jcrop-holder { 34 | text-align: : center; 35 | margin: 0 auto; 36 | } 37 | 38 | .mr-uploader-preview { 39 | position: relative; 40 | float: left; 41 | font-size: 30px; 42 | margin-left: 10px; 43 | overflow: hidden; 44 | background-color: transparent; 45 | box-shadow: 0px 0px 5px 1px #888; 46 | -moz-box-shadow: inset 0px 0px 5px 1px #888; 47 | -webkit-box-shadow: inset 0px 0px 5px 1px #888; 48 | } 49 | 50 | .mr-uploader-ar-landscape { 51 | width: 300px; 52 | height: 200px; 53 | } 54 | 55 | .mr-uploader-ar-portrait { 56 | width: 200px; 57 | height: 300px; 58 | } 59 | 60 | .mr-uploader-ar-square { 61 | width: 200px; 62 | height: 200px; 63 | } 64 | 65 | .mr-uploader-preview-overlay { 66 | position: absolute; 67 | width: 100%; 68 | height: 100%; 69 | opacity: 0.8; 70 | text-align: center; 71 | text-decoration: bold; 72 | color: green; 73 | vertical-align: middle; 74 | line-height: 200px; 75 | text-decoration: bold; 76 | background-color: #ededed; 77 | } 78 | 79 | .mr-uploader-preview .error { 80 | color: red; 81 | font-size: 22px; 82 | } 83 | 84 | .mr-uploader-spinner { 85 | margin: 0 auto; 86 | width: 70px; 87 | text-align: center; 88 | } 89 | 90 | .mr-uploader-spinner > div { 91 | width: 18px; 92 | height: 18px; 93 | background-color: #333; 94 | 95 | border-radius: 100%; 96 | display: inline-block; 97 | -webkit-animation: bouncedelay 0.8s infinite ease-in-out; 98 | animation: bouncedelay 0.8s infinite ease-in-out; 99 | /* Prevent first frame from flickering when animation starts */ 100 | -webkit-animation-fill-mode: both; 101 | animation-fill-mode: both; 102 | } 103 | 104 | .mr-uploader-spinner-bounce1 { 105 | -webkit-animation-delay: -0.32s; 106 | animation-delay: -0.32s; 107 | } 108 | 109 | .mr-uploader-spinner-bounce2 { 110 | -webkit-animation-delay: -0.16s; 111 | animation-delay: -0.16s; 112 | } 113 | 114 | @-webkit-keyframes bouncedelay { 115 | 0%, 80%, 100% { -webkit-transform: scale(0.0) } 116 | 40% { -webkit-transform: scale(1.0) } 117 | } 118 | 119 | @keyframes bouncedelay { 120 | 0%, 80%, 100% { 121 | transform: scale(0.0); 122 | -webkit-transform: scale(0.0); 123 | } 40% { 124 | transform: scale(1.0); 125 | -webkit-transform: scale(1.0); 126 | } 127 | } 128 | 129 | .mr-uploader-ratio-options { 130 | margin: 30px 0px 30px 0px; 131 | } 132 | -------------------------------------------------------------------------------- /src/uploader.coffee: -------------------------------------------------------------------------------- 1 | (($, window) -> 2 | 3 | class MrUploader 4 | 5 | defaults: 6 | multiple: true 7 | cropping: true 8 | onClick: true 9 | uploadUrl: '/upload.php' 10 | aspectRatio: 'landscape' 11 | crop: 12 | boxWidth: 800 13 | aspectRatio: 3/2 14 | keySupport: false 15 | allowSelect: false 16 | minSize: [300, 200] 17 | setSelect: [0, 0, 600, 400] 18 | 19 | constructor: (el, options)-> 20 | @$el = $(el) 21 | @$options = $.extend(true, {}, @defaults, options) 22 | # The elements that we need to keep hold of, so that we show/hide them based on whether there's 23 | # a photo staged (chosen for upload) or not, respectively. 24 | @photoActionsElements = [] 25 | # add the content to the container 26 | @addContent() 27 | 28 | @$el.click(@onElementClick) if @$options.onClick is true 29 | @setStaged(null) 30 | # All the uploaded stuff will live here 31 | @uploads = [] 32 | 33 | on: (event, callback)=> $(@).on(event, callback) 34 | 35 | onElementClick: (e)=> 36 | e.preventDefault() 37 | @showFullscreen() 38 | 39 | getHeaderContent: => 40 | header = $('
') 41 | 42 | close = $('

×

') 43 | close.click(@onCloseClick) 44 | 45 | title = $('

').text('Choose & Crop') 46 | 47 | ratioOptions = @getRatioOptions() 48 | 49 | @photoActionsElements.push(ratioOptions) 50 | 51 | header.append(close, title, ratioOptions) 52 | 53 | return header 54 | 55 | getRatioOptions: => 56 | squareLabel = $(' ') 57 | @squareInput = $(' ') 58 | @squareInput.click => @setSquareAspectRatio() 59 | @squareInput.attr('checked', true) if @$options.aspectRatio is 'square' 60 | square = $('
').append(squareLabel, @squareInput) 61 | 62 | portraitLabel = $(' ') 63 | @portraitInput = $(' ') 64 | @portraitInput.attr('checked', true) if @$options.aspectRatio is 'portrait' 65 | @portraitInput.click => @setPortraitAspectRatio() 66 | portrait = $('
').append(portraitLabel, @portraitInput) 67 | 68 | landscapeLabel = $(' ') 69 | @landscapeInput = $(' ') 70 | @landscapeInput.attr('checked', true) if @$options.aspectRatio is 'landscape' 71 | @landscapeInput.click => @setLandscapeAspectRatio() 72 | landscape = $('
').append(landscapeLabel, @landscapeInput) 73 | 74 | return $('
') 75 | .append(square) 76 | .append(portrait) 77 | .append(landscape) 78 | 79 | getCroppingAreaContent: => 80 | crop = $('
') 81 | 82 | # Add input field 83 | @$input = $('') 84 | @$input.change @onUploaderFileChanged 85 | crop.append(@$input) 86 | 87 | # Add photos container 88 | @$photos = $('
 
') 89 | crop.append(@$photos) 90 | 91 | # Add upload button 92 | upload = $('') 93 | upload.click(@onUploadClick) 94 | 95 | cancel = $('') 96 | cancel.click(@onCancelClick) 97 | 98 | @photoActionsElements.push(upload, cancel) 99 | 100 | crop.append(upload) 101 | crop.append(cancel) 102 | 103 | return crop 104 | 105 | addContent: -> 106 | @$container = $('
') 107 | .hide() 108 | .addClass('mr-uploader-fullscreen-mode') 109 | .css('text-align', 'center') 110 | 111 | # Add header 112 | @$container.append(@getHeaderContent()) 113 | # draw the cropping area 114 | @$croppingArea = @getCroppingAreaContent() 115 | # Add the cropping area 116 | @$container.append(@$croppingArea) 117 | # separator 118 | @$container.append('
') 119 | 120 | @$previews = $('
') 121 | # previews will be added dynamically when 122 | # the image has finished reading (onReaderLoad) 123 | @$container.append(@$previews) 124 | 125 | @hidePhotoActionElements() 126 | 127 | # Append content to the DOM 128 | $('body').append(@$container) 129 | 130 | hidePhotoActionElements: => element.hide() for element in @photoActionsElements 131 | showPhotoActionElements: => element.show() for element in @photoActionsElements 132 | 133 | onCroppingSelected: (crop, image, meta)=> 134 | crop = { 135 | x: Math.round(crop.x) 136 | y: Math.round(crop.y) 137 | x2: Math.round(crop.x2) 138 | y2: Math.round(crop.y2) 139 | width: Math.round(crop.w) 140 | height: Math.round(crop.h) 141 | } 142 | 143 | meta.width = image.width() 144 | meta.height = image.height() 145 | 146 | @setStaged({$image: image, meta: meta, crop: crop}) 147 | 148 | setStaged: (@staged)=> 149 | 150 | resetCroppingArea: => 151 | # reset the cropping area 152 | @$croppingArea.html(@getCroppingAreaContent()) 153 | @hidePhotoActionElements() 154 | 155 | onCancelClick: (e)=> 156 | @resetCroppingArea() 157 | @setStaged(null) 158 | @$preview.remove() 159 | 160 | onUploadClick: (e)=> 161 | e.preventDefault() 162 | return alert('Please choose a photo to upload') if not @staged? 163 | 164 | url = @$options.uploadUrl 165 | photo = @staged.$image.attr('src') 166 | meta = @staged.meta 167 | crop = @staged.crop 168 | 169 | $overlay = @getPreviewOverlay() 170 | 171 | request = $.ajax({ 172 | type: 'POST', 173 | url: url, 174 | cache: false 175 | dataType: 'json' 176 | data: {photo: photo, meta: meta, crop: crop} 177 | beforeSend: (xhr, settings)=> 178 | # remove any previous overlays (if any) 179 | @$preview.find('.mr-uploader-preview-overlay').each -> this.remove() 180 | # add the overlay to the preview 181 | @$preview.prepend($overlay) 182 | # disable cropping 183 | @Jcrop.disable() 184 | }) 185 | 186 | request.done (response, status, xhr)=> 187 | @staged.response = response 188 | # remove staged photo 189 | @uploads.push(@staged) 190 | # reset the cropping area, preparing for another one 191 | @resetCroppingArea() 192 | # display success on uploaded image's overlay 193 | $overlay.html('✓') 194 | # tell listeners about the upload 195 | $(@).trigger('upload', @staged); 196 | # clear the stage 197 | @setStaged(null) 198 | request.fail (xhr, status, error)=> 199 | $overlay.addClass('error').html('× Upload failed, please retry') 200 | 201 | getPreviewOverlay: -> 202 | $('
') 203 | .append('
') 204 | 205 | onUploaderFileChanged: (e)=> 206 | input = @$input[0] 207 | if input.files? and input.files.length > 0 208 | reader = new FileReader() 209 | reader.onload = @onReaderLoad 210 | reader.readAsDataURL(file) for file in input.files 211 | @$input.hide() 212 | @showPhotoActionElements() 213 | 214 | onReaderLoad: (e)=> 215 | img = $('') 216 | crop = @$options.crop 217 | meta = @getStagedFileMeta() 218 | 219 | @$preview = $('
') 220 | 221 | previewImage = $('').attr('src', e.target.result) 222 | @$preview.html(previewImage) 223 | 224 | @$previews.prepend(@$preview) 225 | 226 | crop.onSelect = (crop)=> @onCroppingSelected(crop, img, meta) 227 | crop.onChange = (crop)=> @changePreview(crop, previewImage) 228 | 229 | @$photos.html(img) 230 | 231 | self = @ 232 | img.Jcrop crop, -> self.Jcrop = this 233 | 234 | getPreviewWidth: => 235 | switch @$options.aspectRatio 236 | when 'square', 'portrait' then 200 237 | when 'landscape' then 300 238 | 239 | getPreviewHeight: => 240 | switch @$options.aspectRatio 241 | when 'square', 'landscape' then 200 242 | when 'portrait' then 300 243 | 244 | changePreview: (crop, $thumbnail)=> 245 | if @staged? 246 | width = @getPreviewWidth() 247 | height = @getPreviewHeight() 248 | rx = width / crop.w 249 | ry = height / crop.h 250 | 251 | $thumbnail.css({ 252 | marginTop: '-' + Math.round(ry * crop.y) + 'px', 253 | marginLeft: '-' + Math.round(rx * crop.x) + 'px', 254 | width: Math.round(rx * @staged.meta.width) + 'px', 255 | height: Math.round(ry * @staged.meta.height) + 'px' 256 | }) 257 | 258 | getStagedFileMeta: => 259 | input = @$input[0] 260 | file = input.files[0] 261 | return { 262 | name: file.name 263 | size: file.size 264 | type: file.type 265 | } 266 | 267 | onCloseClick: => @hideFullscreen() 268 | 269 | showFullscreen: => @$container.fadeIn() 270 | 271 | show: => @showFullscreen() 272 | 273 | setSquareAspectRatio: => 274 | if @$options.aspectRatio isnt 'square' 275 | @$preview?.removeClass('mr-uploader-ar-'+@$options.aspectRatio) 276 | @$options.aspectRatio = 'square' 277 | @$options.crop.aspectRatio = 2/2 278 | @$options.crop.minSize = [200, 200] 279 | @Jcrop?.setOptions(@$options.crop) 280 | @$preview?.addClass('mr-uploader-ar-'+@$options.aspectRatio) 281 | @squareInput?.attr('checked', true) 282 | 283 | setPortraitAspectRatio: => 284 | if @$options.aspectRatio isnt 'portrait' 285 | @$preview?.removeClass('mr-uploader-ar-'+@$options.aspectRatio) 286 | @$options.aspectRatio = 'portrait' 287 | @$options.crop.aspectRatio = 2/3 288 | @$options.crop.minSize = [200, 300] 289 | @Jcrop?.setOptions(@$options.crop) 290 | @$preview?.addClass('mr-uploader-ar-'+@$options.aspectRatio) 291 | @portraitInput?.attr('checked', true) 292 | 293 | setLandscapeAspectRatio: => 294 | if @$options.aspectRatio isnt 'landscape' 295 | @$preview?.removeClass('mr-uploader-ar-'+@$options.aspectRatio) 296 | @$options.aspectRatio = 'landscape' 297 | @$options.crop.aspectRatio = 3/2 298 | @$options.crop.minSize = [300, 200] 299 | @Jcrop?.setOptions(@$options.crop) 300 | @$preview?.addClass('mr-uploader-ar-'+@$options.aspectRatio) 301 | @landscapeInput?.attr('checked', true) 302 | 303 | setAspectRatio: (aspectRatio)=> 304 | switch aspectRatio 305 | when 'square' then @setSquareAspectRatio() 306 | when 'portrait' then @setPortraitAspectRatio() 307 | when 'landscape' then @setLandscapeAspectRatio() 308 | 309 | hideFullscreen: => @$container.fadeOut() 310 | 311 | # Define the plugin 312 | $.fn.extend mrUploader: (option, args...) -> 313 | $this = @first() 314 | data = $this.data('mrUploader') 315 | 316 | if !data 317 | upload = new MrUploader(this, option) 318 | $this.data 'mrUploader', (data = upload) 319 | return upload 320 | if typeof option == 'string' 321 | data[optiokn].apply(data, args) 322 | 323 | )(window.jQuery, window) 324 | -------------------------------------------------------------------------------- /vendors/jquery.Jcrop.min.css: -------------------------------------------------------------------------------- 1 | /* jquery.Jcrop.min.css v0.9.12 (build:20130126) */ 2 | .jcrop-holder{direction:ltr;text-align:left;} 3 | .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;} 4 | .jcrop-vline{height:100%;width:1px!important;} 5 | .jcrop-vline.right{right:0;} 6 | .jcrop-hline{height:1px!important;width:100%;} 7 | .jcrop-hline.bottom{bottom:0;} 8 | .jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;} 9 | .jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;} 10 | .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;} 11 | .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;} 12 | .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;} 13 | .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;} 14 | .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;} 15 | .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;} 16 | .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;} 17 | .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;} 18 | .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;} 19 | .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;} 20 | .jcrop-dragbar.ord-n{margin-top:-4px;} 21 | .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;} 22 | .jcrop-dragbar.ord-e{margin-right:-4px;right:0;} 23 | .jcrop-dragbar.ord-w{margin-left:-4px;} 24 | .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;} 25 | .jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;} 26 | .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;} 27 | .jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;} 28 | .solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;} 29 | .jcrop-holder img,img.jcrop-preview{max-width:none;} 30 | -------------------------------------------------------------------------------- /vendors/jquery.Jcrop.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jquery.Jcrop.min.js v0.9.12 (build:20130202) 3 | * jQuery Image Cropping Plugin - released under MIT License 4 | * Copyright (c) 2008-2013 Tapmodo Interactive LLC 5 | * https://github.com/tapmodo/Jcrop 6 | */ 7 | (function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys 8 | (),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring 9 | (0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("
").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2], 10 | a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb 11 | .setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id"). 12 | css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("
").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a("
"),I=a("
").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("
").width("100%").height("100%").css("zIndex",320),K=a("
").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart" 13 | ,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;da+f&&(f-=f+a),0>b+g&&(g-=g+b),FE&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-ah&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):rh&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return cP&&(c=d>0?a+P:a-P),Q&&Math.abs 15 | (f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)0?b+S/U:b-S/U),R/T&&Math.abs(d)0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("
").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb. 16 | isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("
").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("
").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("
").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++ 17 | ).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("
").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if( 21 | b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges 22 | :!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery); 23 | --------------------------------------------------------------------------------