jcrop-rails 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2FkZDhhMWI5ZGE5NzA2Y2MzYjg4YWRiOWM1NDA1OGY3NDhhZWEwMQ==
5
+ data.tar.gz: !binary |-
6
+ ZThhNTEzM2NjNGMzMmJkZTJhOTc3MGVlN2NlNzI2N2JjMTkwODA5Nw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ Yzc5ZTk0YzFlNWE5MTNmYWZmYTAzZGQ5MTE2M2U4OTgwZWRiYTIyZGNjMWI2
10
+ NWFlMGRjNGExMzA0ZjQ5ODkxZDY5YWE2MWE0NjJkM2M5YzBhZDA5NTNjZGEx
11
+ ZGJhMDgxOTYwYThkMDdjOTZmZTc1NGZhNTAwNTUwOGQ1ZDAyMDM=
12
+ data.tar.gz: !binary |-
13
+ NzBlOGU0NWUyZjFiNDEyMmI5ZWYxZjFjYzFhNDI2ODEyNTY0YjZkNTNjZjVh
14
+ ODdkZDY0ZTlmZWUzZTg3NGY3Y2JjMmUyOWE2NTA4ODEzOGE5YjkyMzU4ZDQ3
15
+ MjlkMGZhZGY4NDZhNjgwMGFkNWY1NmE4MDk3YWQwMDg1MjcyY2E=
data/Gemfile CHANGED
@@ -1,9 +1,3 @@
1
1
  source :gemcutter
2
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"
3
+ gemspec
@@ -1,120 +1,94 @@
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
1
  PATH
66
2
  remote: .
67
3
  specs:
68
- jquery-rails (0.3)
69
- rails (~> 3.1)
70
- thor (~> 0.14.4)
4
+ jcrop-rails (1.0.2)
5
+ railties (~> 3.0)
6
+ thor (~> 0.14)
71
7
 
72
8
  GEM
73
9
  remote: http://rubygems.org/
74
10
  specs:
75
- addressable (2.2.4)
76
- arel (2.1.0)
77
- bcrypt-ruby (2.1.4)
11
+ actionmailer (3.2.2)
12
+ actionpack (= 3.2.2)
13
+ mail (~> 2.4.0)
14
+ actionpack (3.2.2)
15
+ activemodel (= 3.2.2)
16
+ activesupport (= 3.2.2)
17
+ builder (~> 3.0.0)
18
+ erubis (~> 2.7.0)
19
+ journey (~> 1.0.1)
20
+ rack (~> 1.4.0)
21
+ rack-cache (~> 1.1)
22
+ rack-test (~> 0.6.1)
23
+ sprockets (~> 2.1.2)
24
+ activemodel (3.2.2)
25
+ activesupport (= 3.2.2)
26
+ builder (~> 3.0.0)
27
+ activerecord (3.2.2)
28
+ activemodel (= 3.2.2)
29
+ activesupport (= 3.2.2)
30
+ arel (~> 3.0.2)
31
+ tzinfo (~> 0.3.29)
32
+ activeresource (3.2.2)
33
+ activemodel (= 3.2.2)
34
+ activesupport (= 3.2.2)
35
+ activesupport (3.2.2)
36
+ i18n (~> 0.6)
37
+ multi_json (~> 1.0)
38
+ arel (3.0.2)
78
39
  builder (3.0.0)
79
- crack (0.1.8)
80
40
  erubis (2.7.0)
81
- hike (1.0.0)
82
- i18n (0.6.0beta1)
83
- mail (2.3.0)
41
+ hike (1.2.1)
42
+ i18n (0.6.0)
43
+ journey (1.0.3)
44
+ json (1.6.5)
45
+ mail (2.4.4)
84
46
  i18n (>= 0.4.0)
85
47
  mime-types (~> 1.16)
86
48
  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)
49
+ mime-types (1.17.2)
50
+ multi_json (1.1.0)
51
+ polyglot (0.3.3)
52
+ rack (1.4.1)
53
+ rack-cache (1.2)
91
54
  rack (>= 0.4)
92
- rack-mount (0.7.2)
93
- rack (>= 1.0.0)
94
55
  rack-ssl (1.3.2)
95
56
  rack
96
- rack-test (0.5.7)
57
+ rack-test (0.6.1)
97
58
  rack (>= 1.0)
98
- rake (0.8.7)
99
- rspec (1.3.1)
59
+ rails (3.2.2)
60
+ actionmailer (= 3.2.2)
61
+ actionpack (= 3.2.2)
62
+ activerecord (= 3.2.2)
63
+ activeresource (= 3.2.2)
64
+ activesupport (= 3.2.2)
65
+ bundler (~> 1.0)
66
+ railties (= 3.2.2)
67
+ railties (3.2.2)
68
+ actionpack (= 3.2.2)
69
+ activesupport (= 3.2.2)
70
+ rack-ssl (~> 1.3.2)
71
+ rake (>= 0.8.7)
72
+ rdoc (~> 3.4)
73
+ thor (~> 0.14.6)
74
+ rake (0.9.2.2)
75
+ rdoc (3.12)
76
+ json (~> 1.4)
77
+ sprockets (2.1.2)
78
+ hike (~> 1.2)
79
+ rack (~> 1.0)
80
+ tilt (~> 1.1, != 1.3.0)
100
81
  thor (0.14.6)
101
- tilt (1.3)
102
- treetop (1.4.9)
82
+ tilt (1.3.3)
83
+ treetop (1.4.10)
84
+ polyglot
103
85
  polyglot (>= 0.3.1)
104
- tzinfo (0.3.27)
105
- webmock (1.6.2)
106
- addressable (>= 2.2.2)
107
- crack (>= 0.1.7)
86
+ tzinfo (0.3.32)
108
87
 
109
88
  PLATFORMS
110
89
  ruby
111
90
 
112
91
  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)
