forked from GNUsocial/gnu-social
		
	
		
			
	
	
		
			1695 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			1695 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|   | /** | ||
|  |  * jquery.Jcrop.js v0.9.12 | ||
|  |  * jQuery Image Cropping Plugin - released under MIT License  | ||
|  |  * Author: Kelly Hallman <khallman@gmail.com> | ||
|  |  * http://github.com/tapmodo/Jcrop
 | ||
|  |  * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{ | ||
|  |  * | ||
|  |  * Permission is hereby granted, free of charge, to any person | ||
|  |  * obtaining a copy of this software and associated documentation | ||
|  |  * files (the "Software"), to deal in the Software without | ||
|  |  * restriction, including without limitation the rights to use, | ||
|  |  * copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
|  |  * copies of the Software, and to permit persons to whom the | ||
|  |  * Software is furnished to do so, subject to the following | ||
|  |  * conditions: | ||
|  |  * | ||
|  |  * The above copyright notice and this permission notice shall be | ||
|  |  * included in all copies or substantial portions of the Software. | ||
|  |  * | ||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
|  |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
|  |  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
|  |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
|  |  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
|  |  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
|  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
|  |  * OTHER DEALINGS IN THE SOFTWARE. | ||
|  |  * | ||
|  |  * }}} | ||
|  |  */ | ||
|  | 
 | ||
