cropper_rails 1.0.1 → 1.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4844080c44e64e78225fbbcbc9130f327ef3f07f835bc7a00074d218940fdbe7
4
- data.tar.gz: 9679739fb40b7f96480ca411a53afa6abcb0a92364fa3ea7db572508c35a873d
3
+ metadata.gz: 1a16ae3c9be3b7647beff042d72711e4632bd95f3d25f98a6ee9bb7c23285cdc
4
+ data.tar.gz: c98a0c096885578226ee8ca90f215b3690bddc9b5989f4954068121e448f5b10
5
5
  SHA512:
6
- metadata.gz: ab94defbf2d9129e4dabc30a79c72264a9e8b1c5314a8123765c0ac9d1a0bb1627da02336ffcc4f0a8e7e5fb74e18263269a986eccc19564b3146fd37832823c
7
- data.tar.gz: e3cb6c68edaa47f92ddf7f43c45a904ff3af127aacd0006c015d92b53106dd6987ef0e102aa8ac02eb796193157055cf07cb79b441583f10b95951d83a30790e
6
+ metadata.gz: 92cc34b1c655d5f5bf21868e5482fdca833b871d0229e6e3f50c4b54aeda93b9943b4350f0efd1af6212d3dbd6a6faea18d0ec84e160f84d6473ae5e3909c045
7
+ data.tar.gz: 19b34b7c6624cb9fabc081944b0a3279bb536fd7a51ce8458b885cf1556092226cfdcea5bfee5ed3a88ae6148fe8293df1ab5627a3f5b6130dafa4fa4a9a15aa
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
- MIT License
1
+ The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018 Fabien LEFEBVRE
3
+ Copyright 2015-present Chen Fengyuan
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
9
  copies of the Software, and to permit persons to whom the Software is
10
10
  furnished to do so, subject to the following conditions:
11
11
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
14
 
15
15
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
16
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
17
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/VERSIONS.md CHANGED
@@ -2,5 +2,10 @@
2
2
 
3
3
  | Gem | Cropper.js | jQuery Cropper |
4
4
  |--------|------------|----------------|
5
+ | 1.1.3 | 1.5.11 | 1.0.1 |
6
+ | 1.1.2 | 1.5.10 | 1.0.1 |
7
+ | 1.1.1 | 1.5.9 | 1.0.1 |
8
+ | 1.1.0 | 1.5.6 | 1.0.1 |
9
+ | 1.0.2 | 1.4.3 | 1.0.0 |
5
10
  | 1.0.1 | 1.4.2 | 1.0.0 |
6
11
  | 1.0.0 | 1.4.1 | 1.0.0 |
@@ -22,5 +22,5 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_runtime_dependency 'jquery-rails', '~> 4.0'
24
24
 
25
- spec.add_development_dependency 'bundler', '~> 1.16'
25
+ spec.add_development_dependency 'bundler', '~> 2.0'
26
26
  end
@@ -1,7 +1,7 @@
1
1
  module Cropper
2
2
  module Rails
3
- VERSION = '1.0.1'.freeze
4
- CROPPER_VERSION = '1.4.2'.freeze
5
- JQUERY_CROPPER_VERSION = '1.0.0'.freeze
3
+ VERSION = '1.1.3'.freeze
4
+ CROPPER_VERSION = '1.5.11'.freeze
5
+ JQUERY_CROPPER_VERSION = '1.0.1'.freeze
6
6
  end
7
7
  end
@@ -1,20 +1,22 @@
1
1
  /*!
2
- * Cropper.js v1.4.2
2
+ * Cropper.js v1.5.11
3
3
  * https://fengyuanchen.github.io/cropperjs
4
4
  *
5
5
  * Copyright 2015-present Chen Fengyuan
6
6
  * Released under the MIT license
7
7
  *
8
- * Date: 2018-10-15T13:27:01.969Z
8
+ * Date: 2021-02-17T11:53:27.572Z
9
9
  */
10
10
 