92
+ bundler (~> 1.0)
93
+ jcrop-rails!
94
+ rails (~> 3.0)
data/LICENSE CHANGED
@@ -1,11 +1,13 @@
1
1
  JCrop jQuery plugin:
2
2
 
3
- Copyright (c) 2011 Tapmodo Interactive LLC,
4
- http://github.com/tapmodo/Jcrop
5
-
3
+ Copyright (c) 2011 Tapmodo Interactive LLC,
4
+ http://github.com/tapmodo/Jcrop
5
+
6
6
  jcrop-rails gem:
7
7
 
8
- Copyright (c) 2011 Nick Ragaz
8
+ Copyright (c) 2011 Nick Ragaz
9
+
10
+ Both:
9
11
 
10
12
  Permission is hereby granted, free of charge, to any person obtaining
11
13
  a copy of this software and associated documentation files (the
@@ -8,14 +8,14 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Nick Ragaz"]
9
9
  s.email = ["nick.ragaz@gmail.com"]
10
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."
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
13
 
14
14
  s.required_rubygems_version = ">= 1.3.6"
15
15
 
16
16
  s.add_dependency "railties", "~> 3.0"
17
17
  s.add_dependency "thor", "~> 0.14"
18
- s.add_development_dependency "bundler", "~> 1.0.0"
18
+ s.add_development_dependency "bundler", "~> 1.0"
19
19
  s.add_development_dependency "rails", "~> 3.0"
20
20
 
21
21
  s.files = `git ls-files`.split("\n")
@@ -1,6 +1,6 @@
1
1
  module Jcrop
2
2
  module Rails
3
- VERSION = "1.0.2"
4
- JCROP_VERSION = "0.9.9"
3
+ VERSION = "1.0.3"
4
+ JCROP_VERSION = "0.9.12"
5
5
  end
6
6
  end
File without changes
@@ -1,8 +1,9 @@
1
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 {{{
2
+ * jquery.Jcrop.js v0.9.12
3
+ * jQuery Image Cropping Plugin - released under MIT License
4
+ * Author: Kelly Hallman <khallman@gmail.com>
5
+ * http://github.com/tapmodo/Jcrop
6
+ * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{
6
7
  *
7
8
  * Permission is hereby granted, free of charge, to any person
8
9
  * obtaining a copy of this software and associated documentation
@@ -32,14 +33,14 @@
32
33
 
33
34
  $.Jcrop = function (obj, opt) {
34
35
  var options = $.extend({}, $.Jcrop.defaults),
35
- docOffset, lastcurs, ie6mode = false;
36
+ docOffset,
37
+ _ua = navigator.userAgent.toLowerCase(),
38
+ is_msie = /msie/.test(_ua),
39
+ ie6mode = /msie [1-6]\./.test(_ua);
36
40
 
37
41
  // Internal Methods {{{
38
42
  function px(n) {
39
- return parseInt(n, 10) + 'px';
40
- }
41
- function pct(n) {
42
- return parseInt(n, 10) + '%';
43
+ return Math.round(n) + 'px';
43
44
  }
44
45
  function cssClass(cl) {
45
46
  return options.baseClass + '-' + cl;
@@ -49,7 +50,6 @@
49
50
  }
50
51
  function getPos(obj) //{{{
51
52
  {
52
- // Updated in v0.9.4 to use built-in dimensions plugin
53
53
  var pos = $(obj).offset();
54
54
  return [pos.left, pos.top];
55
55
  }
@@ -61,37 +61,21 @@
61
61
  //}}}
62
62
  function setOptions(opt) //{{{
63
63
  {
64
- if (typeof(opt) !== 'object') {
65
- opt = {};
66
- }
64
+ if (typeof(opt) !== 'object') opt = {};
67
65
  options = $.extend(options, opt);
68
66
 
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
- }
67
+ $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
68
+ if (typeof(options[e]) !== 'function') options[e] = function () {};
69
+ });
86
70
  }
87
71
  //}}}
88
- function startDragMode(mode, pos) //{{{
72
+ function startDragMode(mode, pos, touch) //{{{
89
73
  {
90
74
  docOffset = getPos($img);
91
75
  Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
92
76
 
93
77
  if (mode === 'move') {
94
- return Tracker.activateHandlers(createMover(pos), doneSelect);
78
+ return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
95
79
  }
96
80
 
97
81
  var fc = Coords.getFixed();
@@ -101,7 +85,7 @@
101
85
  Coords.setPressed(Coords.getCorner(opp));
102
86
  Coords.setCurrent(opc);
103
87
 
104
- Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect);
88
+ Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
105
89
  }
106
90
  //}}}
107
91
  function dragmodeHandler(mode, f) //{{{
@@ -187,6 +171,11 @@
187
171
  if ((ord === 'move') && !options.allowMove) {
188
172
  return false;
189
173
  }
174
+
175
+ // Fix position of crop area when dragged the very first time.
176
+ // Necessary when crop image is in a hidden element when page is loaded.
177
+ docOffset = getPos($img);
178
+
190
179
  btndown = true;
191
180
  startDragMode(ord, mouseAbs(e));
192
181
  e.stopPropagation();
@@ -215,12 +204,12 @@
215
204
  function unscale(c) //{{{
216
205
  {
217
206
  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)
207
+ x: c.x * xscale,
208
+ y: c.y * yscale,
209
+ x2: c.x2 * xscale,
210
+ y2: c.y2 * yscale,
211
+ w: c.w * xscale,
212
+ h: c.h * yscale
224
213
  };
225
214
  }
226
215
  //}}}
@@ -247,11 +236,11 @@
247
236
  btndown = true;
248
237
  docOffset = getPos($img);
249
238
  Selection.disableHandles();
250
- myCursor('crosshair');
239
+ Tracker.setCursor('crosshair');
251
240
  var pos = mouseAbs(e);
