source: trunk/themes/default/js/plugins/jquery.Jcrop.js @ 20816

Last change on this file since 20816 was 19682, checked in by rvelices, 11 years ago

upgraded js libs
jquery from 1.8.2 to 1.8.3
jquery jCrop from 0.9.9 to 0.9.10

File size: 41.4 KB
Line 
1/**
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 {{{
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following
15 * conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * }}}
30 */
31
32(function ($) {
33
34  $.Jcrop = function (obj, opt) {
35    var options = $.extend({}, $.Jcrop.defaults),
36        docOffset, lastcurs, ie6mode = false;
37
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);
63
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');
73
74      if (mode === 'move') {
75        return Tracker.activateHandlers(createMover(pos), doneSelect);
76      }
77
78      var fc = Coords.getFixed();
79      var opp = oppLockCorner(mode);
80      var opc = Coords.getCorner(oppLockCorner(opp));
81
82      Coords.setPressed(Coords.getCorner(opp));
83      Coords.setCurrent(opc);
84
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();
131
132      return function (pos) {
133        Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
134        lloc = pos;
135
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);
175
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();
242
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    //}}}
266
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    };
295
296    var $origimg = $(obj),
297      img_mode = true;
298
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      } 
313
314      var $img = $origimg.clone().removeAttr('id').css(img_css).show();
315
316      $img.width($origimg.width());
317      $img.height($origimg.height());
318      $origimg.after($img).hide();
319
320    } else {
321      $img = $origimg.css(img_css).show();
322      img_mode = false;
323      if (options.shade === null) { options.shade = true; }
324    }
325
326    presize($img, options.boxWidth, options.boxHeight);
327
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);
336
337    if (options.addClass) {
338      $div.addClass(options.addClass);
339    }
340
341    var $img2 = $('<div />'),
342
343        $img_holder = $('<div />') 
344        .width('100%').height('100%').css({
345          zIndex: 310,
346          position: 'absolute',
347          overflow: 'hidden'
348        }),
349
350        $hdl_holder = $('<div />') 
351        .width('100%').height('100%').css('zIndex', 320), 
352
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); 
361
362    if (img_mode) {
363
364      $img2 = $('<img />')
365          .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
366
367      $img_holder.append($img2);
368
369    }
370
371    if (ie6mode) {
372      $sel.css({
373        overflowY: 'hidden'
374      });
375    }
376
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);
384
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;
391
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;
404
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      }
422
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;
462
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];
488
489        if (0 > x1 + ox) {
490          ox -= ox + x1;
491        }
492        if (0 > y1 + oy) {
493          oy -= oy + y1;
494        }
495
496        if (boundy < y2 + oy) {
497          oy += boundy - (y2 + oy);
498        }
499        if (boundx < x2 + ox) {
500          ox += boundx - (x2 + ox);
501        }
502
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;
543
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;
554
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        }
578
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        }
603
604        if (xx < 0) {
605          x1 -= xx;
606          xx = 0;
607        } else if (xx > boundx) {
608          x1 -= xx - boundx;
609          xx = boundx;
610        }
611
612        if (yy < 0) {
613          y1 -= yy;
614          yy = 0;
615        } else if (yy > boundy) {
616          y1 -= yy - boundy;
617          yy = boundy;
618        }
619
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        }
631
632        if (p[0] > boundx) {
633          p[0] = boundx;
634        }
635        if (p[1] > boundy) {
636          p[1] = boundy;
637        }
638
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;
664
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        }
671
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        }
678
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        }
715
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      //}}}
731
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    }());
742
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          };
758
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();
801
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      }
847
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;
869
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);
888
889        if (Touch.support) {
890          jq.bind('touchstart.jcrop', Touch.createDragger(ord));
891        }
892
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();
962
963        Coords.setPressed([c.x, c.y]);
964        Coords.setCurrent([c.x2, c.y2]);
965
966        updateVisible();
967      }
968      //}}}
969
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();
981
982        resize(c.w, c.h);
983        moveto(c.x, c.y);
984        if (options.shade) Shade.updateRaw(c);
985
986        awake || show();
987
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();
1013
1014        if (options.shade) Shade.opacity(bgopacity);
1015          else setBgOpacity(bgopacity,true);
1016
1017        awake = true;
1018      }
1019      //}}}
1020      function release() //{{{
1021      {
1022        disableHandles();
1023        $sel.hide();
1024
1025        if (options.shade) Shade.opacity(1);
1026          else setBgOpacity(1);
1027
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
1071
1072      if (options.dragEdges && $.isArray(options.createDragbars))
1073        createDragbars(options.createDragbars);
1074
1075      if ($.isArray(options.createHandles))
1076        createHandles(options.createHandles);
1077
1078      if (options.drawBorders && $.isArray(options.createBorders))
1079        createBorders(options.createBorders);
1080
1081      //}}}
1082
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      });
1087
1088      var $track = newTracker().mousedown(createDragger('move')).css({
1089        cursor: 'move',
1090        position: 'absolute',
1091        zIndex: 360
1092      });
1093
1094      if (Touch.support) {
1095        $track.bind('touchstart.jcrop', Touch.createDragger('move'));
1096      }
1097
1098      $img_holder.append($track);
1099      disableHandles();
1100
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;
1130
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();
1166
1167        if (btndown) {
1168          btndown = false;
1169
1170          onDone(mouseAbs(e));
1171
1172          if (Selection.isAwake()) {
1173            options.onSelect.call(api, unscale(Coords.getFixed()));
1174          }
1175
1176          toBack();
1177          onMove = function () {};
1178          onDone = function () {};
1179        }
1180
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      //}}}
1212
1213      if (!trackDoc) {
1214        $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
1215      }
1216
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);
1235
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;
1266
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        }
1286
1287        return false;
1288      }
1289      //}}}
1290
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      }
1303
1304
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;
1323
1324      if (animating) {
1325        return;
1326      }
1327
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;
1339
1340      x = animat[0];
1341      y = animat[1];
1342      x2 = animat[2];
1343      y2 = animat[3];
1344
1345      Selection.animMode(true);
1346      var anim_timer;
1347
1348      function queueAnimator() {
1349        window.setTimeout(animator, interv);
1350      }
1351      var animator = (function () {
1352        return function () {
1353          pcent += (100 - pcent) / velocity;
1354
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);
1359
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();
1455
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      }
1489
1490      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
1491      Selection.setCursor(options.allowMove ? 'move' : 'default');
1492
1493      if (options.hasOwnProperty('trueSize')) {
1494        xscale = options.trueSize[0] / boundx;
1495        yscale = options.trueSize[1] / boundy;
1496      }
1497
1498      if (options.hasOwnProperty('setSelect')) {
1499        setSelect(options.setSelect);
1500        Selection.done();
1501        delete(options.setSelect);
1502      }
1503
1504      Shade.refresh();
1505
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      }
1515
1516      if (bgopacity != options.bgOpacity) {
1517        bgopacity = options.bgOpacity;
1518        if (options.shade) Shade.refresh();
1519          else Selection.setBgOpacity(bgopacity);
1520      }
1521
1522      xlimit = options.maxSize[0] || 0;
1523      ylimit = options.maxSize[1] || 0;
1524      xmin = options.minSize[0] || 0;
1525      ymin = options.minSize[1] || 0;
1526
1527      if (options.hasOwnProperty('outerImage')) {
1528        $img.attr('src', options.outerImage);
1529        delete(options.outerImage);
1530      }
1531
1532      Selection.refresh();
1533    }
1534    //}}}
1535    //}}}
1536
1537    if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
1538
1539    $hdl_holder.hide();
1540    interfaceUpdate(true);
1541
1542    var api = {
1543      setImage: setImage,
1544      animateTo: animateTo,
1545      setSelect: setSelect,
1546      setOptions: setOptionsNew,
1547      tellSelect: tellSelect,
1548      tellScaled: tellScaled,
1549      setClass: setClass,
1550
1551      disable: disableCrop,
1552      enable: enableCrop,
1553      cancel: cancelCrop,
1554      release: Selection.release,
1555      destroy: destroy,
1556
1557      focus: KeyManager.watchKeys,
1558
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      },
1572
1573      ui: {
1574        holder: $div,
1575        selection: $sel
1576      }
1577    };
1578
1579    if ($.browser.msie)
1580      $div.bind('selectstart', function () { return false; });
1581
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    });
1612
1613    // Return "this" so the object is chainable (jQuery-style)
1614    return this;
1615  };
1616  //}}}
1617  // $.Jcrop.Loader - basic image loader {{{
1618
1619  $.Jcrop.Loader = function(imgobj,success,error){
1620    var $img = $(imgobj), img = $img[0];
1621
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    }
1629
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));
Note: See TracBrowser for help on using the repository browser.