|  | (function ($) { | ||
|  | 
 | ||
|  |   $.Jcrop = function (obj, opt) { | ||
|  |     var options = $.extend({}, $.Jcrop.defaults), | ||
|  |         docOffset, | ||
|  |         _ua = navigator.userAgent.toLowerCase(), | ||
|  |         is_msie = /msie/.test(_ua), | ||
|  |         ie6mode = /msie [1-6]\./.test(_ua); | ||
|  | 
 | ||
|  |     // Internal Methods {{{
 | ||
|  |     function px(n) { | ||
|  |       return Math.round(n) + 'px'; | ||
|  |     } | ||
|  |     function cssClass(cl) { | ||
|  |       return options.baseClass + '-' + cl; | ||
|  |     } | ||
|  |     function supportsColorFade() { | ||
|  |       return $.fx.step.hasOwnProperty('backgroundColor'); | ||
|  |     } | ||
|  |     function getPos(obj) //{{{
 | ||
|  |     { | ||
|  |       var pos = $(obj).offset(); | ||
|  |       return [pos.left, pos.top]; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function mouseAbs(e) //{{{
 | ||
|  |     { | ||
|  |       return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])]; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function setOptions(opt) //{{{
 | ||
|  |     { | ||
|  |       if (typeof(opt) !== 'object') opt = {}; | ||
|  |       options = $.extend(options, opt); | ||
|  | 
 | ||
|  |       $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) { | ||
|  |         if (typeof(options[e]) !== 'function') options[e] = function () {}; | ||
|  |       }); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function startDragMode(mode, pos, touch) //{{{
 | ||
|  |     { | ||
|  |       docOffset = getPos($img); | ||
|  |       Tracker.setCursor(mode === 'move' ? mode : mode + '-resize'); | ||
|  | 
 | ||
|  |       if (mode === 'move') { | ||
|  |         return Tracker.activateHandlers(createMover(pos), doneSelect, touch); | ||
|  |       } | ||
|  | 
 | ||
|  |       var fc = Coords.getFixed(); | ||
|  |       var opp = oppLockCorner(mode); | ||
|  |       var opc = Coords.getCorner(oppLockCorner(opp)); | ||
|  | 
 | ||
|  |       Coords.setPressed(Coords.getCorner(opp)); | ||
|  |       Coords.setCurrent(opc); | ||
|  | 
 | ||
|  |       Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function dragmodeHandler(mode, f) //{{{
 | ||
|  |     { | ||
|  |       return function (pos) { | ||
|  |         if (!options.aspectRatio) { | ||
|  |           switch (mode) { | ||
|  |           case 'e': | ||
|  |             pos[1] = f.y2; | ||
|  |             break; | ||
|  |           case 'w': | ||
|  |             pos[1] = f.y2; | ||
|  |             break; | ||
|  |           case 'n': | ||
|  |             pos[0] = f.x2; | ||
|  |             break; | ||
|  |           case 's': | ||
|  |             pos[0] = f.x2; | ||
|  |             break; | ||
|  |           } | ||
|  |         } else { | ||
|  |           switch (mode) { | ||
|  |           case 'e': | ||
|  |             pos[1] = f.y + 1; | ||
|  |             break; | ||
|  |           case 'w': | ||
|  |             pos[1] = f.y + 1; | ||
|  |             break; | ||
|  |           case 'n': | ||
|  |             pos[0] = f.x + 1; | ||
|  |             break; | ||
|  |           case 's': | ||
|  |             pos[0] = f.x + 1; | ||
|  |             break; | ||
|  |           } | ||
|  |         } | ||
|  |         Coords.setCurrent(pos); | ||
|  |         Selection.update(); | ||
|  |       }; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function createMover(pos) //{{{
 | ||
|  |     { | ||
|  |       var lloc = pos; | ||
|  |       KeyManager.watchKeys(); | ||
|  | 
 | ||
|  |       return function (pos) { | ||
|  |         Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); | ||
|  |         lloc = pos; | ||
|  | 
 | ||
|  |         Selection.update(); | ||
|  |       }; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function oppLockCorner(ord) //{{{
 | ||
|  |     { | ||
|  |       switch (ord) { | ||
|  |       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 createDragger(ord) //{{{
 | ||
|  |     { | ||
|  |       return function (e) { | ||
|  |         if (options.disabled) { | ||
|  |           return false; | ||
|  |         } | ||
|  |         if ((ord === 'move') && !options.allowMove) { | ||
|  |           return false; | ||
|  |         } | ||
|  |          | ||
|  |         // Fix position of crop area when dragged the very first time.
 | ||
|  |         // Necessary when crop image is in a hidden element when page is loaded.
 | ||
|  |         docOffset = getPos($img); | ||
|  | 
 | ||
|  |         btndown = true; | ||
|  |         startDragMode(ord, mouseAbs(e)); | ||
|  |         e.stopPropagation(); | ||
|  |         e.preventDefault(); | ||
|  |         return false; | ||
|  |       }; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function presize($obj, w, h) //{{{
 | ||
|  |     { | ||
|  |       var nw = $obj.width(), | ||
|  |           nh = $obj.height(); | ||
|  |       if ((nw > w) && w > 0) { | ||
|  |         nw = w; | ||
|  |         nh = (w / $obj.width()) * $obj.height(); | ||
|  |       } | ||
|  |       if ((nh > h) && h > 0) { | ||
|  |         nh = h; | ||
|  |         nw = (h / $obj.height()) * $obj.width(); | ||
|  |       } | ||
|  |       xscale = $obj.width() / nw; | ||
|  |       yscale = $obj.height() / nh; | ||
|  |       $obj.width(nw).height(nh); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function unscale(c) //{{{
 | ||
|  |     { | ||
|  |       return { | ||
|  |         x: c.x * xscale, | ||
|  |         y: c.y * yscale, | ||
|  |         x2: c.x2 * xscale, | ||
|  |         y2: c.y2 * yscale, | ||
|  |         w: c.w * xscale, | ||
|  |         h: c.h * yscale | ||
|  |       }; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function doneSelect(pos) //{{{
 | ||
|  |     { | ||
|  |       var c = Coords.getFixed(); | ||
|  |       if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) { | ||
|  |         Selection.enableHandles(); | ||
|  |         Selection.done(); | ||
|  |       } else { | ||
|  |         Selection.release(); | ||
|  |       } | ||
|  |       Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function newSelection(e) //{{{
 | ||
|  |     { | ||
|  |       if (options.disabled) { | ||
|  |         return false; | ||
|  |       } | ||
|  |       if (!options.allowSelect) { | ||
|  |         return false; | ||
|  |       } | ||
|  |       btndown = true; | ||
|  |       docOffset = getPos($img); | ||
|  |       Selection.disableHandles(); | ||
|  |       Tracker.setCursor('crosshair'); | ||
|  |       var pos = mouseAbs(e); | ||
|  |       Coords.setPressed(pos); | ||
|  |       Selection.update(); | ||
|  |       Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch'); | ||
|  |       KeyManager.watchKeys(); | ||
|  | 
 | ||
|  |       e.stopPropagation(); | ||
|  |       e.preventDefault(); | ||
|  |       return false; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function selectDrag(pos) //{{{
 | ||
|  |     { | ||
|  |       Coords.setCurrent(pos); | ||
|  |       Selection.update(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function newTracker() //{{{
 | ||
|  |     { | ||
|  |       var trk = $('<div></div>').addClass(cssClass('tracker')); | ||
|  |       if (is_msie) { | ||
|  |         trk.css({ | ||
|  |           opacity: 0, | ||
|  |           backgroundColor: 'white' | ||
|  |         }); | ||
|  |       } | ||
|  |       return trk; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  | 
 | ||
|  |     // }}}
 | ||
|  |     // Initialization {{{
 | ||
|  |     // Sanitize some options {{{
 | ||
|  |     if (typeof(obj) !== 'object') { | ||
|  |       obj = $(obj)[0]; | ||
|  |     } | ||
|  |     if (typeof(opt) !== 'object') { | ||
|  |       opt = {}; | ||
|  |     } | ||
|  |     // }}}
 | ||
|  |     setOptions(opt); | ||
|  |     // Initialize some jQuery objects {{{
 | ||
|  |     // The values are SET on the image(s) for the interface
 | ||
|  |     // If the original image has any of these set, they will be reset
 | ||
|  |     // However, if you destroy() the Jcrop instance the original image's
 | ||
|  |     // character in the DOM will be as you left it.
 | ||
|  |     var img_css = { | ||
|  |       border: 'none', | ||
|  |       visibility: 'visible', | ||
|  |       margin: 0, | ||
|  |       padding: 0, | ||
|  |       position: 'absolute', | ||
|  |       top: 0, | ||
|  |       left: 0 | ||
|  |     }; | ||
|  | 
 | ||
|  |     var $origimg = $(obj), | ||
|  |       img_mode = true; | ||
|  | 
 | ||
|  |     if (obj.tagName == 'IMG') { | ||
|  |       // Fix size of crop image.
 | ||
|  |       // Necessary when crop image is within a hidden element when page is loaded.
 | ||
|  |       if ($origimg[0].width != 0 && $origimg[0].height != 0) { | ||
|  |         // Obtain dimensions from contained img element.
 | ||
|  |         $origimg.width($origimg[0].width); | ||
|  |         $origimg.height($origimg[0].height); | ||
|  |       } else { | ||
|  |         // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). 
 | ||
|  |         var tempImage = new Image(); | ||
|  |         tempImage.src = $origimg[0].src; | ||
|  |         $origimg.width(tempImage.width); | ||
|  |         $origimg.height(tempImage.height); | ||
|  |       }  | ||
|  | 
 | ||
|  |       var $img = $origimg.clone().removeAttr('id').css(img_css).show(); | ||
|  | 
 | ||
|  |       $img.width($origimg.width()); | ||
|  |       $img.height($origimg.height()); | ||
|  |       $origimg.after($img).hide(); | ||
|  | 
 | ||
|  |     } else { | ||
|  |       $img = $origimg.css(img_css).show(); | ||
|  |       img_mode = false; | ||
|  |       if (options.shade === null) { options.shade = true; } | ||
|  |     } | ||
|  | 
 | ||
|  |     presize($img, options.boxWidth, options.boxHeight); | ||
|  | 
 | ||
|  |     var boundx = $img.width(), | ||
|  |         boundy = $img.height(), | ||
|  |          | ||
|  |          | ||
|  |         $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({ | ||
|  |         position: 'relative', | ||
|  |         backgroundColor: options.bgColor | ||
|  |       }).insertAfter($origimg).append($img); | ||
|  | 
 | ||
|  |     if (options.addClass) { | ||
|  |       $div.addClass(options.addClass); | ||
|  |     } | ||
|  | 
 | ||
|  |     var $img2 = $('<div />'), | ||
|  | 
 | ||
|  |         $img_holder = $('<div />')  | ||
|  |         .width('100%').height('100%').css({ | ||
|  |           zIndex: 310, | ||
|  |           position: 'absolute', | ||
|  |           overflow: 'hidden' | ||
|  |         }), | ||
|  | 
 | ||
|  |         $hdl_holder = $('<div />')  | ||
|  |         .width('100%').height('100%').css('zIndex', 320),  | ||
|  | 
 | ||
|  |         $sel = $('<div />')  | ||
|  |         .css({ | ||
|  |           position: 'absolute', | ||
|  |           zIndex: 600 | ||
|  |         }).dblclick(function(){ | ||
|  |           var c = Coords.getFixed(); | ||
|  |           options.onDblClick.call(api,c); | ||
|  |         }).insertBefore($img).append($img_holder, $hdl_holder);  | ||
|  | 
 | ||
|  |     if (img_mode) { | ||
|  | 
 | ||
|  |       $img2 = $('<img />') | ||
|  |           .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), | ||
|  | 
 | ||
|  |       $img_holder.append($img2); | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     if (ie6mode) { | ||
|  |       $sel.css({ | ||
|  |         overflowY: 'hidden' | ||
|  |       }); | ||
|  |     } | ||
|  | 
 | ||
|  |     var bound = options.boundary; | ||
|  |     var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({ | ||
|  |       position: 'absolute', | ||
|  |       top: px(-bound), | ||
|  |       left: px(-bound), | ||
|  |       zIndex: 290 | ||
|  |     }).mousedown(newSelection); | ||
|  | 
 | ||
|  |     /* }}} */ | ||
|  |     // Set more variables {{{
 | ||
|  |     var bgcolor = options.bgColor, | ||
|  |         bgopacity = options.bgOpacity, | ||
|  |         xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, | ||
|  |         btndown, animating, shift_down; | ||
|  | 
 | ||
|  |     docOffset = getPos($img); | ||
|  |     // }}}
 | ||
|  |     // }}}
 | ||
|  |     // Internal Modules {{{
 | ||
|  |     // Touch Module {{{ 
 | ||
|  |     var Touch = (function () { | ||
|  |       // Touch support detection function adapted (under MIT License)
 | ||
|  |       // from code by Jeffrey Sambells - http://github.com/iamamused/
 | ||
|  |       function hasTouchSupport() { | ||
|  |         var support = {}, events = ['touchstart', 'touchmove', 'touchend'], | ||
|  |             el = document.createElement('div'), i; | ||
|  | 
 | ||
|  |         try { | ||
|  |           for(i=0; i<events.length; i++) { | ||
|  |             var eventName = events[i]; | ||
|  |             eventName = 'on' + eventName; | ||
|  |             var isSupported = (eventName in el); | ||
|  |             if (!isSupported) { | ||
|  |               el.setAttribute(eventName, 'return;'); | ||
|  |               isSupported = typeof el[eventName] == 'function'; | ||
|  |             } | ||
|  |             support[events[i]] = isSupported; | ||
|  |           } | ||
|  |           return support.touchstart && support.touchend && support.touchmove; | ||
|  |         } | ||
|  |         catch(err) { | ||
|  |           return false; | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  |       function detectSupport() { | ||
|  |         if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport; | ||
|  |           else return hasTouchSupport(); | ||
|  |       } | ||
|  |       return { | ||
|  |         createDragger: function (ord) { | ||
|  |           return function (e) { | ||
|  |             if (options.disabled) { | ||
|  |               return false; | ||
|  |             } | ||
|  |             if ((ord === 'move') && !options.allowMove) { | ||
|  |               return false; | ||
|  |             } | ||
|  |             docOffset = getPos($img); | ||
|  |             btndown = true; | ||
|  |             startDragMode(ord, mouseAbs(Touch.cfilter(e)), true); | ||
|  |             e.stopPropagation(); | ||
|  |             e.preventDefault(); | ||
|  |             return false; | ||
|  |           }; | ||
|  |         }, | ||
|  |         newSelection: function (e) { | ||
|  |           return newSelection(Touch.cfilter(e)); | ||
|  |         }, | ||
|  |         cfilter: function (e){ | ||
|  |           e.pageX = e.originalEvent.changedTouches[0].pageX; | ||
|  |           e.pageY = e.originalEvent.changedTouches[0].pageY; | ||
|  |           return e; | ||
|  |         }, | ||
|  |         isSupported: hasTouchSupport, | ||
|  |         support: detectSupport() | ||
|  |       }; | ||
|  |     }()); | ||
|  |     // }}}
 | ||
|  |     // Coords Module {{{
 | ||
|  |     var Coords = (function () { | ||
|  |       var x1 = 0, | ||
|  |           y1 = 0, | ||
|  |           x2 = 0, | ||
|  |           y2 = 0, | ||
|  |           ox, oy; | ||
|  | 
 | ||
|  |       function setPressed(pos) //{{{
 | ||
|  |       { | ||
|  |         pos = rebound(pos); | ||
|  |         x2 = x1 = pos[0]; | ||
|  |         y2 = y1 = pos[1]; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function setCurrent(pos) //{{{
 | ||
|  |       { | ||
|  |         pos = rebound(pos); | ||
|  |         ox = pos[0] - x2; | ||
|  |         oy = pos[1] - y2; | ||
|  |         x2 = pos[0]; | ||
|  |         y2 = pos[1]; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function getOffset() //{{{
 | ||
|  |       { | ||
|  |         return [ox, oy]; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function moveOffset(offset) //{{{
 | ||
|  |       { | ||
|  |         var ox = offset[0], | ||
|  |             oy = offset[1]; | ||
|  | 
 | ||
|  |         if (0 > x1 + ox) { | ||
|  |           ox -= ox + x1; | ||
|  |         } | ||
|  |         if (0 > y1 + oy) { | ||
|  |           oy -= oy + y1; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (boundy < y2 + oy) { | ||
|  |           oy += boundy - (y2 + oy); | ||
|  |         } | ||
|  |         if (boundx < x2 + ox) { | ||
|  |           ox += boundx - (x2 + ox); | ||
|  |         } | ||
|  | 
 | ||
|  |         x1 += ox; | ||
|  |         x2 += ox; | ||
|  |         y1 += oy; | ||
|  |         y2 += oy; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function getCorner(ord) //{{{
 | ||
|  |       { | ||
|  |         var c = getFixed(); | ||
|  |         switch (ord) { | ||
|  |         case 'ne': | ||
|  |           return [c.x2, c.y]; | ||
|  |         case 'nw': | ||
|  |           return [c.x, c.y]; | ||
|  |         case 'se': | ||
|  |           return [c.x2, c.y2]; | ||
|  |         case 'sw': | ||
|  |           return [c.x, c.y2]; | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function getFixed() //{{{
 | ||
|  |       { | ||
|  |         if (!options.aspectRatio) { | ||
|  |           return getRect(); | ||
|  |         } | ||
|  |         // This function could use some optimization I think...
 | ||
|  |         var aspect = options.aspectRatio, | ||
|  |             min_x = options.minSize[0] / xscale, | ||
|  |              | ||
|  |              | ||
|  |             //min_y = options.minSize[1]/yscale,
 | ||
|  |             max_x = options.maxSize[0] / xscale, | ||
|  |             max_y = options.maxSize[1] / yscale, | ||
|  |             rw = x2 - x1, | ||
|  |             rh = y2 - y1, | ||
|  |             rwa = Math.abs(rw), | ||
|  |             rha = Math.abs(rh), | ||
|  |             real_ratio = rwa / rha, | ||
|  |             xx, yy, w, h; | ||
|  | 
 | ||
|  |         if (max_x === 0) { | ||
|  |           max_x = boundx * 10; | ||
|  |         } | ||
|  |         if (max_y === 0) { | ||
|  |           max_y = boundy * 10; | ||
|  |         } | ||
|  |         if (real_ratio < aspect) { | ||
|  |           yy = y2; | ||
|  |           w = rha * aspect; | ||
|  |           xx = rw < 0 ? x1 - w : w + x1; | ||
|  | 
 | ||
|  |           if (xx < 0) { | ||
|  |             xx = 0; | ||
|  |             h = Math.abs((xx - x1) / aspect); | ||
|  |             yy = rh < 0 ? y1 - h : h + y1; | ||
|  |           } else if (xx > boundx) { | ||
|  |             xx = boundx; | ||
|  |             h = Math.abs((xx - x1) / aspect); | ||
|  |             yy = rh < 0 ? y1 - h : h + y1; | ||
|  |           } | ||
|  |         } else { | ||
|  |           xx = x2; | ||
|  |           h = rwa / aspect; | ||
|  |           yy = rh < 0 ? y1 - h : y1 + h; | ||
|  |           if (yy < 0) { | ||
|  |             yy = 0; | ||
|  |             w = Math.abs((yy - y1) * aspect); | ||
|  |             xx = rw < 0 ? x1 - w : w + x1; | ||
|  |           } else if (yy > boundy) { | ||
|  |             yy = boundy; | ||
|  |             w = Math.abs(yy - y1) * aspect; | ||
|  |             xx = rw < 0 ? x1 - w : w + x1; | ||
|  |           } | ||
|  |         } | ||
|  | 
 | ||
|  |         // Magic %-)
 | ||
|  |         if (xx > x1) { // right side
 | ||
|  |           if (xx - x1 < min_x) { | ||
|  |             xx = x1 + min_x; | ||
|  |           } else if (xx - x1 > max_x) { | ||
|  |             xx = x1 + max_x; | ||
|  |           } | ||
|  |           if (yy > y1) { | ||
|  |             yy = y1 + (xx - x1) / aspect; | ||
|  |           } else { | ||
|  |             yy = y1 - (xx - x1) / aspect; | ||
|  |           } | ||
|  |         } else if (xx < x1) { // left side
 | ||
|  |           if (x1 - xx < min_x) { | ||
|  |             xx = x1 - min_x; | ||
|  |           } else if (x1 - xx > max_x) { | ||
|  |             xx = x1 - max_x; | ||
|  |           } | ||
|  |           if (yy > y1) { | ||
|  |             yy = y1 + (x1 - xx) / aspect; | ||
|  |           } else { | ||
|  |             yy = y1 - (x1 - xx) / aspect; | ||
|  |           } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (xx < 0) { | ||
|  |           x1 -= xx; | ||
|  |           xx = 0; | ||
|  |         } else if (xx > boundx) { | ||
|  |           x1 -= xx - boundx; | ||
|  |           xx = boundx; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (yy < 0) { | ||
|  |           y1 -= yy; | ||
|  |           yy = 0; | ||
|  |         } else if (yy > boundy) { | ||
|  |           y1 -= yy - boundy; | ||
|  |           yy = boundy; | ||
|  |         } | ||
|  | 
 | ||
|  |         return makeObj(flipCoords(x1, y1, xx, yy)); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function rebound(p) //{{{
 | ||
|  |       { | ||
|  |         if (p[0] < 0) p[0] = 0; | ||
|  |         if (p[1] < 0) p[1] = 0; | ||
|  | 
 | ||
|  |         if (p[0] > boundx) p[0] = boundx; | ||
|  |         if (p[1] > boundy) p[1] = boundy; | ||
|  | 
 | ||
|  |         return [Math.round(p[0]), Math.round(p[1])]; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function flipCoords(x1, y1, x2, y2) //{{{
 | ||
|  |       { | ||
|  |         var xa = x1, | ||
|  |             xb = x2, | ||
|  |             ya = y1, | ||
|  |             yb = y2; | ||
|  |         if (x2 < x1) { | ||
|  |           xa = x2; | ||
|  |           xb = x1; | ||
|  |         } | ||
|  |         if (y2 < y1) { | ||
|  |           ya = y2; | ||
|  |           yb = y1; | ||
|  |         } | ||
|  |         return [xa, ya, xb, yb]; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function getRect() //{{{
 | ||
|  |       { | ||
|  |         var xsize = x2 - x1, | ||
|  |             ysize = y2 - y1, | ||
|  |             delta; | ||
|  | 
 | ||
|  |         if (xlimit && (Math.abs(xsize) > xlimit)) { | ||
|  |           x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); | ||
|  |         } | ||
|  |         if (ylimit && (Math.abs(ysize) > ylimit)) { | ||
|  |           y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) { | ||
|  |           y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale); | ||
|  |         } | ||
|  |         if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) { | ||
|  |           x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (x1 < 0) { | ||
|  |           x2 -= x1; | ||
|  |           x1 -= x1; | ||
|  |         } | ||
|  |         if (y1 < 0) { | ||
|  |           y2 -= y1; | ||
|  |           y1 -= y1; | ||
|  |         } | ||
|  |         if (x2 < 0) { | ||
|  |           x1 -= x2; | ||
|  |           x2 -= x2; | ||
|  |         } | ||
|  |         if (y2 < 0) { | ||
|  |           y1 -= y2; | ||
|  |           y2 -= y2; | ||
|  |         } | ||
|  |         if (x2 > boundx) { | ||
|  |           delta = x2 - boundx; | ||
|  |           x1 -= delta; | ||
|  |           x2 -= delta; | ||
|  |         } | ||
|  |         if (y2 > boundy) { | ||
|  |           delta = y2 - boundy; | ||
|  |           y1 -= delta; | ||
|  |           y2 -= delta; | ||
|  |         } | ||
|  |         if (x1 > boundx) { | ||
|  |           delta = x1 - boundy; | ||
|  |           y2 -= delta; | ||
|  |           y1 -= delta; | ||
|  |         } | ||
|  |         if (y1 > boundy) { | ||
|  |           delta = y1 - boundy; | ||
|  |           y2 -= delta; | ||
|  |           y1 -= delta; | ||
|  |         } | ||
|  | 
 | ||
|  |         return makeObj(flipCoords(x1, y1, x2, y2)); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function makeObj(a) //{{{
 | ||
|  |       { | ||
|  |         return { | ||
|  |           x: a[0], | ||
|  |           y: a[1], | ||
|  |           x2: a[2], | ||
|  |           y2: a[3], | ||
|  |           w: a[2] - a[0], | ||
|  |           h: a[3] - a[1] | ||
|  |         }; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  | 
 | ||
|  |       return { | ||
|  |         flipCoords: flipCoords, | ||
|  |         setPressed: setPressed, | ||
|  |         setCurrent: setCurrent, | ||
|  |         getOffset: getOffset, | ||
|  |         moveOffset: moveOffset, | ||
|  |         getCorner: getCorner, | ||
|  |         getFixed: getFixed | ||
|  |       }; | ||
|  |     }()); | ||
|  | 
 | ||
|  |     //}}}
 | ||
|  |     // Shade Module {{{
 | ||
|  |     var Shade = (function() { | ||
|  |       var enabled = false, | ||
|  |           holder = $('<div />').css({ | ||
|  |             position: 'absolute', | ||
|  |             zIndex: 240, | ||
|  |             opacity: 0 | ||
|  |           }), | ||
|  |           shades = { | ||
|  |             top: createShade(), | ||
|  |             left: createShade().height(boundy), | ||
|  |             right: createShade().height(boundy), | ||
|  |             bottom: createShade() | ||
|  |           }; | ||
|  | 
 | ||
|  |       function resizeShades(w,h) { | ||
|  |         shades.left.css({ height: px(h) }); | ||
|  |         shades.right.css({ height: px(h) }); | ||
|  |       } | ||
|  |       function updateAuto() | ||
|  |       { | ||
|  |         return updateShade(Coords.getFixed()); | ||
|  |       } | ||
|  |       function updateShade(c) | ||
|  |       { | ||
|  |         shades.top.css({ | ||
|  |           left: px(c.x), | ||
|  |           width: px(c.w), | ||
|  |           height: px(c.y) | ||
|  |         }); | ||
|  |         shades.bottom.css({ | ||
|  |           top: px(c.y2), | ||
|  |           left: px(c.x), | ||
|  |           width: px(c.w), | ||
|  |           height: px(boundy-c.y2) | ||
|  |         }); | ||
|  |         shades.right.css({ | ||
|  |           left: px(c.x2), | ||
|  |           width: px(boundx-c.x2) | ||
|  |         }); | ||
|  |         shades.left.css({ | ||
|  |           width: px(c.x) | ||
|  |         }); | ||
|  |       } | ||
|  |       function createShade() { | ||
|  |         return $('<div />').css({ | ||
|  |           position: 'absolute', | ||
|  |           backgroundColor: options.shadeColor||options.bgColor | ||
|  |         }).appendTo(holder); | ||
|  |       } | ||
|  |       function enableShade() { | ||
|  |         if (!enabled) { | ||
|  |           enabled = true; | ||
|  |           holder.insertBefore($img); | ||
|  |           updateAuto(); | ||
|  |           Selection.setBgOpacity(1,0,1); | ||
|  |           $img2.hide(); | ||
|  | 
 | ||
|  |           setBgColor(options.shadeColor||options.bgColor,1); | ||
|  |           if (Selection.isAwake()) | ||
|  |           { | ||
|  |             setOpacity(options.bgOpacity,1); | ||
|  |           } | ||
|  |             else setOpacity(1,1); | ||
|  |         } | ||
|  |       } | ||
|  |       function setBgColor(color,now) { | ||
|  |         colorChangeMacro(getShades(),color,now); | ||
|  |       } | ||
|  |       function disableShade() { | ||
|  |         if (enabled) { | ||
|  |           holder.remove(); | ||
|  |           $img2.show(); | ||
|  |           enabled = false; | ||
|  |           if (Selection.isAwake()) { | ||
|  |             Selection.setBgOpacity(options.bgOpacity,1,1); | ||
|  |           } else { | ||
|  |             Selection.setBgOpacity(1,1,1); | ||
|  |             Selection.disableHandles(); | ||
|  |           } | ||
|  |           colorChangeMacro($div,0,1); | ||
|  |         } | ||
|  |       } | ||
|  |       function setOpacity(opacity,now) { | ||
|  |         if (enabled) { | ||
|  |           if (options.bgFade && !now) { | ||
|  |             holder.animate({ | ||
|  |               opacity: 1-opacity | ||
|  |             },{ | ||
|  |               queue: false, | ||
|  |               duration: options.fadeTime | ||
|  |             }); | ||
|  |           } | ||
|  |           else holder.css({opacity:1-opacity}); | ||
|  |         } | ||
|  |       } | ||
|  |       function refreshAll() { | ||
|  |         options.shade ? enableShade() : disableShade(); | ||
|  |         if (Selection.isAwake()) setOpacity(options.bgOpacity); | ||
|  |       } | ||
|  |       function getShades() { | ||
|  |         return holder.children(); | ||
|  |       } | ||
|  | 
 | ||
|  |       return { | ||
|  |         update: updateAuto, | ||
|  |         updateRaw: updateShade, | ||
|  |         getShades: getShades, | ||
|  |         setBgColor: setBgColor, | ||
|  |         enable: enableShade, | ||
|  |         disable: disableShade, | ||
|  |         resize: resizeShades, | ||
|  |         refresh: refreshAll, | ||
|  |         opacity: setOpacity | ||
|  |       }; | ||
|  |     }()); | ||
|  |     // }}}
 | ||
|  |     // Selection Module {{{
 | ||
|  |     var Selection = (function () { | ||
|  |       var awake, | ||
|  |           hdep = 370, | ||
|  |           borders = {}, | ||
|  |           handle = {}, | ||
|  |           dragbar = {}, | ||
|  |           seehandles = false; | ||
|  | 
 | ||
|  |       // Private Methods
 | ||
|  |       function insertBorder(type) //{{{
 | ||
|  |       { | ||
|  |         var jq = $('<div />').css({ | ||
|  |           position: 'absolute', | ||
|  |           opacity: options.borderOpacity | ||
|  |         }).addClass(cssClass(type)); | ||
|  |         $img_holder.append(jq); | ||
|  |         return jq; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function dragDiv(ord, zi) //{{{
 | ||
|  |       { | ||
|  |         var jq = $('<div />').mousedown(createDragger(ord)).css({ | ||
|  |           cursor: ord + '-resize', | ||
|  |           position: 'absolute', | ||
|  |           zIndex: zi | ||
|  |         }).addClass('ord-'+ord); | ||
|  | 
 | ||
|  |         if (Touch.support) { | ||
|  |           jq.bind('touchstart.jcrop', Touch.createDragger(ord)); | ||
|  |         } | ||
|  | 
 | ||
|  |         $hdl_holder.append(jq); | ||
|  |         return jq; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function insertHandle(ord) //{{{
 | ||
|  |       { | ||
|  |         var hs = options.handleSize, | ||
|  | 
 | ||
|  |           div = dragDiv(ord, hdep++).css({ | ||
|  |             opacity: options.handleOpacity | ||
|  |           }).addClass(cssClass('handle')); | ||
|  | 
 | ||
|  |         if (hs) { div.width(hs).height(hs); } | ||
|  | 
 | ||
|  |         return div; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function insertDragbar(ord) //{{{
 | ||
|  |       { | ||
|  |         return dragDiv(ord, hdep++).addClass('jcrop-dragbar'); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function createDragbars(li) //{{{
 | ||
|  |       { | ||
|  |         var i; | ||
|  |         for (i = 0; i < li.length; i++) { | ||
|  |           dragbar[li[i]] = insertDragbar(li[i]); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function createBorders(li) //{{{
 | ||
|  |       { | ||
|  |         var cl,i; | ||
|  |         for (i = 0; i < li.length; i++) { | ||
|  |           switch(li[i]){ | ||
|  |             case'n': cl='hline'; break; | ||
|  |             case's': cl='hline bottom'; break; | ||
|  |             case'e': cl='vline right'; break; | ||
|  |             case'w': cl='vline'; break; | ||
|  |           } | ||
|  |           borders[li[i]] = insertBorder(cl); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function createHandles(li) //{{{
 | ||
|  |       { | ||
|  |         var i; | ||
|  |         for (i = 0; i < li.length; i++) { | ||
|  |           handle[li[i]] = insertHandle(li[i]); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function moveto(x, y) //{{{
 | ||
|  |       { | ||
|  |         if (!options.shade) { | ||
|  |           $img2.css({ | ||
|  |             top: px(-y), | ||
|  |             left: px(-x) | ||
|  |           }); | ||
|  |         } | ||
|  |         $sel.css({ | ||
|  |           top: px(y), | ||
|  |           left: px(x) | ||
|  |         }); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function resize(w, h) //{{{
 | ||
|  |       { | ||
|  |         $sel.width(Math.round(w)).height(Math.round(h)); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function refresh() //{{{
 | ||
|  |       { | ||
|  |         var c = Coords.getFixed(); | ||
|  | 
 | ||
|  |         Coords.setPressed([c.x, c.y]); | ||
|  |         Coords.setCurrent([c.x2, c.y2]); | ||
|  | 
 | ||
|  |         updateVisible(); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  | 
 | ||
|  |       // Internal Methods
 | ||
|  |       function updateVisible(select) //{{{
 | ||
|  |       { | ||
|  |         if (awake) { | ||
|  |           return update(select); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function update(select) //{{{
 | ||
|  |       { | ||
|  |         var c = Coords.getFixed(); | ||
|  | 
 | ||
|  |         resize(c.w, c.h); | ||
|  |         moveto(c.x, c.y); | ||
|  |         if (options.shade) Shade.updateRaw(c); | ||
|  | 
 | ||
|  |         awake || show(); | ||
|  | 
 | ||
|  |         if (select) { | ||
|  |           options.onSelect.call(api, unscale(c)); | ||
|  |         } else { | ||
|  |           options.onChange.call(api, unscale(c)); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function setBgOpacity(opacity,force,now) //{{{
 | ||
|  |       { | ||
|  |         if (!awake && !force) return; | ||
|  |         if (options.bgFade && !now) { | ||
|  |           $img.animate({ | ||
|  |             opacity: opacity | ||
|  |           },{ | ||
|  |             queue: false, | ||
|  |             duration: options.fadeTime | ||
|  |           }); | ||
|  |         } else { | ||
|  |           $img.css('opacity', opacity); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function show() //{{{
 | ||
|  |       { | ||
|  |         $sel.show(); | ||
|  | 
 | ||
|  |         if (options.shade) Shade.opacity(bgopacity); | ||
|  |           else setBgOpacity(bgopacity,true); | ||
|  | 
 | ||
|  |         awake = true; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function release() //{{{
 | ||
|  |       { | ||
|  |         disableHandles(); | ||
|  |         $sel.hide(); | ||
|  | 
 | ||
|  |         if (options.shade) Shade.opacity(1); | ||
|  |           else setBgOpacity(1); | ||
|  | 
 | ||
|  |         awake = false; | ||
|  |         options.onRelease.call(api); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function showHandles() //{{{
 | ||
|  |       { | ||
|  |         if (seehandles) { | ||
|  |           $hdl_holder.show(); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function enableHandles() //{{{
 | ||
|  |       { | ||
|  |         seehandles = true; | ||
|  |         if (options.allowResize) { | ||
|  |           $hdl_holder.show(); | ||
|  |           return true; | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function disableHandles() //{{{
 | ||
|  |       { | ||
|  |         seehandles = false; | ||
|  |         $hdl_holder.hide(); | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       function animMode(v) //{{{
 | ||
|  |       { | ||
|  |         if (v) { | ||
|  |           animating = true; | ||
|  |           disableHandles(); | ||
|  |         } else { | ||
|  |           animating = false; | ||
|  |           enableHandles(); | ||
|  |         } | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       function done() //{{{
 | ||
|  |       { | ||
|  |         animMode(false); | ||
|  |         refresh(); | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       // Insert draggable elements {{{
 | ||
|  |       // Insert border divs for outline
 | ||
|  | 
 | ||
|  |       if (options.dragEdges && $.isArray(options.createDragbars)) | ||
|  |         createDragbars(options.createDragbars); | ||
|  | 
 | ||
|  |       if ($.isArray(options.createHandles)) | ||
|  |         createHandles(options.createHandles); | ||
|  | 
 | ||
|  |       if (options.drawBorders && $.isArray(options.createBorders)) | ||
|  |         createBorders(options.createBorders); | ||
|  | 
 | ||
|  |       //}}}
 | ||
|  | 
 | ||
|  |       // This is a hack for iOS5 to support drag/move touch functionality
 | ||
|  |       $(document).bind('touchstart.jcrop-ios',function(e) { | ||
|  |         if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation(); | ||
|  |       }); | ||
|  | 
 | ||
|  |       var $track = newTracker().mousedown(createDragger('move')).css({ | ||
|  |         cursor: 'move', | ||
|  |         position: 'absolute', | ||
|  |         zIndex: 360 | ||
|  |       }); | ||
|  | 
 | ||
|  |       if (Touch.support) { | ||
|  |         $track.bind('touchstart.jcrop', Touch.createDragger('move')); | ||
|  |       } | ||
|  | 
 | ||
|  |       $img_holder.append($track); | ||
|  |       disableHandles(); | ||
|  | 
 | ||
|  |       return { | ||
|  |         updateVisible: updateVisible, | ||
|  |         update: update, | ||
|  |         release: release, | ||
|  |         refresh: refresh, | ||
|  |         isAwake: function () { | ||
|  |           return awake; | ||
|  |         }, | ||
|  |         setCursor: function (cursor) { | ||
|  |           $track.css('cursor', cursor); | ||
|  |         }, | ||
|  |         enableHandles: enableHandles, | ||
|  |         enableOnly: function () { | ||
|  |           seehandles = true; | ||
|  |         }, | ||
|  |         showHandles: showHandles, | ||
|  |         disableHandles: disableHandles, | ||
|  |         animMode: animMode, | ||
|  |         setBgOpacity: setBgOpacity, | ||
|  |         done: done | ||
|  |       }; | ||
|  |     }()); | ||
|  |      | ||
|  |     //}}}
 | ||
|  |     // Tracker Module {{{
 | ||
|  |     var Tracker = (function () { | ||
|  |       var onMove = function () {}, | ||
|  |           onDone = function () {}, | ||
|  |           trackDoc = options.trackDocument; | ||
|  | 
 | ||
|  |       function toFront(touch) //{{{
 | ||
|  |       { | ||
|  |         $trk.css({ | ||
|  |           zIndex: 450 | ||
|  |         }); | ||
|  | 
 | ||
|  |         if (touch) | ||
|  |           $(document) | ||
|  |             .bind('touchmove.jcrop', trackTouchMove) | ||
|  |             .bind('touchend.jcrop', trackTouchEnd); | ||
|  | 
 | ||
|  |         else if (trackDoc) | ||
|  |           $(document) | ||
|  |             .bind('mousemove.jcrop',trackMove) | ||
|  |             .bind('mouseup.jcrop',trackUp); | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       function toBack() //{{{
 | ||
|  |       { | ||
|  |         $trk.css({ | ||
|  |           zIndex: 290 | ||
|  |         }); | ||
|  |         $(document).unbind('.jcrop'); | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       function trackMove(e) //{{{
 | ||
|  |       { | ||
|  |         onMove(mouseAbs(e)); | ||
|  |         return false; | ||
|  |       }  | ||
|  |       //}}}
 | ||
|  |       function trackUp(e) //{{{
 | ||
|  |       { | ||
|  |         e.preventDefault(); | ||
|  |         e.stopPropagation(); | ||
|  | 
 | ||
|  |         if (btndown) { | ||
|  |           btndown = false; | ||
|  | 
 | ||
|  |           onDone(mouseAbs(e)); | ||
|  | 
 | ||
|  |           if (Selection.isAwake()) { | ||
|  |             options.onSelect.call(api, unscale(Coords.getFixed())); | ||
|  |           } | ||
|  | 
 | ||
|  |           toBack(); | ||
|  |           onMove = function () {}; | ||
|  |           onDone = function () {}; | ||
|  |         } | ||
|  | 
 | ||
|  |         return false; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function activateHandlers(move, done, touch) //{{{
 | ||
|  |       { | ||
|  |         btndown = true; | ||
|  |         onMove = move; | ||
|  |         onDone = done; | ||
|  |         toFront(touch); | ||
|  |         return false; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function trackTouchMove(e) //{{{
 | ||
|  |       { | ||
|  |         onMove(mouseAbs(Touch.cfilter(e))); | ||
|  |         return false; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function trackTouchEnd(e) //{{{
 | ||
|  |       { | ||
|  |         return trackUp(Touch.cfilter(e)); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function setCursor(t) //{{{
 | ||
|  |       { | ||
|  |         $trk.css('cursor', t); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  | 
 | ||
|  |       if (!trackDoc) { | ||
|  |         $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp); | ||
|  |       } | ||
|  | 
 | ||
|  |       $img.before($trk); | ||
|  |       return { | ||
|  |         activateHandlers: activateHandlers, | ||
|  |         setCursor: setCursor | ||
|  |       }; | ||
|  |     }()); | ||
|  |     //}}}
 | ||
|  |     // KeyManager Module {{{
 | ||
|  |     var KeyManager = (function () { | ||
|  |       var $keymgr = $('<input type="radio" />').css({ | ||
|  |         position: 'fixed', | ||
|  |         left: '-120px', | ||
|  |         width: '12px' | ||
|  |       }).addClass('jcrop-keymgr'), | ||
|  | 
 | ||
|  |         $keywrap = $('<div />').css({ | ||
|  |           position: 'absolute', | ||
|  |           overflow: 'hidden' | ||
|  |         }).append($keymgr); | ||
|  | 
 | ||
|  |       function watchKeys() //{{{
 | ||
|  |       { | ||
|  |         if (options.keySupport) { | ||
|  |           $keymgr.show(); | ||
|  |           $keymgr.focus(); | ||
|  |         } | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function onBlur(e) //{{{
 | ||
|  |       { | ||
|  |         $keymgr.hide(); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function doNudge(e, x, y) //{{{
 | ||
|  |       { | ||
|  |         if (options.allowMove) { | ||
|  |           Coords.moveOffset([x, y]); | ||
|  |           Selection.updateVisible(true); | ||
|  |         } | ||
|  |         e.preventDefault(); | ||
|  |         e.stopPropagation(); | ||
|  |       } | ||
|  |       //}}}
 | ||
|  |       function parseKey(e) //{{{
 | ||
|  |       { | ||
|  |         if (e.ctrlKey || e.metaKey) { | ||
|  |           return true; | ||
|  |         } | ||
|  |         shift_down = e.shiftKey ? true : false; | ||
|  |         var nudge = shift_down ? 10 : 1; | ||
|  | 
 | ||
|  |         switch (e.keyCode) { | ||
|  |         case 37: | ||
|  |           doNudge(e, -nudge, 0); | ||
|  |           break; | ||
|  |         case 39: | ||
|  |           doNudge(e, nudge, 0); | ||
|  |           break; | ||
|  |         case 38: | ||
|  |           doNudge(e, 0, -nudge); | ||
|  |           break; | ||
|  |         case 40: | ||
|  |           doNudge(e, 0, nudge); | ||
|  |           break; | ||
|  |         case 27: | ||
|  |           if (options.allowSelect) Selection.release(); | ||
|  |           break; | ||
|  |         case 9: | ||
|  |           return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         return false; | ||
|  |       } | ||
|  |       //}}}
 | ||
|  | 
 | ||
|  |       if (options.keySupport) { | ||
|  |         $keymgr.keydown(parseKey).blur(onBlur); | ||
|  |         if (ie6mode || !options.fixedSupport) { | ||
|  |           $keymgr.css({ | ||
|  |             position: 'absolute', | ||
|  |             left: '-20px' | ||
|  |           }); | ||
|  |           $keywrap.append($keymgr).insertBefore($img); | ||
|  |         } else { | ||
|  |           $keymgr.insertBefore($img); | ||
|  |         } | ||
|  |       } | ||
|  | 
 | ||
|  | 
 | ||
|  |       return { | ||
|  |         watchKeys: watchKeys | ||
|  |       }; | ||
|  |     }()); | ||
|  |     //}}}
 | ||
|  |     // }}}
 | ||
|  |     // API methods {{{
 | ||
|  |     function setClass(cname) //{{{
 | ||
|  |     { | ||
|  |       $div.removeClass().addClass(cssClass('holder')).addClass(cname); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function animateTo(a, callback) //{{{
 | ||
|  |     { | ||
|  |       var x1 = a[0] / xscale, | ||
|  |           y1 = a[1] / yscale, | ||
|  |           x2 = a[2] / xscale, | ||
|  |           y2 = a[3] / yscale; | ||
|  | 
 | ||
|  |       if (animating) { | ||
|  |         return; | ||
|  |       } | ||
|  | 
 | ||
|  |       var animto = Coords.flipCoords(x1, y1, x2, y2), | ||
|  |           c = Coords.getFixed(), | ||
|  |           initcr = [c.x, c.y, c.x2, c.y2], | ||
|  |           animat = initcr, | ||
|  |           interv = options.animationDelay, | ||
|  |           ix1 = animto[0] - initcr[0], | ||
|  |           iy1 = animto[1] - initcr[1], | ||
|  |           ix2 = animto[2] - initcr[2], | ||
|  |           iy2 = animto[3] - initcr[3], | ||
|  |           pcent = 0, | ||
|  |           velocity = options.swingSpeed; | ||
|  | 
 | ||
|  |       x1 = animat[0]; | ||
|  |       y1 = animat[1]; | ||
|  |       x2 = animat[2]; | ||
|  |       y2 = animat[3]; | ||
|  | 
 | ||
|  |       Selection.animMode(true); | ||
|  |       var anim_timer; | ||
|  | 
 | ||
|  |       function queueAnimator() { | ||
|  |         window.setTimeout(animator, interv); | ||
|  |       } | ||
|  |       var animator = (function () { | ||
|  |         return function () { | ||
|  |           pcent += (100 - pcent) / velocity; | ||
|  | 
 | ||
|  |           animat[0] = Math.round(x1 + ((pcent / 100) * ix1)); | ||
|  |           animat[1] = Math.round(y1 + ((pcent / 100) * iy1)); | ||
|  |           animat[2] = Math.round(x2 + ((pcent / 100) * ix2)); | ||
|  |           animat[3] = Math.round(y2 + ((pcent / 100) * iy2)); | ||
|  | 
 | ||
|  |           if (pcent >= 99.8) { | ||
|  |             pcent = 100; | ||
|  |           } | ||
|  |           if (pcent < 100) { | ||
|  |             setSelectRaw(animat); | ||
|  |             queueAnimator(); | ||
|  |           } else { | ||
|  |             Selection.done(); | ||
|  |             Selection.animMode(false); | ||
|  |             if (typeof(callback) === 'function') { | ||
|  |               callback.call(api); | ||
|  |             } | ||
|  |           } | ||
|  |         }; | ||
|  |       }()); | ||
|  |       queueAnimator(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function setSelect(rect) //{{{
 | ||
|  |     { | ||
|  |       setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]); | ||
|  |       options.onSelect.call(api, unscale(Coords.getFixed())); | ||
|  |       Selection.enableHandles(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function setSelectRaw(l) //{{{
 | ||
|  |     { | ||
|  |       Coords.setPressed([l[0], l[1]]); | ||
|  |       Coords.setCurrent([l[2], l[3]]); | ||
|  |       Selection.update(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function tellSelect() //{{{
 | ||
|  |     { | ||
|  |       return unscale(Coords.getFixed()); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function tellScaled() //{{{
 | ||
|  |     { | ||
|  |       return Coords.getFixed(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function setOptionsNew(opt) //{{{
 | ||
|  |     { | ||
|  |       setOptions(opt); | ||
|  |       interfaceUpdate(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function disableCrop() //{{{
 | ||
|  |     { | ||
|  |       options.disabled = true; | ||
|  |       Selection.disableHandles(); | ||
|  |       Selection.setCursor('default'); | ||
|  |       Tracker.setCursor('default'); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function enableCrop() //{{{
 | ||
|  |     { | ||
|  |       options.disabled = false; | ||
|  |       interfaceUpdate(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function cancelCrop() //{{{
 | ||
|  |     { | ||
|  |       Selection.done(); | ||
|  |       Tracker.activateHandlers(null, null); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function destroy() //{{{
 | ||
|  |     { | ||
|  |       $div.remove(); | ||
|  |       $origimg.show(); | ||
|  |       $origimg.css('visibility','visible'); | ||
|  |       $(obj).removeData('Jcrop'); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function setImage(src, callback) //{{{
 | ||
|  |     { | ||
|  |       Selection.release(); | ||
|  |       disableCrop(); | ||
|  |       var img = new Image(); | ||
|  |       img.onload = function () { | ||
|  |         var iw = img.width; | ||
|  |         var ih = img.height; | ||
|  |         var bw = options.boxWidth; | ||
|  |         var bh = options.boxHeight; | ||
|  |         $img.width(iw).height(ih); | ||
|  |         $img.attr('src', src); | ||
|  |         $img2.attr('src', src); | ||
|  |         presize($img, bw, bh); | ||
|  |         boundx = $img.width(); | ||
|  |         boundy = $img.height(); | ||
|  |         $img2.width(boundx).height(boundy); | ||
|  |         $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2)); | ||
|  |         $div.width(boundx).height(boundy); | ||
|  |         Shade.resize(boundx,boundy); | ||
|  |         enableCrop(); | ||
|  | 
 | ||
|  |         if (typeof(callback) === 'function') { | ||
|  |           callback.call(api); | ||
|  |         } | ||
|  |       }; | ||
|  |       img.src = src; | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     function colorChangeMacro($obj,color,now) { | ||
|  |       var mycolor = color || options.bgColor; | ||
|  |       if (options.bgFade && supportsColorFade() && options.fadeTime && !now) { | ||
|  |         $obj.animate({ | ||
|  |           backgroundColor: mycolor | ||
|  |         }, { | ||
|  |           queue: false, | ||
|  |           duration: options.fadeTime | ||
|  |         }); | ||
|  |       } else { | ||
|  |         $obj.css('backgroundColor', mycolor); | ||
|  |       } | ||
|  |     } | ||
|  |     function interfaceUpdate(alt) //{{{
 | ||
|  |     // This method tweaks the interface based on options object.
 | ||
|  |     // Called when options are changed and at end of initialization.
 | ||
|  |     { | ||
|  |       if (options.allowResize) { | ||
|  |         if (alt) { | ||
|  |           Selection.enableOnly(); | ||
|  |         } else { | ||
|  |           Selection.enableHandles(); | ||
|  |         } | ||
|  |       } else { | ||
|  |         Selection.disableHandles(); | ||
|  |       } | ||
|  | 
 | ||
|  |       Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); | ||
|  |       Selection.setCursor(options.allowMove ? 'move' : 'default'); | ||
|  | 
 | ||
|  |       if (options.hasOwnProperty('trueSize')) { | ||
|  |         xscale = options.trueSize[0] / boundx; | ||
|  |         yscale = options.trueSize[1] / boundy; | ||
|  |       } | ||
|  | 
 | ||
|  |       if (options.hasOwnProperty('setSelect')) { | ||
|  |         setSelect(options.setSelect); | ||
|  |         Selection.done(); | ||
|  |         delete(options.setSelect); | ||
|  |       } | ||
|  | 
 | ||
|  |       Shade.refresh(); | ||
|  | 
 | ||
|  |       if (options.bgColor != bgcolor) { | ||
|  |         colorChangeMacro( | ||
|  |           options.shade? Shade.getShades(): $div, | ||
|  |           options.shade? | ||
|  |             (options.shadeColor || options.bgColor): | ||
|  |             options.bgColor | ||
|  |         ); | ||
|  |         bgcolor = options.bgColor; | ||
|  |       } | ||
|  | 
 | ||
|  |       if (bgopacity != options.bgOpacity) { | ||
|  |         bgopacity = options.bgOpacity; | ||
|  |         if (options.shade) Shade.refresh(); | ||
|  |           else Selection.setBgOpacity(bgopacity); | ||
|  |       } | ||
|  | 
 | ||
|  |       xlimit = options.maxSize[0] || 0; | ||
|  |       ylimit = options.maxSize[1] || 0; | ||
|  |       xmin = options.minSize[0] || 0; | ||
|  |       ymin = options.minSize[1] || 0; | ||
|  | 
 | ||
|  |       if (options.hasOwnProperty('outerImage')) { | ||
|  |         $img.attr('src', options.outerImage); | ||
|  |         delete(options.outerImage); | ||
|  |       } | ||
|  | 
 | ||
|  |       Selection.refresh(); | ||
|  |     } | ||
|  |     //}}}
 | ||
|  |     //}}}
 | ||
|  | 
 | ||
|  |     if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection); | ||
|  | 
 | ||
|  |     $hdl_holder.hide(); | ||
|  |     interfaceUpdate(true); | ||
|  | 
 | ||
|  |     var api = { | ||
|  |       setImage: setImage, | ||
|  |       animateTo: animateTo, | ||
|  |       setSelect: setSelect, | ||
|  |       setOptions: setOptionsNew, | ||
|  |       tellSelect: tellSelect, | ||
|  |       tellScaled: tellScaled, | ||
|  |       setClass: setClass, | ||
|  | 
 | ||
|  |       disable: disableCrop, | ||
|  |       enable: enableCrop, | ||
|  |       cancel: cancelCrop, | ||
|  |       release: Selection.release, | ||
|  |       destroy: destroy, | ||
|  | 
 | ||
|  |       focus: KeyManager.watchKeys, | ||
|  | 
 | ||
|  |       getBounds: function () { | ||
|  |         return [boundx * xscale, boundy * yscale]; | ||
|  |       }, | ||
|  |       getWidgetSize: function () { | ||
|  |         return [boundx, boundy]; | ||
|  |       }, | ||
|  |       getScaleFactor: function () { | ||
|  |         return [xscale, yscale]; | ||
|  |       }, | ||
|  |       getOptions: function() { | ||
|  |         // careful: internal values are returned
 | ||
|  |         return options; | ||
|  |       }, | ||
|  | 
 | ||
|  |       ui: { | ||
|  |         holder: $div, | ||
|  |         selection: $sel | ||
|  |       } | ||
|  |     }; | ||
|  | 
 | ||
|  |     if (is_msie) $div.bind('selectstart', function () { return false; }); | ||
|  | 
 | ||
|  |     $origimg.data('Jcrop', api); | ||
|  |     return api; | ||
|  |   }; | ||
|  |   $.fn.Jcrop = function (options, callback) //{{{
 | ||
|  |   { | ||
|  |     var api; | ||
|  |     // Iterate over each object, attach Jcrop
 | ||
|  |     this.each(function () { | ||
|  |       // If we've already attached to this object
 | ||
|  |       if ($(this).data('Jcrop')) { | ||
|  |         // The API can be requested this way (undocumented)
 | ||
|  |         if (options === 'api') return $(this).data('Jcrop'); | ||
|  |         // Otherwise, we just reset the options...
 | ||
|  |         else $(this).data('Jcrop').setOptions(options); | ||
|  |       } | ||
|  |       // If we haven't been attached, preload and attach
 | ||
|  |       else { | ||
|  |         if (this.tagName == 'IMG') | ||
|  |           $.Jcrop.Loader(this,function(){ | ||
|  |             $(this).css({display:'block',visibility:'hidden'}); | ||
|  |             api = $.Jcrop(this, options); | ||
|  |             if ($.isFunction(callback)) callback.call(api); | ||
|  |           }); | ||
|  |         else { | ||
|  |           $(this).css({display:'block',visibility:'hidden'}); | ||
|  |           api = $.Jcrop(this, options); | ||
|  |           if ($.isFunction(callback)) callback.call(api); | ||
|  |         } | ||
|  |       } | ||
|  |     }); | ||
|  | 
 | ||
|  |     // Return "this" so the object is chainable (jQuery-style)
 | ||
|  |     return this; | ||
|  |   }; | ||
|  |   //}}}
 | ||
|  |   // $.Jcrop.Loader - basic image loader {{{
 | ||
|  | 
 | ||
|  |   $.Jcrop.Loader = function(imgobj,success,error){ | ||
|  |     var $img = $(imgobj), img = $img[0]; | ||
|  | 
 | ||
|  |     function completeCheck(){ | ||
|  |       if (img.complete) { | ||
|  |         $img.unbind('.jcloader'); | ||
|  |         if ($.isFunction(success)) success.call(img); | ||
|  |       } | ||
|  |       else window.setTimeout(completeCheck,50); | ||
|  |     } | ||
|  | 
 | ||
|  |     $img | ||
|  |       .bind('load.jcloader',completeCheck) | ||
|  |       .bind('error.jcloader',function(e){ | ||
|  |         $img.unbind('.jcloader'); | ||
|  |         if ($.isFunction(error)) error.call(img); | ||
|  |       }); | ||
|  | 
 | ||
|  |     if (img.complete && $.isFunction(success)){ | ||
|  |       $img.unbind('.jcloader'); | ||
|  |       success.call(img); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   //}}}
 | ||
|  |   // Global Defaults {{{
 | ||
|  |   $.Jcrop.defaults = { | ||
|  | 
 | ||
|  |     // Basic Settings
 | ||
|  |     allowSelect: true, | ||
|  |     allowMove: true, | ||
|  |     allowResize: true, | ||
|  | 
 | ||
|  |     trackDocument: true, | ||
|  | 
 | ||
|  |     // Styling Options
 | ||
|  |     baseClass: 'jcrop', | ||
|  |     addClass: null, | ||
|  |     bgColor: 'black', | ||
|  |     bgOpacity: 0.6, | ||
|  |     bgFade: false, | ||
|  |     borderOpacity: 0.4, | ||
|  |     handleOpacity: 0.5, | ||
|  |     handleSize: null, | ||
|  | 
 | ||
|  |     aspectRatio: 0, | ||
|  |     keySupport: true, | ||
|  |     createHandles: ['n','s','e','w','nw','ne','se','sw'], | ||
|  |     createDragbars: ['n','s','e','w'], | ||
|  |     createBorders: ['n','s','e','w'], | ||
|  |     drawBorders: true, | ||
|  |     dragEdges: true, | ||
|  |     fixedSupport: true, | ||
|  |     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], | ||
|  | 
 | ||
|  |     // Callbacks / Event Handlers
 | ||
|  |     onChange: function () {}, | ||
|  |     onSelect: function () {}, | ||
|  |     onDblClick: function () {}, | ||
|  |     onRelease: function () {} | ||
|  |   }; | ||
|  | 
 | ||
|  |   // }}}
 | ||
|  | }(jQuery)); |