252
241
  Coords.setPressed(pos);
253
242
  Selection.update();
254
- Tracker.activateHandlers(selectDrag, doneSelect);
243
+ Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch');
255
244
  KeyManager.watchKeys();
256
245
 
257
246
  e.stopPropagation();
@@ -268,7 +257,7 @@
268
257
  function newTracker() //{{{
269
258
  {
270
259
  var trk = $('<div></div>').addClass(cssClass('tracker'));
271
- if ($.browser.msie) {
260
+ if (is_msie) {
272
261
  trk.css({
273
262
  opacity: 0,
274
263
  backgroundColor: 'white'
@@ -281,9 +270,6 @@
281
270
  // }}}
282
271
  // Initialization {{{
283
272
  // Sanitize some options {{{
284
- if ($.browser.msie && ($.browser.version.split('.')[0] === '6')) {
285
- ie6mode = true;
286
- }
287
273
  if (typeof(obj) !== 'object') {
288
274
  obj = $(obj)[0];
289
275
  }
@@ -299,52 +285,88 @@
299
285
  // character in the DOM will be as you left it.
300
286
  var img_css = {
301
287
  border: 'none',
288
+ visibility: 'visible',
302
289
  margin: 0,
303
290
  padding: 0,
304
- position: 'absolute'
291
+ position: 'absolute',
292
+ top: 0,
293
+ left: 0
305
294
  };
306
295
 
307
- var $origimg = $(obj);
308
- var $img = $origimg.clone().removeAttr('id').css(img_css);
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();
309
319
 
310
- $img.width($origimg.width());
311
- $img.height($origimg.height());
312
- $origimg.after($img).hide();
320
+ } else {
321
+ $img = $origimg.css(img_css).show();
322
+ img_mode = false;
323
+ if (options.shade === null) { options.shade = true; }
324
+ }
313
325
 
314
326
  presize($img, options.boxWidth, options.boxHeight);
315
327
 
316
328
  var boundx = $img.width(),
317
329
  boundy = $img.height(),
318
-
319
-
330
+
331
+
320
332
  $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
321
333
  position: 'relative',
322
334
  backgroundColor: options.bgColor
323
335
  }).insertAfter($origimg).append($img);
324
336
 
325
- delete(options.bgColor);
326
337
  if (options.addClass) {
327
338
  $div.addClass(options.addClass);
328
339
  }
329
340
 
330
- var $img2 = $('<img />')
331
- .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
341
+ var $img2 = $('<div />'),
332
342
 
333
- $img_holder = $('<div />')
334
- .width(pct(100)).height(pct(100)).css({
343
+ $img_holder = $('<div />')
344
+ .width('100%').height('100%').css({
335
345
  zIndex: 310,
336
346
  position: 'absolute',
337
347
  overflow: 'hidden'
338
- }).append($img2),
348
+ }),
339
349
 
340
- $hdl_holder = $('<div />')
341
- .width(pct(100)).height(pct(100)).css('zIndex', 320),
350
+ $hdl_holder = $('<div />')
351
+ .width('100%').height('100%').css('zIndex', 320),
342
352
 
343
- $sel = $('<div />')
353
+ $sel = $('<div />')
344
354
  .css({
345
355
  position: 'absolute',
346
- zIndex: 300
347
- }).insertBefore($img).append($img_holder, $hdl_holder);
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
+ }
348
370
 
349
371
  if (ie6mode) {
350
372
  $sel.css({
@@ -362,7 +384,8 @@
362
384
 
363
385
  /* }}} */
364
386
  // Set more variables {{{
365
- var bgopacity = options.bgOpacity,
387
+ var bgcolor = options.bgColor,
388
+ bgopacity = options.bgOpacity,
366
389
  xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
367
390
  btndown, animating, shift_down;
368
391
 
@@ -370,13 +393,12 @@
370
393
  // }}}
371
394
  // }}}
372
395
  // Internal Modules {{{
373
- // Touch Module {{{
396
+ // Touch Module {{{
374
397
  var Touch = (function () {
375
398
  // Touch support detection function adapted (under MIT License)
376
399
  // from code by Jeffrey Sambells - http://github.com/iamamused/
377
400
  function hasTouchSupport() {
378
- var support = {},
379
- events = ['touchstart', 'touchmove', 'touchend'],
401
+ var support = {}, events = ['touchstart', 'touchmove', 'touchend'],
380
402
  el = document.createElement('div'), i;
381
403
 
382
404
  try {
@@ -404,25 +426,27 @@
404
426
  return {
405
427
  createDragger: function (ord) {
406
428
  return function (e) {
407
- e.pageX = e.originalEvent.changedTouches[0].pageX;
408
- e.pageY = e.originalEvent.changedTouches[0].pageY;
409
429
  if (options.disabled) {
410
430
  return false;
411
431
  }
412
432
  if ((ord === 'move') && !options.allowMove) {
413
433
  return false;
414
434
  }
435
+ docOffset = getPos($img);
415
436
  btndown = true;
416
- startDragMode(ord, mouseAbs(e));
437
+ startDragMode(ord, mouseAbs(Touch.cfilter(e)), true);
417
438
  e.stopPropagation();
418
439
  e.preventDefault();
419
440
  return false;
420
441
  };
421
442
  },
422
443
  newSelection: function (e) {
444
+ return newSelection(Touch.cfilter(e));
445
+ },
446
+ cfilter: function (e){
423
447
  e.pageX = e.originalEvent.changedTouches[0].pageX;
424
448
  e.pageY = e.originalEvent.changedTouches[0].pageY;
425
- return newSelection(e);
449
+ return e;
426
450
  },
427
451
  isSupported: hasTouchSupport,
428
452
  support: detectSupport()
@@ -506,8 +530,8 @@
506
530
  // This function could use some optimization I think...
507
531
  var aspect = options.aspectRatio,
508
532
  min_x = options.minSize[0] / xscale,
509
-
510
-
533
+
534
+
511
535
  //min_y = options.minSize[1]/yscale,
512
536
  max_x = options.maxSize[0] / xscale,
513
537
  max_y = options.maxSize[1] / yscale,
@@ -516,7 +540,7 @@
516
540
  rwa = Math.abs(rw),
517
541
  rha = Math.abs(rh),
518
542
  real_ratio = rwa / rha,
519
- xx, yy;
543
+ xx, yy, w, h;
520
544
 
521
545
  if (max_x === 0) {
522
546
  max_x = boundx * 10;
@@ -599,21 +623,13 @@
599
623
  //}}}
600
624
  function rebound(p) //{{{
601
625
  {
602
- if (p[0] < 0) {
603
- p[0] = 0;
604
- }
605
- if (p[1] < 0) {
606
- p[1] = 0;
607
- }
626
+ if (p[0] < 0) p[0] = 0;
627
+ if (p[1] < 0) p[1] = 0;
608
628
 
609
- if (p[0] > boundx) {
610
- p[0] = boundx;
611
- }
612
- if (p[1] > boundy) {
613
- p[1] = boundy;
614
- }
629
+ if (p[0] > boundx) p[0] = boundx;
630
+ if (p[1] > boundy) p[1] = boundy;
615
631
 
616
- return [p[0], p[1]];
632
+ return [Math.round(p[0]), Math.round(p[1])];
617
633
  }
618
634
  //}}}
619
635
  function flipCoords(x1, y1, x2, y2) //{{{
@@ -630,7 +646,7 @@
630
646
  ya = y2;
631
647
  yb = y1;
632
648
  }
633
- return [Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb)];
649
+ return [xa, ya, xb, yb];
634
650
  }
635
651
  //}}}
636
652
  function getRect() //{{{
@@ -718,13 +734,131 @@
718
734
  }());
719
735
 
720
736
  //}}}
737
+ // Shade Module {{{
738
+ var Shade = (function() {
739
+ var enabled = false,
740
+ holder = $('<div />').css({
741
+ position: 'absolute',
742
+ zIndex: 240,
743
+ opacity: 0
744
+ }),
745
+ shades = {
746
+ top: createShade(),
747
+ left: createShade().height(boundy),
748
+ right: createShade().height(boundy),
749
+ bottom: createShade()
750
+ };
751
+
752
+ function resizeShades(w,h) {
753
+ shades.left.css({ height: px(h) });
754
+ shades.right.css({ height: px(h) });
755
+ }
756
+ function updateAuto()
757
+ {
758
+ return updateShade(Coords.getFixed());
759
+ }
760
+ function updateShade(c)
761
+ {
762
+ shades.top.css({
763
+ left: px(c.x),
764
+ width: px(c.w),
765
+ height: px(c.y)
766
+ });
767
+ shades.bottom.css({
768
+ top: px(c.y2),
769
+ left: px(c.x),
770
+ width: px(c.w),
771
+ height: px(boundy-c.y2)
772
+ });
773
+ shades.right.css({
774
+ left: px(c.x2),
775
+ width: px(boundx-c.x2)
776
+ });
777
+ shades.left.css({
778
+ width: px(c.x)
779
+ });
780
+ }
781
+ function createShade() {
782
+ return $('<div />').css({
783
+ position: 'absolute',
784
+ backgroundColor: options.shadeColor||options.bgColor
785
+ }).appendTo(holder);
786
+ }
787
+ function enableShade() {
788
+ if (!enabled) {
789
+ enabled = true;
790
+ holder.insertBefore($img);
791
+ updateAuto();
792
+ Selection.setBgOpacity(1,0,1);
793
+ $img2.hide();
794
+
795
+ setBgColor(options.shadeColor||options.bgColor,1);
796
+ if (Selection.isAwake())
797
+ {
798
+ setOpacity(options.bgOpacity,1);
799
+ }
800
+ else setOpacity(1,1);
801
+ }
802
+ }
803
+ function setBgColor(color,now) {
804
+ colorChangeMacro(getShades(),color,now);
805
+ }
806
+ function disableShade() {
807
+ if (enabled) {
808
+ holder.remove();
809
+ $img2.show();
810
+ enabled = false;
811
+ if (Selection.isAwake()) {
812
+ Selection.setBgOpacity(options.bgOpacity,1,1);
813
+ } else {
814
+ Selection.setBgOpacity(1,1,1);
815
+ Selection.disableHandles();
816
+ }
817
+ colorChangeMacro($div,0,1);
818
+ }
819
+ }
820
+ function setOpacity(opacity,now) {
821
+ if (enabled) {
822
+ if (options.bgFade && !now) {
823
+ holder.animate({
824
+ opacity: 1-opacity
825
+ },{
826
+ queue: false,
827
+ duration: options.fadeTime
828
+ });
829
+ }
830
+ else holder.css({opacity:1-opacity});
831
+ }
832
+ }
833
+ function refreshAll() {
834
+ options.shade ? enableShade() : disableShade();
835
+ if (Selection.isAwake()) setOpacity(options.bgOpacity);
836
+ }
837
+ function getShades() {
838
+ return holder.children();
839
+ }
840
+
841
+ return {
842
+ update: updateAuto,
843
+ updateRaw: updateShade,
844
+ getShades: getShades,
845
+ setBgColor: setBgColor,
846
+ enable: enableShade,
847
+ disable: disableShade,
848
+ resize: resizeShades,
849
+ refresh: refreshAll,
850
+ opacity: setOpacity
851
+ };
852
+ }());
853
+ // }}}
721
854
  // Selection Module {{{
722
855
  var Selection = (function () {
723
- var awake, hdep = 370;
724
- var borders = {};
725
- var handle = {};
726
- var seehandles = false;
727
- var hhs = options.handleOffset;
856
+ var awake,
857
+ hdep = 370,
858
+ borders = {},
859
+ handle = {},
860
+ dragbar = {},
861
+ seehandles = false;
728
862
 
729
863
  // Private Methods
730
864
  function insertBorder(type) //{{{
@@ -743,10 +877,10 @@
743
877
  cursor: ord + '-resize',
744
878
  position: 'absolute',
745
879
  zIndex: zi
746
- });
880
+ }).addClass('ord-'+ord);
747
881
 
748
882
  if (Touch.support) {
749
- jq.bind('touchstart', Touch.createDragger(ord));
883
+ jq.bind('touchstart.jcrop', Touch.createDragger(ord));
750
884
  }
751
885
 
752
886
  $hdl_holder.append(jq);
@@ -755,100 +889,60 @@
755
889
  //}}}
756
890
  function insertHandle(ord) //{{{
757
891
  {
758
- return dragDiv(ord, hdep++).css({
759
- top: px(-hhs + 1),
760
- left: px(-hhs + 1),
761
- opacity: options.handleOpacity
762
- }).addClass(cssClass('handle'));
892
+ var hs = options.handleSize,
893
+
894
+ div = dragDiv(ord, hdep++).css({
895
+ opacity: options.handleOpacity
896
+ }).addClass(cssClass('handle'));
897
+
898
+ if (hs) { div.width(hs).height(hs); }
899
+
900
+ return div;
763
901
  }
764
902
  //}}}
765
903
  function insertDragbar(ord) //{{{
766
904
  {
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
- });
905
+ return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
788
906
  }
789
907
  //}}}
790
- function createHandles(li) //{{{
908
+ function createDragbars(li) //{{{
791
909
  {
792
910
  var i;
793
911
  for (i = 0; i < li.length; i++) {
794
- handle[li[i]] = insertHandle(li[i]);
912
+ dragbar[li[i]] = insertDragbar(li[i]);
795
913
  }
796
914
  }
797
915
  //}}}
798
- function moveHandles(c) //{{{
916
+ function createBorders(li) //{{{
799
917
  {
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
- });
918
+ var cl,i;
919
+ for (i = 0; i < li.length; i++) {
920
+ switch(li[i]){
921
+ case'n': cl='hline'; break;
922
+ case's': cl='hline bottom'; break;
923
+ case'e': cl='vline right'; break;
924
+ case'w': cl='vline'; break;
925
+ }
926
+ borders[li[i]] = insertBorder(cl);
835
927
  }
