jcrop-rails 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ tmp
3
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in jquery-rails.gemspec
4
+ gemspec
5
+ # Rails is already being pulled in through gemspec
6
+ # gem "rails", :git => "git://github.com/rails/rails.git"
7
+ gem "rack", :git => "git://github.com/rack/rack.git"
8
+ gem "sprockets", :git => "git://github.com/sstephenson/sprockets.git"
9
+ gem "i18n", "0.6.0beta1"
data/Gemfile.lock ADDED
@@ -0,0 +1,120 @@
1
+ GIT
2
+ remote: git://github.com/rack/rack.git
3
+ revision: a9beb476b27914794743d0677b327d5bafb5e8a3
4
+ specs:
5
+ rack (1.2.1)
6
+
7
+ GIT
8
+ remote: git://github.com/rails/rails.git
9
+ revision: 2fbbd08616c25dc2931eca914349dd2161766f69
10
+ specs:
11
+ actionmailer (3.1.0.beta)
12
+ actionpack (= 3.1.0.beta)
13
+ mail (~> 2.3.0)
14
+ actionpack (3.1.0.beta)
15
+ activemodel (= 3.1.0.beta)
16
+ activesupport (= 3.1.0.beta)
17
+ builder (~> 3.0.0)
18
+ erubis (~> 2.7.0)
19
+ i18n (~> 0.6.0beta1)
20
+ rack (~> 1.2.1)
21
+ rack-cache (~> 1.0.0)
22
+ rack-mount (~> 0.7.2)
23
+ rack-test (~> 0.5.7)
24
+ sprockets (~> 2.0.0.beta.2)
25
+ tzinfo (~> 0.3.23)
26
+ activemodel (3.1.0.beta)
27
+ activesupport (= 3.1.0.beta)
28
+ bcrypt-ruby (~> 2.1.4)
29
+ builder (~> 3.0.0)
30
+ i18n (~> 0.6.0beta1)
31
+ activerecord (3.1.0.beta)
32
+ activemodel (= 3.1.0.beta)
33
+ activesupport (= 3.1.0.beta)
34
+ arel (~> 2.1.0)
35
+ tzinfo (~> 0.3.23)
36
+ activeresource (3.1.0.beta)
37
+ activemodel (= 3.1.0.beta)
38
+ activesupport (= 3.1.0.beta)
39
+ activesupport (3.1.0.beta)
40
+ multi_json (~> 1.0.0)
41
+ rails (3.1.0.beta)
42
+ actionmailer (= 3.1.0.beta)
43
+ actionpack (= 3.1.0.beta)
44
+ activerecord (= 3.1.0.beta)
45
+ activeresource (= 3.1.0.beta)
46
+ activesupport (= 3.1.0.beta)
47
+ bundler (~> 1.0)
48
+ railties (= 3.1.0.beta)
49
+ railties (3.1.0.beta)
50
+ actionpack (= 3.1.0.beta)
51
+ activesupport (= 3.1.0.beta)
52
+ rack-ssl (~> 1.3.2)
53
+ rake (>= 0.8.7)
54
+ thor (~> 0.14.4)
55
+
56
+ GIT
57
+ remote: git://github.com/sstephenson/sprockets.git
58
+ revision: c4800417792744c11eb1fb888bbe9a3a82859952
59
+ specs:
60
+ sprockets (2.0.0.beta.2)
61
+ hike (~> 1.0)
62
+ rack (~> 1.0)
63
+ tilt (~> 1.0)
64
+
65
+ PATH
66
+ remote: .
67
+ specs:
68
+ jquery-rails (0.3)
69
+ rails (~> 3.1)
70
+ thor (~> 0.14.4)
71
+
72
+ GEM
73
+ remote: http://rubygems.org/
74
+ specs:
75
+ addressable (2.2.4)
76
+ arel (2.1.0)
77
+ bcrypt-ruby (2.1.4)
78
+ builder (3.0.0)
79
+ crack (0.1.8)
80
+ erubis (2.7.0)
81
+ hike (1.0.0)
82
+ i18n (0.6.0beta1)
83
+ mail (2.3.0)
84
+ i18n (>= 0.4.0)
85
+ mime-types (~> 1.16)
86
+ treetop (~> 1.4.8)
87
+ mime-types (1.16)
88
+ multi_json (1.0.0)
89
+ polyglot (0.3.1)
90
+ rack-cache (1.0.1)
91
+ rack (>= 0.4)
92
+ rack-mount (0.7.2)
93
+ rack (>= 1.0.0)
94
+ rack-ssl (1.3.2)
95
+ rack
96
+ rack-test (0.5.7)
97
+ rack (>= 1.0)
98
+ rake (0.8.7)
99
+ rspec (1.3.1)
100
+ thor (0.14.6)
101
+ tilt (1.3)
102
+ treetop (1.4.9)
103
+ polyglot (>= 0.3.1)
104
+ tzinfo (0.3.27)
105
+ webmock (1.6.2)
106
+ addressable (>= 2.2.2)
107
+ crack (>= 0.1.7)
108
+
109
+ PLATFORMS
110
+ ruby
111
+
112
+ DEPENDENCIES
113
+ bundler (~> 1.0.0)
114
+ i18n (= 0.6.0beta1)
115
+ jquery-rails!
116
+ rack!
117
+ rails!
118
+ rspec (~> 1.3)
119
+ sprockets!
120
+ webmock (~> 1.6.2)
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ JCrop jQuery plugin:
2
+
3
+ Copyright (c) 2011 Tapmodo Interactive LLC,
4
+ http://github.com/tapmodo/Jcrop
5
+
6
+ jcrop-rails gem:
7
+
8
+ Copyright (c) 2011 Nick Ragaz
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining
11
+ a copy of this software and associated documentation files (the
12
+ "Software"), to deal in the Software without restriction, including
13
+ without limitation the rights to use, copy, modify, merge, publish,
14
+ distribute, sublicense, and/or sell copies of the Software, and to
15
+ permit persons to whom the Software is furnished to do so, subject to
16
+ the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be
19
+ included in all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # jcrop-rails
2
+
3
+ This gem provides the Jcrop jQuery plugin for your Rails 3.1 app.
4
+
5
+ For more information about Jcrop, visit http://deepliquid.com/content/Jcrop.html
6
+
7
+ ----
8
+
9
+ Maintenance
10
+
11
+ Update CSS to use sass-rails helper:
12
+
13
+ image_url('jcrop/Jcrop.gif')
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/jcrop/rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "jcrop-rails"
6
+ s.version = Jcrop::Rails::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Nick Ragaz"]
9
+ s.email = ["nick.ragaz@gmail.com"]
10
+ s.homepage = "http://rubygems.org/gems/jcrop-rails"
11
+ s.summary = "Use the Jcrop jQuery plugin with Rails 3.1"
12
+ s.description = "This gem provides the Jcrop jQuery plugin for your Rails 3.1 application."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+
16
+ s.add_dependency "railties", "~> 3.0"
17
+ s.add_dependency "thor", "~> 0.14"
18
+ s.add_development_dependency "bundler", "~> 1.0.0"
19
+ s.add_development_dependency "rails", "~> 3.0"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.executables = `git ls-files`.split("\n").select{|f| f =~ /^bin/}
23
+ s.require_path = 'lib'
24
+ end
@@ -0,0 +1 @@
1
+ require 'jcrop/rails'
@@ -0,0 +1,6 @@
1
+ module Jcrop
2
+ module Rails
3
+ require 'jcrop/rails/engine'
4
+ require 'jcrop/rails/version'
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Jcrop
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Jcrop
2
+ module Rails
3
+ VERSION = "1.0.2"
4
+ JCROP_VERSION = "0.9.9"
5
+ end
6
+ end
@@ -0,0 +1,1600 @@
1
+ /**
2
+ * jquery.Jcrop.js v0.9.9
3
+ * jQuery Image Cropping Plugin
4
+ * @author Kelly Hallman <khallman@gmail.com>
5
+ * Copyright (c) 2008-2011 Kelly Hallman - released under MIT License {{{
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person
8
+ * obtaining a copy of this software and associated documentation
9
+ * files (the "Software"), to deal in the Software without
10
+ * restriction, including without limitation the rights to use,
11
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the
13
+ * Software is furnished to do so, subject to the following
14
+ * conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be
17
+ * included in all copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26
+ * OTHER DEALINGS IN THE SOFTWARE.
27
+ *
28
+ * }}}
29
+ */
30
+
31
+ (function ($) {
32
+
33
+ $.Jcrop = function (obj, opt) {
34
+ var options = $.extend({}, $.Jcrop.defaults),
35
+ docOffset, lastcurs, ie6mode = false;
36
+
37
+ // Internal Methods {{{
38
+ function px(n) {
39
+ return parseInt(n, 10) + 'px';
40
+ }
41
+ function pct(n) {
42
+ return parseInt(n, 10) + '%';
43
+ }
44
+ function cssClass(cl) {
45
+ return options.baseClass + '-' + cl;
46
+ }
47
+ function supportsColorFade() {
48
+ return $.fx.step.hasOwnProperty('backgroundColor');
49
+ }
50
+ function getPos(obj) //{{{
51
+ {
52
+ // Updated in v0.9.4 to use built-in dimensions plugin
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') {
65
+ opt = {};
66
+ }
67
+ options = $.extend(options, opt);
68
+
69
+ if (typeof(options.onChange) !== 'function') {
70
+ options.onChange = function () {};
71
+ }
72
+ if (typeof(options.onSelect) !== 'function') {
73
+ options.onSelect = function () {};
74
+ }
75
+ if (typeof(options.onRelease) !== 'function') {
76
+ options.onRelease = function () {};
77
+ }
78
+ }
79
+ //}}}
80
+ function myCursor(type) //{{{
81
+ {
82
+ if (type !== lastcurs) {
83
+ Tracker.setCursor(type);
84
+ lastcurs = type;
85
+ }
86
+ }
87
+ //}}}
88
+ function startDragMode(mode, pos) //{{{
89
+ {
90
+ docOffset = getPos($img);
91
+ Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
92
+
93
+ if (mode === 'move') {
94
+ return Tracker.activateHandlers(createMover(pos), doneSelect);
95
+ }
96
+
97
+ var fc = Coords.getFixed();
98
+ var opp = oppLockCorner(mode);
99
+ var opc = Coords.getCorner(oppLockCorner(opp));
100
+
101
+ Coords.setPressed(Coords.getCorner(opp));
102
+ Coords.setCurrent(opc);
103
+
104
+ Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect);
105
+ }
106
+ //}}}
107
+ function dragmodeHandler(mode, f) //{{{
108
+ {
109
+ return function (pos) {
110
+ if (!options.aspectRatio) {
111
+ switch (mode) {
112
+ case 'e':
113
+ pos[1] = f.y2;
114
+ break;
115
+ case 'w':
116
+ pos[1] = f.y2;
117
+ break;
118
+ case 'n':
119
+ pos[0] = f.x2;
120
+ break;
121
+ case 's':
122
+ pos[0] = f.x2;
123
+ break;
124
+ }
125
+ } else {
126
+ switch (mode) {
127
+ case 'e':
128
+ pos[1] = f.y + 1;
129
+ break;
130
+ case 'w':
131
+ pos[1] = f.y + 1;
132
+ break;
133
+ case 'n':
134
+ pos[0] = f.x + 1;
135
+ break;
136
+ case 's':
137
+ pos[0] = f.x + 1;
138
+ break;
139
+ }
140
+ }
141
+ Coords.setCurrent(pos);
142
+ Selection.update();
143
+ };
144
+ }
145
+ //}}}
146
+ function createMover(pos) //{{{
147
+ {
148
+ var lloc = pos;
149
+ KeyManager.watchKeys();
150
+
151
+ return function (pos) {
152
+ Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
153
+ lloc = pos;
154
+
155
+ Selection.update();
156
+ };
157
+ }
158
+ //}}}
159
+ function oppLockCorner(ord) //{{{
160
+ {
161
+ switch (ord) {
162
+ case 'n':
163
+ return 'sw';
164
+ case 's':
165
+ return 'nw';
166
+ case 'e':
167
+ return 'nw';
168
+ case 'w':
169
+ return 'ne';
170
+ case 'ne':
171
+ return 'sw';
172
+ case 'nw':
173
+ return 'se';
174
+ case 'se':
175
+ return 'nw';
176
+ case 'sw':
177
+ return 'ne';
178
+ }
179
+ }
180
+ //}}}
181
+ function createDragger(ord) //{{{
182
+ {
183
+ return function (e) {
184
+ if (options.disabled) {
185
+ return false;
186
+ }
187
+ if ((ord === 'move') && !options.allowMove) {
188
+ return false;
189
+ }
190
+ btndown = true;
191
+ startDragMode(ord, mouseAbs(e));
192
+ e.stopPropagation();
193
+ e.preventDefault();
194
+ return false;
195
+ };
196
+ }
197
+ //}}}
198
+ function presize($obj, w, h) //{{{
199
+ {
200
+ var nw = $obj.width(),
201
+ nh = $obj.height();
202
+ if ((nw > w) && w > 0) {
203
+ nw = w;
204
+ nh = (w / $obj.width()) * $obj.height();
205
+ }
206
+ if ((nh > h) && h > 0) {
207
+ nh = h;
208
+ nw = (h / $obj.height()) * $obj.width();
209
+ }
210
+ xscale = $obj.width() / nw;
211
+ yscale = $obj.height() / nh;
212
+ $obj.width(nw).height(nh);
213
+ }
214
+ //}}}
215
+ function unscale(c) //{{{
216
+ {
217
+ return {
218
+ x: parseInt(c.x * xscale, 10),
219
+ y: parseInt(c.y * yscale, 10),
220
+ x2: parseInt(c.x2 * xscale, 10),
221
+ y2: parseInt(c.y2 * yscale, 10),
222
+ w: parseInt(c.w * xscale, 10),
223
+ h: parseInt(c.h * yscale, 10)
224
+ };
225
+ }
226
+ //}}}
227
+ function doneSelect(pos) //{{{
228
+ {
229
+ var c = Coords.getFixed();
230
+ if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
231
+ Selection.enableHandles();
232
+ Selection.done();
233
+ } else {
234
+ Selection.release();
235
+ }
236
+ Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
237
+ }
238
+ //}}}
239
+ function newSelection(e) //{{{
240
+ {
241
+ if (options.disabled) {
242
+ return false;
243
+ }
244
+ if (!options.allowSelect) {
245
+ return false;
246
+ }
247
+ btndown = true;
248
+ docOffset = getPos($img);
249
+ Selection.disableHandles();
250
+ myCursor('crosshair');
251
+ var pos = mouseAbs(e);
252
+ Coords.setPressed(pos);
253
+ Selection.update();
254
+ Tracker.activateHandlers(selectDrag, doneSelect);
255
+ KeyManager.watchKeys();
256
+
257
+ e.stopPropagation();
258
+ e.preventDefault();
259
+ return false;
260
+ }
261
+ //}}}
262
+ function selectDrag(pos) //{{{
263
+ {
264
+ Coords.setCurrent(pos);
265
+ Selection.update();
266
+ }
267
+ //}}}
268
+ function newTracker() //{{{
269
+ {
270
+ var trk = $('<div></div>').addClass(cssClass('tracker'));
271
+ if ($.browser.msie) {
272
+ trk.css({
273
+ opacity: 0,
274
+ backgroundColor: 'white'
275
+ });
276
+ }
277
+ return trk;
278
+ }
279
+ //}}}
280
+
281
+ // }}}
282
+ // Initialization {{{
283
+ // Sanitize some options {{{
284
+ if ($.browser.msie && ($.browser.version.split('.')[0] === '6')) {
285
+ ie6mode = true;
286
+ }
287
+ if (typeof(obj) !== 'object') {
288
+ obj = $(obj)[0];
289
+ }
290
+ if (typeof(opt) !== 'object') {
291
+ opt = {};
292
+ }
293
+ // }}}
294
+ setOptions(opt);
295
+ // Initialize some jQuery objects {{{
296
+ // The values are SET on the image(s) for the interface
297
+ // If the original image has any of these set, they will be reset
298
+ // However, if you destroy() the Jcrop instance the original image's
299
+ // character in the DOM will be as you left it.
300
+ var img_css = {
301
+ border: 'none',
302
+ margin: 0,
303
+ padding: 0,
304
+ position: 'absolute'
305
+ };
306
+
307
+ var $origimg = $(obj);
308
+ var $img = $origimg.clone().removeAttr('id').css(img_css);
309
+
310
+ $img.width($origimg.width());
311
+ $img.height($origimg.height());
312
+ $origimg.after($img).hide();
313
+
314
+ presize($img, options.boxWidth, options.boxHeight);
315
+
316
+ var boundx = $img.width(),
317
+ boundy = $img.height(),
318
+
319
+
320
+ $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
321
+ position: 'relative',
322
+ backgroundColor: options.bgColor
323
+ }).insertAfter($origimg).append($img);
324
+
325
+ delete(options.bgColor);
326
+ if (options.addClass) {
327
+ $div.addClass(options.addClass);
328
+ }
329
+
330
+ var $img2 = $('<img />')
331
+ .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
332
+
333
+ $img_holder = $('<div />')
334
+ .width(pct(100)).height(pct(100)).css({
335
+ zIndex: 310,
336
+ position: 'absolute',
337
+ overflow: 'hidden'
338
+ }).append($img2),
339
+
340
+ $hdl_holder = $('<div />')
341
+ .width(pct(100)).height(pct(100)).css('zIndex', 320),
342
+
343
+ $sel = $('<div />')
344
+ .css({
345
+ position: 'absolute',
346
+ zIndex: 300
347
+ }).insertBefore($img).append($img_holder, $hdl_holder);
348
+
349
+ if (ie6mode) {
350
+ $sel.css({
351
+ overflowY: 'hidden'
352
+ });
353
+ }
354
+
355
+ var bound = options.boundary;
356
+ var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
357
+ position: 'absolute',
358
+ top: px(-bound),
359
+ left: px(-bound),
360
+ zIndex: 290
361
+ }).mousedown(newSelection);
362
+
363
+ /* }}} */
364
+ // Set more variables {{{
365
+ var bgopacity = options.bgOpacity,
366
+ xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
367
+ btndown, animating, shift_down;
368
+
369
+ docOffset = getPos($img);
370
+ // }}}
371
+ // }}}
372
+ // Internal Modules {{{
373
+ // Touch Module {{{
374
+ var Touch = (function () {
375
+ // Touch support detection function adapted (under MIT License)
376
+ // from code by Jeffrey Sambells - http://github.com/iamamused/
377
+ function hasTouchSupport() {
378
+ var support = {},
379
+ events = ['touchstart', 'touchmove', 'touchend'],
380
+ el = document.createElement('div'), i;
381
+
382
+ try {
383
+ for(i=0; i<events.length; i++) {
384
+ var eventName = events[i];
385
+ eventName = 'on' + eventName;
386
+ var isSupported = (eventName in el);
387
+ if (!isSupported) {
388
+ el.setAttribute(eventName, 'return;');
389
+ isSupported = typeof el[eventName] == 'function';
390
+ }
391
+ support[events[i]] = isSupported;
392
+ }
393
+ return support.touchstart && support.touchend && support.touchmove;
394
+ }
395
+ catch(err) {
396
+ return false;
397
+ }
398
+ }
399
+
400
+ function detectSupport() {
401
+ if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
402
+ else return hasTouchSupport();
403
+ }
404
+ return {
405
+ createDragger: function (ord) {
406
+ return function (e) {
407
+ e.pageX = e.originalEvent.changedTouches[0].pageX;
408
+ e.pageY = e.originalEvent.changedTouches[0].pageY;
409
+ if (options.disabled) {
410
+ return false;
411
+ }
412
+ if ((ord === 'move') && !options.allowMove) {
413
+ return false;
414
+ }
415
+ btndown = true;
416
+ startDragMode(ord, mouseAbs(e));
417
+ e.stopPropagation();
418
+ e.preventDefault();
419
+ return false;
420
+ };
421
+ },
422
+ newSelection: function (e) {
423
+ e.pageX = e.originalEvent.changedTouches[0].pageX;
424
+ e.pageY = e.originalEvent.changedTouches[0].pageY;
425
+ return newSelection(e);
426
+ },
427
+ isSupported: hasTouchSupport,
428
+ support: detectSupport()
429
+ };
430
+ }());
431
+ // }}}
432
+ // Coords Module {{{
433
+ var Coords = (function () {
434
+ var x1 = 0,
435
+ y1 = 0,
436
+ x2 = 0,
437
+ y2 = 0,
438
+ ox, oy;
439
+
440
+ function setPressed(pos) //{{{
441
+ {
442
+ pos = rebound(pos);
443
+ x2 = x1 = pos[0];
444
+ y2 = y1 = pos[1];
445
+ }
446
+ //}}}
447
+ function setCurrent(pos) //{{{
448
+ {
449
+ pos = rebound(pos);
450
+ ox = pos[0] - x2;
451
+ oy = pos[1] - y2;
452
+ x2 = pos[0];
453
+ y2 = pos[1];
454
+ }
455
+ //}}}
456
+ function getOffset() //{{{
457
+ {
458
+ return [ox, oy];
459
+ }
460
+ //}}}
461
+ function moveOffset(offset) //{{{
462
+ {
463
+ var ox = offset[0],
464
+ oy = offset[1];
465
+
466
+ if (0 > x1 + ox) {
467
+ ox -= ox + x1;
468
+ }
469
+ if (0 > y1 + oy) {
470
+ oy -= oy + y1;
471
+ }
472
+
473
+ if (boundy < y2 + oy) {
474
+ oy += boundy - (y2 + oy);
475
+ }
476
+ if (boundx < x2 + ox) {
477
+ ox += boundx - (x2 + ox);
478
+ }
479
+
480
+ x1 += ox;
481
+ x2 += ox;
482
+ y1 += oy;
483
+ y2 += oy;
484
+ }
485
+ //}}}
486
+ function getCorner(ord) //{{{
487
+ {
488
+ var c = getFixed();
489
+ switch (ord) {
490
+ case 'ne':
491
+ return [c.x2, c.y];
492
+ case 'nw':
493
+ return [c.x, c.y];
494
+ case 'se':
495
+ return [c.x2, c.y2];
496
+ case 'sw':
497
+ return [c.x, c.y2];
498
+ }
499
+ }
500
+ //}}}
501
+ function getFixed() //{{{
502
+ {
503
+ if (!options.aspectRatio) {
504
+ return getRect();
505
+ }
506
+ // This function could use some optimization I think...
507
+ var aspect = options.aspectRatio,
508
+ min_x = options.minSize[0] / xscale,
509
+
510
+
511
+ //min_y = options.minSize[1]/yscale,
512
+ max_x = options.maxSize[0] / xscale,
513
+ max_y = options.maxSize[1] / yscale,
514
+ rw = x2 - x1,
515
+ rh = y2 - y1,
516
+ rwa = Math.abs(rw),
517
+ rha = Math.abs(rh),
518
+ real_ratio = rwa / rha,
519
+ xx, yy;
520
+
521
+ if (max_x === 0) {
522
+ max_x = boundx * 10;
523
+ }
524
+ if (max_y === 0) {
525
+ max_y = boundy * 10;
526
+ }
527
+ if (real_ratio < aspect) {
528
+ yy = y2;
529
+ w = rha * aspect;
530
+ xx = rw < 0 ? x1 - w : w + x1;
531
+
532
+ if (xx < 0) {
533
+ xx = 0;
534
+ h = Math.abs((xx - x1) / aspect);
535
+ yy = rh < 0 ? y1 - h : h + y1;
536
+ } else if (xx > boundx) {
537
+ xx = boundx;
538
+ h = Math.abs((xx - x1) / aspect);
539
+ yy = rh < 0 ? y1 - h : h + y1;
540
+ }
541
+ } else {
542
+ xx = x2;
543
+ h = rwa / aspect;
544
+ yy = rh < 0 ? y1 - h : y1 + h;
545
+ if (yy < 0) {
546
+ yy = 0;
547
+ w = Math.abs((yy - y1) * aspect);
548
+ xx = rw < 0 ? x1 - w : w + x1;
549
+ } else if (yy > boundy) {
550
+ yy = boundy;
551
+ w = Math.abs(yy - y1) * aspect;
552
+ xx = rw < 0 ? x1 - w : w + x1;
553
+ }
554
+ }
555
+
556
+ // Magic %-)
557
+ if (xx > x1) { // right side
558
+ if (xx - x1 < min_x) {
559
+ xx = x1 + min_x;
560
+ } else if (xx - x1 > max_x) {
561
+ xx = x1 + max_x;
562
+ }
563
+ if (yy > y1) {
564
+ yy = y1 + (xx - x1) / aspect;
565
+ } else {
566
+ yy = y1 - (xx - x1) / aspect;
567
+ }
568
+ } else if (xx < x1) { // left side
569
+ if (x1 - xx < min_x) {
570
+ xx = x1 - min_x;
571
+ } else if (x1 - xx > max_x) {
572
+ xx = x1 - max_x;
573
+ }
574
+ if (yy > y1) {
575
+ yy = y1 + (x1 - xx) / aspect;
576
+ } else {
577
+ yy = y1 - (x1 - xx) / aspect;
578
+ }
579
+ }
580
+
581
+ if (xx < 0) {
582
+ x1 -= xx;
583
+ xx = 0;
584
+ } else if (xx > boundx) {
585
+ x1 -= xx - boundx;
586
+ xx = boundx;
587
+ }
588
+
589
+ if (yy < 0) {
590
+ y1 -= yy;
591
+ yy = 0;
592
+ } else if (yy > boundy) {
593
+ y1 -= yy - boundy;
594
+ yy = boundy;
595
+ }
596
+
597
+ return makeObj(flipCoords(x1, y1, xx, yy));
598
+ }
599
+ //}}}
600
+ function rebound(p) //{{{
601
+ {
602
+ if (p[0] < 0) {
603
+ p[0] = 0;
604
+ }
605
+ if (p[1] < 0) {
606
+ p[1] = 0;
607
+ }
608
+
609
+ if (p[0] > boundx) {
610
+ p[0] = boundx;
611
+ }
612
+ if (p[1] > boundy) {
613
+ p[1] = boundy;
614
+ }
615
+
616
+ return [p[0], p[1]];
617
+ }
618
+ //}}}
619
+ function flipCoords(x1, y1, x2, y2) //{{{
620
+ {
621
+ var xa = x1,
622
+ xb = x2,
623
+ ya = y1,
624
+ yb = y2;
625
+ if (x2 < x1) {
626
+ xa = x2;
627
+ xb = x1;
628
+ }
629
+ if (y2 < y1) {
630
+ ya = y2;
631
+ yb = y1;
632
+ }
633
+ return [Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb)];
634
+ }
635
+ //}}}
636
+ function getRect() //{{{
637
+ {
638
+ var xsize = x2 - x1,
639
+ ysize = y2 - y1,
640
+ delta;
641
+
642
+ if (xlimit && (Math.abs(xsize) > xlimit)) {
643
+ x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
644
+ }
645
+ if (ylimit && (Math.abs(ysize) > ylimit)) {
646
+ y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
647
+ }
648
+
649
+ if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
650
+ y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
651
+ }
652
+ if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
653
+ x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
654
+ }
655
+
656
+ if (x1 < 0) {
657
+ x2 -= x1;
658
+ x1 -= x1;
659
+ }
660
+ if (y1 < 0) {
661
+ y2 -= y1;
662
+ y1 -= y1;
663
+ }
664
+ if (x2 < 0) {
665
+ x1 -= x2;
666
+ x2 -= x2;
667
+ }
668
+ if (y2 < 0) {
669
+ y1 -= y2;
670
+ y2 -= y2;
671
+ }
672
+ if (x2 > boundx) {
673
+ delta = x2 - boundx;
674
+ x1 -= delta;
675
+ x2 -= delta;
676
+ }
677
+ if (y2 > boundy) {
678
+ delta = y2 - boundy;
679
+ y1 -= delta;
680
+ y2 -= delta;
681
+ }
682
+ if (x1 > boundx) {
683
+ delta = x1 - boundy;
684
+ y2 -= delta;
685
+ y1 -= delta;
686
+ }
687
+ if (y1 > boundy) {
688
+ delta = y1 - boundy;
689
+ y2 -= delta;
690
+ y1 -= delta;
691
+ }
692
+
693
+ return makeObj(flipCoords(x1, y1, x2, y2));
694
+ }
695
+ //}}}
696
+ function makeObj(a) //{{{
697
+ {
698
+ return {
699
+ x: a[0],
700
+ y: a[1],
701
+ x2: a[2],
702
+ y2: a[3],
703
+ w: a[2] - a[0],
704
+ h: a[3] - a[1]
705
+ };
706
+ }
707
+ //}}}
708
+
709
+ return {
710
+ flipCoords: flipCoords,
711
+ setPressed: setPressed,
712
+ setCurrent: setCurrent,
713
+ getOffset: getOffset,
714
+ moveOffset: moveOffset,
715
+ getCorner: getCorner,
716
+ getFixed: getFixed
717
+ };
718
+ }());
719
+
720
+ //}}}
721
+ // Selection Module {{{
722
+ var Selection = (function () {
723
+ var awake, hdep = 370;
724
+ var borders = {};
725
+ var handle = {};
726
+ var seehandles = false;
727
+ var hhs = options.handleOffset;
728
+
729
+ // Private Methods
730
+ function insertBorder(type) //{{{
731
+ {
732
+ var jq = $('<div />').css({
733
+ position: 'absolute',
734
+ opacity: options.borderOpacity
735
+ }).addClass(cssClass(type));
736
+ $img_holder.append(jq);
737
+ return jq;
738
+ }
739
+ //}}}
740
+ function dragDiv(ord, zi) //{{{
741
+ {
742
+ var jq = $('<div />').mousedown(createDragger(ord)).css({
743
+ cursor: ord + '-resize',
744
+ position: 'absolute',
745
+ zIndex: zi
746
+ });
747
+
748
+ if (Touch.support) {
749
+ jq.bind('touchstart', Touch.createDragger(ord));
750
+ }
751
+
752
+ $hdl_holder.append(jq);
753
+ return jq;
754
+ }
755
+ //}}}
756
+ function insertHandle(ord) //{{{
757
+ {
758
+ return dragDiv(ord, hdep++).css({
759
+ top: px(-hhs + 1),
760
+ left: px(-hhs + 1),
761
+ opacity: options.handleOpacity
762
+ }).addClass(cssClass('handle'));
763
+ }
764
+ //}}}
765
+ function insertDragbar(ord) //{{{
766
+ {
767
+ var s = options.handleSize,
768
+ h = s,
769
+ w = s,
770
+ t = hhs,
771
+ l = hhs;
772
+
773
+ switch (ord) {
774
+ case 'n':
775
+ case 's':
776
+ w = pct(100);
777
+ break;
778
+ case 'e':
779
+ case 'w':
780
+ h = pct(100);
781
+ break;
782
+ }
783
+
784
+ return dragDiv(ord, hdep++).width(w).height(h).css({
785
+ top: px(-t + 1),
786
+ left: px(-l + 1)
787
+ });
788
+ }
789
+ //}}}
790
+ function createHandles(li) //{{{
791
+ {
792
+ var i;
793
+ for (i = 0; i < li.length; i++) {
794
+ handle[li[i]] = insertHandle(li[i]);
795
+ }
796
+ }
797
+ //}}}
798
+ function moveHandles(c) //{{{
799
+ {
800
+ var midvert = Math.round((c.h / 2) - hhs),
801
+ midhoriz = Math.round((c.w / 2) - hhs),
802
+ north = -hhs + 1,
803
+ west = -hhs + 1,
804
+ east = c.w - hhs,
805
+ south = c.h - hhs,
806
+ x, y;
807
+
808
+ if (handle.e) {
809
+ handle.e.css({
810
+ top: px(midvert),
811
+ left: px(east)
812
+ });
813
+ handle.w.css({
814
+ top: px(midvert)
815
+ });
816
+ handle.s.css({
817
+ top: px(south),
818
+ left: px(midhoriz)
819
+ });
820
+ handle.n.css({
821
+ left: px(midhoriz)
822
+ });
823
+ }
824
+ if (handle.ne) {
825
+ handle.ne.css({
826
+ left: px(east)
827
+ });
828
+ handle.se.css({
829
+ top: px(south),
830
+ left: px(east)
831
+ });
832
+ handle.sw.css({
833
+ top: px(south)
834
+ });
835
+ }
836
+ if (handle.b) {
837
+ handle.b.css({
838
+ top: px(south)
839
+ });
840
+ handle.r.css({
841
+ left: px(east)
842
+ });
843
+ }
844
+ }
845
+ //}}}
846
+ function moveto(x, y) //{{{
847
+ {
848
+ $img2.css({
849
+ top: px(-y),
850
+ left: px(-x)
851
+ });
852
+ $sel.css({
853
+ top: px(y),
854
+ left: px(x)
855
+ });
856
+ }
857
+ //}}}
858
+ function resize(w, h) //{{{
859
+ {
860
+ $sel.width(w).height(h);
861
+ }
862
+ //}}}
863
+ function refresh() //{{{
864
+ {
865
+ var c = Coords.getFixed();
866
+
867
+ Coords.setPressed([c.x, c.y]);
868
+ Coords.setCurrent([c.x2, c.y2]);
869
+
870
+ updateVisible();
871
+ }
872
+ //}}}
873
+
874
+ // Internal Methods
875
+ function updateVisible() //{{{
876
+ {
877
+ if (awake) {
878
+ return update();
879
+ }
880
+ }
881
+ //}}}
882
+ function update() //{{{
883
+ {
884
+ var c = Coords.getFixed();
885
+
886
+ resize(c.w, c.h);
887
+ moveto(c.x, c.y);
888
+
889
+ /*
890
+ options.drawBorders &&
891
+ borders.right.css({ left: px(c.w-1) }) &&
892
+ borders.bottom.css({ top: px(c.h-1) });
893
+ */
894
+
895
+ if (seehandles) {
896
+ moveHandles(c);
897
+ }
898
+ if (!awake) {
899
+ show();
900
+ }
901
+
902
+ options.onChange.call(api, unscale(c));
903
+ }
904
+ //}}}
905
+ function show() //{{{
906
+ {
907
+ $sel.show();
908
+
909
+ if (options.bgFade) {
910
+ $img.fadeTo(options.fadeTime, bgopacity);
911
+ } else {
912
+ $img.css('opacity', bgopacity);
913
+ }
914
+
915
+ awake = true;
916
+ }
917
+ //}}}
918
+ function release() //{{{
919
+ {
920
+ disableHandles();
921
+ $sel.hide();
922
+
923
+ if (options.bgFade) {
924
+ $img.fadeTo(options.fadeTime, 1);
925
+ } else {
926
+ $img.css('opacity', 1);
927
+ }
928
+
929
+ awake = false;
930
+ options.onRelease.call(api);
931
+ }
932
+ //}}}
933
+ function showHandles() //{{{
934
+ {
935
+ if (seehandles) {
936
+ moveHandles(Coords.getFixed());
937
+ $hdl_holder.show();
938
+ }
939
+ }
940
+ //}}}
941
+ function enableHandles() //{{{
942
+ {
943
+ seehandles = true;
944
+ if (options.allowResize) {
945
+ moveHandles(Coords.getFixed());
946
+ $hdl_holder.show();
947
+ return true;
948
+ }
949
+ }
950
+ //}}}
951
+ function disableHandles() //{{{
952
+ {
953
+ seehandles = false;
954
+ $hdl_holder.hide();
955
+ }
956
+ //}}}
957
+ function animMode(v) //{{{
958
+ {
959
+ if (animating === v) {
960
+ disableHandles();
961
+ } else {
962
+ enableHandles();
963
+ }
964
+ }
965
+ //}}}
966
+ function done() //{{{
967
+ {
968
+ animMode(false);
969
+ refresh();
970
+ }
971
+ //}}}
972
+ /* Insert draggable elements {{{*/
973
+
974
+ // Insert border divs for outline
975
+ if (options.drawBorders) {
976
+ borders = {
977
+ top: insertBorder('hline'),
978
+ bottom: insertBorder('hline bottom'),
979
+ left: insertBorder('vline'),
980
+ right: insertBorder('vline right')
981
+ };
982
+ }
983
+
984
+ // Insert handles on edges
985
+ if (options.dragEdges) {
986
+ handle.t = insertDragbar('n');
987
+ handle.b = insertDragbar('s');
988
+ handle.r = insertDragbar('e');
989
+ handle.l = insertDragbar('w');
990
+ }
991
+
992
+ // Insert side and corner handles
993
+ if (options.sideHandles) {
994
+ createHandles(['n', 's', 'e', 'w']);
995
+ }
996
+ if (options.cornerHandles) {
997
+ createHandles(['sw', 'nw', 'ne', 'se']);
998
+ }
999
+
1000
+
1001
+ //}}}
1002
+
1003
+ var $track = newTracker().mousedown(createDragger('move')).css({
1004
+ cursor: 'move',
1005
+ position: 'absolute',
1006
+ zIndex: 360
1007
+ });
1008
+
1009
+ if (Touch.support) {
1010
+ $track.bind('touchstart.jcrop', Touch.createDragger('move'));
1011
+ }
1012
+
1013
+ $img_holder.append($track);
1014
+ disableHandles();
1015
+
1016
+ return {
1017
+ updateVisible: updateVisible,
1018
+ update: update,
1019
+ release: release,
1020
+ refresh: refresh,
1021
+ isAwake: function () {
1022
+ return awake;
1023
+ },
1024
+ setCursor: function (cursor) {
1025
+ $track.css('cursor', cursor);
1026
+ },
1027
+ enableHandles: enableHandles,
1028
+ enableOnly: function () {
1029
+ seehandles = true;
1030
+ },
1031
+ showHandles: showHandles,
1032
+ disableHandles: disableHandles,
1033
+ animMode: animMode,
1034
+ done: done
1035
+ };
1036
+ }());
1037
+
1038
+ //}}}
1039
+ // Tracker Module {{{
1040
+ var Tracker = (function () {
1041
+ var onMove = function () {},
1042
+ onDone = function () {},
1043
+ trackDoc = options.trackDocument;
1044
+
1045
+ function toFront() //{{{
1046
+ {
1047
+ $trk.css({
1048
+ zIndex: 450
1049
+ });
1050
+ if (trackDoc) {
1051
+ $(document)
1052
+ .bind('mousemove',trackMove)
1053
+ .bind('mouseup',trackUp);
1054
+ }
1055
+ }
1056
+ //}}}
1057
+ function toBack() //{{{
1058
+ {
1059
+ $trk.css({
1060
+ zIndex: 290
1061
+ });
1062
+ if (trackDoc) {
1063
+ $(document)
1064
+ .unbind('mousemove', trackMove)
1065
+ .unbind('mouseup', trackUp);
1066
+ }
1067
+ }
1068
+ //}}}
1069
+ function trackMove(e) //{{{
1070
+ {
1071
+ onMove(mouseAbs(e));
1072
+ return false;
1073
+ }
1074
+ //}}}
1075
+ function trackUp(e) //{{{
1076
+ {
1077
+ e.preventDefault();
1078
+ e.stopPropagation();
1079
+
1080
+ if (btndown) {
1081
+ btndown = false;
1082
+
1083
+ onDone(mouseAbs(e));
1084
+
1085
+ if (Selection.isAwake()) {
1086
+ options.onSelect.call(api, unscale(Coords.getFixed()));
1087
+ }
1088
+
1089
+ toBack();
1090
+ onMove = function () {};
1091
+ onDone = function () {};
1092
+ }
1093
+
1094
+ return false;
1095
+ }
1096
+ //}}}
1097
+ function activateHandlers(move, done) //{{{
1098
+ {
1099
+ btndown = true;
1100
+ onMove = move;
1101
+ onDone = done;
1102
+ toFront();
1103
+ return false;
1104
+ }
1105
+ //}}}
1106
+ function trackTouchMove(e) //{{{
1107
+ {
1108
+ e.pageX = e.originalEvent.changedTouches[0].pageX;
1109
+ e.pageY = e.originalEvent.changedTouches[0].pageY;
1110
+ return trackMove(e);
1111
+ }
1112
+ //}}}
1113
+ function trackTouchEnd(e) //{{{
1114
+ {
1115
+ e.pageX = e.originalEvent.changedTouches[0].pageX;
1116
+ e.pageY = e.originalEvent.changedTouches[0].pageY;
1117
+ return trackUp(e);
1118
+ }
1119
+ //}}}
1120
+ function setCursor(t) //{{{
1121
+ {
1122
+ $trk.css('cursor', t);
1123
+ }
1124
+ //}}}
1125
+
1126
+ if (Touch.support) {
1127
+ $(document)
1128
+ .bind('touchmove', trackTouchMove)
1129
+ .bind('touchend', trackTouchEnd);
1130
+ }
1131
+
1132
+ if (!trackDoc) {
1133
+ $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
1134
+ }
1135
+
1136
+ $img.before($trk);
1137
+ return {
1138
+ activateHandlers: activateHandlers,
1139
+ setCursor: setCursor
1140
+ };
1141
+ }());
1142
+ //}}}
1143
+ // KeyManager Module {{{
1144
+ var KeyManager = (function () {
1145
+ var $keymgr = $('<input type="radio" />').css({
1146
+ position: 'fixed',
1147
+ left: '-120px',
1148
+ width: '12px'
1149
+ }),
1150
+ $keywrap = $('<div />').css({
1151
+ position: 'absolute',
1152
+ overflow: 'hidden'
1153
+ }).append($keymgr);
1154
+
1155
+ function watchKeys() //{{{
1156
+ {
1157
+ if (options.keySupport) {
1158
+ $keymgr.show();
1159
+ $keymgr.focus();
1160
+ }
1161
+ }
1162
+ //}}}
1163
+ function onBlur(e) //{{{
1164
+ {
1165
+ $keymgr.hide();
1166
+ }
1167
+ //}}}
1168
+ function doNudge(e, x, y) //{{{
1169
+ {
1170
+ if (options.allowMove) {
1171
+ Coords.moveOffset([x, y]);
1172
+ Selection.updateVisible();
1173
+ }
1174
+ e.preventDefault();
1175
+ e.stopPropagation();
1176
+ }
1177
+ //}}}
1178
+ function parseKey(e) //{{{
1179
+ {
1180
+ if (e.ctrlKey) {
1181
+ return true;
1182
+ }
1183
+ shift_down = e.shiftKey ? true : false;
1184
+ var nudge = shift_down ? 10 : 1;
1185
+
1186
+ switch (e.keyCode) {
1187
+ case 37:
1188
+ doNudge(e, -nudge, 0);
1189
+ break;
1190
+ case 39:
1191
+ doNudge(e, nudge, 0);
1192
+ break;
1193
+ case 38:
1194
+ doNudge(e, 0, -nudge);
1195
+ break;
1196
+ case 40:
1197
+ doNudge(e, 0, nudge);
1198
+ break;
1199
+ case 27:
1200
+ Selection.release();
1201
+ break;
1202
+ case 9:
1203
+ return true;
1204
+ }
1205
+
1206
+ return false;
1207
+ }
1208
+ //}}}
1209
+
1210
+ if (options.keySupport) {
1211
+ $keymgr.keydown(parseKey).blur(onBlur);
1212
+ if (ie6mode || !options.fixedSupport) {
1213
+ $keymgr.css({
1214
+ position: 'absolute',
1215
+ left: '-20px'
1216
+ });
1217
+ $keywrap.append($keymgr).insertBefore($img);
1218
+ } else {
1219
+ $keymgr.insertBefore($img);
1220
+ }
1221
+ }
1222
+
1223
+
1224
+ return {
1225
+ watchKeys: watchKeys
1226
+ };
1227
+ }());
1228
+ //}}}
1229
+ // }}}
1230
+ // API methods {{{
1231
+ function setClass(cname) //{{{
1232
+ {
1233
+ $div.removeClass().addClass(cssClass('holder')).addClass(cname);
1234
+ }
1235
+ //}}}
1236
+ function animateTo(a, callback) //{{{
1237
+ {
1238
+ var x1 = parseInt(a[0], 10) / xscale,
1239
+ y1 = parseInt(a[1], 10) / yscale,
1240
+ x2 = parseInt(a[2], 10) / xscale,
1241
+ y2 = parseInt(a[3], 10) / yscale;
1242
+
1243
+ if (animating) {
1244
+ return;
1245
+ }
1246
+
1247
+ var animto = Coords.flipCoords(x1, y1, x2, y2),
1248
+ c = Coords.getFixed(),
1249
+ initcr = [c.x, c.y, c.x2, c.y2],
1250
+ animat = initcr,
1251
+ interv = options.animationDelay,
1252
+ ix1 = animto[0] - initcr[0],
1253
+ iy1 = animto[1] - initcr[1],
1254
+ ix2 = animto[2] - initcr[2],
1255
+ iy2 = animto[3] - initcr[3],
1256
+ pcent = 0,
1257
+ velocity = options.swingSpeed;
1258
+
1259
+ x = animat[0];
1260
+ y = animat[1];
1261
+ x2 = animat[2];
1262
+ y2 = animat[3];
1263
+
1264
+ Selection.animMode(true);
1265
+ var anim_timer;
1266
+
1267
+ function queueAnimator() {
1268
+ window.setTimeout(animator, interv);
1269
+ }
1270
+ var animator = (function () {
1271
+ return function () {
1272
+ pcent += (100 - pcent) / velocity;
1273
+
1274
+ animat[0] = x + ((pcent / 100) * ix1);
1275
+ animat[1] = y + ((pcent / 100) * iy1);
1276
+ animat[2] = x2 + ((pcent / 100) * ix2);
1277
+ animat[3] = y2 + ((pcent / 100) * iy2);
1278
+
1279
+ if (pcent >= 99.8) {
1280
+ pcent = 100;
1281
+ }
1282
+ if (pcent < 100) {
1283
+ setSelectRaw(animat);
1284
+ queueAnimator();
1285
+ } else {
1286
+ Selection.done();
1287
+ if (typeof(callback) === 'function') {
1288
+ callback.call(api);
1289
+ }
1290
+ }
1291
+ };
1292
+ }());
1293
+ queueAnimator();
1294
+ }
1295
+ //}}}
1296
+ function setSelect(rect) //{{{
1297
+ {
1298
+ setSelectRaw([
1299
+ parseInt(rect[0], 10) / xscale, parseInt(rect[1], 10) / yscale, parseInt(rect[2], 10) / xscale, parseInt(rect[3], 10) / yscale]);
1300
+ }
1301
+ //}}}
1302
+ function setSelectRaw(l) //{{{
1303
+ {
1304
+ Coords.setPressed([l[0], l[1]]);
1305
+ Coords.setCurrent([l[2], l[3]]);
1306
+ Selection.update();
1307
+ }
1308
+ //}}}
1309
+ function tellSelect() //{{{
1310
+ {
1311
+ return unscale(Coords.getFixed());
1312
+ }
1313
+ //}}}
1314
+ function tellScaled() //{{{
1315
+ {
1316
+ return Coords.getFixed();
1317
+ }
1318
+ //}}}
1319
+ function setOptionsNew(opt) //{{{
1320
+ {
1321
+ setOptions(opt);
1322
+ interfaceUpdate();
1323
+ }
1324
+ //}}}
1325
+ function disableCrop() //{{{
1326
+ {
1327
+ options.disabled = true;
1328
+ Selection.disableHandles();
1329
+ Selection.setCursor('default');
1330
+ Tracker.setCursor('default');
1331
+ }
1332
+ //}}}
1333
+ function enableCrop() //{{{
1334
+ {
1335
+ options.disabled = false;
1336
+ interfaceUpdate();
1337
+ }
1338
+ //}}}
1339
+ function cancelCrop() //{{{
1340
+ {
1341
+ Selection.done();
1342
+ Tracker.activateHandlers(null, null);
1343
+ }
1344
+ //}}}
1345
+ function destroy() //{{{
1346
+ {
1347
+ $div.remove();
1348
+ $origimg.show();
1349
+ $(obj).removeData('Jcrop');
1350
+ }
1351
+ //}}}
1352
+ function setImage(src, callback) //{{{
1353
+ {
1354
+ Selection.release();
1355
+ disableCrop();
1356
+ var img = new Image();
1357
+ img.onload = function () {
1358
+ var iw = img.width;
1359
+ var ih = img.height;
1360
+ var bw = options.boxWidth;
1361
+ var bh = options.boxHeight;
1362
+ $img.width(iw).height(ih);
1363
+ $img.attr('src', src);
1364
+ $img2.attr('src', src);
1365
+ presize($img, bw, bh);
1366
+ boundx = $img.width();
1367
+ boundy = $img.height();
1368
+ $img2.width(boundx).height(boundy);
1369
+ $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
1370
+ $div.width(boundx).height(boundy);
1371
+ enableCrop();
1372
+
1373
+ if (typeof(callback) === 'function') {
1374
+ callback.call(api);
1375
+ }
1376
+ };
1377
+ img.src = src;
1378
+ }
1379
+ //}}}
1380
+ function interfaceUpdate(alt) //{{{
1381
+ // This method tweaks the interface based on options object.
1382
+ // Called when options are changed and at end of initialization.
1383
+ {
1384
+ if (options.allowResize) {
1385
+ if (alt) {
1386
+ Selection.enableOnly();
1387
+ } else {
1388
+ Selection.enableHandles();
1389
+ }
1390
+ } else {
1391
+ Selection.disableHandles();
1392
+ }
1393
+
1394
+ Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
1395
+ Selection.setCursor(options.allowMove ? 'move' : 'default');
1396
+
1397
+
1398
+ if (options.hasOwnProperty('setSelect')) {
1399
+ setSelect(options.setSelect);
1400
+ Selection.done();
1401
+ delete(options.setSelect);
1402
+ }
1403
+
1404
+ if (options.hasOwnProperty('trueSize')) {
1405
+ xscale = options.trueSize[0] / boundx;
1406
+ yscale = options.trueSize[1] / boundy;
1407
+ }
1408
+ if (options.hasOwnProperty('bgColor')) {
1409
+
1410
+ if (supportsColorFade() && options.fadeTime) {
1411
+ $div.animate({
1412
+ backgroundColor: options.bgColor
1413
+ }, {
1414
+ queue: false,
1415
+ duration: options.fadeTime
1416
+ });
1417
+ } else {
1418
+ $div.css('backgroundColor', options.bgColor);
1419
+ }
1420
+
1421
+ delete(options.bgColor);
1422
+ }
1423
+ if (options.hasOwnProperty('bgOpacity')) {
1424
+ bgopacity = options.bgOpacity;
1425
+
1426
+ if (Selection.isAwake()) {
1427
+ if (options.fadeTime) {
1428
+ $img.fadeTo(options.fadeTime, bgopacity);
1429
+ } else {
1430
+ $div.css('opacity', options.opacity);
1431
+ }
1432
+ }
1433
+ delete(options.bgOpacity);
1434
+ }
1435
+
1436
+ xlimit = options.maxSize[0] || 0;
1437
+ ylimit = options.maxSize[1] || 0;
1438
+ xmin = options.minSize[0] || 0;
1439
+ ymin = options.minSize[1] || 0;
1440
+
1441
+ if (options.hasOwnProperty('outerImage')) {
1442
+ $img.attr('src', options.outerImage);
1443
+ delete(options.outerImage);
1444
+ }
1445
+
1446
+ Selection.refresh();
1447
+ }
1448
+ //}}}
1449
+ //}}}
1450
+
1451
+ if (Touch.support) {
1452
+ $trk.bind('touchstart', Touch.newSelection);
1453
+ }
1454
+
1455
+ $hdl_holder.hide();
1456
+ interfaceUpdate(true);
1457
+
1458
+ var api = {
1459
+ setImage: setImage,
1460
+ animateTo: animateTo,
1461
+ setSelect: setSelect,
1462
+ setOptions: setOptionsNew,
1463
+ tellSelect: tellSelect,
1464
+ tellScaled: tellScaled,
1465
+ setClass: setClass,
1466
+
1467
+ disable: disableCrop,
1468
+ enable: enableCrop,
1469
+ cancel: cancelCrop,
1470
+ release: Selection.release,
1471
+ destroy: destroy,
1472
+
1473
+ focus: KeyManager.watchKeys,
1474
+
1475
+ getBounds: function () {
1476
+ return [boundx * xscale, boundy * yscale];
1477
+ },
1478
+ getWidgetSize: function () {
1479
+ return [boundx, boundy];
1480
+ },
1481
+ getScaleFactor: function () {
1482
+ return [xscale, yscale];
1483
+ },
1484
+
1485
+ ui: {
1486
+ holder: $div,
1487
+ selection: $sel
1488
+ }
1489
+ };
1490
+
1491
+ if ($.browser.msie) {
1492
+ $div.bind('selectstart', function () {
1493
+ return false;
1494
+ });
1495
+ }
1496
+
1497
+ $origimg.data('Jcrop', api);
1498
+ return api;
1499
+ };
1500
+ $.fn.Jcrop = function (options, callback) //{{{
1501
+ {
1502
+
1503
+ function attachWhenDone(from) //{{{
1504
+ {
1505
+ var opt = (typeof(options) === 'object') ? options : {};
1506
+ var loadsrc = opt.useImg || from.src;
1507
+ var img = new Image();
1508
+ img.onload = function () {
1509
+ function attachJcrop() {
1510
+ var api = $.Jcrop(from, opt);
1511
+ if (typeof(callback) === 'function') {
1512
+ callback.call(api);
1513
+ }
1514
+ }
1515
+
1516
+ function attachAttempt() {
1517
+ if (!img.width || !img.height) {
1518
+ window.setTimeout(attachAttempt, 50);
1519
+ } else {
1520
+ attachJcrop();
1521
+ }
1522
+ }
1523
+ window.setTimeout(attachAttempt, 50);
1524
+ };
1525
+ img.src = loadsrc;
1526
+ }
1527
+ //}}}
1528
+
1529
+ // Iterate over each object, attach Jcrop
1530
+ this.each(function () {
1531
+ // If we've already attached to this object
1532
+ if ($(this).data('Jcrop')) {
1533
+ // The API can be requested this way (undocumented)
1534
+ if (options === 'api') {
1535
+ return $(this).data('Jcrop');
1536
+ }
1537
+ // Otherwise, we just reset the options...
1538
+ else {
1539
+ $(this).data('Jcrop').setOptions(options);
1540
+ }
1541
+ }
1542
+ // If we haven't been attached, preload and attach
1543
+ else {
1544
+ attachWhenDone(this);
1545
+ }
1546
+ });
1547
+
1548
+ // Return "this" so the object is chainable (jQuery-style)
1549
+ return this;
1550
+ };
1551
+ //}}}
1552
+ // Global Defaults {{{
1553
+ $.Jcrop.defaults = {
1554
+
1555
+ // Basic Settings
1556
+ allowSelect: true,
1557
+ allowMove: true,
1558
+ allowResize: true,
1559
+
1560
+ trackDocument: true,
1561
+
1562
+ // Styling Options
1563
+ baseClass: 'jcrop',
1564
+ addClass: null,
1565
+ bgColor: 'black',
1566
+ bgOpacity: 0.6,
1567
+ bgFade: false,
1568
+ borderOpacity: 0.4,
1569
+ handleOpacity: 0.5,
1570
+ handleSize: 9,
1571
+ handleOffset: 5,
1572
+
1573
+ aspectRatio: 0,
1574
+ keySupport: true,
1575
+ cornerHandles: true,
1576
+ sideHandles: true,
1577
+ drawBorders: true,
1578
+ dragEdges: true,
1579
+ fixedSupport: true,
1580
+ touchSupport: null,
1581
+
1582
+ boxWidth: 0,
1583
+ boxHeight: 0,
1584
+ boundary: 2,
1585
+ fadeTime: 400,
1586
+ animationDelay: 20,
1587
+ swingSpeed: 3,
1588
+
1589
+ minSelect: [0, 0],
1590
+ maxSize: [0, 0],
1591
+ minSize: [0, 0],
1592
+
1593
+ // Callbacks / Event Handlers
1594
+ onChange: function () {},
1595
+ onSelect: function () {},
1596
+ onRelease: function () {}
1597
+ };
1598
+
1599
+ // }}}
1600
+ }(jQuery));