rails_admin_jcrop 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ module RailsAdminJcrop
2
+ module Orm
3
+ module ActiveRecord
4
+
5
+ CropFields = [:crop_x, :crop_y, :crop_w, :crop_h, :crop_field]
6
+
7
+ def self.included(base)
8
+ base.send :attr_accessor, *CropFields
9
+ base.after_update :rails_admin_crop_callback, :if => :rails_admin_cropping?
10
+
11
+ base.uploaders.each do |name, klass|
12
+ klass.send :include, CarrierWaveUploaderMixin
13
+ end
14
+ end
15
+
16
+ def rails_admin_crop_callback
17
+ self.send(self.crop_field).recreate_versions!
18
+ end
19
+
20
+ def rails_admin_cropping?
21
+ CropFields.all? {|f| send(f).present?}
22
+ end
23
+
24
+ def rails_admin_crop!(params)
25
+ CropFields.each {|f| self.send "#{f}=", params[f] }
26
+ save!
27
+ end
28
+
29
+ module CarrierWaveUploaderMixin
30
+ def rails_admin_crop
31
+ return unless model.rails_admin_cropping?
32
+ manipulate! do |img|
33
+ geometry = "#{model.crop_w}x#{model.crop_h}+#{model.crop_x}+#{model.crop_y}"
34
+ img.crop geometry
35
+ img
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module RailsAdminJcrop
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,10 @@
1
+ require "rails_admin_jcrop/engine"
2
+
3
+ module RailsAdminJcrop
4
+ module Orm
5
+ autoload :ActiveRecord, 'rails_admin_jcrop/orm/active_record'
6
+ end
7
+ end
8
+
9
+ require 'rails_admin_jcrop/extensions/carrierwave'
10
+ require 'rails_admin_jcrop/extensions/rails_admin'
@@ -0,0 +1,86 @@
1
+ /* jquery.Jcrop.css v0.9.10 - MIT License */
2
+
3
+ /*
4
+ The outer-most container in a typical Jcrop instance
5
+ If you are having difficulty with formatting related to styles
6
+ on a parent element, place any fixes here or in a like selector
7
+
8
+ You can also style this element if you want to add a border, etc
9
+ A better method for styling can be seen below with .jcrop-light
10
+ (Add a class to the holder and style elements for that extended class)
11
+ */
12
+ .jcrop-holder {
13
+ direction: ltr;
14
+ text-align: left;
15
+ }
16
+
17
+ /* These styles define the border lines */
18
+ .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif) top left repeat;font-size:0;position:absolute;}
19
+ .jcrop-vline{height:100%;width:1px!important;}
20
+ .jcrop-hline{height:1px!important;width:100%;}
21
+ .jcrop-vline.right{right:0;}
22
+ .jcrop-hline.bottom{bottom:0;}
23
+
24
+ /* Handle style - size is set by Jcrop handleSize option (currently) */
25
+ .jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;}
26
+
27
+ /* This style is used for invisible click targets */
28
+ .jcrop-tracker
29
+ {
30
+ height: 100%;
31
+ width: 100%;
32
+ -webkit-tap-highlight-color: transparent; /* "turn off" link highlight */
33
+ -webkit-touch-callout: none; /* disable callout, image save panel */
34
+ -webkit-user-select: none; /* disable cut copy paste */
35
+ }
36
+
37
+ /* Positioning of handles and drag bars */
38
+ .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
39
+ .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
40
+ .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
41
+ .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
42
+ .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
43
+ .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
44
+ .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
45
+ .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
46
+ .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
47
+ .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
48
+ .jcrop-dragbar.ord-n{margin-top:-4px;}
49
+ .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
50
+ .jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
51
+ .jcrop-dragbar.ord-w{margin-left:-4px;}
52
+
53
+ /* The "jcrop-light" class/extension */
54
+ .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline
55
+ {
56
+ background:#FFF;
57
+ filter:Alpha(opacity=70)!important;
58
+ opacity:.70!important;
59
+ }
60
+ .jcrop-light .jcrop-handle
61
+ {
62
+ -moz-border-radius:3px;
63
+ -webkit-border-radius:3px;
64
+ background-color:#000;
65
+ border-color:#FFF;
66
+ border-radius:3px;
67
+ }
68
+
69
+ /* The "jcrop-dark" class/extension */
70
+ .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline
71
+ {
72
+ background:#000;
73
+ filter:Alpha(opacity=70)!important;
74
+ opacity:.7!important;
75
+ }
76
+ .jcrop-dark .jcrop-handle
77
+ {
78
+ -moz-border-radius:3px;
79
+ -webkit-border-radius:3px;
80
+ background-color:#FFF;
81
+ border-color:#000;
82
+ border-radius:3px;
83
+ }
84
+
85
+ /* Fix for twitter bootstrap et al. */
86
+ .jcrop-holder img,img.jcrop-preview{ max-width: none; }
@@ -0,0 +1,1695 @@
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));