836
- if (handle.b) {
837
- handle.b.css({
838
- top: px(south)
839
- });
840
- handle.r.css({
841
- left: px(east)
842
- });
928
+ }
929
+ //}}}
930
+ function createHandles(li) //{{{
931
+ {
932
+ var i;
933
+ for (i = 0; i < li.length; i++) {
934
+ handle[li[i]] = insertHandle(li[i]);
843
935
  }
844
936
  }
845
937
  //}}}
846
938
  function moveto(x, y) //{{{
847
939
  {
848
- $img2.css({
849
- top: px(-y),
850
- left: px(-x)
851
- });
940
+ if (!options.shade) {
941
+ $img2.css({
942
+ top: px(-y),
943
+ left: px(-x)
944
+ });
945
+ }
852
946
  $sel.css({
853
947
  top: px(y),
854
948
  left: px(x)
@@ -857,7 +951,7 @@
857
951
  //}}}
858
952
  function resize(w, h) //{{{
859
953
  {
860
- $sel.width(w).height(h);
954
+ $sel.width(Math.round(w)).height(Math.round(h));
861
955
  }
862
956
  //}}}
863
957
  function refresh() //{{{
@@ -872,45 +966,51 @@
872
966
  //}}}
873
967
 
874
968
  // Internal Methods
875
- function updateVisible() //{{{
969
+ function updateVisible(select) //{{{
876
970
  {
877
971
  if (awake) {
878
- return update();
972
+ return update(select);
879
973
  }
880
974
  }
881
975
  //}}}
882
- function update() //{{{
976
+ function update(select) //{{{
883
977
  {
884
978
  var c = Coords.getFixed();
885
979
 
886
980
  resize(c.w, c.h);
887
981
  moveto(c.x, c.y);
982
+ if (options.shade) Shade.updateRaw(c);
888
983
 
889
- /*
890
- options.drawBorders &&
891
- borders.right.css({ left: px(c.w-1) }) &&
892
- borders.bottom.css({ top: px(c.h-1) });
893
- */
984
+ awake || show();
894
985
 
895
- if (seehandles) {
896
- moveHandles(c);
986
+ if (select) {
987
+ options.onSelect.call(api, unscale(c));
988
+ } else {
989
+ options.onChange.call(api, unscale(c));
897
990
  }
898
- if (!awake) {
899
- show();
991
+ }
992
+ //}}}
993
+ function setBgOpacity(opacity,force,now) //{{{
994
+ {
995
+ if (!awake && !force) return;
996
+ if (options.bgFade && !now) {
997
+ $img.animate({
998
+ opacity: opacity
999
+ },{
1000
+ queue: false,
1001
+ duration: options.fadeTime
1002
+ });
1003
+ } else {
1004
+ $img.css('opacity', opacity);
900
1005
  }
901
-
902
- options.onChange.call(api, unscale(c));
903
1006
  }
904
1007
  //}}}
905
1008
  function show() //{{{
906
1009
  {
907
1010
  $sel.show();
908
1011
 
909
- if (options.bgFade) {
910
- $img.fadeTo(options.fadeTime, bgopacity);
911
- } else {
912
- $img.css('opacity', bgopacity);
913
- }
1012
+ if (options.shade) Shade.opacity(bgopacity);
1013
+ else setBgOpacity(bgopacity,true);
914
1014
 
915
1015
  awake = true;
916
1016
  }
@@ -920,11 +1020,8 @@
920
1020
  disableHandles();
921
1021
  $sel.hide();
922
1022
 
923
- if (options.bgFade) {
924
- $img.fadeTo(options.fadeTime, 1);
925
- } else {
926
- $img.css('opacity', 1);
927
- }
1023
+ if (options.shade) Shade.opacity(1);
1024
+ else setBgOpacity(1);
928
1025
 
929
1026
  awake = false;
930
1027
  options.onRelease.call(api);
@@ -933,7 +1030,6 @@
933
1030
  function showHandles() //{{{
934
1031
  {
935
1032
  if (seehandles) {
936
- moveHandles(Coords.getFixed());
937
1033
  $hdl_holder.show();
938
1034
  }
939
1035
  }
@@ -942,7 +1038,6 @@
942
1038
  {
943
1039
  seehandles = true;
944
1040
  if (options.allowResize) {
945
- moveHandles(Coords.getFixed());
946
1041
  $hdl_holder.show();
947
1042
  return true;
948
1043
  }
@@ -952,54 +1047,44 @@
952
1047
  {
953
1048
  seehandles = false;
954
1049
  $hdl_holder.hide();
955
- }
1050
+ }
956
1051
  //}}}
957
1052
  function animMode(v) //{{{
958
1053
  {
959
- if (animating === v) {
1054
+ if (v) {
1055
+ animating = true;
960
1056
  disableHandles();
961
1057
  } else {
1058
+ animating = false;
962
1059
  enableHandles();
963
1060
  }
964
- }
1061
+ }
965
1062
  //}}}
966
1063
  function done() //{{{
967
1064
  {
968
1065
  animMode(false);
969
1066
  refresh();
970
- }
1067
+ }
971
1068
  //}}}
972
- /* Insert draggable elements {{{*/
973
-
1069
+ // Insert draggable elements {{{
974
1070
  // 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
1071
 
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
- }
1072
+ if (options.dragEdges && $.isArray(options.createDragbars))
1073
+ createDragbars(options.createDragbars);
991
1074
 
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
- }
1075
+ if ($.isArray(options.createHandles))
1076
+ createHandles(options.createHandles);
1077
+
1078
+ if (options.drawBorders && $.isArray(options.createBorders))
1079
+ createBorders(options.createBorders);
999
1080
 
1000
-
1001
1081
  //}}}
1002
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
+
1003
1088
  var $track = newTracker().mousedown(createDragger('move')).css({
1004
1089
  cursor: 'move',
1005
1090
  position: 'absolute',
@@ -1031,10 +1116,11 @@
1031
1116
  showHandles: showHandles,
1032
1117
  disableHandles: disableHandles,
1033
1118
  animMode: animMode,
1119
+ setBgOpacity: setBgOpacity,
1034
1120
  done: done
1035
1121
  };
1036
1122
  }());
1037
-
1123
+
1038
1124
  //}}}
1039
1125
  // Tracker Module {{{
1040
1126
  var Tracker = (function () {
@@ -1042,35 +1128,36 @@
1042
1128
  onDone = function () {},
1043
1129
  trackDoc = options.trackDocument;
1044
1130
 
1045
- function toFront() //{{{
1131
+ function toFront(touch) //{{{
1046
1132
  {
1047
1133
  $trk.css({
1048
1134
  zIndex: 450
1049
1135
  });
1050
- if (trackDoc) {
1136
+
1137
+ if (touch)
1051
1138
  $(document)
1052
- .bind('mousemove',trackMove)
1053
- .bind('mouseup',trackUp);
1054
- }
1055
- }
1139
+ .bind('touchmove.jcrop', trackTouchMove)
1140
+ .bind('touchend.jcrop', trackTouchEnd);
1141
+
1142
+ else if (trackDoc)
1143
+ $(document)
1144
+ .bind('mousemove.jcrop',trackMove)
1145
+ .bind('mouseup.jcrop',trackUp);
1146
+ }
1056
1147
  //}}}
1057
1148
  function toBack() //{{{
1058
1149
  {
1059
1150
  $trk.css({
1060
1151
  zIndex: 290
1061
1152
  });
1062
- if (trackDoc) {
1063
- $(document)
1064
- .unbind('mousemove', trackMove)
1065
- .unbind('mouseup', trackUp);
1066
- }
1067
- }
1153
+ $(document).unbind('.jcrop');
1154
+ }
1068
1155
  //}}}
1069
1156
  function trackMove(e) //{{{
1070
1157
  {
1071
1158
  onMove(mouseAbs(e));
1072
1159
  return false;
1073
- }
1160
+ }
1074
1161
  //}}}
