Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
/**
2
 * jquery.Jcrop.js v0.9.12
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-2013 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,
37
        _ua = navigator.userAgent.toLowerCase(),
38
        is_msie = /msie/.test(_ua),
39
        ie6mode = /msie [1-6]\./.test(_ua);
40
 
41
    // Internal Methods {{{
42
    function px(n) {
43
      return Math.round(n) + 'px';
44
    }
45
    function cssClass(cl) {
46
      return options.baseClass + '-' + cl;
47
    }
48
    function supportsColorFade() {
49
      return $.fx.step.hasOwnProperty('backgroundColor');
50
    }
51
    function getPos(obj) //{{{
52
    {
53
      var pos = $(obj).offset();
54
      return [pos.left, pos.top];
55
    }
56
    //}}}
57
    function mouseAbs(e) //{{{
58
    {
59
      return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
60
    }
61
    //}}}
62
    function setOptions(opt) //{{{
63
    {
64
      if (typeof(opt) !== 'object') opt = {};
65
      options = $.extend(options, opt);
66
 
67
      $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
68
        if (typeof(options[e]) !== 'function') options[e] = function () {};
69
      });
70
    }
71
    //}}}
72
    function startDragMode(mode, pos, touch) //{{{
73
    {
74
      docOffset = getPos($img);
75
      Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
76
 
77
      if (mode === 'move') {
78
        return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
79
      }
80
 
81
      var fc = Coords.getFixed();
82
      var opp = oppLockCorner(mode);
83
      var opc = Coords.getCorner(oppLockCorner(opp));
84
 
85
      Coords.setPressed(Coords.getCorner(opp));
86
      Coords.setCurrent(opc);
87
 
88
      Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
89
    }
90
    //}}}
91
    function dragmodeHandler(mode, f) //{{{
92
    {
93
      return function (pos) {
94
        if (!options.aspectRatio) {
95
          switch (mode) {
96
          case 'e':
97
            pos[1] = f.y2;
98
            break;
99
          case 'w':
100
            pos[1] = f.y2;
101
            break;
102
          case 'n':
103
            pos[0] = f.x2;
104
            break;
105
          case 's':
106
            pos[0] = f.x2;
107
            break;
108
          }
109
        } else {
110
          switch (mode) {
111
          case 'e':
112
            pos[1] = f.y + 1;
113
            break;
114
          case 'w':
115
            pos[1] = f.y + 1;
116
            break;
117
          case 'n':
118
            pos[0] = f.x + 1;
119
            break;
120
          case 's':
121
            pos[0] = f.x + 1;
122
            break;
123
          }
124
        }
125
        Coords.setCurrent(pos);
126
        Selection.update();
127
      };
128
    }
129
    //}}}
130
    function createMover(pos) //{{{
131
    {
132
      var lloc = pos;
133
      KeyManager.watchKeys();
134
 
135
      return function (pos) {
136
        Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
137
        lloc = pos;
138
 
139
        Selection.update();
140
      };
141
    }
142
    //}}}
143
    function oppLockCorner(ord) //{{{
144
    {
145
      switch (ord) {
146
      case 'n':
147
        return 'sw';
148
      case 's':
149
        return 'nw';
150
      case 'e':
151
        return 'nw';
152
      case 'w':
153
        return 'ne';
154
      case 'ne':
155
        return 'sw';
156
      case 'nw':
157
        return 'se';
158
      case 'se':
159
        return 'nw';
160
      case 'sw':
161
        return 'ne';
162
      }
163
    }
164
    //}}}
165
    function createDragger(ord) //{{{
166
    {
167
      return function (e) {
168
        if (options.disabled) {
169
          return false;
170
        }
171
        if ((ord === 'move') && !options.allowMove) {
172
          return false;
173
        }
174
 
175
        // Fix position of crop area when dragged the very first time.
176
        // Necessary when crop image is in a hidden element when page is loaded.
177
        docOffset = getPos($img);
178
 
179
        btndown = true;
180
        startDragMode(ord, mouseAbs(e));
181
        e.stopPropagation();
182
        e.preventDefault();
183
        return false;
184
      };
185
    }
186
    //}}}
187
    function presize($obj, w, h) //{{{
188
    {
189
      var nw = $obj.width(),
190
          nh = $obj.height();
191
      if ((nw > w) && w > 0) {
192
        nw = w;
193
        nh = (w / $obj.width()) * $obj.height();
194
      }
195
      if ((nh > h) && h > 0) {
196
        nh = h;
197
        nw = (h / $obj.height()) * $obj.width();
198
      }
199
      xscale = $obj.width() / nw;
200
      yscale = $obj.height() / nh;
201
      $obj.width(nw).height(nh);
202
    }
203
    //}}}
204
    function unscale(c) //{{{
205
    {
206
      return {
207
        x: c.x * xscale,
208
        y: c.y * yscale,
209
        x2: c.x2 * xscale,
210
        y2: c.y2 * yscale,
211
        w: c.w * xscale,
212
        h: c.h * yscale
213
      };
214
    }
215
    //}}}
216
    function doneSelect(pos) //{{{
217
    {
218
      var c = Coords.getFixed();
219
      if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
220
        Selection.enableHandles();
221
        Selection.done();
222
      } else {
223
        Selection.release();
224
      }
225
      Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
226
    }
227
    //}}}
228
    function newSelection(e) //{{{
229
    {
230
      if (options.disabled) {
231
        return false;
232
      }
233
      if (!options.allowSelect) {
234
        return false;
235
      }
236
      btndown = true;
237
      docOffset = getPos($img);
238
      Selection.disableHandles();
239
      Tracker.setCursor('crosshair');
240
      var pos = mouseAbs(e);
241
      Coords.setPressed(pos);
242
      Selection.update();
243
      Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch');
244
      KeyManager.watchKeys();
245
 
246
      e.stopPropagation();
247
      e.preventDefault();
248
      return false;
249
    }
250
    //}}}
251
    function selectDrag(pos) //{{{
252
    {
253
      Coords.setCurrent(pos);
254
      Selection.update();
255
    }
256
    //}}}
257
    function newTracker() //{{{
258
    {
259
      var trk = $('<div></div>').addClass(cssClass('tracker'));
260
      if (is_msie) {
261
        trk.css({
262
          opacity: 0,
263
          backgroundColor: 'white'
264
        });
265
      }
266
      return trk;
267
    }
268
    //}}}
269
 
270
    // }}}
271
    // Initialization {{{
272
    // Sanitize some options {{{
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 = {}, events = ['touchstart', 'touchmove', 'touchend'],
402
            el = document.createElement('div'), i;
403
 
404
        try {
405
          for(i=0; i<events.length; i++) {
406
            var eventName = events[i];
407
            eventName = 'on' + eventName;
408
            var isSupported = (eventName in el);
409
            if (!isSupported) {
410
              el.setAttribute(eventName, 'return;');
411
              isSupported = typeof el[eventName] == 'function';
412
            }
413
            support[events[i]] = isSupported;
414
          }
415
          return support.touchstart && support.touchend && support.touchmove;
416
        }
417
        catch(err) {
418
          return false;
419
        }
420
      }
421
 
422
      function detectSupport() {
423
        if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
424
          else return hasTouchSupport();
425
      }
426
      return {
427
        createDragger: function (ord) {
428
          return function (e) {
429
            if (options.disabled) {
430
              return false;
431
            }
432
            if ((ord === 'move') && !options.allowMove) {
433
              return false;
434
            }
435
            docOffset = getPos($img);
436
            btndown = true;
437
            startDragMode(ord, mouseAbs(Touch.cfilter(e)), true);
438
            e.stopPropagation();
439
            e.preventDefault();
440
            return false;
441
          };
442
        },
443
        newSelection: function (e) {
444
          return newSelection(Touch.cfilter(e));
445
        },
446
        cfilter: function (e){
447
          e.pageX = e.originalEvent.changedTouches[0].pageX;
448
          e.pageY = e.originalEvent.changedTouches[0].pageY;
449
          return e;
450
        },
451
        isSupported: hasTouchSupport,
452
        support: detectSupport()
453
      };
454
    }());
455
    // }}}
456
    // Coords Module {{{
457
    var Coords = (function () {
458
      var x1 = 0,
459
          y1 = 0,
460
          x2 = 0,
461
          y2 = 0,
462
          ox, oy;
463
 
464
      function setPressed(pos) //{{{
465
      {
466
        pos = rebound(pos);
467
        x2 = x1 = pos[0];
468
        y2 = y1 = pos[1];
469
      }
470
      //}}}
471
      function setCurrent(pos) //{{{
472
      {
473
        pos = rebound(pos);
474
        ox = pos[0] - x2;
475
        oy = pos[1] - y2;
476
        x2 = pos[0];
477
        y2 = pos[1];
478
      }
479
      //}}}
480
      function getOffset() //{{{
481
      {
482
        return [ox, oy];
483
      }
484
      //}}}
485
      function moveOffset(offset) //{{{
486
      {
487
        var ox = offset[0],
488
            oy = offset[1];
489
 
490
        if (0 > x1 + ox) {
491
          ox -= ox + x1;
492
        }
493
        if (0 > y1 + oy) {
494
          oy -= oy + y1;
495
        }
496
 
497
        if (boundy < y2 + oy) {
498
          oy += boundy - (y2 + oy);
499
        }
500
        if (boundx < x2 + ox) {
501
          ox += boundx - (x2 + ox);
502
        }
503
 
504
        x1 += ox;
505
        x2 += ox;
506
        y1 += oy;
507
        y2 += oy;
508
      }
509
      //}}}
510
      function getCorner(ord) //{{{
511
      {
512
        var c = getFixed();
513
        switch (ord) {
514
        case 'ne':
515
          return [c.x2, c.y];
516
        case 'nw':
517
          return [c.x, c.y];
518
        case 'se':
519
          return [c.x2, c.y2];
520
        case 'sw':
521
          return [c.x, c.y2];
522
        }
523
      }
524
      //}}}
525
      function getFixed() //{{{
526
      {
527
        if (!options.aspectRatio) {
528
          return getRect();
529
        }
530
        // This function could use some optimization I think...
531
        var aspect = options.aspectRatio,
532
            min_x = options.minSize[0] / xscale,
533
 
534
 
535
            //min_y = options.minSize[1]/yscale,
536
            max_x = options.maxSize[0] / xscale,
537
            max_y = options.maxSize[1] / yscale,
538
            rw = x2 - x1,
539
            rh = y2 - y1,
540
            rwa = Math.abs(rw),
541
            rha = Math.abs(rh),
542
            real_ratio = rwa / rha,
543
            xx, yy, w, h;
544
 
545
        if (max_x === 0) {
546
          max_x = boundx * 10;
547
        }
548
        if (max_y === 0) {
549
          max_y = boundy * 10;
550
        }
551
        if (real_ratio < aspect) {
552
          yy = y2;
553
          w = rha * aspect;
554
          xx = rw < 0 ? x1 - w : w + x1;
555
 
556
          if (xx < 0) {
557
            xx = 0;
558
            h = Math.abs((xx - x1) / aspect);
559
            yy = rh < 0 ? y1 - h : h + y1;
560
          } else if (xx > boundx) {
561
            xx = boundx;
562
            h = Math.abs((xx - x1) / aspect);
563
            yy = rh < 0 ? y1 - h : h + y1;
564
          }
565
        } else {
566
          xx = x2;
567
          h = rwa / aspect;
568
          yy = rh < 0 ? y1 - h : y1 + h;
569
          if (yy < 0) {
570
            yy = 0;
571
            w = Math.abs((yy - y1) * aspect);
572
            xx = rw < 0 ? x1 - w : w + x1;
573
          } else if (yy > boundy) {
574
            yy = boundy;
575
            w = Math.abs(yy - y1) * aspect;
576
            xx = rw < 0 ? x1 - w : w + x1;
577
          }
578
        }
579
 
580
        // Magic %-)
581
        if (xx > x1) { // right side
582
          if (xx - x1 < min_x) {
583
            xx = x1 + min_x;
584
          } else if (xx - x1 > max_x) {
585
            xx = x1 + max_x;
586
          }
587
          if (yy > y1) {
588
            yy = y1 + (xx - x1) / aspect;
589
          } else {
590
            yy = y1 - (xx - x1) / aspect;
591
          }
592
        } else if (xx < x1) { // left side
593
          if (x1 - xx < min_x) {
594
            xx = x1 - min_x;
595
          } else if (x1 - xx > max_x) {
596
            xx = x1 - max_x;
597
          }
598
          if (yy > y1) {
599
            yy = y1 + (x1 - xx) / aspect;
600
          } else {
601
            yy = y1 - (x1 - xx) / aspect;
602
          }
603
        }
604
 
605
        if (xx < 0) {
606
          x1 -= xx;
607
          xx = 0;
608
        } else if (xx > boundx) {
609
          x1 -= xx - boundx;
610
          xx = boundx;
611
        }
612
 
613
        if (yy < 0) {
614
          y1 -= yy;
615
          yy = 0;
616
        } else if (yy > boundy) {
617
          y1 -= yy - boundy;
618
          yy = boundy;
619
        }
620
 
621
        return makeObj(flipCoords(x1, y1, xx, yy));
622
      }
623
      //}}}
624
      function rebound(p) //{{{
625
      {
626
        if (p[0] < 0) p[0] = 0;
627
        if (p[1] < 0) p[1] = 0;
628
 
629
        if (p[0] > boundx) p[0] = boundx;
630
        if (p[1] > boundy) p[1] = boundy;
631
 
632
        return [Math.round(p[0]), Math.round(p[1])];
633
      }
634
      //}}}
635
      function flipCoords(x1, y1, x2, y2) //{{{
636
      {
637
        var xa = x1,
638
            xb = x2,
639
            ya = y1,
640
            yb = y2;
641
        if (x2 < x1) {
642
          xa = x2;
643
          xb = x1;
644
        }
645
        if (y2 < y1) {
646
          ya = y2;
647
          yb = y1;
648
        }
649
        return [xa, ya, xb, yb];
650
      }
651
      //}}}
652
      function getRect() //{{{
653
      {
654
        var xsize = x2 - x1,
655
            ysize = y2 - y1,
656
            delta;
657
 
658
        if (xlimit && (Math.abs(xsize) > xlimit)) {
659
          x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
660
        }
661
        if (ylimit && (Math.abs(ysize) > ylimit)) {
662
          y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
663
        }
664
 
665
        if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
666
          y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
667
        }
668
        if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
669
          x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
670
        }
671
 
672
        if (x1 < 0) {
673
          x2 -= x1;
674
          x1 -= x1;
675
        }
676
        if (y1 < 0) {
677
          y2 -= y1;
678
          y1 -= y1;
679
        }
680
        if (x2 < 0) {
681
          x1 -= x2;
682
          x2 -= x2;
683
        }
684
        if (y2 < 0) {
685
          y1 -= y2;
686
          y2 -= y2;
687
        }
688
        if (x2 > boundx) {
689
          delta = x2 - boundx;
690
          x1 -= delta;
691
          x2 -= delta;
692
        }
693
        if (y2 > boundy) {
694
          delta = y2 - boundy;
695
          y1 -= delta;
696
          y2 -= delta;
697
        }
698
        if (x1 > boundx) {
699
          delta = x1 - boundy;
700
          y2 -= delta;
701
          y1 -= delta;
702
        }
703
        if (y1 > boundy) {
704
          delta = y1 - boundy;
705
          y2 -= delta;
706
          y1 -= delta;
707
        }
708
 
709
        return makeObj(flipCoords(x1, y1, x2, y2));
710
      }
711
      //}}}
712
      function makeObj(a) //{{{
713
      {
714
        return {
715
          x: a[0],
716
          y: a[1],
717
          x2: a[2],
718
          y2: a[3],
719
          w: a[2] - a[0],
720
          h: a[3] - a[1]
721
        };
722
      }
723
      //}}}
724
 
725
      return {
726
        flipCoords: flipCoords,
727
        setPressed: setPressed,
728
        setCurrent: setCurrent,
729
        getOffset: getOffset,
730
        moveOffset: moveOffset,
731
        getCorner: getCorner,
732
        getFixed: getFixed
733
      };
734
    }());
735
 
736
    //}}}
737
    // Shade Module {{{
738
    var Shade = (function() {
739
      var enabled = false,
740
          holder = $('<div />').css({
741
            position: 'absolute',
742
            zIndex: 240,
743
            opacity: 0
744
          }),
745
          shades = {
746
            top: createShade(),
747
            left: createShade().height(boundy),
748
            right: createShade().height(boundy),
749
            bottom: createShade()
750
          };
751
 
752
      function resizeShades(w,h) {
753
        shades.left.css({ height: px(h) });
754
        shades.right.css({ height: px(h) });
755
      }
756
      function updateAuto()
757
      {
758
        return updateShade(Coords.getFixed());
759
      }
760
      function updateShade(c)
761
      {
762
        shades.top.css({
763
          left: px(c.x),
764
          width: px(c.w),
765
          height: px(c.y)
766
        });
767
        shades.bottom.css({
768
          top: px(c.y2),
769
          left: px(c.x),
770
          width: px(c.w),
771
          height: px(boundy-c.y2)
772
        });
773
        shades.right.css({
774
          left: px(c.x2),
775
          width: px(boundx-c.x2)
776
        });
777
        shades.left.css({
778
          width: px(c.x)
779
        });
780
      }
781
      function createShade() {
782
        return $('<div />').css({
783
          position: 'absolute',
784
          backgroundColor: options.shadeColor||options.bgColor
785
        }).appendTo(holder);
786
      }
787
      function enableShade() {
788
        if (!enabled) {
789
          enabled = true;
790
          holder.insertBefore($img);
791
          updateAuto();
792
          Selection.setBgOpacity(1,0,1);
793
          $img2.hide();
794
 
795
          setBgColor(options.shadeColor||options.bgColor,1);
796
          if (Selection.isAwake())
797
          {
798
            setOpacity(options.bgOpacity,1);
799
          }
800
            else setOpacity(1,1);
801
        }
802
      }
803
      function setBgColor(color,now) {
804
        colorChangeMacro(getShades(),color,now);
805
      }
806
      function disableShade() {
807
        if (enabled) {
808
          holder.remove();
809
          $img2.show();
810
          enabled = false;
811
          if (Selection.isAwake()) {
812
            Selection.setBgOpacity(options.bgOpacity,1,1);
813
          } else {
814
            Selection.setBgOpacity(1,1,1);
815
            Selection.disableHandles();
816
          }
817
          colorChangeMacro($div,0,1);
818
        }
819
      }
820
      function setOpacity(opacity,now) {
821
        if (enabled) {
822
          if (options.bgFade && !now) {
823
            holder.animate({
824
              opacity: 1-opacity
825
            },{
826
              queue: false,
827
              duration: options.fadeTime
828
            });
829
          }
830
          else holder.css({opacity:1-opacity});
831
        }
832
      }
833
      function refreshAll() {
834
        options.shade ? enableShade() : disableShade();
835
        if (Selection.isAwake()) setOpacity(options.bgOpacity);
836
      }
837
      function getShades() {
838
        return holder.children();
839
      }
840
 
841
      return {
842
        update: updateAuto,
843
        updateRaw: updateShade,
844
        getShades: getShades,
845
        setBgColor: setBgColor,
846
        enable: enableShade,
847
        disable: disableShade,
848
        resize: resizeShades,
849
        refresh: refreshAll,
850
        opacity: setOpacity
851
      };
852
    }());
853
    // }}}
854
    // Selection Module {{{
855
    var Selection = (function () {
856
      var awake,
857
          hdep = 370,
858
          borders = {},
859
          handle = {},
860
          dragbar = {},
861
          seehandles = false;
862
 
863
      // Private Methods
864
      function insertBorder(type) //{{{
865
      {
866
        var jq = $('<div />').css({
867
          position: 'absolute',
868
          opacity: options.borderOpacity
869
        }).addClass(cssClass(type));
870
        $img_holder.append(jq);
871
        return jq;
872
      }
873
      //}}}
874
      function dragDiv(ord, zi) //{{{
875
      {
876
        var jq = $('<div />').mousedown(createDragger(ord)).css({
877
          cursor: ord + '-resize',
878
          position: 'absolute',
879
          zIndex: zi
880
        }).addClass('ord-'+ord);
881
 
882
        if (Touch.support) {
883
          jq.bind('touchstart.jcrop', Touch.createDragger(ord));
884
        }
885
 
886
        $hdl_holder.append(jq);
887
        return jq;
888
      }
889
      //}}}
890
      function insertHandle(ord) //{{{
891
      {
892
        var hs = options.handleSize,
893
 
894
          div = dragDiv(ord, hdep++).css({
895
            opacity: options.handleOpacity
896
          }).addClass(cssClass('handle'));
897
 
898
        if (hs) { div.width(hs).height(hs); }
899
 
900
        return div;
901
      }
902
      //}}}
903
      function insertDragbar(ord) //{{{
904
      {
905
        return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
906
      }
907
      //}}}
908
      function createDragbars(li) //{{{
909
      {
910
        var i;
911
        for (i = 0; i < li.length; i++) {
912
          dragbar[li[i]] = insertDragbar(li[i]);
913
        }
914
      }
915
      //}}}
916
      function createBorders(li) //{{{
917
      {
918
        var cl,i;
919
        for (i = 0; i < li.length; i++) {
920
          switch(li[i]){
921
            case'n': cl='hline'; break;
922
            case's': cl='hline bottom'; break;
923
            case'e': cl='vline right'; break;
924
            case'w': cl='vline'; break;
925
          }
926
          borders[li[i]] = insertBorder(cl);
927
        }
928
      }
929
      //}}}
930
      function createHandles(li) //{{{
931
      {
932
        var i;
933
        for (i = 0; i < li.length; i++) {
934
          handle[li[i]] = insertHandle(li[i]);
935
        }
936
      }
937
      //}}}
938
      function moveto(x, y) //{{{
939
      {
940
        if (!options.shade) {
941
          $img2.css({
942
            top: px(-y),
943
            left: px(-x)
944
          });
945
        }
946
        $sel.css({
947
          top: px(y),
948
          left: px(x)
949
        });
950
      }
951
      //}}}
952
      function resize(w, h) //{{{
953
      {
954
        $sel.width(Math.round(w)).height(Math.round(h));
955
      }
956
      //}}}
957
      function refresh() //{{{
958
      {
959
        var c = Coords.getFixed();
960
 
961
        Coords.setPressed([c.x, c.y]);
962
        Coords.setCurrent([c.x2, c.y2]);
963
 
964
        updateVisible();
965
      }
966
      //}}}
967
 
968
      // Internal Methods
969
      function updateVisible(select) //{{{
970
      {
971
        if (awake) {
972
          return update(select);
973
        }
974
      }
975
      //}}}
976
      function update(select) //{{{
977
      {
978
        var c = Coords.getFixed();
979
 
980
        resize(c.w, c.h);
981
        moveto(c.x, c.y);
982
        if (options.shade) Shade.updateRaw(c);
983
 
984
        awake || show();
985
 
986
        if (select) {
987
          options.onSelect.call(api, unscale(c));
988
        } else {
989
          options.onChange.call(api, unscale(c));
990
        }
991
      }
992
      //}}}
993
      function setBgOpacity(opacity,force,now) //{{{
994
      {
995
        if (!awake && !force) return;
996
        if (options.bgFade && !now) {
997
          $img.animate({
998
            opacity: opacity
999
          },{
1000
            queue: false,
1001
            duration: options.fadeTime
1002
          });
1003
        } else {
1004
          $img.css('opacity', opacity);
1005
        }
1006
      }
1007
      //}}}
1008
      function show() //{{{
1009
      {
1010
        $sel.show();
1011
 
1012
        if (options.shade) Shade.opacity(bgopacity);
1013
          else setBgOpacity(bgopacity,true);
1014
 
1015
        awake = true;
1016
      }
1017
      //}}}
1018
      function release() //{{{
1019
      {
1020
        disableHandles();
1021
        $sel.hide();
1022
 
1023
        if (options.shade) Shade.opacity(1);
1024
          else setBgOpacity(1);
1025
 
1026
        awake = false;
1027
        options.onRelease.call(api);
1028
      }
1029
      //}}}
1030
      function showHandles() //{{{
1031
      {
1032
        if (seehandles) {
1033
          $hdl_holder.show();
1034
        }
1035
      }
1036
      //}}}
1037
      function enableHandles() //{{{
1038
      {
1039
        seehandles = true;
1040
        if (options.allowResize) {
1041
          $hdl_holder.show();
1042
          return true;
1043
        }
1044
      }
1045
      //}}}
1046
      function disableHandles() //{{{
1047
      {
1048
        seehandles = false;
1049
        $hdl_holder.hide();
1050
      }
1051
      //}}}
1052
      function animMode(v) //{{{
1053
      {
1054
        if (v) {
1055
          animating = true;
1056
          disableHandles();
1057
        } else {
1058
          animating = false;
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(touch) //{{{
1132
      {
1133
        $trk.css({
1134
          zIndex: 450
1135
        });
1136
 
1137
        if (touch)
1138
          $(document)
1139
            .bind('touchmove.jcrop', trackTouchMove)
1140
            .bind('touchend.jcrop', trackTouchEnd);
1141
 
1142
        else if (trackDoc)
1143
          $(document)
1144
            .bind('mousemove.jcrop',trackMove)
1145
            .bind('mouseup.jcrop',trackUp);
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, touch) //{{{
1185
      {
1186
        btndown = true;
1187
        onMove = move;
1188
        onDone = done;
1189
        toFront(touch);
1190
        return false;
1191
      }
1192
      //}}}
1193
      function trackTouchMove(e) //{{{
1194
      {
1195
        onMove(mouseAbs(Touch.cfilter(e)));
1196
        return false;
1197
      }
1198
      //}}}
1199
      function trackTouchEnd(e) //{{{
1200
      {
1201
        return trackUp(Touch.cfilter(e));
1202
      }
1203
      //}}}
1204
      function setCursor(t) //{{{
1205
      {
1206
        $trk.css('cursor', t);
1207
      }
1208
      //}}}
1209
 
1210
      if (!trackDoc) {
1211
        $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
1212
      }
1213
 
1214
      $img.before($trk);
1215
      return {
1216
        activateHandlers: activateHandlers,
1217
        setCursor: setCursor
1218
      };
1219
    }());
1220
    //}}}
1221
    // KeyManager Module {{{
1222
    var KeyManager = (function () {
1223
      var $keymgr = $('<input type="radio" />').css({
1224
        position: 'fixed',
1225
        left: '-120px',
1226
        width: '12px'
1227
      }).addClass('jcrop-keymgr'),
1228
 
1229
        $keywrap = $('<div />').css({
1230
          position: 'absolute',
1231
          overflow: 'hidden'
1232
        }).append($keymgr);
1233
 
1234
      function watchKeys() //{{{
1235
      {
1236
        if (options.keySupport) {
1237
          $keymgr.show();
1238
          $keymgr.focus();
1239
        }
1240
      }
1241
      //}}}
1242
      function onBlur(e) //{{{
1243
      {
1244
        $keymgr.hide();
1245
      }
1246
      //}}}
1247
      function doNudge(e, x, y) //{{{
1248
      {
1249
        if (options.allowMove) {
1250
          Coords.moveOffset([x, y]);
1251
          Selection.updateVisible(true);
1252
        }
1253
        e.preventDefault();
1254
        e.stopPropagation();
1255
      }
1256
      //}}}
1257
      function parseKey(e) //{{{
1258
      {
1259
        if (e.ctrlKey || e.metaKey) {
1260
          return true;
1261
        }
1262
        shift_down = e.shiftKey ? true : false;
1263
        var nudge = shift_down ? 10 : 1;
1264
 
1265
        switch (e.keyCode) {
1266
        case 37:
1267
          doNudge(e, -nudge, 0);
1268
          break;
1269
        case 39:
1270
          doNudge(e, nudge, 0);
1271
          break;
1272
        case 38:
1273
          doNudge(e, 0, -nudge);
1274
          break;
1275
        case 40:
1276
          doNudge(e, 0, nudge);
1277
          break;
1278
        case 27:
1279
          if (options.allowSelect) Selection.release();
1280
          break;
1281
        case 9:
1282
          return true;
1283
        }
1284
 
1285
        return false;
1286
      }
1287
      //}}}
1288
 
1289
      if (options.keySupport) {
1290
        $keymgr.keydown(parseKey).blur(onBlur);
1291
        if (ie6mode || !options.fixedSupport) {
1292
          $keymgr.css({
1293
            position: 'absolute',
1294
            left: '-20px'
1295
          });
1296
          $keywrap.append($keymgr).insertBefore($img);
1297
        } else {
1298
          $keymgr.insertBefore($img);
1299
        }
1300
      }
1301
 
1302
 
1303
      return {
1304
        watchKeys: watchKeys
1305
      };
1306
    }());
1307
    //}}}
1308
    // }}}
1309
    // API methods {{{
1310
    function setClass(cname) //{{{
1311
    {
1312
      $div.removeClass().addClass(cssClass('holder')).addClass(cname);
1313
    }
1314
    //}}}
1315
    function animateTo(a, callback) //{{{
1316
    {
1317
      var x1 = a[0] / xscale,
1318
          y1 = a[1] / yscale,
1319
          x2 = a[2] / xscale,
1320
          y2 = a[3] / yscale;
1321
 
1322
      if (animating) {
1323
        return;
1324
      }
1325
 
1326
      var animto = Coords.flipCoords(x1, y1, x2, y2),
1327
          c = Coords.getFixed(),
1328
          initcr = [c.x, c.y, c.x2, c.y2],
1329
          animat = initcr,
1330
          interv = options.animationDelay,
1331
          ix1 = animto[0] - initcr[0],
1332
          iy1 = animto[1] - initcr[1],
1333
          ix2 = animto[2] - initcr[2],
1334
          iy2 = animto[3] - initcr[3],
1335
          pcent = 0,
1336
          velocity = options.swingSpeed;
1337
 
1338
      x1 = animat[0];
1339
      y1 = animat[1];
1340
      x2 = animat[2];
1341
      y2 = animat[3];
1342
 
1343
      Selection.animMode(true);
1344
      var anim_timer;
1345
 
1346
      function queueAnimator() {
1347
        window.setTimeout(animator, interv);
1348
      }
1349
      var animator = (function () {
1350
        return function () {
1351
          pcent += (100 - pcent) / velocity;
1352
 
1353
          animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
1354
          animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
1355
          animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
1356
          animat[3] = Math.round(y2 + ((pcent / 100) * iy2));
1357
 
1358
          if (pcent >= 99.8) {
1359
            pcent = 100;
1360
          }
1361
          if (pcent < 100) {
1362
            setSelectRaw(animat);
1363
            queueAnimator();
1364
          } else {
1365
            Selection.done();
1366
            Selection.animMode(false);
1367
            if (typeof(callback) === 'function') {
1368
              callback.call(api);
1369
            }
1370
          }
1371
        };
1372
      }());
1373
      queueAnimator();
1374
    }
1375
    //}}}
1376
    function setSelect(rect) //{{{
1377
    {
1378
      setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
1379
      options.onSelect.call(api, unscale(Coords.getFixed()));
1380
      Selection.enableHandles();
1381
    }
1382
    //}}}
1383
    function setSelectRaw(l) //{{{
1384
    {
1385
      Coords.setPressed([l[0], l[1]]);
1386
      Coords.setCurrent([l[2], l[3]]);
1387
      Selection.update();
1388
    }
1389
    //}}}
1390
    function tellSelect() //{{{
1391
    {
1392
      return unscale(Coords.getFixed());
1393
    }
1394
    //}}}
1395
    function tellScaled() //{{{
1396
    {
1397
      return Coords.getFixed();
1398
    }
1399
    //}}}
1400
    function setOptionsNew(opt) //{{{
1401
    {
1402
      setOptions(opt);
1403
      interfaceUpdate();
1404
    }
1405
    //}}}
1406
    function disableCrop() //{{{
1407
    {
1408
      options.disabled = true;
1409
      Selection.disableHandles();
1410
      Selection.setCursor('default');
1411
      Tracker.setCursor('default');
1412
    }
1413
    //}}}
1414
    function enableCrop() //{{{
1415
    {
1416
      options.disabled = false;
1417
      interfaceUpdate();
1418
    }
1419
    //}}}
1420
    function cancelCrop() //{{{
1421
    {
1422
      Selection.done();
1423
      Tracker.activateHandlers(null, null);
1424
    }
1425
    //}}}
1426
    function destroy() //{{{
1427
    {
1428
      $div.remove();
1429
      $origimg.show();
1430
      $origimg.css('visibility','visible');
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 (is_msie) $div.bind('selectstart', function () { return false; });
1580
 
1581
    $origimg.data('Jcrop', api);
1582
    return api;
1583
  };
1584
  $.fn.Jcrop = function (options, callback) //{{{
1585
  {
1586
    var api;
1587
    // Iterate over each object, attach Jcrop
1588
    this.each(function () {
1589
      // If we've already attached to this object
1590
      if ($(this).data('Jcrop')) {
1591
        // The API can be requested this way (undocumented)
1592
        if (options === 'api') return $(this).data('Jcrop');
1593
        // Otherwise, we just reset the options...
1594
        else $(this).data('Jcrop').setOptions(options);
1595
      }
1596
      // If we haven't been attached, preload and attach
1597
      else {
1598
        if (this.tagName == 'IMG')
1599
          $.Jcrop.Loader(this,function(){
1600
            $(this).css({display:'block',visibility:'hidden'});
1601
            api = $.Jcrop(this, options);
1602
            if ($.isFunction(callback)) callback.call(api);
1603
          });
1604
        else {
1605
          $(this).css({display:'block',visibility:'hidden'});
1606
          api = $.Jcrop(this, options);
1607
          if ($.isFunction(callback)) callback.call(api);
1608
        }
1609
      }
1610
    });
1611
 
1612
    // Return "this" so the object is chainable (jQuery-style)
1613
    return this;
1614
  };
1615
  //}}}
1616
  // $.Jcrop.Loader - basic image loader {{{
1617
 
1618
  $.Jcrop.Loader = function(imgobj,success,error){
1619
    var $img = $(imgobj), img = $img[0];
1620
 
1621
    function completeCheck(){
1622
      if (img.complete) {
1623
        $img.unbind('.jcloader');
1624
        if ($.isFunction(success)) success.call(img);
1625
      }
1626
      else window.setTimeout(completeCheck,50);
1627
    }
1628
 
1629
    $img
1630
      .bind('load.jcloader',completeCheck)
1631
      .bind('error.jcloader',function(e){
1632
        $img.unbind('.jcloader');
1633
        if ($.isFunction(error)) error.call(img);
1634
      });
1635
 
1636
    if (img.complete && $.isFunction(success)){
1637
      $img.unbind('.jcloader');
1638
      success.call(img);
1639
    }
1640
  };
1641
 
1642
  //}}}
1643
  // Global Defaults {{{
1644
  $.Jcrop.defaults = {
1645
 
1646
    // Basic Settings
1647
    allowSelect: true,
1648
    allowMove: true,
1649
    allowResize: true,
1650
 
1651
    trackDocument: true,
1652
 
1653
    // Styling Options
1654
    baseClass: 'jcrop',
1655
    addClass: null,
1656
    bgColor: 'black',
1657
    bgOpacity: 0.6,
1658
    bgFade: false,
1659
    borderOpacity: 0.4,
1660
    handleOpacity: 0.5,
1661
    handleSize: null,
1662
 
1663
    aspectRatio: 0,
1664
    keySupport: true,
1665
    createHandles: ['n','s','e','w','nw','ne','se','sw'],
1666
    createDragbars: ['n','s','e','w'],
1667
    createBorders: ['n','s','e','w'],
1668
    drawBorders: true,
1669
    dragEdges: true,
1670
    fixedSupport: true,
1671
    touchSupport: null,
1672
 
1673
    shade: null,
1674
 
1675
    boxWidth: 0,
1676
    boxHeight: 0,
1677
    boundary: 2,
1678
    fadeTime: 400,
1679
    animationDelay: 20,
1680
    swingSpeed: 3,
1681
 
1682
    minSelect: [0, 0],
1683
    maxSize: [0, 0],
1684
    minSize: [0, 0],
1685
 
1686
    // Callbacks / Event Handlers
1687
    onChange: function () {},
1688
    onSelect: function () {},
1689
    onDblClick: function () {},
1690
    onRelease: function () {}
1691
  };
1692
 
1693
  // }}}
1694
}(jQuery));