Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
malwaredllc
GitHub Repository: malwaredllc/byob
Path: blob/master/web-gui/buildyourownbotnet/assets/js/jcrop/jquery.Jcrop.js
1293 views
1
/**
2
* jquery.Jcrop.js v0.9.12
3
* jQuery Image Cropping Plugin - released under MIT License
4
* Author: Kelly Hallman <[email protected]>
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));
1695
1696