1075
1162
  function trackUp(e) //{{{
1076
1163
  {
@@ -1094,27 +1181,24 @@
1094
1181
  return false;
1095
1182
  }
1096
1183
  //}}}
1097
- function activateHandlers(move, done) //{{{
1184
+ function activateHandlers(move, done, touch) //{{{
1098
1185
  {
1099
1186
  btndown = true;
1100
1187
  onMove = move;
1101
1188
  onDone = done;
1102
- toFront();
1189
+ toFront(touch);
1103
1190
  return false;
1104
1191
  }
1105
1192
  //}}}
1106
1193
  function trackTouchMove(e) //{{{
1107
1194
  {
1108
- e.pageX = e.originalEvent.changedTouches[0].pageX;
1109
- e.pageY = e.originalEvent.changedTouches[0].pageY;
1110
- return trackMove(e);
1195
+ onMove(mouseAbs(Touch.cfilter(e)));
1196
+ return false;
1111
1197
  }
1112
1198
  //}}}
1113
1199
  function trackTouchEnd(e) //{{{
1114
1200
  {
1115
- e.pageX = e.originalEvent.changedTouches[0].pageX;
1116
- e.pageY = e.originalEvent.changedTouches[0].pageY;
1117
- return trackUp(e);
1201
+ return trackUp(Touch.cfilter(e));
1118
1202
  }
