jcrop-rails 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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));