11
11
  (function (global, factory) {
12
12
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13
13
  typeof define === 'function' && define.amd ? define(factory) :
14
- (global.Cropper = factory());
14
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Cropper = factory());
15
15
  }(this, (function () { 'use strict';
16
16
 
17
17
  function _typeof(obj) {
18
+ "@babel/helpers - typeof";
19
+
18
20
  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
19
21
  _typeof = function (obj) {
20
22
  return typeof obj;
@@ -50,28 +52,92 @@
50
52
  return Constructor;
51
53
  }
52
54
 
53
- function _toConsumableArray(arr) {
54
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
55
+ function _defineProperty(obj, key, value) {
56
+ if (key in obj) {
57
+ Object.defineProperty(obj, key, {
58
+ value: value,
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true
62
+ });
63
+ } else {
64
+ obj[key] = value;
65
+ }
66
+
67
+ return obj;
55
68
  }
56
69
 
57
- function _arrayWithoutHoles(arr) {
58
- if (Array.isArray(arr)) {
59
- for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
70
+ function ownKeys(object, enumerableOnly) {
71
+ var keys = Object.keys(object);
60
72
 
61
- return arr2;
73
+ if (Object.getOwnPropertySymbols) {
74
+ var symbols = Object.getOwnPropertySymbols(object);
75
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
76
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
77
+ });
78
+ keys.push.apply(keys, symbols);
62
79
  }
80
+
81
+ return keys;
82
+ }
83
+
84
+ function _objectSpread2(target) {
85
+ for (var i = 1; i < arguments.length; i++) {
86
+ var source = arguments[i] != null ? arguments[i] : {};
87
+
88
+ if (i % 2) {
89
+ ownKeys(Object(source), true).forEach(function (key) {
90
+ _defineProperty(target, key, source[key]);
91
+ });
92
+ } else if (Object.getOwnPropertyDescriptors) {
93
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
94
+ } else {
95
+ ownKeys(Object(source)).forEach(function (key) {
96
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
97
+ });
98
+ }
99
+ }
100
+
101
+ return target;
102
+ }
103
+
104
+ function _toConsumableArray(arr) {
105
+ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
106
+ }
107
+
108
+ function _arrayWithoutHoles(arr) {
109
+ if (Array.isArray(arr)) return _arrayLikeToArray(arr);
63
110
  }
64
111
 
65
112
  function _iterableToArray(iter) {
66
- if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
113
+ if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
114
+ }
115
+
116
+ function _unsupportedIterableToArray(o, minLen) {
117
+ if (!o) return;
118
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
119
+ var n = Object.prototype.toString.call(o).slice(8, -1);
120
+ if (n === "Object" && o.constructor) n = o.constructor.name;
121
+ if (n === "Map" || n === "Set") return Array.from(o);
122
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
123
+ }
124
+
125
+ function _arrayLikeToArray(arr, len) {
126
+ if (len == null || len > arr.length) len = arr.length;
127
+
128
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
129
+
130
+ return arr2;
67
131
  }
68
132
 
69
133
  function _nonIterableSpread() {
70
- throw new TypeError("Invalid attempt to spread non-iterable instance");
134
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
71
135
  }
72
136
 
73
- var IN_BROWSER = typeof window !== 'undefined';
74
- var WINDOW = IN_BROWSER ? window : {};
137
+ var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';
138
+ var WINDOW = IS_BROWSER ? window : {};
139
+ var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? 'ontouchstart' in WINDOW.document.documentElement : false;
140
+ var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
75
141
  var NAMESPACE = 'cropper'; // Actions
76
142
 
77
143
  var ACTION_ALL = 'all';
@@ -107,20 +173,27 @@
107
173
  var EVENT_CROP_MOVE = 'cropmove';
108
174
  var EVENT_CROP_START = 'cropstart';
109
175
  var EVENT_DBLCLICK = 'dblclick';
110
- var EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown';
111
- var EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove';
112
- var EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup';
176
+ var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
177
+ var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
178
+ var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
179
+ var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
180
+ var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
181
+ var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
113
182
  var EVENT_READY = 'ready';
114
183
  var EVENT_RESIZE = 'resize';
115
- var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
184
+ var EVENT_WHEEL = 'wheel';
116
185
  var EVENT_ZOOM = 'zoom'; // Mime types
117
186
 
118
187
  var MIME_TYPE_JPEG = 'image/jpeg'; // RegExps
119
188
 
120
- var REGEXP_ACTIONS = /^(?:e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/;
189
+ var REGEXP_ACTIONS = /^e|w|s|n|se|sw|ne|nw|all|crop|move|zoom$/;
121
190
  var REGEXP_DATA_URL = /^data:/;
122
191
  var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/;
123
- var REGEXP_TAG_NAME = /^(?:img|canvas)$/i;
192
+ var REGEXP_TAG_NAME = /^img|canvas$/i; // Misc
193
+ // Inspired by the default width and height of a canvas element.
194
+
195
+ var MIN_CONTAINER_WIDTH = 200;
196
+ var MIN_CONTAINER_HEIGHT = 100;
124
197
 
125
198
  var DEFAULTS = {
126
199
  // Define the view mode of the cropper
@@ -184,8 +257,8 @@
184
257
  minCanvasHeight: 0,
185
258
  minCropBoxWidth: 0,
186
259
  minCropBoxHeight: 0,
187
- minContainerWidth: 200,
188
- minContainerHeight: 100,
260
+ minContainerWidth: MIN_CONTAINER_WIDTH,
261
+ minContainerHeight: MIN_CONTAINER_HEIGHT,
189
262
  // Shortcuts of events
190
263
  ready: null,
191
264
  cropstart: null,
@@ -211,6 +284,15 @@
211
284
  function isNumber(value) {
212
285
  return typeof value === 'number' && !isNaN(value);
213
286
  }
287
+ /**
288
+ * Check if the given value is a positive number.
289
+ * @param {*} value - The value to check.
290
+ * @returns {boolean} Returns `true` if the given value is a positive number, else `false`.
291
+ */
292
+
293
+ var isPositiveNumber = function isPositiveNumber(value) {
294
+ return value > 0 && value < Infinity;
295
+ };
214
296
  /**
215
297
  * Check if the given value is undefined.
216
298
  * @param {*} value - The value to check.
@@ -245,7 +327,7 @@
245
327
  var _constructor = value.constructor;
246
328
  var prototype = _constructor.prototype;
247
329
  return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
248
- } catch (e) {
330
+ } catch (error) {
249
331
  return false;
250
332
  }
251
333
  }
@@ -258,6 +340,16 @@
258
340
  function isFunction(value) {
259
341
  return typeof value === 'function';
260
342
  }
343
+ var slice = Array.prototype.slice;
344
+ /**
345
+ * Convert array-like or iterable object to an array.
346
+ * @param {*} value - The value to convert.
347
+ * @returns {Array} Returns a new array.
348
+ */
349
+
350
+ function toArray(value) {
351
+ return Array.from ? Array.from(value) : slice.call(value);
352
+ }
261
353
  /**
262
354
  * Iterate the given data.
263
355
  * @param {*} data - The data to iterate.
@@ -270,14 +362,9 @@
270
362
  if (Array.isArray(data) || isNumber(data.length)
271
363
  /* array-like */
272
364
  ) {
273
- var length = data.length;
274
- var i;
275
-
276
- for (i = 0; i < length; i += 1) {
277
- if (callback.call(data, data[i], i, data) === false) {
278
- break;
279
- }
280
- }
365
+ toArray(data).forEach(function (value, key) {
366
+ callback.call(data, value, key, data);
367
+ });
281
368
  } else if (isObject(data)) {
282
369
  Object.keys(data).forEach(function (key) {
283
370
  callback.call(data, data[key], key, data);
@@ -289,32 +376,32 @@
289
376
  }
290
377
  /**
291
378
  * Extend the given object.
292
- * @param {*} obj - The object to be extended.
293
- * @param {*} args - The rest objects which will be merged to the first object.
379
+ * @param {*} target - The target object to extend.
380
+ * @param {*} args - The rest objects for merging to the target object.
294
381
  * @returns {Object} The extended object.
295
382
  */
296
383
 
297
- var assign = Object.assign || function assign(obj) {
384
+ var assign = Object.assign || function assign(target) {
298
385
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
299
386
  args[_key - 1] = arguments[_key];
300
387
  }
301
388
 
302
- if (isObject(obj) && args.length > 0) {
389
+ if (isObject(target) && args.length > 0) {
303
390
  args.forEach(function (arg) {
304
391
  if (isObject(arg)) {
305
392
  Object.keys(arg).forEach(function (key) {
306
- obj[key] = arg[key];
393
+ target[key] = arg[key];
307
394
  });
308
395
  }
309
396
  });
310
397
  }
311
398
 
312
- return obj;
399
+ return target;
313
400
  };
314
401
  var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/;
315
402
  /**
316
403
  * Normalize decimal number.
317
- * Check out {@link http://0.30000000000000004.com/}
404
+ * Check out {@link https://0.30000000000000004.com/}
318
405
  * @param {number} value - The value to normalize.
319
406
  * @param {number} [times=100000000000] - The times for normalizing.
320
407
  * @returns {number} Returns the normalized number.
@@ -324,7 +411,7 @@
324
411
  var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000;
325
412
  return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value;
326
413
  }
327
- var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
414
+ var REGEXP_SUFFIX = /^width|height|left|top|marginLeft|marginTop$/;
328
415
  /**
329
416
  * Apply styles to the given element.
330
417
  * @param {Element} element - The target element.
@@ -335,7 +422,7 @@
335
422
  var style = element.style;
336
423
  forEach(styles, function (value, property) {
337
424
  if (REGEXP_SUFFIX.test(property) && isNumber(value)) {
338
- value += 'px';
425
+ value = "".concat(value, "px");
339
426
  }
340
427
 
341
428
  style[property] = value;
@@ -435,15 +522,15 @@
435
522
  removeClass(element, value);
436
523
  }
437
524
  }
438
- var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
525
+ var REGEXP_CAMEL_CASE = /([a-z\d])([A-Z])/g;
439
526
  /**
440
527
  * Transform the given string from camelCase to kebab-case
441
528
  * @param {string} value - The value to transform.
442
529
  * @returns {string} The transformed value.
443
530
  */
444
531
 
445
- function hyphenate(value) {
446
- return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
532
+ function toParamCase(value) {
533
+ return value.replace(REGEXP_CAMEL_CASE, '$1-$2').toLowerCase();
447
534
  }
448
535
  /**
449
536
  * Get data from the given element.
@@ -461,7 +548,7 @@
461
548
  return element.dataset[name];
462
549
  }
463
550
 
464
- return element.getAttribute("data-".concat(hyphenate(name)));
551
+ return element.getAttribute("data-".concat(toParamCase(name)));
465
552
  }
466
553
  /**
467
554
  * Set data to the given element.
@@ -476,7 +563,7 @@
476
563
  } else if (element.dataset) {
477
564
  element.dataset[name] = data;
478
565
  } else {
479
- element.setAttribute("data-".concat(hyphenate(name)), data);
566
+ element.setAttribute("data-".concat(toParamCase(name)), data);
480
567
  }
481
568
  }
482
569
  /**
@@ -489,18 +576,18 @@
489
576
  if (isObject(element[name])) {
490
577
  try {
491
578
  delete element[name];
492
- } catch (e) {
579
+ } catch (error) {
493
580
  element[name] = undefined;
494
581
  }
495
582
  } else if (element.dataset) {
496
583
  // #128 Safari not allows to delete dataset property
497
584
  try {
498
585
  delete element.dataset[name];
499
- } catch (e) {
586
+ } catch (error) {
500
587
  element.dataset[name] = undefined;
501
588
  }
502
589
  } else {
503
- element.removeAttribute("data-".concat(hyphenate(name)));
590
+ element.removeAttribute("data-".concat(toParamCase(name)));
504
591
  }
505
592
  }
506
593
  var REGEXP_SPACES = /\s\s*/;
@@ -508,7 +595,7 @@
508
595
  var onceSupported = function () {
509
596
  var supported = false;
510
597
 
511
- if (IN_BROWSER) {
598
+ if (IS_BROWSER) {
512
599
  var once = false;
513
600
 
514
601
  var listener = function listener() {};
@@ -647,7 +734,7 @@
647
734
  };
648
735
  }
649
736
  var location = WINDOW.location;
650
- var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i;
737
+ var REGEXP_ORIGINS = /^(\w+:)\/\/([^:/?#]*):?(\d*)/i;
651
738
  /**
652
739
  * Check if the given URL is a cross origin URL.
653
740
  * @param {string} url - The target URL.
@@ -656,7 +743,7 @@
656
743
 
657
744
  function isCrossOriginURL(url) {
658
745
  var parts = url.match(REGEXP_ORIGINS);
659
- return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
746
+ return parts !== null && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
660
747
  }
661
748
  /**
662
749
  * Add timestamp to the given URL.
@@ -717,8 +804,9 @@
717
804
  */
718
805
 
719
806
  function getMaxZoomRatio(pointers) {
720
- var pointers2 = assign({}, pointers);
721
- var ratios = [];
807
+ var pointers2 = _objectSpread2({}, pointers);
808
+
809
+ var maxRatio = 0;
722
810
  forEach(pointers, function (pointer, pointerId) {
723
811
  delete pointers2[pointerId];
724
812
  forEach(pointers2, function (pointer2) {
@@ -729,13 +817,13 @@
729
817
  var z1 = Math.sqrt(x1 * x1 + y1 * y1);
730
818
  var z2 = Math.sqrt(x2 * x2 + y2 * y2);
731
819
  var ratio = (z2 - z1) / z1;
732
- ratios.push(ratio);
820
+
821
+ if (Math.abs(ratio) > Math.abs(maxRatio)) {
822
+ maxRatio = ratio;
823
+ }
733
824
  });
734
825
  });
735
- ratios.sort(function (a, b) {
736
- return Math.abs(a) < Math.abs(b);
737
- });
738
- return ratios[0];
826
+ return maxRatio;
739
827
  }
740
828
  /**
741
829
  * Get a pointer from an event object.
@@ -751,7 +839,7 @@
751
839
  endX: pageX,
752
840
  endY: pageY
753
841
  };
754
- return endOnly ? end : assign({
842
+ return endOnly ? end : _objectSpread2({
755
843
  startX: pageX,
756
844
  startY: pageY
757
845
  }, end);
@@ -780,11 +868,6 @@
780
868
  pageY: pageY
781
869
  };
782
870
  }
783
- /**
784
- * Check if the given value is a finite number.
785
- */
786
-
787
- var isFinite = Number.isFinite || WINDOW.isFinite;
788
871
  /**
789
872
  * Get the max sizes in a rectangle under the given aspect ratio.
790
873
  * @param {Object} data - The original sizes.
@@ -798,12 +881,10 @@
798
881
  height = _ref4.height,
799
882
  width = _ref4.width;
800
883
  var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'contain';
884
+ var isValidWidth = isPositiveNumber(width);
885
+ var isValidHeight = isPositiveNumber(height);
801
886
 
802
- var isValidNumber = function isValidNumber(value) {
803
- return isFinite(value) && value > 0;
804
- };
805
-
806
- if (isValidNumber(width) && isValidNumber(height)) {
887
+ if (isValidWidth && isValidHeight) {
807
888
  var adjustedWidth = height * aspectRatio;
808
889
 
809
890
  if (type === 'contain' && adjustedWidth > width || type === 'cover' && adjustedWidth < width) {
@@ -811,9 +892,9 @@
811
892
  } else {
812
893
  width = height * aspectRatio;
813
894
  }
814
- } else if (isValidNumber(width)) {
895
+ } else if (isValidWidth) {
815
896
  height = width / aspectRatio;
816
- } else if (isValidNumber(height)) {
897
+ } else if (isValidHeight) {
817
898
  width = height * aspectRatio;
818
899
  }
819
900
 
@@ -946,10 +1027,9 @@
946
1027
 
947
1028
  function getStringFromCharCode(dataView, start, length) {
948
1029
  var str = '';
949
- var i;
950
1030
  length += start;
951
1031
 
952
- for (i = start; i < length; i += 1) {
1032
+ for (var i = start; i < length; i += 1) {
953
1033
  str += fromCharCode(dataView.getUint8(i));
954
1034
  }
955
1035
 
@@ -980,12 +1060,15 @@
980
1060
  */
981
1061
 
982
1062
  function arrayBufferToDataURL(arrayBuffer, mimeType) {
983
- var chunks = [];
1063
+ var chunks = []; // Chunk Typed Array for better performance (#435)
1064
+
984
1065
  var chunkSize = 8192;
985
1066
  var uint8 = new Uint8Array(arrayBuffer);
986
1067
 
987
1068
  while (uint8.length > 0) {
988
- chunks.push(fromCharCode.apply(void 0, _toConsumableArray(uint8.subarray(0, chunkSize))));
1069
+ // XXX: Babel's `toConsumableArray` helper will throw error in IE or Safari 9
1070
+ // eslint-disable-next-line prefer-spread
1071
+ chunks.push(fromCharCode.apply(null, toArray(uint8.subarray(0, chunkSize))));
989
1072
  uint8 = uint8.subarray(chunkSize);
990
1073
  }
991
1074
 
@@ -999,69 +1082,74 @@
999
1082
 
1000
1083
  function resetAndGetOrientation(arrayBuffer) {
1001
1084
  var dataView = new DataView(arrayBuffer);
1002
- var orientation;
1003
- var littleEndian;
1004
- var app1Start;
1005
- var ifdStart; // Only handle JPEG image (start by 0xFFD8)
1006
-
1007
- if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
1008
- var length = dataView.byteLength;
1009
- var offset = 2;
1010
-
1011
- while (offset < length) {
1012
- if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
1013
- app1Start = offset;
1014
- break;
1015
- }
1085
+ var orientation; // Ignores range error when the image does not have correct Exif information
1086
+
1087
+ try {
1088
+ var littleEndian;
1089
+ var app1Start;
1090
+ var ifdStart; // Only handle JPEG image (start by 0xFFD8)
1016
1091
 
1017
- offset += 1;
1092
+ if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
1093
+ var length = dataView.byteLength;
1094
+ var offset = 2;
1095
+
1096
+ while (offset + 1 < length) {
1097
+ if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
1098
+ app1Start = offset;
1099
+ break;
1100
+ }
1101
+
1102
+ offset += 1;
1103
+ }
1018
1104
  }
1019
- }
1020
1105
 
1021
- if (app1Start) {
1022
- var exifIDCode = app1Start + 4;
1023
- var tiffOffset = app1Start + 10;
1106
+ if (app1Start) {
1107
+ var exifIDCode = app1Start + 4;
1108
+ var tiffOffset = app1Start + 10;
1024
1109
 
1025
- if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
1026
- var endianness = dataView.getUint16(tiffOffset);
1027
- littleEndian = endianness === 0x4949;
1110
+ if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
1111
+ var endianness = dataView.getUint16(tiffOffset);
1112
+ littleEndian = endianness === 0x4949;
1028
1113
 
1029
- if (littleEndian || endianness === 0x4D4D
1030
- /* bigEndian */
1031
- ) {
1032
- if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
1033
- var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
1114
+ if (littleEndian || endianness === 0x4D4D
1115
+ /* bigEndian */
1116
+ ) {
1117
+ if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
1118
+ var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
1034
1119
 
1035
- if (firstIFDOffset >= 0x00000008) {
1036
- ifdStart = tiffOffset + firstIFDOffset;
1120
+ if (firstIFDOffset >= 0x00000008) {
1121
+ ifdStart = tiffOffset + firstIFDOffset;
1122
+ }
1037
1123
  }
1038
1124
  }
1039
- }
1125
+ }
1040
1126
  }
1041
- }
1042
1127
 
1043
- if (ifdStart) {
1044
- var _length = dataView.getUint16(ifdStart, littleEndian);
1128
+ if (ifdStart) {
1129
+ var _length = dataView.getUint16(ifdStart, littleEndian);
1045
1130
 
1046
- var _offset;
1131
+ var _offset;
1047
1132
 
1048
- var i;
1133
+ var i;
1049
1134
 
1050
- for (i = 0; i < _length; i += 1) {
1051
- _offset = ifdStart + i * 12 + 2;
1135
+ for (i = 0; i < _length; i += 1) {
1136
+ _offset = ifdStart + i * 12 + 2;
1052
1137
 
1053
- if (dataView.getUint16(_offset, littleEndian) === 0x0112
1054
- /* Orientation */
1055
- ) {
1056
- // 8 is the offset of the current tag's value
1057
- _offset += 8; // Get the original orientation value
1138
+ if (dataView.getUint16(_offset, littleEndian) === 0x0112
1139
+ /* Orientation */
1140
+ ) {
1141
+ // 8 is the offset of the current tag's value
1142
+ _offset += 8; // Get the original orientation value
1058
1143
 
1059
- orientation = dataView.getUint16(_offset, littleEndian); // Override the orientation with its default value
1144
+ orientation = dataView.getUint16(_offset, littleEndian); // Override the orientation with its default value
1060
1145
 
1061
- dataView.setUint16(_offset, 1, littleEndian);
1062
- break;
1063
- }
1146
+ dataView.setUint16(_offset, 1, littleEndian);
1147
+ break;
1148
+ }
1149
+ }
1064
1150
  }
1151
+ } catch (error) {
1152
+ orientation = 1;
1065
1153
  }
1066
1154
 
1067
1155
  return orientation;
@@ -1114,8 +1202,6 @@
1114
1202
  case 8:
1115
1203
  rotate = -90;
1116
1204
  break;
1117
-
1118
- default:
1119
1205
  }
1120
1206
 
1121
1207
  return {
@@ -1141,11 +1227,13 @@
1141
1227
  options = this.options,
1142
1228
  container = this.container,
1143
1229
  cropper = this.cropper;
1230
+ var minWidth = Number(options.minContainerWidth);
1231
+ var minHeight = Number(options.minContainerHeight);
1144
1232
  addClass(cropper, CLASS_HIDDEN);
1145
1233
  removeClass(element, CLASS_HIDDEN);
1146
1234
  var containerData = {
1147
- width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200),
1148
- height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100)
1235
+ width: Math.max(container.offsetWidth, minWidth >= 0 ? minWidth : MIN_CONTAINER_WIDTH),
1236
+ height: Math.max(container.offsetHeight, minHeight >= 0 ? minHeight : MIN_CONTAINER_HEIGHT)
1149
1237
  };
1150
1238
  this.containerData = containerData;
1151
1239
  setStyle(cropper, {
@@ -1186,14 +1274,15 @@
1186
1274
  width: canvasWidth,
1187
1275
  height: canvasHeight
1188
1276
  };
1189
- canvasData.left = (containerData.width - canvasWidth) / 2;
1190
- canvasData.top = (containerData.height - canvasHeight) / 2;
1191
- canvasData.oldLeft = canvasData.left;
1192
- canvasData.oldTop = canvasData.top;
1193
1277
  this.canvasData = canvasData;
1194
1278
  this.limited = viewMode === 1 || viewMode === 2;
1195
1279
  this.limitCanvas(true, true);
1196
- this.initialImageData = assign({}, imageData);
1280
+ canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth);
1281
+ canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight);
1282
+ canvasData.left = (containerData.width - canvasData.width) / 2;
1283
+ canvasData.top = (containerData.height - canvasData.height) / 2;
1284
+ canvasData.oldLeft = canvasData.left;
1285
+ canvasData.oldTop = canvasData.top;
1197
1286
  this.initialCanvasData = assign({}, canvasData);
1198
1287
  },
1199
1288
  limitCanvas: function limitCanvas(sizeLimited, positionLimited) {
@@ -1502,9 +1591,11 @@
1502
1591
 
1503
1592
  var preview = {
1504
1593
  initPreview: function initPreview() {
1505
- var crossOrigin = this.crossOrigin;
1594
+ var element = this.element,
1595
+ crossOrigin = this.crossOrigin;
1506
1596
  var preview = this.options.preview;
1507
1597
  var url = crossOrigin ? this.crossOriginUrl : this.url;
1598
+ var alt = element.alt || 'The image to preview';
1508
1599
  var image = document.createElement('img');
1509
1600
 
1510
1601
  if (crossOrigin) {
@@ -1512,6 +1603,7 @@
1512
1603
  }
1513
1604
 
1514
1605
  image.src = url;
1606
+ image.alt = alt;
1515
1607
  this.viewBox.appendChild(image);
1516
1608
  this.viewBoxImage = image;
1517
1609
 
@@ -1522,7 +1614,7 @@
1522
1614
  var previews = preview;
1523
1615
 
1524
1616
  if (typeof preview === 'string') {
1525
- previews = this.element.ownerDocument.querySelectorAll(preview);
1617
+ previews = element.ownerDocument.querySelectorAll(preview);
1526
1618
  } else if (preview.querySelector) {
1527
1619
  previews = [preview];
1528
1620
  }
@@ -1542,6 +1634,7 @@
1542
1634
  }
1543
1635
 
1544
1636
  img.src = url;
1637
+ img.alt = alt;
1545
1638
  /**
1546
1639
  * Override img element styles
1547
1640
  * Add `display:block` to avoid margin top issue
@@ -1650,7 +1743,10 @@
1650
1743
  addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = this.cropStart.bind(this));
1651
1744
 
1652
1745
  if (options.zoomable && options.zoomOnWheel) {
1653
- addListener(cropper, EVENT_WHEEL, this.onWheel = this.wheel.bind(this));
1746
+ addListener(cropper, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
1747
+ passive: false,
1748
+ capture: true
1749
+ });
1654
1750
  }
1655
1751
 
1656
1752
  if (options.toggleDragModeOnDblclick) {
@@ -1692,7 +1788,10 @@
1692
1788
  removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart);
1693
1789
 
1694
1790
  if (options.zoomable && options.zoomOnWheel) {
1695
- removeListener(cropper, EVENT_WHEEL, this.onWheel);
1791
+ removeListener(cropper, EVENT_WHEEL, this.onWheel, {
1792
+ passive: false,
1793
+ capture: true
1794
+ });
1696
1795
  }
1697
1796
 
1698
1797
  if (options.toggleDragModeOnDblclick) {
@@ -1710,16 +1809,13 @@
1710
1809
 
1711
1810
  var handlers = {
1712
1811
  resize: function resize() {
1713
- var options = this.options,
1714
- container = this.container,
1715
- containerData = this.containerData;
1716
- var minContainerWidth = Number(options.minContainerWidth) || 200;
1717
- var minContainerHeight = Number(options.minContainerHeight) || 100;
1718
-
1719
- if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) {
1812
+ if (this.disabled) {
1720
1813
  return;
1721
1814
  }
1722
1815
 
1816
+ var options = this.options,
1817
+ container = this.container,
1818
+ containerData = this.containerData;
1723
1819
  var ratio = container.offsetWidth / containerData.width; // Resize when width changed or height changed
1724
1820
 
1725
1821
  if (ratio !== 1 || container.offsetHeight !== containerData.height) {
@@ -1750,7 +1846,7 @@
1750
1846
 
1751
1847
  this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP);
1752
1848
  },
1753
- wheel: function wheel(e) {
1849
+ wheel: function wheel(event) {
1754
1850
  var _this = this;
1755
1851
 
1756
1852
  var ratio = Number(this.options.wheelZoomRatio) || 0.1;
@@ -1760,7 +1856,7 @@
1760
1856
  return;
1761
1857
  }
1762
1858
 
1763
- e.preventDefault(); // Limit wheel speed to prevent zoom too fast (#21)
1859
+ event.preventDefault(); // Limit wheel speed to prevent zoom too fast (#21)
1764
1860
 
1765
1861
  if (this.wheeling) {
1766
1862
  return;
@@ -1771,18 +1867,24 @@
1771
1867
  _this.wheeling = false;
1772
1868
  }, 50);
1773
1869
 
1774
- if (e.deltaY) {
1775
- delta = e.deltaY > 0 ? 1 : -1;
1776
- } else if (e.wheelDelta) {
1777
- delta = -e.wheelDelta / 120;
1778
- } else if (e.detail) {
1779
- delta = e.detail > 0 ? 1 : -1;
1870
+ if (event.deltaY) {
1871
+ delta = event.deltaY > 0 ? 1 : -1;
1872
+ } else if (event.wheelDelta) {
1873
+ delta = -event.wheelDelta / 120;
1874
+ } else if (event.detail) {
1875
+ delta = event.detail > 0 ? 1 : -1;
1780
1876
  }
1781
1877
 
1782
- this.zoom(-delta * ratio, e);
1878
+ this.zoom(-delta * ratio, event);
1783
1879
  },
1784
- cropStart: function cropStart(e) {
1785
- if (this.disabled) {
1880
+ cropStart: function cropStart(event) {
1881
+ var buttons = event.buttons,
1882
+ button = event.button;
1883
+
1884
+ if (this.disabled // Handle mouse event and pointer event and ignore touch event
1885
+ || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)
1886
+ isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1887
+ || event.ctrlKey)) {
1786
1888
  return;
1787
1889
  }
1788
1890
 
@@ -1790,20 +1892,20 @@
1790
1892
  pointers = this.pointers;
1791
1893
  var action;
1792
1894
 
1793
- if (e.changedTouches) {
1895
+ if (event.changedTouches) {
1794
1896
  // Handle touch event
1795
- forEach(e.changedTouches, function (touch) {
1897
+ forEach(event.changedTouches, function (touch) {
1796
1898
  pointers[touch.identifier] = getPointer(touch);
1797
1899
  });
1798
1900
  } else {
1799
1901
  // Handle mouse event and pointer event
1800
- pointers[e.pointerId || 0] = getPointer(e);
1902
+ pointers[event.pointerId || 0] = getPointer(event);
1801
1903
  }
1802
1904
 
1803
1905
  if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) {
1804
1906
  action = ACTION_ZOOM;
1805
1907
  } else {
1806
- action = getData(e.target, DATA_ACTION);
1908
+ action = getData(event.target, DATA_ACTION);
1807
1909
  }
1808
1910
 
1809
1911
  if (!REGEXP_ACTIONS.test(action)) {
@@ -1811,14 +1913,14 @@
1811
1913
  }
1812
1914
 
1813
1915
  if (dispatchEvent(this.element, EVENT_CROP_START, {
1814
- originalEvent: e,
1916
+ originalEvent: event,
1815
1917
  action: action
1816
1918
  }) === false) {
1817
1919
  return;
1818
1920
  } // This line is required for preventing page zooming in iOS browsers
1819
1921
 
1820
1922
 
1821
- e.preventDefault();
1923
+ event.preventDefault();
1822
1924
  this.action = action;
1823
1925
  this.cropping = false;
1824
1926
 
@@ -1827,7 +1929,7 @@
1827
1929
  addClass(this.dragBox, CLASS_MODAL);
1828
1930
  }
1829
1931
  },
1830
- cropMove: function cropMove(e) {
1932
+ cropMove: function cropMove(event) {
1831
1933
  var action = this.action;
1832
1934
 
1833
1935
  if (this.disabled || !action) {
@@ -1835,27 +1937,27 @@
1835
1937
  }
1836
1938
 
1837
1939
  var pointers = this.pointers;
1838
- e.preventDefault();
1940
+ event.preventDefault();
1839
1941
 
1840
1942
  if (dispatchEvent(this.element, EVENT_CROP_MOVE, {
1841
- originalEvent: e,
1943
+ originalEvent: event,
1842
1944
  action: action
1843
1945
  }) === false) {
1844
1946
  return;
1845
1947
  }
1846
1948
 
1847
- if (e.changedTouches) {
1848
- forEach(e.changedTouches, function (touch) {
1949
+ if (event.changedTouches) {
1950
+ forEach(event.changedTouches, function (touch) {
1849
1951
  // The first parameter should not be undefined (#432)
1850
1952
  assign(pointers[touch.identifier] || {}, getPointer(touch, true));
1851
1953
  });
1852
1954
  } else {
1853
- assign(pointers[e.pointerId || 0] || {}, getPointer(e, true));
1955
+ assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
1854
1956
  }
1855
1957
 
1856
- this.change(e);
1958
+ this.change(event);
1857
1959
  },
1858
- cropEnd: function cropEnd(e) {
1960
+ cropEnd: function cropEnd(event) {
1859
1961
  if (this.disabled) {
1860
1962
  return;
1861
1963
  }
@@ -1863,19 +1965,19 @@
1863
1965
  var action = this.action,
1864
1966
  pointers = this.pointers;
1865
1967
 
1866
- if (e.changedTouches) {
1867
- forEach(e.changedTouches, function (touch) {
1968
+ if (event.changedTouches) {
1969
+ forEach(event.changedTouches, function (touch) {
1868
1970
  delete pointers[touch.identifier];
1869
1971
  });
1870
1972
  } else {
1871
- delete pointers[e.pointerId || 0];
1973
+ delete pointers[event.pointerId || 0];
1872
1974
  }
1873
1975
 
1874
1976
  if (!action) {
1875
1977
  return;
1876
1978
  }
1877
1979
 
1878
- e.preventDefault();
1980
+ event.preventDefault();
1879
1981
 
1880
1982
  if (!Object.keys(pointers).length) {
1881
1983
  this.action = '';
@@ -1887,14 +1989,14 @@
1887
1989
  }
1888
1990
 
1889
1991
  dispatchEvent(this.element, EVENT_CROP_END, {
1890
- originalEvent: e,
1992
+ originalEvent: event,
1891
1993
  action: action
1892
1994
  });
1893
1995
  }
1894
1996
  };
1895
1997
 
1896
1998
  var change = {
1897
- change: function change(e) {
1999
+ change: function change(event) {
1898
2000
  var options = this.options,
1899
2001
  canvasData = this.canvasData,
1900
2002
  containerData = this.containerData,
@@ -1915,7 +2017,7 @@
1915
2017
  var renderable = true;
1916
2018
  var offset; // Locking aspect ratio in "free mode" by holding shift key
1917
2019
 
1918
- if (!aspectRatio && e.shiftKey) {
2020
+ if (!aspectRatio && event.shiftKey) {
1919
2021
  aspectRatio = width && height ? width / height : 1;
1920
2022
  }
1921
2023
 
@@ -1961,8 +2063,6 @@
1961
2063
  }
1962
2064
 
1963
2065
  break;
1964
-
1965
- default:
1966
2066
  }
1967
2067
  };
1968
2068
 
@@ -2288,7 +2388,7 @@
2288
2388
  // Zoom canvas
2289
2389
 
2290
2390
  case ACTION_ZOOM:
2291
- this.zoom(getMaxZoomRatio(pointers), e);
2391
+ this.zoom(getMaxZoomRatio(pointers), event);
2292
2392
  renderable = false;
2293
2393
  break;
2294
2394
  // Create crop box
@@ -2327,8 +2427,6 @@
2327
2427
  }
2328
2428
 
2329
2429
  break;
2330
-
2331
- default:
2332
2430
  }
2333
2431
 
2334
2432
  if (renderable) {
@@ -2680,7 +2778,7 @@
2680
2778
  * @param {boolean} [rounded=false] - Indicate if round the data values or not.
2681
2779
  * @returns {Object} The result cropped data.
2682
2780
  */
2683
- getData: function getData$$1() {
2781
+ getData: function getData() {
2684
2782
  var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2685
2783
  var options = this.options,
2686
2784
  imageData = this.imageData,
@@ -2736,7 +2834,7 @@
2736
2834
  * @param {Object} data - The new data.
2737
2835
  * @returns {Cropper} this
2738
2836
  */
2739
- setData: function setData$$1(data) {
2837
+ setData: function setData(data) {
2740
2838
  var options = this.options,
2741
2839
  imageData = this.imageData,
2742
2840
  canvasData = this.canvasData;
@@ -3110,9 +3208,7 @@
3110
3208
 
3111
3209
  var AnotherCropper = WINDOW.Cropper;
3112
3210
 
3113
- var Cropper =
3114
- /*#__PURE__*/
3115
- function () {
3211
+ var Cropper = /*#__PURE__*/function () {
3116
3212
  /**
3117
3213
  * Create a new Cropper.
3118
3214
  * @param {Element} element - The target element for cropping.
@@ -3161,7 +3257,7 @@
3161
3257
 
3162
3258
  if (!url) {
3163
3259
  return;
3164
- } // e.g.: "http://example.com/img/picture.jpg"
3260
+ } // e.g.: "https://example.com/img/picture.jpg"
3165
3261
 
3166
3262
 
3167
3263
  url = element.src;
@@ -3193,28 +3289,38 @@
3193
3289
  if (!options.checkOrientation || !window.ArrayBuffer) {
3194
3290
  this.clone();
3195
3291
  return;
3196
- } // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari
3292
+ } // Detect the mime type of the image directly if it is a Data URL
3197
3293
 
3198
3294
 
3199
3295
  if (REGEXP_DATA_URL.test(url)) {
3296
+ // Read ArrayBuffer from Data URL of JPEG images directly for better performance
3200
3297
  if (REGEXP_DATA_URL_JPEG.test(url)) {
3201
3298
  this.read(dataURLToArrayBuffer(url));
3202
3299
  } else {
3300
+ // Only a JPEG image may contains Exif Orientation information,
3301
+ // the rest types of Data URLs are not necessary to check orientation at all.
3203
3302
  this.clone();
3204
3303
  }
3205
3304
 
3206
3305
  return;
3207
- }
3306
+ } // 1. Detect the mime type of the image by a XMLHttpRequest.
3307
+ // 2. Load the image as ArrayBuffer for reading orientation if its a JPEG image.
3308
+
3208
3309
 
3209
3310
  var xhr = new XMLHttpRequest();
3210
3311
  var clone = this.clone.bind(this);
3211
3312
  this.reloading = true;
3212
- this.xhr = xhr;
3213
- xhr.ontimeout = clone;
3313
+ this.xhr = xhr; // 1. Cross origin requests are only supported for protocol schemes:
3314
+ // http, https, data, chrome, chrome-extension.
3315
+ // 2. Access to XMLHttpRequest from a Data URL will be blocked by CORS policy
3316
+ // in some browsers as IE11 and Safari.
3317
+
3214
3318
  xhr.onabort = clone;
3215
3319
  xhr.onerror = clone;
3320
+ xhr.ontimeout = clone;
3216
3321
 
3217
3322
  xhr.onprogress = function () {
3323
+ // Abort the request directly if it not a JPEG image for better performance
3218
3324
  if (xhr.getResponseHeader('content-type') !== MIME_TYPE_JPEG) {
3219
3325
  xhr.abort();
3220
3326
  }
@@ -3232,9 +3338,10 @@
3232
3338
 
3233
3339
  if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) {
3234
3340
  url = addTimestamp(url);
3235
- }
3341
+ } // The third parameter is required for avoiding side-effect (#682)
3236
3342
 
3237
- xhr.open('GET', url);
3343
+
3344
+ xhr.open('GET', url, true);
3238
3345
  xhr.responseType = 'arraybuffer';
3239
3346
  xhr.withCredentials = element.crossOrigin === 'use-credentials';
3240
3347
  xhr.send();
@@ -3243,15 +3350,16 @@
3243
3350
  key: "read",
3244
3351
  value: function read(arrayBuffer) {
3245
3352
  var options = this.options,
3246
- imageData = this.imageData;
3353
+ imageData = this.imageData; // Reset the orientation value to its default value 1
3354
+ // as some iOS browsers will render image with its orientation
3355
+
3247
3356
  var orientation = resetAndGetOrientation(arrayBuffer);
3248
3357
  var rotate = 0;
3249
3358
  var scaleX = 1;
3250
3359
  var scaleY = 1;
3251
3360
 
3252
3361
  if (orientation > 1) {
3253
- // Generate a new Data URL with the orientation value set to 1
3254
- // as some iOS browsers will render image with its orientation
3362
+ // Generate a new URL which has the default orientation value
3255
3363
  this.url = arrayBufferToDataURL(arrayBuffer, MIME_TYPE_JPEG);
3256
3364
 
3257
3365
  var _parseOrientation = parseOrientation(orientation);
@@ -3277,19 +3385,16 @@
3277
3385
  value: function clone() {
3278
3386
  var element = this.element,
3279
3387
  url = this.url;
3280
- var crossOrigin;
3281
- var crossOriginUrl;
3388
+ var crossOrigin = element.crossOrigin;
3389
+ var crossOriginUrl = url;
3282
3390
 
3283
3391
  if (this.options.checkCrossOrigin && isCrossOriginURL(url)) {
3284
- crossOrigin = element.crossOrigin;
3392
+ if (!crossOrigin) {
3393
+ crossOrigin = 'anonymous';
3394
+ } // Bust cache when there is not a "crossOrigin" property (#519)
3285
3395
 
3286
- if (crossOrigin) {
3287
- crossOriginUrl = url;
3288
- } else {
3289
- crossOrigin = 'anonymous'; // Bust cache when there is not a "crossOrigin" property
3290
3396
 
3291
- crossOriginUrl = addTimestamp(url);
3292
- }
3397
+ crossOriginUrl = addTimestamp(url);
3293
3398
  }
3294
3399
 
3295
3400
  this.crossOrigin = crossOrigin;
@@ -3301,6 +3406,7 @@
3301
3406
  }
3302
3407
 
3303
3408
  image.src = crossOriginUrl || url;
3409
+ image.alt = element.alt || 'The image to crop';
3304
3410
  this.image = image;
3305
3411
  image.onload = this.start.bind(this);
3306
3412
  image.onerror = this.stop.bind(this);
@@ -3312,11 +3418,13 @@
3312
3418
  value: function start() {
3313
3419
  var _this2 = this;
3314
3420
 
3315
- var image = this.isImg ? this.element : this.image;
3421
+ var image = this.image;
3316
3422
  image.onload = null;
3317
3423
  image.onerror = null;
3318
- this.sizing = true;
3319
- var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
3424
+ this.sizing = true; // Match all browsers that use WebKit as the layout engine in iOS devices,
3425
+ // such as Safari for iOS, Chrome for iOS, and in-app browsers.
3426
+
3427
+ var isIOSWebKit = WINDOW.navigator && /(?:iPad|iPhone|iPod).*?AppleWebKit/i.test(WINDOW.navigator.userAgent);
3320
3428
 
3321
3429
  var done = function done(naturalWidth, naturalHeight) {
3322
3430
  assign(_this2.imageData, {
@@ -3324,14 +3432,15 @@
3324
3432
  naturalHeight: naturalHeight,
3325
3433
  aspectRatio: naturalWidth / naturalHeight
3326
3434
  });
3435
+ _this2.initialImageData = assign({}, _this2.imageData);
3327
3436
  _this2.sizing = false;
3328
3437
  _this2.sized = true;
3329
3438
 
3330
3439
  _this2.build();
3331
- }; // Modern browsers (except Safari)
3440
+ }; // Most modern browsers (excepts iOS WebKit)
3332
3441
 
3333
3442
 
3334
- if (image.naturalWidth && !IS_SAFARI) {
3443
+ if (image.naturalWidth && !isIOSWebKit) {
3335
3444
  done(image.naturalWidth, image.naturalHeight);
3336
3445
  return;
3337
3446
  }
@@ -3343,15 +3452,15 @@
3343
3452
  sizingImage.onload = function () {
3344
3453
  done(sizingImage.width, sizingImage.height);
3345
3454
 
3346
- if (!IS_SAFARI) {
3455
+ if (!isIOSWebKit) {
3347
3456
  body.removeChild(sizingImage);
3348
3457
  }
3349
3458
  };
3350
3459
 
3351
- sizingImage.src = image.src; // iOS Safari will convert the image automatically
3460
+ sizingImage.src = image.src; // iOS WebKit will convert the image automatically
3352
3461
  // with its orientation once append it into DOM (#279)
3353
3462
 
3354
- if (!IS_SAFARI) {
3463
+ if (!isIOSWebKit) {
3355
3464
  sizingImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;';
3356
3465
  body.appendChild(sizingImage);
3357
3466
  }