WordPress.org

Make WordPress Core

Ticket #20728: jcrop.diff

File jcrop.diff, 71.8 KB (added by niallkennedy, 23 months ago)

Jcrop 0.9.10 JS and CSS diff

  • wp-includes/js/jcrop/jquery.Jcrop.css

     
    1 /* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */ 
    2 .jcrop-holder { text-align: left; } 
     1/* jquery.Jcrop.css v0.9.10 - MIT License */ 
    32 
    4 .jcrop-vline, .jcrop-hline 
     3/* 
     4  The outer-most container in a typical Jcrop instance 
     5  If you are having difficulty with formatting related to styles 
     6  on a parent element, place any fixes here or in a like selector 
     7 
     8  You can also style this element if you want to add a border, etc 
     9  A better method for styling can be seen below with .jcrop-light 
     10  (Add a class to the holder and style elements for that extended class) 
     11*/ 
     12.jcrop-holder { 
     13  direction: ltr; 
     14  text-align: left; 
     15} 
     16 
     17/* These styles define the border lines */ 
     18.jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif) top left repeat;font-size:0;position:absolute;} 
     19.jcrop-vline{height:100%;width:1px!important;} 
     20.jcrop-hline{height:1px!important;width:100%;} 
     21.jcrop-vline.right{right:0;} 
     22.jcrop-hline.bottom{bottom:0;} 
     23 
     24/* Handle style - size is set by Jcrop handleSize option (currently) */ 
     25.jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;} 
     26 
     27/* This style is used for invisible click targets */ 
     28.jcrop-tracker 
    529{ 
    6         font-size: 0; 
    7         position: absolute; 
    8         background: white url('Jcrop.gif') top left repeat; 
     30  height: 100%;  
     31  width: 100%; 
     32  -webkit-tap-highlight-color: transparent; /* "turn off" link highlight */ 
     33  -webkit-touch-callout: none;              /* disable callout, image save panel */ 
     34  -webkit-user-select: none;                /* disable cut copy paste */ 
    935} 
    10 .jcrop-vline { height: 100%; width: 1px !important; } 
    11 .jcrop-hline { width: 100%; height: 1px !important; } 
    12 .jcrop-handle { 
    13         font-size: 1px; 
    14         width: 7px !important; 
    15         height: 7px !important; 
    16         border: 1px #eee solid; 
    17         background-color: #333; 
    18         *width: 9px; 
    19         *height: 9px; 
    20 } 
    2136 
    22 .jcrop-tracker { width: 100%; height: 100%; } 
     37/* Positioning of handles and drag bars */ 
     38.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;} 
     39.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;} 
     40.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;} 
     41.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;} 
     42.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;} 
     43.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;} 
     44.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;} 
     45.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;} 
     46.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;} 
     47.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;} 
     48.jcrop-dragbar.ord-n{margin-top:-4px;} 
     49.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;} 
     50.jcrop-dragbar.ord-e{margin-right:-4px;right:0;} 
     51.jcrop-dragbar.ord-w{margin-left:-4px;} 
    2352 
    24 .custom .jcrop-vline, 
    25 .custom .jcrop-hline 
     53/* The "jcrop-light" class/extension */ 
     54.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline 
    2655{ 
    27         background: yellow; 
     56        background:#FFF; 
     57        filter:Alpha(opacity=70)!important; 
     58        opacity:.70!important; 
    2859} 
    29 .custom .jcrop-handle 
     60.jcrop-light .jcrop-handle 
    3061{ 
    31         border-color: black; 
    32         background-color: #C7BB00; 
    33         -moz-border-radius: 3px; 
    34         -webkit-border-radius: 3px; 
     62        -moz-border-radius:3px; 
     63        -webkit-border-radius:3px; 
     64        background-color:#000; 
     65        border-color:#FFF; 
     66        border-radius:3px; 
    3567} 
     68 
     69/* The "jcrop-dark" class/extension */ 
     70.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline 
     71{ 
     72        background:#000; 
     73        filter:Alpha(opacity=70)!important; 
     74        opacity:.7!important; 
     75} 
     76.jcrop-dark .jcrop-handle 
     77{ 
     78        -moz-border-radius:3px; 
     79        -webkit-border-radius:3px; 
     80        background-color:#FFF; 
     81        border-color:#000; 
     82        border-radius:3px; 
     83} 
     84 
     85/* Fix for twitter bootstrap et al. */ 
     86.jcrop-holder img,img.jcrop-preview{ max-width: none; } 
  • wp-includes/js/jcrop/jquery.Jcrop.dev.js

     
    11/** 
    2  * jquery.Jcrop.js v0.9.8 
    3  * jQuery Image Cropping Plugin 
    4  * @author Kelly Hallman <khallman@gmail.com> 
    5  * Copyright (c) 2008-2009 Kelly Hallman - released under MIT License {{{ 
     2 * jquery.Jcrop.js v0.9.10 
     3 * jQuery Image Cropping Plugin - released under MIT License  
     4 * Author: Kelly Hallman <khallman@gmail.com> 
     5 * http://github.com/tapmodo/Jcrop 
     6 * Copyright (c) 2008-2012 Tapmodo Interactive LLC {{{ 
    67 * 
    78 * Permission is hereby granted, free of charge, to any person 
    89 * obtaining a copy of this software and associated documentation 
     
    1213 * copies of the Software, and to permit persons to whom the 
    1314 * Software is furnished to do so, subject to the following 
    1415 * conditions: 
    15  
     16 * 
    1617 * The above copyright notice and this permission notice shall be 
    1718 * included in all copies or substantial portions of the Software. 
    18  
     19 * 
    1920 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    2021 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
    2122 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     
    2425 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    2526 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
    2627 * OTHER DEALINGS IN THE SOFTWARE. 
    27  
     28 * 
    2829 * }}} 
    2930 */ 
    3031 
    31 (function($) { 
     32(function ($) { 
    3233 
    33 $.Jcrop = function(obj,opt) 
    34 { 
    35         // Initialization {{{ 
     34  $.Jcrop = function (obj, opt) { 
     35    var options = $.extend({}, $.Jcrop.defaults), 
     36        docOffset, lastcurs, ie6mode = false; 
    3637 
    37         // Sanitize some options {{{ 
    38         var obj = obj, opt = opt; 
     38    // Internal Methods {{{ 
     39    function px(n) { 
     40      return n + 'px'; 
     41    } 
     42    function cssClass(cl) { 
     43      return options.baseClass + '-' + cl; 
     44    } 
     45    function supportsColorFade() { 
     46      return $.fx.step.hasOwnProperty('backgroundColor'); 
     47    } 
     48    function getPos(obj) //{{{ 
     49    { 
     50      var pos = $(obj).offset(); 
     51      return [pos.left, pos.top]; 
     52    } 
     53    //}}} 
     54    function mouseAbs(e) //{{{ 
     55    { 
     56      return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])]; 
     57    } 
     58    //}}} 
     59    function setOptions(opt) //{{{ 
     60    { 
     61      if (typeof(opt) !== 'object') opt = {}; 
     62      options = $.extend(options, opt); 
    3963 
    40         if (typeof(obj) !== 'object') obj = $(obj)[0]; 
    41         if (typeof(opt) !== 'object') opt = { }; 
     64      $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) { 
     65        if (typeof(options[e]) !== 'function') options[e] = function () {}; 
     66      }); 
     67    } 
     68    //}}} 
     69    function startDragMode(mode, pos) //{{{ 
     70    { 
     71      docOffset = getPos($img); 
     72      Tracker.setCursor(mode === 'move' ? mode : mode + '-resize'); 
    4273 
    43         // Some on-the-fly fixes for MSIE...sigh 
    44         if (!('trackDocument' in opt)) 
    45         { 
    46                 opt.trackDocument = $.browser.msie ? false : true; 
    47                 if ($.browser.msie && $.browser.version.split('.')[0] == '8') 
    48                         opt.trackDocument = true; 
    49         } 
     74      if (mode === 'move') { 
     75        return Tracker.activateHandlers(createMover(pos), doneSelect); 
     76      } 
    5077 
    51         if (!('keySupport' in opt)) 
    52                         opt.keySupport = $.browser.msie ? false : true; 
    53                  
    54         // }}} 
    55         // Extend the default options {{{ 
    56         var defaults = { 
     78      var fc = Coords.getFixed(); 
     79      var opp = oppLockCorner(mode); 
     80      var opc = Coords.getCorner(oppLockCorner(opp)); 
    5781 
    58                 // Basic Settings 
    59                 trackDocument:          false, 
    60                 baseClass:                      'jcrop', 
    61                 addClass:                       null, 
     82      Coords.setPressed(Coords.getCorner(opp)); 
     83      Coords.setCurrent(opc); 
    6284 
    63                 // Styling Options 
    64                 bgColor:                        'black', 
    65                 bgOpacity:                      .6, 
    66                 borderOpacity:          .4, 
    67                 handleOpacity:          .5, 
     85      Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect); 
     86    } 
     87    //}}} 
     88    function dragmodeHandler(mode, f) //{{{ 
     89    { 
     90      return function (pos) { 
     91        if (!options.aspectRatio) { 
     92          switch (mode) { 
     93          case 'e': 
     94            pos[1] = f.y2; 
     95            break; 
     96          case 'w': 
     97            pos[1] = f.y2; 
     98            break; 
     99          case 'n': 
     100            pos[0] = f.x2; 
     101            break; 
     102          case 's': 
     103            pos[0] = f.x2; 
     104            break; 
     105          } 
     106        } else { 
     107          switch (mode) { 
     108          case 'e': 
     109            pos[1] = f.y + 1; 
     110            break; 
     111          case 'w': 
     112            pos[1] = f.y + 1; 
     113            break; 
     114          case 'n': 
     115            pos[0] = f.x + 1; 
     116            break; 
     117          case 's': 
     118            pos[0] = f.x + 1; 
     119            break; 
     120          } 
     121        } 
     122        Coords.setCurrent(pos); 
     123        Selection.update(); 
     124      }; 
     125    } 
     126    //}}} 
     127    function createMover(pos) //{{{ 
     128    { 
     129      var lloc = pos; 
     130      KeyManager.watchKeys(); 
    68131 
    69                 handlePad:                      5, 
    70                 handleSize:                     9, 
    71                 handleOffset:           5, 
    72                 edgeMargin:                     14, 
     132      return function (pos) { 
     133        Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); 
     134        lloc = pos; 
    73135 
    74                 aspectRatio:            0, 
    75                 keySupport:                     true, 
    76                 cornerHandles:          true, 
    77                 sideHandles:            true, 
    78                 drawBorders:            true, 
    79                 dragEdges:                      true, 
     136        Selection.update(); 
     137      }; 
     138    } 
     139    //}}} 
     140    function oppLockCorner(ord) //{{{ 
     141    { 
     142      switch (ord) { 
     143      case 'n': 
     144        return 'sw'; 
     145      case 's': 
     146        return 'nw'; 
     147      case 'e': 
     148        return 'nw'; 
     149      case 'w': 
     150        return 'ne'; 
     151      case 'ne': 
     152        return 'sw'; 
     153      case 'nw': 
     154        return 'se'; 
     155      case 'se': 
     156        return 'nw'; 
     157      case 'sw': 
     158        return 'ne'; 
     159      } 
     160    } 
     161    //}}} 
     162    function createDragger(ord) //{{{ 
     163    { 
     164      return function (e) { 
     165        if (options.disabled) { 
     166          return false; 
     167        } 
     168        if ((ord === 'move') && !options.allowMove) { 
     169          return false; 
     170        } 
     171         
     172        // Fix position of crop area when dragged the very first time. 
     173        // Necessary when crop image is in a hidden element when page is loaded. 
     174        docOffset = getPos($img); 
    80175 
    81                 boxWidth:                       0, 
    82                 boxHeight:                      0, 
     176        btndown = true; 
     177        startDragMode(ord, mouseAbs(e)); 
     178        e.stopPropagation(); 
     179        e.preventDefault(); 
     180        return false; 
     181      }; 
     182    } 
     183    //}}} 
     184    function presize($obj, w, h) //{{{ 
     185    { 
     186      var nw = $obj.width(), 
     187          nh = $obj.height(); 
     188      if ((nw > w) && w > 0) { 
     189        nw = w; 
     190        nh = (w / $obj.width()) * $obj.height(); 
     191      } 
     192      if ((nh > h) && h > 0) { 
     193        nh = h; 
     194        nw = (h / $obj.height()) * $obj.width(); 
     195      } 
     196      xscale = $obj.width() / nw; 
     197      yscale = $obj.height() / nh; 
     198      $obj.width(nw).height(nh); 
     199    } 
     200    //}}} 
     201    function unscale(c) //{{{ 
     202    { 
     203      return { 
     204        x: c.x * xscale, 
     205        y: c.y * yscale, 
     206        x2: c.x2 * xscale, 
     207        y2: c.y2 * yscale, 
     208        w: c.w * xscale, 
     209        h: c.h * yscale 
     210      }; 
     211    } 
     212    //}}} 
     213    function doneSelect(pos) //{{{ 
     214    { 
     215      var c = Coords.getFixed(); 
     216      if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) { 
     217        Selection.enableHandles(); 
     218        Selection.done(); 
     219      } else { 
     220        Selection.release(); 
     221      } 
     222      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); 
     223    } 
     224    //}}} 
     225    function newSelection(e) //{{{ 
     226    { 
     227      if (options.disabled) { 
     228        return false; 
     229      } 
     230      if (!options.allowSelect) { 
     231        return false; 
     232      } 
     233      btndown = true; 
     234      docOffset = getPos($img); 
     235      Selection.disableHandles(); 
     236      Tracker.setCursor('crosshair'); 
     237      var pos = mouseAbs(e); 
     238      Coords.setPressed(pos); 
     239      Selection.update(); 
     240      Tracker.activateHandlers(selectDrag, doneSelect); 
     241      KeyManager.watchKeys(); 
    83242 
    84                 boundary:                       8, 
    85                 animationDelay:         20, 
    86                 swingSpeed:                     3, 
     243      e.stopPropagation(); 
     244      e.preventDefault(); 
     245      return false; 
     246    } 
     247    //}}} 
     248    function selectDrag(pos) //{{{ 
     249    { 
     250      Coords.setCurrent(pos); 
     251      Selection.update(); 
     252    } 
     253    //}}} 
     254    function newTracker() //{{{ 
     255    { 
     256      var trk = $('<div></div>').addClass(cssClass('tracker')); 
     257      if ($.browser.msie) { 
     258        trk.css({ 
     259          opacity: 0, 
     260          backgroundColor: 'white' 
     261        }); 
     262      } 
     263      return trk; 
     264    } 
     265    //}}} 
    87266 
    88                 allowSelect:            true, 
    89                 allowMove:                      true, 
    90                 allowResize:            true, 
     267    // }}} 
     268    // Initialization {{{ 
     269    // Sanitize some options {{{ 
     270    if ($.browser.msie && ($.browser.version.split('.')[0] === '6')) { 
     271      ie6mode = true; 
     272    } 
     273    if (typeof(obj) !== 'object') { 
     274      obj = $(obj)[0]; 
     275    } 
     276    if (typeof(opt) !== 'object') { 
     277      opt = {}; 
     278    } 
     279    // }}} 
     280    setOptions(opt); 
     281    // Initialize some jQuery objects {{{ 
     282    // The values are SET on the image(s) for the interface 
     283    // If the original image has any of these set, they will be reset 
     284    // However, if you destroy() the Jcrop instance the original image's 
     285    // character in the DOM will be as you left it. 
     286    var img_css = { 
     287      border: 'none', 
     288      visibility: 'visible', 
     289      margin: 0, 
     290      padding: 0, 
     291      position: 'absolute', 
     292      top: 0, 
     293      left: 0 
     294    }; 
    91295 
    92                 minSelect:                      [ 0, 0 ], 
    93                 maxSize:                        [ 0, 0 ], 
    94                 minSize:                        [ 0, 0 ], 
     296    var $origimg = $(obj), 
     297      img_mode = true; 
    95298 
    96                 // Callbacks / Event Handlers 
    97                 onChange: function() { }, 
    98                 onSelect: function() { } 
     299    if (obj.tagName == 'IMG') { 
     300      // Fix size of crop image. 
     301      // Necessary when crop image is within a hidden element when page is loaded. 
     302      if ($origimg[0].width != 0 && $origimg[0].height != 0) { 
     303        // Obtain dimensions from contained img element. 
     304        $origimg.width($origimg[0].width); 
     305        $origimg.height($origimg[0].height); 
     306      } else { 
     307        // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0).  
     308        var tempImage = new Image(); 
     309        tempImage.src = $origimg[0].src; 
     310        $origimg.width(tempImage.width); 
     311        $origimg.height(tempImage.height); 
     312      }  
    99313 
    100         }; 
    101         var options = defaults; 
    102         setOptions(opt); 
     314      var $img = $origimg.clone().removeAttr('id').css(img_css).show(); 
    103315 
    104         // }}} 
    105         // Initialize some jQuery objects {{{ 
     316      $img.width($origimg.width()); 
     317      $img.height($origimg.height()); 
     318      $origimg.after($img).hide(); 
    106319 
    107         var $origimg = $(obj); 
    108         var $img = $origimg.clone().removeAttr('id').css({ position: 'absolute' }); 
     320    } else { 
     321      $img = $origimg.css(img_css).show(); 
     322      img_mode = false; 
     323      if (options.shade === null) { options.shade = true; } 
     324    } 
    109325 
    110         $img.width($origimg.width()); 
    111         $img.height($origimg.height()); 
    112         $origimg.after($img).hide(); 
     326    presize($img, options.boxWidth, options.boxHeight); 
    113327 
    114         presize($img,options.boxWidth,options.boxHeight); 
     328    var boundx = $img.width(), 
     329        boundy = $img.height(), 
     330         
     331         
     332        $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({ 
     333        position: 'relative', 
     334        backgroundColor: options.bgColor 
     335      }).insertAfter($origimg).append($img); 
    115336 
    116         var boundx = $img.width(), 
    117                 boundy = $img.height(), 
     337    if (options.addClass) { 
     338      $div.addClass(options.addClass); 
     339    } 
    118340 
    119                 $div = $('<div />') 
    120                         .width(boundx).height(boundy) 
    121                         .addClass(cssClass('holder')) 
    122                         .css({ 
    123                                 position: 'relative', 
    124                                 backgroundColor: options.bgColor 
    125                         }).insertAfter($origimg).append($img); 
    126         ; 
    127          
    128         if (options.addClass) $div.addClass(options.addClass); 
    129         //$img.wrap($div); 
     341    var $img2 = $('<div />'), 
    130342 
    131         var $img2 = $('<img />')/*{{{*/ 
    132                         .attr('src',$img.attr('src')) 
    133                         .css('position','absolute') 
    134                         .width(boundx).height(boundy) 
    135         ;/*}}}*/ 
    136         var $img_holder = $('<div />')/*{{{*/ 
    137                 .width(pct(100)).height(pct(100)) 
    138                 .css({ 
    139                         zIndex: 310, 
    140                         position: 'absolute', 
    141                         overflow: 'hidden' 
    142                 }) 
    143                 .append($img2) 
    144         ;/*}}}*/ 
    145         var $hdl_holder = $('<div />')/*{{{*/ 
    146                 .width(pct(100)).height(pct(100)) 
    147                 .css('zIndex',320); 
    148         /*}}}*/ 
    149         var $sel = $('<div />')/*{{{*/ 
    150                 .css({ 
    151                         position: 'absolute', 
    152                         zIndex: 300 
    153                 }) 
    154                 .insertBefore($img) 
    155                 .append($img_holder,$hdl_holder) 
    156         ;/*}}}*/ 
     343        $img_holder = $('<div />')  
     344        .width('100%').height('100%').css({ 
     345          zIndex: 310, 
     346          position: 'absolute', 
     347          overflow: 'hidden' 
     348        }), 
    157349 
    158         var bound = options.boundary; 
    159         var $trk = newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)) 
    160                 .css({ position: 'absolute', top: px(-bound), left: px(-bound), zIndex: 290 }) 
    161                 .mousedown(newSelection);        
    162          
    163         /* }}} */ 
    164         // Set more variables {{{ 
     350        $hdl_holder = $('<div />')  
     351        .width('100%').height('100%').css('zIndex', 320),  
    165352 
    166         var xlimit, ylimit, xmin, ymin; 
    167         var xscale, yscale, enabled = true; 
    168         var docOffset = getPos($img), 
    169                 // Internal states 
    170                 btndown, lastcurs, dimmed, animating, 
    171                 shift_down; 
     353        $sel = $('<div />')  
     354        .css({ 
     355          position: 'absolute', 
     356          zIndex: 600 
     357        }).dblclick(function(){ 
     358          var c = Coords.getFixed(); 
     359          options.onDblClick.call(api,c); 
     360        }).insertBefore($img).append($img_holder, $hdl_holder);  
    172361 
    173         // }}} 
    174                  
     362    if (img_mode) { 
    175363 
    176                 // }}} 
    177         // Internal Modules {{{ 
     364      $img2 = $('<img />') 
     365          .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), 
    178366 
    179         var Coords = function()/*{{{*/ 
    180         { 
    181                 var x1 = 0, y1 = 0, x2 = 0, y2 = 0, ox, oy; 
     367      $img_holder.append($img2); 
    182368 
    183                 function setPressed(pos)/*{{{*/ 
    184                 { 
    185                         var pos = rebound(pos); 
    186                         x2 = x1 = pos[0]; 
    187                         y2 = y1 = pos[1]; 
    188                 }; 
    189                 /*}}}*/ 
    190                 function setCurrent(pos)/*{{{*/ 
    191                 { 
    192                         var pos = rebound(pos); 
    193                         ox = pos[0] - x2; 
    194                         oy = pos[1] - y2; 
    195                         x2 = pos[0]; 
    196                         y2 = pos[1]; 
    197                 }; 
    198                 /*}}}*/ 
    199                 function getOffset()/*{{{*/ 
    200                 { 
    201                         return [ ox, oy ]; 
    202                 }; 
    203                 /*}}}*/ 
    204                 function moveOffset(offset)/*{{{*/ 
    205                 { 
    206                         var ox = offset[0], oy = offset[1]; 
     369    } 
    207370 
    208                         if (0 > x1 + ox) ox -= ox + x1; 
    209                         if (0 > y1 + oy) oy -= oy + y1; 
     371    if (ie6mode) { 
     372      $sel.css({ 
     373        overflowY: 'hidden' 
     374      }); 
     375    } 
    210376 
    211                         if (boundy < y2 + oy) oy += boundy - (y2 + oy); 
    212                         if (boundx < x2 + ox) ox += boundx - (x2 + ox); 
     377    var bound = options.boundary; 
     378    var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({ 
     379      position: 'absolute', 
     380      top: px(-bound), 
     381      left: px(-bound), 
     382      zIndex: 290 
     383    }).mousedown(newSelection); 
    213384 
    214                         x1 += ox; 
    215                         x2 += ox; 
    216                         y1 += oy; 
    217                         y2 += oy; 
    218                 }; 
    219                 /*}}}*/ 
    220                 function getCorner(ord)/*{{{*/ 
    221                 { 
    222                         var c = getFixed(); 
    223                         switch(ord) 
    224                         { 
    225                                 case 'ne': return [ c.x2, c.y ]; 
    226                                 case 'nw': return [ c.x, c.y ]; 
    227                                 case 'se': return [ c.x2, c.y2 ]; 
    228                                 case 'sw': return [ c.x, c.y2 ]; 
    229                         } 
    230                 }; 
    231                 /*}}}*/ 
    232                 function getFixed()/*{{{*/ 
    233                 { 
    234                         if (!options.aspectRatio) return getRect(); 
    235                         // This function could use some optimization I think... 
    236                         var aspect = options.aspectRatio, 
    237                                 min_x = options.minSize[0]/xscale,  
    238                                 min_y = options.minSize[1]/yscale, 
    239                                 max_x = options.maxSize[0]/xscale,  
    240                                 max_y = options.maxSize[1]/yscale, 
    241                                 rw = x2 - x1, 
    242                                 rh = y2 - y1, 
    243                                 rwa = Math.abs(rw), 
    244                                 rha = Math.abs(rh), 
    245                                 real_ratio = rwa / rha, 
    246                                 xx, yy 
    247                         ; 
    248                         if (max_x == 0) { max_x = boundx * 10 } 
    249                         if (max_y == 0) { max_y = boundy * 10 } 
    250                         if (real_ratio < aspect) 
    251                         { 
    252                                 yy = y2; 
    253                                 w = rha * aspect; 
    254                                 xx = rw < 0 ? x1 - w : w + x1; 
     385    /* }}} */ 
     386    // Set more variables {{{ 
     387    var bgcolor = options.bgColor, 
     388        bgopacity = options.bgOpacity, 
     389        xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, 
     390        btndown, animating, shift_down; 
    255391 
    256                                 if (xx < 0) 
    257                                 { 
    258                                         xx = 0; 
    259                                         h = Math.abs((xx - x1) / aspect); 
    260                                         yy = rh < 0 ? y1 - h: h + y1; 
    261                                 } 
    262                                 else if (xx > boundx) 
    263                                 { 
    264                                         xx = boundx; 
    265                                         h = Math.abs((xx - x1) / aspect); 
    266                                         yy = rh < 0 ? y1 - h : h + y1; 
    267                                 } 
    268                         } 
    269                         else 
    270                         { 
    271                                 xx = x2; 
    272                                 h = rwa / aspect; 
    273                                 yy = rh < 0 ? y1 - h : y1 + h; 
    274                                 if (yy < 0) 
    275                                 { 
    276                                         yy = 0; 
    277                                         w = Math.abs((yy - y1) * aspect); 
    278                                         xx = rw < 0 ? x1 - w : w + x1; 
    279                                 } 
    280                                 else if (yy > boundy) 
    281                                 { 
    282                                         yy = boundy; 
    283                                         w = Math.abs(yy - y1) * aspect; 
    284                                         xx = rw < 0 ? x1 - w : w + x1; 
    285                                 } 
    286                         } 
     392    docOffset = getPos($img); 
     393    // }}} 
     394    // }}} 
     395    // Internal Modules {{{ 
     396    // Touch Module {{{  
     397    var Touch = (function () { 
     398      // Touch support detection function adapted (under MIT License) 
     399      // from code by Jeffrey Sambells - http://github.com/iamamused/ 
     400      function hasTouchSupport() { 
     401        var support = {}, 
     402            events = ['touchstart', 'touchmove', 'touchend'], 
     403            el = document.createElement('div'), i; 
    287404 
    288                         // Magic %-) 
    289                         if(xx > x1) { // right side 
    290                           if(xx - x1 < min_x) { 
    291                                 xx = x1 + min_x; 
    292                           } else if (xx - x1 > max_x) { 
    293                                 xx = x1 + max_x; 
    294                           } 
    295                           if(yy > y1) { 
    296                                 yy = y1 + (xx - x1)/aspect; 
    297                           } else { 
    298                                 yy = y1 - (xx - x1)/aspect; 
    299                           } 
    300                         } else if (xx < x1) { // left side 
    301                           if(x1 - xx < min_x) { 
    302                                 xx = x1 - min_x 
    303                           } else if (x1 - xx > max_x) { 
    304                                 xx = x1 - max_x; 
    305                           } 
    306                           if(yy > y1) { 
    307                                 yy = y1 + (x1 - xx)/aspect; 
    308                           } else { 
    309                                 yy = y1 - (x1 - xx)/aspect; 
    310                           } 
    311                         } 
     405        try { 
     406          for(i=0; i<events.length; i++) { 
     407            var eventName = events[i]; 
     408            eventName = 'on' + eventName; 
     409            var isSupported = (eventName in el); 
     410            if (!isSupported) { 
     411              el.setAttribute(eventName, 'return;'); 
     412              isSupported = typeof el[eventName] == 'function'; 
     413            } 
     414            support[events[i]] = isSupported; 
     415          } 
     416          return support.touchstart && support.touchend && support.touchmove; 
     417        } 
     418        catch(err) { 
     419          return false; 
     420        } 
     421      } 
    312422 
    313                         if(xx < 0) { 
    314                                 x1 -= xx; 
    315                                 xx = 0; 
    316                         } else  if (xx > boundx) { 
    317                                 x1 -= xx - boundx; 
    318                                 xx = boundx; 
    319                         } 
     423      function detectSupport() { 
     424        if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport; 
     425          else return hasTouchSupport(); 
     426      } 
     427      return { 
     428        createDragger: function (ord) { 
     429          return function (e) { 
     430            e.pageX = e.originalEvent.changedTouches[0].pageX; 
     431            e.pageY = e.originalEvent.changedTouches[0].pageY; 
     432            if (options.disabled) { 
     433              return false; 
     434            } 
     435            if ((ord === 'move') && !options.allowMove) { 
     436              return false; 
     437            } 
     438            btndown = true; 
     439            startDragMode(ord, mouseAbs(e)); 
     440            e.stopPropagation(); 
     441            e.preventDefault(); 
     442            return false; 
     443          }; 
     444        }, 
     445        newSelection: function (e) { 
     446          e.pageX = e.originalEvent.changedTouches[0].pageX; 
     447          e.pageY = e.originalEvent.changedTouches[0].pageY; 
     448          return newSelection(e); 
     449        }, 
     450        isSupported: hasTouchSupport, 
     451        support: detectSupport() 
     452      }; 
     453    }()); 
     454    // }}} 
     455    // Coords Module {{{ 
     456    var Coords = (function () { 
     457      var x1 = 0, 
     458          y1 = 0, 
     459          x2 = 0, 
     460          y2 = 0, 
     461          ox, oy; 
    320462 
    321                         if(yy < 0) { 
    322                                 y1 -= yy; 
    323                                 yy = 0; 
    324                         } else  if (yy > boundy) { 
    325                                 y1 -= yy - boundy; 
    326                                 yy = boundy; 
    327                         } 
     463      function setPressed(pos) //{{{ 
     464      { 
     465        pos = rebound(pos); 
     466        x2 = x1 = pos[0]; 
     467        y2 = y1 = pos[1]; 
     468      } 
     469      //}}} 
     470      function setCurrent(pos) //{{{ 
     471      { 
     472        pos = rebound(pos); 
     473        ox = pos[0] - x2; 
     474        oy = pos[1] - y2; 
     475        x2 = pos[0]; 
     476        y2 = pos[1]; 
     477      } 
     478      //}}} 
     479      function getOffset() //{{{ 
     480      { 
     481        return [ox, oy]; 
     482      } 
     483      //}}} 
     484      function moveOffset(offset) //{{{ 
     485      { 
     486        var ox = offset[0], 
     487            oy = offset[1]; 
    328488 
    329                         return last = makeObj(flipCoords(x1,y1,xx,yy)); 
    330                 }; 
    331                 /*}}}*/ 
    332                 function rebound(p)/*{{{*/ 
    333                 { 
    334                         if (p[0] < 0) p[0] = 0; 
    335                         if (p[1] < 0) p[1] = 0; 
     489        if (0 > x1 + ox) { 
     490          ox -= ox + x1; 
     491        } 
     492        if (0 > y1 + oy) { 
     493          oy -= oy + y1; 
     494        } 
    336495 
    337                         if (p[0] > boundx) p[0] = boundx; 
    338                         if (p[1] > boundy) p[1] = boundy; 
     496        if (boundy < y2 + oy) { 
     497          oy += boundy - (y2 + oy); 
     498        } 
     499        if (boundx < x2 + ox) { 
     500          ox += boundx - (x2 + ox); 
     501        } 
    339502 
    340                         return [ p[0], p[1] ]; 
    341                 }; 
    342                 /*}}}*/ 
    343                 function flipCoords(x1,y1,x2,y2)/*{{{*/ 
    344                 { 
    345                         var xa = x1, xb = x2, ya = y1, yb = y2; 
    346                         if (x2 < x1) 
    347                         { 
    348                                 xa = x2; 
    349                                 xb = x1; 
    350                         } 
    351                         if (y2 < y1) 
    352                         { 
    353                                 ya = y2; 
    354                                 yb = y1; 
    355                         } 
    356                         return [ Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb) ]; 
    357                 }; 
    358                 /*}}}*/ 
    359                 function getRect()/*{{{*/ 
    360                 { 
    361                         var xsize = x2 - x1; 
    362                         var ysize = y2 - y1; 
     503        x1 += ox; 
     504        x2 += ox; 
     505        y1 += oy; 
     506        y2 += oy; 
     507      } 
     508      //}}} 
     509      function getCorner(ord) //{{{ 
     510      { 
     511        var c = getFixed(); 
     512        switch (ord) { 
     513        case 'ne': 
     514          return [c.x2, c.y]; 
     515        case 'nw': 
     516          return [c.x, c.y]; 
     517        case 'se': 
     518          return [c.x2, c.y2]; 
     519        case 'sw': 
     520          return [c.x, c.y2]; 
     521        } 
     522      } 
     523      //}}} 
     524      function getFixed() //{{{ 
     525      { 
     526        if (!options.aspectRatio) { 
     527          return getRect(); 
     528        } 
     529        // This function could use some optimization I think... 
     530        var aspect = options.aspectRatio, 
     531            min_x = options.minSize[0] / xscale, 
     532             
     533             
     534            //min_y = options.minSize[1]/yscale, 
     535            max_x = options.maxSize[0] / xscale, 
     536            max_y = options.maxSize[1] / yscale, 
     537            rw = x2 - x1, 
     538            rh = y2 - y1, 
     539            rwa = Math.abs(rw), 
     540            rha = Math.abs(rh), 
     541            real_ratio = rwa / rha, 
     542            xx, yy, w, h; 
    363543 
    364                         if (xlimit && (Math.abs(xsize) > xlimit)) 
    365                                 x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); 
    366                         if (ylimit && (Math.abs(ysize) > ylimit)) 
    367                                 y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); 
     544        if (max_x === 0) { 
     545          max_x = boundx * 10; 
     546        } 
     547        if (max_y === 0) { 
     548          max_y = boundy * 10; 
     549        } 
     550        if (real_ratio < aspect) { 
     551          yy = y2; 
     552          w = rha * aspect; 
     553          xx = rw < 0 ? x1 - w : w + x1; 
    368554 
    369                         if (ymin && (Math.abs(ysize) < ymin)) 
    370                                 y2 = (ysize > 0) ? (y1 + ymin) : (y1 - ymin); 
    371                         if (xmin && (Math.abs(xsize) < xmin)) 
    372                                 x2 = (xsize > 0) ? (x1 + xmin) : (x1 - xmin); 
     555          if (xx < 0) { 
     556            xx = 0; 
     557            h = Math.abs((xx - x1) / aspect); 
     558            yy = rh < 0 ? y1 - h : h + y1; 
     559          } else if (xx > boundx) { 
     560            xx = boundx; 
     561            h = Math.abs((xx - x1) / aspect); 
     562            yy = rh < 0 ? y1 - h : h + y1; 
     563          } 
     564        } else { 
     565          xx = x2; 
     566          h = rwa / aspect; 
     567          yy = rh < 0 ? y1 - h : y1 + h; 
     568          if (yy < 0) { 
     569            yy = 0; 
     570            w = Math.abs((yy - y1) * aspect); 
     571            xx = rw < 0 ? x1 - w : w + x1; 
     572          } else if (yy > boundy) { 
     573            yy = boundy; 
     574            w = Math.abs(yy - y1) * aspect; 
     575            xx = rw < 0 ? x1 - w : w + x1; 
     576          } 
     577        } 
    373578 
    374                         if (x1 < 0) { x2 -= x1; x1 -= x1; } 
    375                         if (y1 < 0) { y2 -= y1; y1 -= y1; } 
    376                         if (x2 < 0) { x1 -= x2; x2 -= x2; } 
    377                         if (y2 < 0) { y1 -= y2; y2 -= y2; } 
    378                         if (x2 > boundx) { var delta = x2 - boundx; x1 -= delta; x2 -= delta; } 
    379                         if (y2 > boundy) { var delta = y2 - boundy; y1 -= delta; y2 -= delta; } 
    380                         if (x1 > boundx) { var delta = x1 - boundy; y2 -= delta; y1 -= delta; } 
    381                         if (y1 > boundy) { var delta = y1 - boundy; y2 -= delta; y1 -= delta; } 
     579        // Magic %-) 
     580        if (xx > x1) { // right side 
     581          if (xx - x1 < min_x) { 
     582            xx = x1 + min_x; 
     583          } else if (xx - x1 > max_x) { 
     584            xx = x1 + max_x; 
     585          } 
     586          if (yy > y1) { 
     587            yy = y1 + (xx - x1) / aspect; 
     588          } else { 
     589            yy = y1 - (xx - x1) / aspect; 
     590          } 
     591        } else if (xx < x1) { // left side 
     592          if (x1 - xx < min_x) { 
     593            xx = x1 - min_x; 
     594          } else if (x1 - xx > max_x) { 
     595            xx = x1 - max_x; 
     596          } 
     597          if (yy > y1) { 
     598            yy = y1 + (x1 - xx) / aspect; 
     599          } else { 
     600            yy = y1 - (x1 - xx) / aspect; 
     601          } 
     602        } 
    382603 
    383                         return makeObj(flipCoords(x1,y1,x2,y2)); 
    384                 }; 
    385                 /*}}}*/ 
    386                 function makeObj(a)/*{{{*/ 
    387                 { 
    388                         return { x: a[0], y: a[1], x2: a[2], y2: a[3], 
    389                                 w: a[2] - a[0], h: a[3] - a[1] }; 
    390                 }; 
    391                 /*}}}*/ 
     604        if (xx < 0) { 
     605          x1 -= xx; 
     606          xx = 0; 
     607        } else if (xx > boundx) { 
     608          x1 -= xx - boundx; 
     609          xx = boundx; 
     610        } 
    392611 
    393                 return { 
    394                         flipCoords: flipCoords, 
    395                         setPressed: setPressed, 
    396                         setCurrent: setCurrent, 
    397                         getOffset: getOffset, 
    398                         moveOffset: moveOffset, 
    399                         getCorner: getCorner, 
    400                         getFixed: getFixed 
    401                 }; 
    402         }(); 
     612        if (yy < 0) { 
     613          y1 -= yy; 
     614          yy = 0; 
     615        } else if (yy > boundy) { 
     616          y1 -= yy - boundy; 
     617          yy = boundy; 
     618        } 
    403619 
    404         /*}}}*/ 
    405         var Selection = function()/*{{{*/ 
    406         { 
    407                 var start, end, dragmode, awake, hdep = 370; 
    408                 var borders = { }; 
    409                 var handle = { }; 
    410                 var seehandles = false; 
    411                 var hhs = options.handleOffset; 
     620        return makeObj(flipCoords(x1, y1, xx, yy)); 
     621      } 
     622      //}}} 
     623      function rebound(p) //{{{ 
     624      { 
     625        if (p[0] < 0) { 
     626          p[0] = 0; 
     627        } 
     628        if (p[1] < 0) { 
     629          p[1] = 0; 
     630        } 
    412631 
    413                 /* Insert draggable elements {{{*/ 
     632        if (p[0] > boundx) { 
     633          p[0] = boundx; 
     634        } 
     635        if (p[1] > boundy) { 
     636          p[1] = boundy; 
     637        } 
    414638 
    415                 // Insert border divs for outline 
    416                 if (options.drawBorders) { 
    417                         borders = { 
    418                                         top: insertBorder('hline') 
    419                                                 .css('top',$.browser.msie?px(-1):px(0)), 
    420                                         bottom: insertBorder('hline'), 
    421                                         left: insertBorder('vline'), 
    422                                         right: insertBorder('vline') 
    423                         }; 
    424                 } 
     639        return [p[0], p[1]]; 
     640      } 
     641      //}}} 
     642      function flipCoords(x1, y1, x2, y2) //{{{ 
     643      { 
     644        var xa = x1, 
     645            xb = x2, 
     646            ya = y1, 
     647            yb = y2; 
     648        if (x2 < x1) { 
     649          xa = x2; 
     650          xb = x1; 
     651        } 
     652        if (y2 < y1) { 
     653          ya = y2; 
     654          yb = y1; 
     655        } 
     656        return [xa, ya, xb, yb]; 
     657      } 
     658      //}}} 
     659      function getRect() //{{{ 
     660      { 
     661        var xsize = x2 - x1, 
     662            ysize = y2 - y1, 
     663            delta; 
    425664 
    426                 // Insert handles on edges 
    427                 if (options.dragEdges) { 
    428                         handle.t = insertDragbar('n'); 
    429                         handle.b = insertDragbar('s'); 
    430                         handle.r = insertDragbar('e'); 
    431                         handle.l = insertDragbar('w'); 
    432                 } 
     665        if (xlimit && (Math.abs(xsize) > xlimit)) { 
     666          x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); 
     667        } 
     668        if (ylimit && (Math.abs(ysize) > ylimit)) { 
     669          y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); 
     670        } 
    433671 
    434                 // Insert side handles 
    435                 options.sideHandles && 
    436                         createHandles(['n','s','e','w']); 
     672        if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) { 
     673          y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale); 
     674        } 
     675        if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) { 
     676          x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale); 
     677        } 
    437678 
    438                 // Insert corner handles 
    439                 options.cornerHandles && 
    440                         createHandles(['sw','nw','ne','se']); 
     679        if (x1 < 0) { 
     680          x2 -= x1; 
     681          x1 -= x1; 
     682        } 
     683        if (y1 < 0) { 
     684          y2 -= y1; 
     685          y1 -= y1; 
     686        } 
     687        if (x2 < 0) { 
     688          x1 -= x2; 
     689          x2 -= x2; 
     690        } 
     691        if (y2 < 0) { 
     692          y1 -= y2; 
     693          y2 -= y2; 
     694        } 
     695        if (x2 > boundx) { 
     696          delta = x2 - boundx; 
     697          x1 -= delta; 
     698          x2 -= delta; 
     699        } 
     700        if (y2 > boundy) { 
     701          delta = y2 - boundy; 
     702          y1 -= delta; 
     703          y2 -= delta; 
     704        } 
     705        if (x1 > boundx) { 
     706          delta = x1 - boundy; 
     707          y2 -= delta; 
     708          y1 -= delta; 
     709        } 
     710        if (y1 > boundy) { 
     711          delta = y1 - boundy; 
     712          y2 -= delta; 
     713          y1 -= delta; 
     714        } 
    441715 
    442                 /*}}}*/ 
    443                 // Private Methods 
    444                 function insertBorder(type)/*{{{*/ 
    445                 { 
    446                         var jq = $('<div />') 
    447                                 .css({position: 'absolute', opacity: options.borderOpacity }) 
    448                                 .addClass(cssClass(type)); 
    449                         $img_holder.append(jq); 
    450                         return jq; 
    451                 }; 
    452                 /*}}}*/ 
    453                 function dragDiv(ord,zi)/*{{{*/ 
    454                 { 
    455                         var jq = $('<div />') 
    456                                 .mousedown(createDragger(ord)) 
    457                                 .css({ 
    458                                         cursor: ord+'-resize', 
    459                                         position: 'absolute', 
    460                                         zIndex: zi  
    461                                 }) 
    462                         ; 
    463                         $hdl_holder.append(jq); 
    464                         return jq; 
    465                 }; 
    466                 /*}}}*/ 
    467                 function insertHandle(ord)/*{{{*/ 
    468                 { 
    469                         return dragDiv(ord,hdep++) 
    470                                 .css({ top: px(-hhs+1), left: px(-hhs+1), opacity: options.handleOpacity }) 
    471                                 .addClass(cssClass('handle')); 
    472                 }; 
    473                 /*}}}*/ 
    474                 function insertDragbar(ord)/*{{{*/ 
    475                 { 
    476                         var s = options.handleSize, 
    477                                 o = hhs, 
    478                                 h = s, w = s, 
    479                                 t = o, l = o; 
     716        return makeObj(flipCoords(x1, y1, x2, y2)); 
     717      } 
     718      //}}} 
     719      function makeObj(a) //{{{ 
     720      { 
     721        return { 
     722          x: a[0], 
     723          y: a[1], 
     724          x2: a[2], 
     725          y2: a[3], 
     726          w: a[2] - a[0], 
     727          h: a[3] - a[1] 
     728        }; 
     729      } 
     730      //}}} 
    480731 
    481                         switch(ord) 
    482                         { 
    483                                 case 'n': case 's': w = pct(100); break; 
    484                                 case 'e': case 'w': h = pct(100); break; 
    485                         } 
     732      return { 
     733        flipCoords: flipCoords, 
     734        setPressed: setPressed, 
     735        setCurrent: setCurrent, 
     736        getOffset: getOffset, 
     737        moveOffset: moveOffset, 
     738        getCorner: getCorner, 
     739        getFixed: getFixed 
     740      }; 
     741    }()); 
    486742 
    487                         return dragDiv(ord,hdep++).width(w).height(h) 
    488                                 .css({ top: px(-t+1), left: px(-l+1)}); 
    489                 }; 
    490                 /*}}}*/ 
    491                 function createHandles(li)/*{{{*/ 
    492                 { 
    493                         for(i in li) handle[li[i]] = insertHandle(li[i]); 
    494                 }; 
    495                 /*}}}*/ 
    496                 function moveHandles(c)/*{{{*/ 
    497                 { 
    498                         var midvert  = Math.round((c.h / 2) - hhs), 
    499                                 midhoriz = Math.round((c.w / 2) - hhs), 
    500                                 north = west = -hhs+1, 
    501                                 east = c.w - hhs, 
    502                                 south = c.h - hhs, 
    503                                 x, y; 
     743    //}}} 
     744    // Shade Module {{{ 
     745    var Shade = (function() { 
     746      var enabled = false, 
     747          holder = $('<div />').css({ 
     748            position: 'absolute', 
     749            zIndex: 240, 
     750            opacity: 0 
     751          }), 
     752          shades = { 
     753            top: createShade(), 
     754            left: createShade().height(boundy), 
     755            right: createShade().height(boundy), 
     756            bottom: createShade() 
     757          }; 
    504758 
    505                         'e' in handle && 
    506                                 handle.e.css({ top: px(midvert), left: px(east) }) && 
    507                                 handle.w.css({ top: px(midvert) }) && 
    508                                 handle.s.css({ top: px(south), left: px(midhoriz) }) && 
    509                                 handle.n.css({ left: px(midhoriz) }); 
     759      function resizeShades(w,h) { 
     760        shades.left.css({ height: px(h) }); 
     761        shades.right.css({ height: px(h) }); 
     762      } 
     763      function updateAuto() 
     764      { 
     765        return updateShade(Coords.getFixed()); 
     766      } 
     767      function updateShade(c) 
     768      { 
     769        shades.top.css({ 
     770          left: px(c.x), 
     771          width: px(c.w), 
     772          height: px(c.y) 
     773        }); 
     774        shades.bottom.css({ 
     775          top: px(c.y2), 
     776          left: px(c.x), 
     777          width: px(c.w), 
     778          height: px(boundy-c.y2) 
     779        }); 
     780        shades.right.css({ 
     781          left: px(c.x2), 
     782          width: px(boundx-c.x2) 
     783        }); 
     784        shades.left.css({ 
     785          width: px(c.x) 
     786        }); 
     787      } 
     788      function createShade() { 
     789        return $('<div />').css({ 
     790          position: 'absolute', 
     791          backgroundColor: options.shadeColor||options.bgColor 
     792        }).appendTo(holder); 
     793      } 
     794      function enableShade() { 
     795        if (!enabled) { 
     796          enabled = true; 
     797          holder.insertBefore($img); 
     798          updateAuto(); 
     799          Selection.setBgOpacity(1,0,1); 
     800          $img2.hide(); 
    510801 
    511                         'ne' in handle && 
    512                                 handle.ne.css({ left: px(east) }) && 
    513                                 handle.se.css({ top: px(south), left: px(east) }) && 
    514                                 handle.sw.css({ top: px(south) }); 
     802          setBgColor(options.shadeColor||options.bgColor,1); 
     803          if (Selection.isAwake()) 
     804          { 
     805            setOpacity(options.bgOpacity,1); 
     806          } 
     807            else setOpacity(1,1); 
     808        } 
     809      } 
     810      function setBgColor(color,now) { 
     811        colorChangeMacro(getShades(),color,now); 
     812      } 
     813      function disableShade() { 
     814        if (enabled) { 
     815          holder.remove(); 
     816          $img2.show(); 
     817          enabled = false; 
     818          if (Selection.isAwake()) { 
     819            Selection.setBgOpacity(options.bgOpacity,1,1); 
     820          } else { 
     821            Selection.setBgOpacity(1,1,1); 
     822            Selection.disableHandles(); 
     823          } 
     824          colorChangeMacro($div,0,1); 
     825        } 
     826      } 
     827      function setOpacity(opacity,now) { 
     828        if (enabled) { 
     829          if (options.bgFade && !now) { 
     830            holder.animate({ 
     831              opacity: 1-opacity 
     832            },{ 
     833              queue: false, 
     834              duration: options.fadeTime 
     835            }); 
     836          } 
     837          else holder.css({opacity:1-opacity}); 
     838        } 
     839      } 
     840      function refreshAll() { 
     841        options.shade ? enableShade() : disableShade(); 
     842        if (Selection.isAwake()) setOpacity(options.bgOpacity); 
     843      } 
     844      function getShades() { 
     845        return holder.children(); 
     846      } 
    515847 
    516                         'b' in handle && 
    517                                 handle.b.css({ top: px(south) }) && 
    518                                 handle.r.css({ left: px(east) }); 
    519                 }; 
    520                 /*}}}*/ 
    521                 function moveto(x,y)/*{{{*/ 
    522                 { 
    523                         $img2.css({ top: px(-y), left: px(-x) }); 
    524                         $sel.css({ top: px(y), left: px(x) }); 
    525                 }; 
    526                 /*}}}*/ 
    527                 function resize(w,h)/*{{{*/ 
    528                 { 
    529                         $sel.width(w).height(h); 
    530                 }; 
    531                 /*}}}*/ 
    532                 function refresh()/*{{{*/ 
    533                 { 
    534                         var c = Coords.getFixed(); 
     848      return { 
     849        update: updateAuto, 
     850        updateRaw: updateShade, 
     851        getShades: getShades, 
     852        setBgColor: setBgColor, 
     853        enable: enableShade, 
     854        disable: disableShade, 
     855        resize: resizeShades, 
     856        refresh: refreshAll, 
     857        opacity: setOpacity 
     858      }; 
     859    }()); 
     860    // }}} 
     861    // Selection Module {{{ 
     862    var Selection = (function () { 
     863      var awake, 
     864          hdep = 370, 
     865          borders = {}, 
     866          handle = {}, 
     867          dragbar = {}, 
     868          seehandles = false; 
    535869 
    536                         Coords.setPressed([c.x,c.y]); 
    537                         Coords.setCurrent([c.x2,c.y2]); 
     870      // Private Methods 
     871      function insertBorder(type) //{{{ 
     872      { 
     873        var jq = $('<div />').css({ 
     874          position: 'absolute', 
     875          opacity: options.borderOpacity 
     876        }).addClass(cssClass(type)); 
     877        $img_holder.append(jq); 
     878        return jq; 
     879      } 
     880      //}}} 
     881      function dragDiv(ord, zi) //{{{ 
     882      { 
     883        var jq = $('<div />').mousedown(createDragger(ord)).css({ 
     884          cursor: ord + '-resize', 
     885          position: 'absolute', 
     886          zIndex: zi 
     887        }).addClass('ord-'+ord); 
    538888 
    539                         updateVisible(); 
    540                 }; 
    541                 /*}}}*/ 
     889        if (Touch.support) { 
     890          jq.bind('touchstart.jcrop', Touch.createDragger(ord)); 
     891        } 
    542892 
    543                 // Internal Methods 
    544                 function updateVisible()/*{{{*/ 
    545                         { if (awake) return update(); }; 
    546                 /*}}}*/ 
    547                 function update()/*{{{*/ 
    548                 { 
    549                         var c = Coords.getFixed(); 
     893        $hdl_holder.append(jq); 
     894        return jq; 
     895      } 
     896      //}}} 
     897      function insertHandle(ord) //{{{ 
     898      { 
     899        var hs = options.handleSize; 
     900        return dragDiv(ord, hdep++).css({ 
     901          opacity: options.handleOpacity 
     902        }).width(hs).height(hs).addClass(cssClass('handle')); 
     903      } 
     904      //}}} 
     905      function insertDragbar(ord) //{{{ 
     906      { 
     907        return dragDiv(ord, hdep++).addClass('jcrop-dragbar'); 
     908      } 
     909      //}}} 
     910      function createDragbars(li) //{{{ 
     911      { 
     912        var i; 
     913        for (i = 0; i < li.length; i++) { 
     914          dragbar[li[i]] = insertDragbar(li[i]); 
     915        } 
     916      } 
     917      //}}} 
     918      function createBorders(li) //{{{ 
     919      { 
     920        var cl,i; 
     921        for (i = 0; i < li.length; i++) { 
     922          switch(li[i]){ 
     923            case'n': cl='hline'; break; 
     924            case's': cl='hline bottom'; break; 
     925            case'e': cl='vline right'; break; 
     926            case'w': cl='vline'; break; 
     927          } 
     928          borders[li[i]] = insertBorder(cl); 
     929        } 
     930      } 
     931      //}}} 
     932      function createHandles(li) //{{{ 
     933      { 
     934        var i; 
     935        for (i = 0; i < li.length; i++) { 
     936          handle[li[i]] = insertHandle(li[i]); 
     937        } 
     938      } 
     939      //}}} 
     940      function moveto(x, y) //{{{ 
     941      { 
     942        if (!options.shade) { 
     943          $img2.css({ 
     944            top: px(-y), 
     945            left: px(-x) 
     946          }); 
     947        } 
     948        $sel.css({ 
     949          top: px(y), 
     950          left: px(x) 
     951        }); 
     952      } 
     953      //}}} 
     954      function resize(w, h) //{{{ 
     955      { 
     956        $sel.width(w).height(h); 
     957      } 
     958      //}}} 
     959      function refresh() //{{{ 
     960      { 
     961        var c = Coords.getFixed(); 
    550962 
    551                         resize(c.w,c.h); 
    552                         moveto(c.x,c.y); 
     963        Coords.setPressed([c.x, c.y]); 
     964        Coords.setCurrent([c.x2, c.y2]); 
    553965 
    554                         options.drawBorders && 
    555                                 borders['right'].css({ left: px(c.w-1) }) && 
    556                                         borders['bottom'].css({ top: px(c.h-1) }); 
     966        updateVisible(); 
     967      } 
     968      //}}} 
    557969 
    558                         seehandles && moveHandles(c); 
    559                         awake || show(); 
     970      // Internal Methods 
     971      function updateVisible(select) //{{{ 
     972      { 
     973        if (awake) { 
     974          return update(select); 
     975        } 
     976      } 
     977      //}}} 
     978      function update(select) //{{{ 
     979      { 
     980        var c = Coords.getFixed(); 
    560981 
    561                         options.onChange(unscale(c)); 
    562                 }; 
    563                 /*}}}*/ 
    564                 function show()/*{{{*/ 
    565                 { 
    566                         $sel.show(); 
    567                         $img.css('opacity',options.bgOpacity); 
    568                         awake = true; 
    569                 }; 
    570                 /*}}}*/ 
    571                 function release()/*{{{*/ 
    572                 { 
    573                         disableHandles(); 
    574                         $sel.hide(); 
    575                         $img.css('opacity',1); 
    576                         awake = false; 
    577                 }; 
    578                 /*}}}*/ 
    579                 function showHandles()//{{{ 
    580                 { 
    581                         if (seehandles) 
    582                         { 
    583                                 moveHandles(Coords.getFixed()); 
    584                                 $hdl_holder.show(); 
    585                         } 
    586                 }; 
    587                 //}}} 
    588                 function enableHandles()/*{{{*/ 
    589                 {  
    590                         seehandles = true; 
    591                         if (options.allowResize) 
    592                         { 
    593                                 moveHandles(Coords.getFixed()); 
    594                                 $hdl_holder.show(); 
    595                                 return true; 
    596                         } 
    597                 }; 
    598                 /*}}}*/ 
    599                 function disableHandles()/*{{{*/ 
    600                 { 
    601                         seehandles = false; 
    602                         $hdl_holder.hide(); 
    603                 }; 
    604                 /*}}}*/ 
    605                 function animMode(v)/*{{{*/ 
    606                 { 
    607                         (animating = v) ? disableHandles(): enableHandles(); 
    608                 }; 
    609                 /*}}}*/ 
    610                 function done()/*{{{*/ 
    611                 { 
    612                         animMode(false); 
    613                         refresh(); 
    614                 }; 
    615                 /*}}}*/ 
     982        resize(c.w, c.h); 
     983        moveto(c.x, c.y); 
     984        if (options.shade) Shade.updateRaw(c); 
    616985 
    617                 var $track = newTracker().mousedown(createDragger('move')) 
    618                                 .css({ cursor: 'move', position: 'absolute', zIndex: 360 }) 
     986        awake || show(); 
    619987 
    620                 $img_holder.append($track); 
    621                 disableHandles(); 
     988        if (select) { 
     989          options.onSelect.call(api, unscale(c)); 
     990        } else { 
     991          options.onChange.call(api, unscale(c)); 
     992        } 
     993      } 
     994      //}}} 
     995      function setBgOpacity(opacity,force,now) //{{{ 
     996      { 
     997        if (!awake && !force) return; 
     998        if (options.bgFade && !now) { 
     999          $img.animate({ 
     1000            opacity: opacity 
     1001          },{ 
     1002            queue: false, 
     1003            duration: options.fadeTime 
     1004          }); 
     1005        } else { 
     1006          $img.css('opacity', opacity); 
     1007        } 
     1008      } 
     1009      //}}} 
     1010      function show() //{{{ 
     1011      { 
     1012        $sel.show(); 
    6221013 
    623                 return { 
    624                         updateVisible: updateVisible, 
    625                         update: update, 
    626                         release: release, 
    627                         refresh: refresh, 
    628                         setCursor: function (cursor) { $track.css('cursor',cursor); }, 
    629                         enableHandles: enableHandles, 
    630                         enableOnly: function() { seehandles = true; }, 
    631                         showHandles: showHandles, 
    632                         disableHandles: disableHandles, 
    633                         animMode: animMode, 
    634                         done: done 
    635                 }; 
    636         }(); 
    637         /*}}}*/ 
    638         var Tracker = function()/*{{{*/ 
    639         { 
    640                 var onMove              = function() { }, 
    641                         onDone          = function() { }, 
    642                         trackDoc        = options.trackDocument; 
     1014        if (options.shade) Shade.opacity(bgopacity); 
     1015          else setBgOpacity(bgopacity,true); 
    6431016 
    644                 if (!trackDoc) 
    645                 { 
    646                         $trk 
    647                                 .mousemove(trackMove) 
    648                                 .mouseup(trackUp) 
    649                                 .mouseout(trackUp) 
    650                         ; 
    651                 } 
     1017        awake = true; 
     1018      } 
     1019      //}}} 
     1020      function release() //{{{ 
     1021      { 
     1022        disableHandles(); 
     1023        $sel.hide(); 
    6521024 
    653                 function toFront()/*{{{*/ 
    654                 { 
    655                         $trk.css({zIndex:450}); 
    656                         if (trackDoc) 
    657                         { 
    658                                 $(document) 
    659                                         .mousemove(trackMove) 
    660                                         .mouseup(trackUp) 
    661                                 ; 
    662                         } 
    663                 } 
    664                 /*}}}*/ 
    665                 function toBack()/*{{{*/ 
    666                 { 
    667                         $trk.css({zIndex:290}); 
    668                         if (trackDoc) 
    669                         { 
    670                                 $(document) 
    671                                         .unbind('mousemove',trackMove) 
    672                                         .unbind('mouseup',trackUp) 
    673                                 ; 
    674                         } 
    675                 } 
    676                 /*}}}*/ 
    677                 function trackMove(e)/*{{{*/ 
    678                 { 
    679                         onMove(mouseAbs(e)); 
    680                 }; 
    681                 /*}}}*/ 
    682                 function trackUp(e)/*{{{*/ 
    683                 { 
    684                         e.preventDefault(); 
    685                         e.stopPropagation(); 
     1025        if (options.shade) Shade.opacity(1); 
     1026          else setBgOpacity(1); 
    6861027 
    687                         if (btndown) 
    688                         { 
    689                                 btndown = false; 
     1028        awake = false; 
     1029        options.onRelease.call(api); 
     1030      } 
     1031      //}}} 
     1032      function showHandles() //{{{ 
     1033      { 
     1034        if (seehandles) { 
     1035          $hdl_holder.show(); 
     1036        } 
     1037      } 
     1038      //}}} 
     1039      function enableHandles() //{{{ 
     1040      { 
     1041        seehandles = true; 
     1042        if (options.allowResize) { 
     1043          $hdl_holder.show(); 
     1044          return true; 
     1045        } 
     1046      } 
     1047      //}}} 
     1048      function disableHandles() //{{{ 
     1049      { 
     1050        seehandles = false; 
     1051        $hdl_holder.hide(); 
     1052      }  
     1053      //}}} 
     1054      function animMode(v) //{{{ 
     1055      { 
     1056        if (animating === v) { 
     1057          disableHandles(); 
     1058        } else { 
     1059          enableHandles(); 
     1060        } 
     1061      }  
     1062      //}}} 
     1063      function done() //{{{ 
     1064      { 
     1065        animMode(false); 
     1066        refresh(); 
     1067      }  
     1068      //}}} 
     1069      // Insert draggable elements {{{ 
     1070      // Insert border divs for outline 
    6901071 
    691                                 onDone(mouseAbs(e)); 
    692                                 options.onSelect(unscale(Coords.getFixed())); 
    693                                 toBack(); 
    694                                 onMove = function() { }; 
    695                                 onDone = function() { }; 
    696                         } 
     1072      if (options.dragEdges && $.isArray(options.createDragbars)) 
     1073        createDragbars(options.createDragbars); 
    6971074 
    698                         return false; 
    699                 }; 
    700                 /*}}}*/ 
     1075      if ($.isArray(options.createHandles)) 
     1076        createHandles(options.createHandles); 
    7011077 
    702                 function activateHandlers(move,done)/* {{{ */ 
    703                 { 
    704                         btndown = true; 
    705                         onMove = move; 
    706                         onDone = done; 
    707                         toFront(); 
    708                         return false; 
    709                 }; 
    710                 /* }}} */ 
     1078      if (options.drawBorders && $.isArray(options.createBorders)) 
     1079        createBorders(options.createBorders); 
    7111080 
    712                 function setCursor(t) { $trk.css('cursor',t); }; 
     1081      //}}} 
    7131082 
    714                 $img.before($trk); 
    715                 return { 
    716                         activateHandlers: activateHandlers, 
    717                         setCursor: setCursor 
    718                 }; 
    719         }(); 
    720         /*}}}*/ 
    721         var KeyManager = function()/*{{{*/ 
    722         { 
    723                 var $keymgr = $('<input type="radio" />') 
    724                                 .css({ position: 'absolute', left: '-30px' }) 
    725                                 .keypress(parseKey) 
    726                                 .blur(onBlur), 
     1083      // This is a hack for iOS5 to support drag/move touch functionality 
     1084      $(document).bind('touchstart.jcrop-ios',function(e) { 
     1085        if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation(); 
     1086      }); 
    7271087 
    728                         $keywrap = $('<div />') 
    729                                 .css({ 
    730                                         position: 'absolute', 
    731                                         overflow: 'hidden' 
    732                                 }) 
    733                                 .append($keymgr) 
    734                 ; 
     1088      var $track = newTracker().mousedown(createDragger('move')).css({ 
     1089        cursor: 'move', 
     1090        position: 'absolute', 
     1091        zIndex: 360 
     1092      }); 
    7351093 
    736                 function watchKeys()/*{{{*/ 
    737                 { 
    738                         if (options.keySupport) 
    739                         { 
    740                                 $keymgr.show(); 
    741                                 $keymgr.focus(); 
    742                         } 
    743                 }; 
    744                 /*}}}*/ 
    745                 function onBlur(e)/*{{{*/ 
    746                 { 
    747                         $keymgr.hide(); 
    748                 }; 
    749                 /*}}}*/ 
    750                 function doNudge(e,x,y)/*{{{*/ 
    751                 { 
    752                         if (options.allowMove) { 
    753                                 Coords.moveOffset([x,y]); 
    754                                 Selection.updateVisible(); 
    755                         }; 
    756                         e.preventDefault(); 
    757                         e.stopPropagation(); 
    758                 }; 
    759                 /*}}}*/ 
    760                 function parseKey(e)/*{{{*/ 
    761                 { 
    762                         if (e.ctrlKey) return true; 
    763                         shift_down = e.shiftKey ? true : false; 
    764                         var nudge = shift_down ? 10 : 1; 
    765                         switch(e.keyCode) 
    766                         { 
    767                                 case 37: doNudge(e,-nudge,0); break; 
    768                                 case 39: doNudge(e,nudge,0); break; 
    769                                 case 38: doNudge(e,0,-nudge); break; 
    770                                 case 40: doNudge(e,0,nudge); break; 
     1094      if (Touch.support) { 
     1095        $track.bind('touchstart.jcrop', Touch.createDragger('move')); 
     1096      } 
    7711097 
    772                                 case 27: Selection.release(); break; 
     1098      $img_holder.append($track); 
     1099      disableHandles(); 
    7731100 
    774                                 case 9: return true; 
    775                         } 
     1101      return { 
     1102        updateVisible: updateVisible, 
     1103        update: update, 
     1104        release: release, 
     1105        refresh: refresh, 
     1106        isAwake: function () { 
     1107          return awake; 
     1108        }, 
     1109        setCursor: function (cursor) { 
     1110          $track.css('cursor', cursor); 
     1111        }, 
     1112        enableHandles: enableHandles, 
     1113        enableOnly: function () { 
     1114          seehandles = true; 
     1115        }, 
     1116        showHandles: showHandles, 
     1117        disableHandles: disableHandles, 
     1118        animMode: animMode, 
     1119        setBgOpacity: setBgOpacity, 
     1120        done: done 
     1121      }; 
     1122    }()); 
     1123     
     1124    //}}} 
     1125    // Tracker Module {{{ 
     1126    var Tracker = (function () { 
     1127      var onMove = function () {}, 
     1128          onDone = function () {}, 
     1129          trackDoc = options.trackDocument; 
    7761130 
    777                         return nothing(e); 
    778                 }; 
    779                 /*}}}*/ 
    780                  
    781                 if (options.keySupport) $keywrap.insertBefore($img); 
    782                 return { 
    783                         watchKeys: watchKeys 
    784                 }; 
    785         }(); 
    786         /*}}}*/ 
     1131      function toFront() //{{{ 
     1132      { 
     1133        $trk.css({ 
     1134          zIndex: 450 
     1135        }); 
     1136        if (Touch.support) { 
     1137          $(document) 
     1138            .bind('touchmove.jcrop', trackTouchMove) 
     1139            .bind('touchend.jcrop', trackTouchEnd); 
     1140        } 
     1141        if (trackDoc) { 
     1142          $(document) 
     1143            .bind('mousemove.jcrop',trackMove) 
     1144            .bind('mouseup.jcrop',trackUp); 
     1145        } 
     1146      }  
     1147      //}}} 
     1148      function toBack() //{{{ 
     1149      { 
     1150        $trk.css({ 
     1151          zIndex: 290 
     1152        }); 
     1153        $(document).unbind('.jcrop'); 
     1154      }  
     1155      //}}} 
     1156      function trackMove(e) //{{{ 
     1157      { 
     1158        onMove(mouseAbs(e)); 
     1159        return false; 
     1160      }  
     1161      //}}} 
     1162      function trackUp(e) //{{{ 
     1163      { 
     1164        e.preventDefault(); 
     1165        e.stopPropagation(); 
    7871166 
    788         // }}} 
    789         // Internal Methods {{{ 
     1167        if (btndown) { 
     1168          btndown = false; 
    7901169 
    791         function px(n) { return '' + parseInt(n) + 'px'; }; 
    792         function pct(n) { return '' + parseInt(n) + '%'; }; 
    793         function cssClass(cl) { return options.baseClass + '-' + cl; }; 
    794         function getPos(obj)/*{{{*/ 
    795         { 
    796                 // Updated in v0.9.4 to use built-in dimensions plugin 
    797                 var pos = $(obj).offset(); 
    798                 return [ pos.left, pos.top ]; 
    799         }; 
    800         /*}}}*/ 
    801         function mouseAbs(e)/*{{{*/ 
    802         { 
    803                 return [ (e.pageX - docOffset[0]), (e.pageY - docOffset[1]) ]; 
    804         }; 
    805         /*}}}*/ 
    806         function myCursor(type)/*{{{*/ 
    807         { 
    808                 if (type != lastcurs) 
    809                 { 
    810                         Tracker.setCursor(type); 
    811                         //Handles.xsetCursor(type); 
    812                         lastcurs = type; 
    813                 } 
    814         }; 
    815         /*}}}*/ 
    816         function startDragMode(mode,pos)/*{{{*/ 
    817         { 
    818                 docOffset = getPos($img); 
    819                 Tracker.setCursor(mode=='move'?mode:mode+'-resize'); 
     1170          onDone(mouseAbs(e)); 
    8201171 
    821                 if (mode == 'move') 
    822                         return Tracker.activateHandlers(createMover(pos), doneSelect); 
     1172          if (Selection.isAwake()) { 
     1173            options.onSelect.call(api, unscale(Coords.getFixed())); 
     1174          } 
    8231175 
    824                 var fc = Coords.getFixed(); 
    825                 var opp = oppLockCorner(mode); 
    826                 var opc = Coords.getCorner(oppLockCorner(opp)); 
     1176          toBack(); 
     1177          onMove = function () {}; 
     1178          onDone = function () {}; 
     1179        } 
    8271180 
    828                 Coords.setPressed(Coords.getCorner(opp)); 
    829                 Coords.setCurrent(opc); 
     1181        return false; 
     1182      } 
     1183      //}}} 
     1184      function activateHandlers(move, done) //{{{ 
     1185      { 
     1186        btndown = true; 
     1187        onMove = move; 
     1188        onDone = done; 
     1189        toFront(); 
     1190        return false; 
     1191      } 
     1192      //}}} 
     1193      function trackTouchMove(e) //{{{ 
     1194      { 
     1195        e.pageX = e.originalEvent.changedTouches[0].pageX; 
     1196        e.pageY = e.originalEvent.changedTouches[0].pageY; 
     1197        return trackMove(e); 
     1198      } 
     1199      //}}} 
     1200      function trackTouchEnd(e) //{{{ 
     1201      { 
     1202        e.pageX = e.originalEvent.changedTouches[0].pageX; 
     1203        e.pageY = e.originalEvent.changedTouches[0].pageY; 
     1204        return trackUp(e); 
     1205      } 
     1206      //}}} 
     1207      function setCursor(t) //{{{ 
     1208      { 
     1209        $trk.css('cursor', t); 
     1210      } 
     1211      //}}} 
    8301212 
    831                 Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect); 
    832         }; 
    833         /*}}}*/ 
    834         function dragmodeHandler(mode,f)/*{{{*/ 
    835         { 
    836                 return function(pos) { 
    837                         if (!options.aspectRatio) switch(mode) 
    838                         { 
    839                                 case 'e': pos[1] = f.y2; break; 
    840                                 case 'w': pos[1] = f.y2; break; 
    841                                 case 'n': pos[0] = f.x2; break; 
    842                                 case 's': pos[0] = f.x2; break; 
    843                         } 
    844                         else switch(mode) 
    845                         { 
    846                                 case 'e': pos[1] = f.y+1; break; 
    847                                 case 'w': pos[1] = f.y+1; break; 
    848                                 case 'n': pos[0] = f.x+1; break; 
    849                                 case 's': pos[0] = f.x+1; break; 
    850                         } 
    851                         Coords.setCurrent(pos); 
    852                         Selection.update(); 
    853                 }; 
    854         }; 
    855         /*}}}*/ 
    856         function createMover(pos)/*{{{*/ 
    857         { 
    858                 var lloc = pos; 
    859                 KeyManager.watchKeys(); 
     1213      if (!trackDoc) { 
     1214        $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp); 
     1215      } 
    8601216 
    861                 return function(pos) 
    862                 { 
    863                         Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); 
    864                         lloc = pos; 
    865                          
    866                         Selection.update(); 
    867                 }; 
    868         }; 
    869         /*}}}*/ 
    870         function oppLockCorner(ord)/*{{{*/ 
    871         { 
    872                 switch(ord) 
    873                 { 
    874                         case 'n': return 'sw'; 
    875                         case 's': return 'nw'; 
    876                         case 'e': return 'nw'; 
    877                         case 'w': return 'ne'; 
    878                         case 'ne': return 'sw'; 
    879                         case 'nw': return 'se'; 
    880                         case 'se': return 'nw'; 
    881                         case 'sw': return 'ne'; 
    882                 }; 
    883         }; 
    884         /*}}}*/ 
    885         function createDragger(ord)/*{{{*/ 
    886         { 
    887                 return function(e) { 
    888                         if (options.disabled) return false; 
    889                         if ((ord == 'move') && !options.allowMove) return false; 
    890                         btndown = true; 
    891                         startDragMode(ord,mouseAbs(e)); 
    892                         e.stopPropagation(); 
    893                         e.preventDefault(); 
    894                         return false; 
    895                 }; 
    896         }; 
    897         /*}}}*/ 
    898         function presize($obj,w,h)/*{{{*/ 
    899         { 
    900                 var nw = $obj.width(), nh = $obj.height(); 
    901                 if ((nw > w) && w > 0) 
    902                 { 
    903                         nw = w; 
    904                         nh = (w/$obj.width()) * $obj.height(); 
    905                 } 
    906                 if ((nh > h) && h > 0) 
    907                 { 
    908                         nh = h; 
    909                         nw = (h/$obj.height()) * $obj.width(); 
    910                 } 
    911                 xscale = $obj.width() / nw; 
    912                 yscale = $obj.height() / nh; 
    913                 $obj.width(nw).height(nh); 
    914         }; 
    915         /*}}}*/ 
    916         function unscale(c)/*{{{*/ 
    917         { 
    918                 return { 
    919                         x: parseInt(c.x * xscale), y: parseInt(c.y * yscale),  
    920                         x2: parseInt(c.x2 * xscale), y2: parseInt(c.y2 * yscale),  
    921                         w: parseInt(c.w * xscale), h: parseInt(c.h * yscale) 
    922                 }; 
    923         }; 
    924         /*}}}*/ 
    925         function doneSelect(pos)/*{{{*/ 
    926         { 
    927                 var c = Coords.getFixed(); 
    928                 if (c.w > options.minSelect[0] && c.h > options.minSelect[1]) 
    929                 { 
    930                         Selection.enableHandles(); 
    931                         Selection.done(); 
    932                 } 
    933                 else 
    934                 { 
    935                         Selection.release(); 
    936                 } 
    937                 Tracker.setCursor( options.allowSelect?'crosshair':'default' ); 
    938         }; 
    939         /*}}}*/ 
    940         function newSelection(e)/*{{{*/ 
    941         { 
    942                 if (options.disabled) return false; 
    943                 if (!options.allowSelect) return false; 
    944                 btndown = true; 
    945                 docOffset = getPos($img); 
    946                 Selection.disableHandles(); 
    947                 myCursor('crosshair'); 
    948                 var pos = mouseAbs(e); 
    949                 Coords.setPressed(pos); 
    950                 Tracker.activateHandlers(selectDrag,doneSelect); 
    951                 KeyManager.watchKeys(); 
    952                 Selection.update(); 
     1217      $img.before($trk); 
     1218      return { 
     1219        activateHandlers: activateHandlers, 
     1220        setCursor: setCursor 
     1221      }; 
     1222    }()); 
     1223    //}}} 
     1224    // KeyManager Module {{{ 
     1225    var KeyManager = (function () { 
     1226      var $keymgr = $('<input type="radio" />').css({ 
     1227        position: 'fixed', 
     1228        left: '-120px', 
     1229        width: '12px' 
     1230      }), 
     1231          $keywrap = $('<div />').css({ 
     1232          position: 'absolute', 
     1233          overflow: 'hidden' 
     1234        }).append($keymgr); 
    9531235 
    954                 e.stopPropagation(); 
    955                 e.preventDefault(); 
    956                 return false; 
    957         }; 
    958         /*}}}*/ 
    959         function selectDrag(pos)/*{{{*/ 
    960         { 
    961                 Coords.setCurrent(pos); 
    962                 Selection.update(); 
    963         }; 
    964         /*}}}*/ 
    965         function newTracker() 
    966         { 
    967                 var trk = $('<div></div>').addClass(cssClass('tracker')); 
    968                 $.browser.msie && trk.css({ opacity: 0, backgroundColor: 'white' }); 
    969                 return trk; 
    970         }; 
     1236      function watchKeys() //{{{ 
     1237      { 
     1238        if (options.keySupport) { 
     1239          $keymgr.show(); 
     1240          $keymgr.focus(); 
     1241        } 
     1242      } 
     1243      //}}} 
     1244      function onBlur(e) //{{{ 
     1245      { 
     1246        $keymgr.hide(); 
     1247      } 
     1248      //}}} 
     1249      function doNudge(e, x, y) //{{{ 
     1250      { 
     1251        if (options.allowMove) { 
     1252          Coords.moveOffset([x, y]); 
     1253          Selection.updateVisible(true); 
     1254        } 
     1255        e.preventDefault(); 
     1256        e.stopPropagation(); 
     1257      } 
     1258      //}}} 
     1259      function parseKey(e) //{{{ 
     1260      { 
     1261        if (e.ctrlKey || e.metaKey) { 
     1262          return true; 
     1263        } 
     1264        shift_down = e.shiftKey ? true : false; 
     1265        var nudge = shift_down ? 10 : 1; 
    9711266 
    972         // }}} 
    973         // API methods {{{ 
    974                  
    975         function animateTo(a)/*{{{*/ 
    976         { 
    977                 var x1 = a[0] / xscale, 
    978                         y1 = a[1] / yscale, 
    979                         x2 = a[2] / xscale, 
    980                         y2 = a[3] / yscale; 
     1267        switch (e.keyCode) { 
     1268        case 37: 
     1269          doNudge(e, -nudge, 0); 
     1270          break; 
     1271        case 39: 
     1272          doNudge(e, nudge, 0); 
     1273          break; 
     1274        case 38: 
     1275          doNudge(e, 0, -nudge); 
     1276          break; 
     1277        case 40: 
     1278          doNudge(e, 0, nudge); 
     1279          break; 
     1280        case 27: 
     1281          if (options.allowSelect) Selection.release(); 
     1282          break; 
     1283        case 9: 
     1284          return true; 
     1285        } 
    9811286 
    982                 if (animating) return; 
     1287        return false; 
     1288      } 
     1289      //}}} 
    9831290 
    984                 var animto = Coords.flipCoords(x1,y1,x2,y2); 
    985                 var c = Coords.getFixed(); 
    986                 var animat = initcr = [ c.x, c.y, c.x2, c.y2 ]; 
    987                 var interv = options.animationDelay; 
     1291      if (options.keySupport) { 
     1292        $keymgr.keydown(parseKey).blur(onBlur); 
     1293        if (ie6mode || !options.fixedSupport) { 
     1294          $keymgr.css({ 
     1295            position: 'absolute', 
     1296            left: '-20px' 
     1297          }); 
     1298          $keywrap.append($keymgr).insertBefore($img); 
     1299        } else { 
     1300          $keymgr.insertBefore($img); 
     1301        } 
     1302      } 
    9881303 
    989                 var x = animat[0]; 
    990                 var y = animat[1]; 
    991                 var x2 = animat[2]; 
    992                 var y2 = animat[3]; 
    993                 var ix1 = animto[0] - initcr[0]; 
    994                 var iy1 = animto[1] - initcr[1]; 
    995                 var ix2 = animto[2] - initcr[2]; 
    996                 var iy2 = animto[3] - initcr[3]; 
    997                 var pcent = 0; 
    998                 var velocity = options.swingSpeed; 
    9991304 
    1000                 Selection.animMode(true); 
     1305      return { 
     1306        watchKeys: watchKeys 
     1307      }; 
     1308    }()); 
     1309    //}}} 
     1310    // }}} 
     1311    // API methods {{{ 
     1312    function setClass(cname) //{{{ 
     1313    { 
     1314      $div.removeClass().addClass(cssClass('holder')).addClass(cname); 
     1315    } 
     1316    //}}} 
     1317    function animateTo(a, callback) //{{{ 
     1318    { 
     1319      var x1 = a[0] / xscale, 
     1320          y1 = a[1] / yscale, 
     1321          x2 = a[2] / xscale, 
     1322          y2 = a[3] / yscale; 
    10011323 
    1002                 var animator = function() 
    1003                 { 
    1004                         return function() 
    1005                         { 
    1006                                 pcent += (100 - pcent) / velocity; 
     1324      if (animating) { 
     1325        return; 
     1326      } 
    10071327 
    1008                                 animat[0] = x + ((pcent / 100) * ix1); 
    1009                                 animat[1] = y + ((pcent / 100) * iy1); 
    1010                                 animat[2] = x2 + ((pcent / 100) * ix2); 
    1011                                 animat[3] = y2 + ((pcent / 100) * iy2); 
     1328      var animto = Coords.flipCoords(x1, y1, x2, y2), 
     1329          c = Coords.getFixed(), 
     1330          initcr = [c.x, c.y, c.x2, c.y2], 
     1331          animat = initcr, 
     1332          interv = options.animationDelay, 
     1333          ix1 = animto[0] - initcr[0], 
     1334          iy1 = animto[1] - initcr[1], 
     1335          ix2 = animto[2] - initcr[2], 
     1336          iy2 = animto[3] - initcr[3], 
     1337          pcent = 0, 
     1338          velocity = options.swingSpeed; 
    10121339 
    1013                                 if (pcent < 100) animateStart(); 
    1014                                         else Selection.done(); 
     1340      x = animat[0]; 
     1341      y = animat[1]; 
     1342      x2 = animat[2]; 
     1343      y2 = animat[3]; 
    10151344 
    1016                                 if (pcent >= 99.8) pcent = 100; 
     1345      Selection.animMode(true); 
     1346      var anim_timer; 
    10171347 
    1018                                 setSelectRaw(animat); 
    1019                         }; 
    1020                 }(); 
     1348      function queueAnimator() { 
     1349        window.setTimeout(animator, interv); 
     1350      } 
     1351      var animator = (function () { 
     1352        return function () { 
     1353          pcent += (100 - pcent) / velocity; 
    10211354 
    1022                 function animateStart() 
    1023                         { window.setTimeout(animator,interv); }; 
     1355          animat[0] = x + ((pcent / 100) * ix1); 
     1356          animat[1] = y + ((pcent / 100) * iy1); 
     1357          animat[2] = x2 + ((pcent / 100) * ix2); 
     1358          animat[3] = y2 + ((pcent / 100) * iy2); 
    10241359 
    1025                 animateStart(); 
    1026         }; 
    1027         /*}}}*/ 
    1028         function setSelect(rect)//{{{ 
    1029         { 
    1030                 setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]); 
    1031         }; 
    1032         //}}} 
    1033         function setSelectRaw(l) /*{{{*/ 
    1034         { 
    1035                 Coords.setPressed([l[0],l[1]]); 
    1036                 Coords.setCurrent([l[2],l[3]]); 
    1037                 Selection.update(); 
    1038         }; 
    1039         /*}}}*/ 
    1040         function setOptions(opt)/*{{{*/ 
    1041         { 
    1042                 if (typeof(opt) != 'object') opt = { }; 
    1043                 options = $.extend(options,opt); 
     1360          if (pcent >= 99.8) { 
     1361            pcent = 100; 
     1362          } 
     1363          if (pcent < 100) { 
     1364            setSelectRaw(animat); 
     1365            queueAnimator(); 
     1366          } else { 
     1367            Selection.done(); 
     1368            if (typeof(callback) === 'function') { 
     1369              callback.call(api); 
     1370            } 
     1371          } 
     1372        }; 
     1373      }()); 
     1374      queueAnimator(); 
     1375    } 
     1376    //}}} 
     1377    function setSelect(rect) //{{{ 
     1378    { 
     1379      setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]); 
     1380      options.onSelect.call(api, unscale(Coords.getFixed())); 
     1381      Selection.enableHandles(); 
     1382    } 
     1383    //}}} 
     1384    function setSelectRaw(l) //{{{ 
     1385    { 
     1386      Coords.setPressed([l[0], l[1]]); 
     1387      Coords.setCurrent([l[2], l[3]]); 
     1388      Selection.update(); 
     1389    } 
     1390    //}}} 
     1391    function tellSelect() //{{{ 
     1392    { 
     1393      return unscale(Coords.getFixed()); 
     1394    } 
     1395    //}}} 
     1396    function tellScaled() //{{{ 
     1397    { 
     1398      return Coords.getFixed(); 
     1399    } 
     1400    //}}} 
     1401    function setOptionsNew(opt) //{{{ 
     1402    { 
     1403      setOptions(opt); 
     1404      interfaceUpdate(); 
     1405    } 
     1406    //}}} 
     1407    function disableCrop() //{{{ 
     1408    { 
     1409      options.disabled = true; 
     1410      Selection.disableHandles(); 
     1411      Selection.setCursor('default'); 
     1412      Tracker.setCursor('default'); 
     1413    } 
     1414    //}}} 
     1415    function enableCrop() //{{{ 
     1416    { 
     1417      options.disabled = false; 
     1418      interfaceUpdate(); 
     1419    } 
     1420    //}}} 
     1421    function cancelCrop() //{{{ 
     1422    { 
     1423      Selection.done(); 
     1424      Tracker.activateHandlers(null, null); 
     1425    } 
     1426    //}}} 
     1427    function destroy() //{{{ 
     1428    { 
     1429      $div.remove(); 
     1430      $origimg.show(); 
     1431      $(obj).removeData('Jcrop'); 
     1432    } 
     1433    //}}} 
     1434    function setImage(src, callback) //{{{ 
     1435    { 
     1436      Selection.release(); 
     1437      disableCrop(); 
     1438      var img = new Image(); 
     1439      img.onload = function () { 
     1440        var iw = img.width; 
     1441        var ih = img.height; 
     1442        var bw = options.boxWidth; 
     1443        var bh = options.boxHeight; 
     1444        $img.width(iw).height(ih); 
     1445        $img.attr('src', src); 
     1446        $img2.attr('src', src); 
     1447        presize($img, bw, bh); 
     1448        boundx = $img.width(); 
     1449        boundy = $img.height(); 
     1450        $img2.width(boundx).height(boundy); 
     1451        $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2)); 
     1452        $div.width(boundx).height(boundy); 
     1453        Shade.resize(boundx,boundy); 
     1454        enableCrop(); 
    10441455 
    1045                 if (typeof(options.onChange)!=='function') 
    1046                         options.onChange = function() { }; 
     1456        if (typeof(callback) === 'function') { 
     1457          callback.call(api); 
     1458        } 
     1459      }; 
     1460      img.src = src; 
     1461    } 
     1462    //}}} 
     1463    function colorChangeMacro($obj,color,now) { 
     1464      var mycolor = color || options.bgColor; 
     1465      if (options.bgFade && supportsColorFade() && options.fadeTime && !now) { 
     1466        $obj.animate({ 
     1467          backgroundColor: mycolor 
     1468        }, { 
     1469          queue: false, 
     1470          duration: options.fadeTime 
     1471        }); 
     1472      } else { 
     1473        $obj.css('backgroundColor', mycolor); 
     1474      } 
     1475    } 
     1476    function interfaceUpdate(alt) //{{{ 
     1477    // This method tweaks the interface based on options object. 
     1478    // Called when options are changed and at end of initialization. 
     1479    { 
     1480      if (options.allowResize) { 
     1481        if (alt) { 
     1482          Selection.enableOnly(); 
     1483        } else { 
     1484          Selection.enableHandles(); 
     1485        } 
     1486      } else { 
     1487        Selection.disableHandles(); 
     1488      } 
    10471489 
    1048                 if (typeof(options.onSelect)!=='function') 
    1049                         options.onSelect = function() { }; 
     1490      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); 
     1491      Selection.setCursor(options.allowMove ? 'move' : 'default'); 
    10501492 
    1051         }; 
    1052         /*}}}*/ 
    1053         function tellSelect()/*{{{*/ 
    1054         { 
    1055                 return unscale(Coords.getFixed()); 
    1056         }; 
    1057         /*}}}*/ 
    1058         function tellScaled()/*{{{*/ 
    1059         { 
    1060                 return Coords.getFixed(); 
    1061         }; 
    1062         /*}}}*/ 
    1063         function setOptionsNew(opt)/*{{{*/ 
    1064         { 
    1065                 setOptions(opt); 
    1066                 interfaceUpdate(); 
    1067         }; 
    1068         /*}}}*/ 
    1069         function disableCrop()//{{{ 
    1070         { 
    1071                 options.disabled = true; 
    1072                 Selection.disableHandles(); 
    1073                 Selection.setCursor('default'); 
    1074                 Tracker.setCursor('default'); 
    1075         }; 
    1076         //}}} 
    1077         function enableCrop()//{{{ 
    1078         { 
    1079                 options.disabled = false; 
    1080                 interfaceUpdate(); 
    1081         }; 
    1082         //}}} 
    1083         function cancelCrop()//{{{ 
    1084         { 
    1085                 Selection.done(); 
    1086                 Tracker.activateHandlers(null,null); 
    1087         }; 
    1088         //}}} 
    1089         function destroy()//{{{ 
    1090         { 
    1091                 $div.remove(); 
    1092                 $origimg.show(); 
    1093         }; 
    1094         //}}} 
     1493      if (options.hasOwnProperty('trueSize')) { 
     1494        xscale = options.trueSize[0] / boundx; 
     1495        yscale = options.trueSize[1] / boundy; 
     1496      } 
    10951497 
    1096         function interfaceUpdate(alt)//{{{ 
    1097         // This method tweaks the interface based on options object. 
    1098         // Called when options are changed and at end of initialization. 
    1099         { 
    1100                 options.allowResize ? 
    1101                         alt?Selection.enableOnly():Selection.enableHandles(): 
    1102                         Selection.disableHandles(); 
     1498      if (options.hasOwnProperty('setSelect')) { 
     1499        setSelect(options.setSelect); 
     1500        Selection.done(); 
     1501        delete(options.setSelect); 
     1502      } 
    11031503 
    1104                 Tracker.setCursor( options.allowSelect? 'crosshair': 'default' ); 
    1105                 Selection.setCursor( options.allowMove? 'move': 'default' ); 
     1504      Shade.refresh(); 
    11061505 
    1107                 $div.css('backgroundColor',options.bgColor); 
     1506      if (options.bgColor != bgcolor) { 
     1507        colorChangeMacro( 
     1508          options.shade? Shade.getShades(): $div, 
     1509          options.shade? 
     1510            (options.shadeColor || options.bgColor): 
     1511            options.bgColor 
     1512        ); 
     1513        bgcolor = options.bgColor; 
     1514      } 
    11081515 
    1109                 if ('setSelect' in options) { 
    1110                         setSelect(opt.setSelect); 
    1111                         Selection.done(); 
    1112                         delete(options.setSelect); 
    1113                 } 
     1516      if (bgopacity != options.bgOpacity) { 
     1517        bgopacity = options.bgOpacity; 
     1518        if (options.shade) Shade.refresh(); 
     1519          else Selection.setBgOpacity(bgopacity); 
     1520      } 
    11141521 
    1115                 if ('trueSize' in options) { 
    1116                         xscale = options.trueSize[0] / boundx; 
    1117                         yscale = options.trueSize[1] / boundy; 
    1118                 } 
     1522      xlimit = options.maxSize[0] || 0; 
     1523      ylimit = options.maxSize[1] || 0; 
     1524      xmin = options.minSize[0] || 0; 
     1525      ymin = options.minSize[1] || 0; 
    11191526 
    1120                 xlimit = options.maxSize[0] || 0; 
    1121                 ylimit = options.maxSize[1] || 0; 
    1122                 xmin = options.minSize[0] || 0; 
    1123                 ymin = options.minSize[1] || 0; 
     1527      if (options.hasOwnProperty('outerImage')) { 
     1528        $img.attr('src', options.outerImage); 
     1529        delete(options.outerImage); 
     1530      } 
    11241531 
    1125                 if ('outerImage' in options) 
    1126                 { 
    1127                         $img.attr('src',options.outerImage); 
    1128                         delete(options.outerImage); 
    1129                 } 
     1532      Selection.refresh(); 
     1533    } 
     1534    //}}} 
     1535    //}}} 
    11301536 
    1131                 Selection.refresh(); 
    1132         }; 
    1133         //}}} 
     1537    if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection); 
    11341538 
    1135         // }}} 
     1539    $hdl_holder.hide(); 
     1540    interfaceUpdate(true); 
    11361541 
    1137         $hdl_holder.hide(); 
    1138         interfaceUpdate(true); 
    1139          
    1140         var api = { 
    1141                 animateTo: animateTo, 
    1142                 setSelect: setSelect, 
    1143                 setOptions: setOptionsNew, 
    1144                 tellSelect: tellSelect, 
    1145                 tellScaled: tellScaled, 
     1542    var api = { 
     1543      setImage: setImage, 
     1544      animateTo: animateTo, 
     1545      setSelect: setSelect, 
     1546      setOptions: setOptionsNew, 
     1547      tellSelect: tellSelect, 
     1548      tellScaled: tellScaled, 
     1549      setClass: setClass, 
    11461550 
    1147                 disable: disableCrop, 
    1148                 enable: enableCrop, 
    1149                 cancel: cancelCrop, 
     1551      disable: disableCrop, 
     1552      enable: enableCrop, 
     1553      cancel: cancelCrop, 
     1554      release: Selection.release, 
     1555      destroy: destroy, 
    11501556 
    1151                 focus: KeyManager.watchKeys, 
     1557      focus: KeyManager.watchKeys, 
    11521558 
    1153                 getBounds: function() { return [ boundx * xscale, boundy * yscale ]; }, 
    1154                 getWidgetSize: function() { return [ boundx, boundy ]; }, 
     1559      getBounds: function () { 
     1560        return [boundx * xscale, boundy * yscale]; 
     1561      }, 
     1562      getWidgetSize: function () { 
     1563        return [boundx, boundy]; 
     1564      }, 
     1565      getScaleFactor: function () { 
     1566        return [xscale, yscale]; 
     1567      }, 
     1568      getOptions: function() { 
     1569        // careful: internal values are returned 
     1570        return options; 
     1571      }, 
    11551572 
    1156                 release: Selection.release, 
    1157                 destroy: destroy 
     1573      ui: { 
     1574        holder: $div, 
     1575        selection: $sel 
     1576      } 
     1577    }; 
    11581578 
    1159         }; 
     1579    if ($.browser.msie) 
     1580      $div.bind('selectstart', function () { return false; }); 
    11601581 
    1161         $origimg.data('Jcrop',api); 
    1162         return api; 
    1163 }; 
     1582    $origimg.data('Jcrop', api); 
     1583    return api; 
     1584  }; 
     1585  $.fn.Jcrop = function (options, callback) //{{{ 
     1586  { 
     1587    var api; 
     1588    // Iterate over each object, attach Jcrop 
     1589    this.each(function () { 
     1590      // If we've already attached to this object 
     1591      if ($(this).data('Jcrop')) { 
     1592        // The API can be requested this way (undocumented) 
     1593        if (options === 'api') return $(this).data('Jcrop'); 
     1594        // Otherwise, we just reset the options... 
     1595        else $(this).data('Jcrop').setOptions(options); 
     1596      } 
     1597      // If we haven't been attached, preload and attach 
     1598      else { 
     1599        if (this.tagName == 'IMG') 
     1600          $.Jcrop.Loader(this,function(){ 
     1601            $(this).css({display:'block',visibility:'hidden'}); 
     1602            api = $.Jcrop(this, options); 
     1603            if ($.isFunction(callback)) callback.call(api); 
     1604          }); 
     1605        else { 
     1606          $(this).css({display:'block',visibility:'hidden'}); 
     1607          api = $.Jcrop(this, options); 
     1608          if ($.isFunction(callback)) callback.call(api); 
     1609        } 
     1610      } 
     1611    }); 
    11641612 
    1165 $.fn.Jcrop = function(options)/*{{{*/ 
    1166 { 
    1167         function attachWhenDone(from)/*{{{*/ 
    1168         { 
    1169                 var loadsrc = options.useImg || from.src; 
    1170                 var img = new Image(); 
    1171                 img.onload = function() { $.Jcrop(from,options); }; 
    1172                 img.src = loadsrc; 
    1173         }; 
    1174         /*}}}*/ 
    1175         if (typeof(options) !== 'object') options = { }; 
     1613    // Return "this" so the object is chainable (jQuery-style) 
     1614    return this; 
     1615  }; 
     1616  //}}} 
     1617  // $.Jcrop.Loader - basic image loader {{{ 
    11761618 
    1177         // Iterate over each object, attach Jcrop 
    1178         this.each(function() 
    1179         { 
    1180                 // If we've already attached to this object 
    1181                 if ($(this).data('Jcrop')) 
    1182                 { 
    1183                         // The API can be requested this way (undocumented) 
    1184                         if (options == 'api') return $(this).data('Jcrop'); 
    1185                         // Otherwise, we just reset the options... 
    1186                         else $(this).data('Jcrop').setOptions(options); 
    1187                 } 
    1188                 // If we haven't been attached, preload and attach 
    1189                 else attachWhenDone(this); 
    1190         }); 
     1619  $.Jcrop.Loader = function(imgobj,success,error){ 
     1620    var $img = $(imgobj), img = $img[0]; 
    11911621 
    1192         // Return "this" so we're chainable a la jQuery plugin-style! 
    1193         return this; 
    1194 }; 
    1195 /*}}}*/ 
     1622    function completeCheck(){ 
     1623      if (img.complete) { 
     1624        $img.unbind('.jcloader'); 
     1625        if ($.isFunction(success)) success.call(img); 
     1626      } 
     1627      else window.setTimeout(completeCheck,50); 
     1628    } 
    11961629 
    1197 })(jQuery); 
     1630    $img 
     1631      .bind('load.jcloader',completeCheck) 
     1632      .bind('error.jcloader',function(e){ 
     1633        $img.unbind('.jcloader'); 
     1634        if ($.isFunction(error)) error.call(img); 
     1635      }); 
     1636 
     1637    if (img.complete && $.isFunction(success)){ 
     1638      $img.unbind('.jcloader'); 
     1639      success.call(img); 
     1640    } 
     1641  }; 
     1642 
     1643  //}}} 
     1644  // Global Defaults {{{ 
     1645  $.Jcrop.defaults = { 
     1646 
     1647    // Basic Settings 
     1648    allowSelect: true, 
     1649    allowMove: true, 
     1650    allowResize: true, 
     1651 
     1652    trackDocument: true, 
     1653 
     1654    // Styling Options 
     1655    baseClass: 'jcrop', 
     1656    addClass: null, 
     1657    bgColor: 'black', 
     1658    bgOpacity: 0.6, 
     1659    bgFade: false, 
     1660    borderOpacity: 0.4, 
     1661    handleOpacity: 0.5, 
     1662    handleSize: 7, 
     1663 
     1664    aspectRatio: 0, 
     1665    keySupport: true, 
     1666    createHandles: ['n','s','e','w','nw','ne','se','sw'], 
     1667    createDragbars: ['n','s','e','w'], 
     1668    createBorders: ['n','s','e','w'], 
     1669    drawBorders: true, 
     1670    dragEdges: true, 
     1671    fixedSupport: true, 
     1672    touchSupport: null, 
     1673 
     1674    shade: null, 
     1675 
     1676    boxWidth: 0, 
     1677    boxHeight: 0, 
     1678    boundary: 2, 
     1679    fadeTime: 400, 
     1680    animationDelay: 20, 
     1681    swingSpeed: 3, 
     1682 
     1683    minSelect: [0, 0], 
     1684    maxSize: [0, 0], 
     1685    minSize: [0, 0], 
     1686 
     1687    // Callbacks / Event Handlers 
     1688    onChange: function () {}, 
     1689    onSelect: function () {}, 
     1690    onDblClick: function () {}, 
     1691    onRelease: function () {} 
     1692  }; 
     1693 
     1694  // }}} 
     1695}(jQuery));