1119
1203
  //}}}
1120
1204
  function setCursor(t) //{{{
@@ -1123,12 +1207,6 @@
1123
1207
  }
1124
1208
  //}}}
1125
1209
 
1126
- if (Touch.support) {
1127
- $(document)
1128
- .bind('touchmove', trackTouchMove)
1129
- .bind('touchend', trackTouchEnd);
1130
- }
1131
-
1132
1210
  if (!trackDoc) {
1133
1211
  $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
1134
1212
  }
@@ -1146,8 +1224,9 @@
1146
1224
  position: 'fixed',
1147
1225
  left: '-120px',
1148
1226
  width: '12px'
1149
- }),
1150
- $keywrap = $('<div />').css({
1227
+ }).addClass('jcrop-keymgr'),
1228
+
1229
+ $keywrap = $('<div />').css({
1151
1230
  position: 'absolute',
1152
1231
  overflow: 'hidden'
1153
1232
  }).append($keymgr);
@@ -1169,7 +1248,7 @@
1169
1248
  {
1170
1249
  if (options.allowMove) {
1171
1250
  Coords.moveOffset([x, y]);
1172
- Selection.updateVisible();
1251
+ Selection.updateVisible(true);
1173
1252
  }
1174
1253
  e.preventDefault();
1175
1254
  e.stopPropagation();
@@ -1177,7 +1256,7 @@
1177
1256
  //}}}
1178
1257
  function parseKey(e) //{{{
1179
1258
  {
1180
- if (e.ctrlKey) {
1259
+ if (e.ctrlKey || e.metaKey) {
1181
1260
  return true;
1182
1261
  }
1183
1262
  shift_down = e.shiftKey ? true : false;
@@ -1197,7 +1276,7 @@
1197
1276
  doNudge(e, 0, nudge);
1198
1277
  break;
1199
1278
  case 27:
1200
- Selection.release();
1279
+ if (options.allowSelect) Selection.release();
1201
1280
  break;
1202
1281
  case 9:
1203
1282
  return true;
@@ -1235,10 +1314,10 @@
1235
1314
  //}}}
1236
1315
  function animateTo(a, callback) //{{{
1237
1316
  {
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;
1317
+ var x1 = a[0] / xscale,
1318
+ y1 = a[1] / yscale,
1319
+ x2 = a[2] / xscale,
1320
+ y2 = a[3] / yscale;
1242
1321
 
1243
1322
  if (animating) {
1244
1323
  return;
@@ -1256,8 +1335,8 @@
1256
1335
  pcent = 0,
1257
1336
  velocity = options.swingSpeed;
1258
1337
 
1259
- x = animat[0];
1260
- y = animat[1];
1338
+ x1 = animat[0];
1339
+ y1 = animat[1];
1261
1340
  x2 = animat[2];
1262
1341
  y2 = animat[3];
1263
1342
 
@@ -1271,10 +1350,10 @@
1271
1350
  return function () {
1272
1351
  pcent += (100 - pcent) / velocity;
1273
1352
 
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);
1353
+ animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
1354
+ animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
1355
+ animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
1356
+ animat[3] = Math.round(y2 + ((pcent / 100) * iy2));
1278
1357
 
1279
1358
  if (pcent >= 99.8) {
1280
1359
  pcent = 100;
@@ -1284,6 +1363,7 @@
1284
1363
  queueAnimator();
1285
1364
  } else {
1286
1365
  Selection.done();
1366
+ Selection.animMode(false);
1287
1367
  if (typeof(callback) === 'function') {
1288
1368
  callback.call(api);
1289
1369
  }
@@ -1295,8 +1375,9 @@
1295
1375
  //}}}
1296
1376
  function setSelect(rect) //{{{
1297
1377
  {
1298
- setSelectRaw([
1299
- parseInt(rect[0], 10) / xscale, parseInt(rect[1], 10) / yscale, parseInt(rect[2], 10) / xscale, parseInt(rect[3], 10) / yscale]);
1378
+ setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
1379
+ options.onSelect.call(api, unscale(Coords.getFixed()));
1380
+ Selection.enableHandles();
1300
1381
  }
1301
1382
  //}}}
1302
1383
  function setSelectRaw(l) //{{{
@@ -1346,6 +1427,7 @@
1346
1427
  {
1347
1428
  $div.remove();
1348
1429
  $origimg.show();
1430
+ $origimg.css('visibility','visible');
1349
1431
  $(obj).removeData('Jcrop');
1350
1432
  }
1351
1433
  //}}}
@@ -1368,6 +1450,7 @@
1368
1450
  $img2.width(boundx).height(boundy);
1369
1451
  $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
1370
1452
  $div.width(boundx).height(boundy);
1453
+ Shade.resize(boundx,boundy);
1371
1454
  enableCrop();
1372
1455
 
1373
1456
  if (typeof(callback) === 'function') {
@@ -1377,6 +1460,19 @@
1377
1460
  img.src = src;
1378
1461
  }
1379
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
+ }
1380
1476
  function interfaceUpdate(alt) //{{{
1381
1477
  // This method tweaks the interface based on options object.
1382
1478
  // Called when options are changed and at end of initialization.
@@ -1394,6 +1490,10 @@
1394
1490
  Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
1395
1491
  Selection.setCursor(options.allowMove ? 'move' : 'default');
1396
1492
 
1493
+ if (options.hasOwnProperty('trueSize')) {
1494
+ xscale = options.trueSize[0] / boundx;
1495
+ yscale = options.trueSize[1] / boundy;
1496
+ }
1397
1497
 
1398
1498
  if (options.hasOwnProperty('setSelect')) {
1399
1499
  setSelect(options.setSelect);
@@ -1401,36 +1501,22 @@
1401
1501
  delete(options.setSelect);
1402
1502
  }
1403
1503
 
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
- }
1504
+ Shade.refresh();
1420
1505
 
1421
- delete(options.bgColor);
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;
1422
1514
  }
1423
- if (options.hasOwnProperty('bgOpacity')) {
1424
- bgopacity = options.bgOpacity;
1425
1515
 
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);
1516
+ if (bgopacity != options.bgOpacity) {
1517
+ bgopacity = options.bgOpacity;
1518
+ if (options.shade) Shade.refresh();
1519
+ else Selection.setBgOpacity(bgopacity);
1434
1520
  }
1435
1521
 
1436
1522
  xlimit = options.maxSize[0] || 0;
@@ -1448,9 +1534,7 @@
1448
1534
  //}}}
1449
1535
  //}}}
1450
1536
 
1451
- if (Touch.support) {
1452
- $trk.bind('touchstart', Touch.newSelection);
1453
- }
1537
+ if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
1454
1538
 
1455
1539
  $hdl_holder.hide();
1456
1540
  interfaceUpdate(true);
@@ -1481,6 +1565,10 @@
1481
1565
  getScaleFactor: function () {
1482
1566
  return [xscale, yscale];
1483
1567
  },
1568
+ getOptions: function() {
1569
+ // careful: internal values are returned
1570
+ return options;
1571
+ },
1484
1572
 
1485
1573
  ui: {
1486
1574
  holder: $div,
@@ -1488,66 +1576,69 @@
1488
1576
  }
1489
1577
  };
1490
1578
 
1491
- if ($.browser.msie) {
1492
- $div.bind('selectstart', function () {
1493
- return false;
1494
- });
1495
- }
1579
+ if (is_msie) $div.bind('selectstart', function () { return false; });
1496
1580
 
1497
1581
  $origimg.data('Jcrop', api);
1498
1582
  return api;
1499
1583
  };
1500
1584
  $.fn.Jcrop = function (options, callback) //{{{
1501
1585
  {
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
-
1586
+ var api;
1529
1587
  // Iterate over each object, attach Jcrop
1530
1588
  this.each(function () {
1531
1589
  // If we've already attached to this object
1532
1590
  if ($(this).data('Jcrop')) {
1533
1591
  // The API can be requested this way (undocumented)
1534
- if (options === 'api') {
1535
- return $(this).data('Jcrop');
1536
- }
1592
+ if (options === 'api') return $(this).data('Jcrop');
1537
1593
  // Otherwise, we just reset the options...
1538
- else {
1539
- $(this).data('Jcrop').setOptions(options);
1540
- }
1594
+ else $(this).data('Jcrop').setOptions(options);
1541
1595
  }
1542
1596
  // If we haven't been attached, preload and attach
1543
1597
  else {
1544
- attachWhenDone(this);
1598
+ if (this.tagName == 'IMG')
1599
+ $.Jcrop.Loader(this,function(){
1600
+ $(this).css({display:'block',visibility:'hidden'});
1601
+ api = $.Jcrop(this, options);
1602
+ if ($.isFunction(callback)) callback.call(api);
1603
+ });
1604
+ else {
1605
+ $(this).css({display:'block',visibility:'hidden'});
1606
+ api = $.Jcrop(this, options);
1607
+ if ($.isFunction(callback)) callback.call(api);
1608
+ }
1545
1609
  }
1546
1610
  });
1547
1611
 
1548
1612
  // Return "this" so the object is chainable (jQuery-style)
1549
1613
  return this;
1550
1614
  };
1615
+ //}}}
1616
+ // $.Jcrop.Loader - basic image loader {{{
1617
+
1618
+ $.Jcrop.Loader = function(imgobj,success,error){
1619
+ var $img = $(imgobj), img = $img[0];
1620
+
1621
+ function completeCheck(){
1622
+ if (img.complete) {
1623
+ $img.unbind('.jcloader');
1624
+ if ($.isFunction(success)) success.call(img);
1625
+ }
1626
+ else window.setTimeout(completeCheck,50);
1627
+ }
1628
+
1629
+ $img
1630
+ .bind('load.jcloader',completeCheck)
1631
+ .bind('error.jcloader',function(e){
1632
+ $img.unbind('.jcloader');
1633
+ if ($.isFunction(error)) error.call(img);
1634
+ });
1635
+
1636
+ if (img.complete && $.isFunction(success)){
1637
+ $img.unbind('.jcloader');
1638
+ success.call(img);
1639
+ }
1640
+ };
1641
+
1551
1642
  //}}}
1552
1643
  // Global Defaults {{{
1553
1644
  $.Jcrop.defaults = {
@@ -1567,18 +1658,20 @@
1567
1658
  bgFade: false,
1568
1659
  borderOpacity: 0.4,
1569
1660
  handleOpacity: 0.5,
1570
- handleSize: 9,
1571
- handleOffset: 5,
1661
+ handleSize: null,
1572
1662
 
1573
1663
  aspectRatio: 0,
1574
1664
  keySupport: true,
1575
- cornerHandles: true,
1576
- sideHandles: true,
1665
+ createHandles: ['n','s','e','w','nw','ne','se','sw'],
1666
+ createDragbars: ['n','s','e','w'],
1667
+ createBorders: ['n','s','e','w'],
1577
1668
  drawBorders: true,
1578
1669
  dragEdges: true,
1579
1670
  fixedSupport: true,
1580
1671
  touchSupport: null,
1581
1672
 
1673
+ shade: null,
1674
+
1582
1675
  boxWidth: 0,
1583
1676
  boxHeight: 0,
1584
1677
  boundary: 2,
@@ -1593,6 +1686,7 @@
1593
1686
  // Callbacks / Event Handlers
1594
1687
  onChange: function () {},
1595
1688
  onSelect: function () {},
1689
+ onDblClick: function () {},
1596
1690
  onRelease: function () {}
1597
1691
  };
1598
1692