PageSourceSearch

https://www.motonline.it/js/croppie.js

js motonline.it collected 2026-10-10 01:02:47 UTC 58,292 bytes, 1,625 lines download raw bytes

vendor: 7,927 bytes, lines 1-178
1/*************************
2 * Croppie
3 * Copyright 2019
4 * Foliotek
5 * Version: 2.6.4
6 *************************/
7(function (root, factory) {
8    if (typeof define === 'function' && define.amd) {
9        // AMD. Register as an anonymous module.
10        define(factory);
11    } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
12        // CommonJS
13        module.exports = factory();
14    } else {
15        // Browser globals
16        root.Croppie = factory();
17    }
18}(typeof self !== 'undefined' ? self : this, function () {
19
20    /* Polyfills */
21    if (typeof Promise !== 'function') {
22        /*! promise-polyfill 3.1.0 */
23        !function(a){function b(a,b){return function(){a.apply(b,arguments)}}function c(a){if("object"!==typeof this)throw new TypeError("Promises must be constructed via new");if("function"!==typeof a)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],i(a,b(e,this),b(f,this))}function d(a){var b=this;return null===this._state?void this._deferreds.push(a):void k(function(){var c=b._state?a.onFulfilled:a.onRejected;if(null===c)return void(b._state?a.resolve:a.reject)(b._value);var d;try{d=c(b._value)}catch(e){return void a.reject(e)}a.resolve(d)})}function e(a){try{if(a===this)throw new TypeError("A promise cannot be resolved with itself.");if(a&&("object"===typeof a||"function"===typeof a)){var c=a.then;if("function"===typeof c)return void i(b(c,a),b(e,this),b(f,this))}this._state=!0,this._value=a,g.call(this)}catch(d){f.call(this,d)}}function f(a){this._state=!1,this._value=a,g.call(this)}function g(){for(var a=0,b=this._deferreds.length;b>a;a++)d.call(this,this._deferreds[a]);this._deferreds=null}function h(a,b,c,d){this.onFulfilled="function"===typeof a?a:null,this.onRejected="function"===typeof b?b:null,this.resolve=c,this.reject=d}function i(a,b,c){var d=!1;try{a(function(a){d||(d=!0,b(a))},function(a){d||(d=!0,c(a))})}catch(e){if(d)return;d=!0,c(e)}}var j=setTimeout,k="function"===typeof setImmediate&&setImmediate||function(a){j(a,1)},l=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};c.prototype["catch"]=function(a){return this.then(null,a)},c.prototype.then=function(a,b){var e=this;return new c(function(c,f){d.call(e,new h(a,b,c,f))})},c.all=function(){var a=Array.prototype.slice.call(1===arguments.length&&l(arguments[0])?arguments[0]:arguments);return new c(function(b,c){function d(f,g){try{if(g&&("object"===typeof g||"function"===typeof g)){var h=g.then;if("function"===typeof h)return void h.call(g,function(a){d(f,a)},c)}a[f]=g,0===--e&&b(a)}catch(i){c(i)}}if(0===a.length)return b([]);for(var e=a.length,f=0;f<a.length;f++)d(f,a[f])})},c.resolve=function(a){return a&&"object"===typeof a&&a.constructor===c?a:new c(function(b){b(a)})},c.reject=function(a){return new c(function(b,c){c(a)})},c.race=function(a){return new c(function(b,c){for(var d=0,e=a.length;e>d;d++)a[d].then(b,c)})},c._setImmediateFn=function(a){k=a},"undefined"!==typeof module&&module.exports?module.exports=c:a.Promise||(a.Promise=c)}(this);
24    }
25
26    if ( typeof window.CustomEvent !== "function" ) {
27        (function(){
28            function CustomEvent ( event, params ) {
29                params = params || { bubbles: false, cancelable: false, detail: undefined };
30                var evt = document.createEvent( 'CustomEvent' );
31                evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
32                return evt;
33            }
34            CustomEvent.prototype = window.Event.prototype;
35            window.CustomEvent = CustomEvent;
36        }());
37    }
38
39    if (!HTMLCanvasElement.prototype.toBlob) {
40        Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
41            value: function (callback, type, quality) {
42                var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
43                len = binStr.length,
44                arr = new Uint8Array(len);
45
46                for (var i=0; i<len; i++ ) {
47                    arr[i] = binStr.charCodeAt(i);
48                }
49
50                callback( new Blob( [arr], {type: type || 'image/png'} ) );
51            }
52        });
53    }
54    /* End Polyfills */
55
56    var cssPrefixes = ['Webkit', 'Moz', 'ms'],
57        emptyStyles = document.createElement('div').style,
58        EXIF_NORM = [1,8,3,6],
59        EXIF_FLIP = [2,7,4,5],
60        CSS_TRANS_ORG,
61        CSS_TRANSFORM,
62        CSS_USERSELECT;
63
64    function vendorPrefix(prop) {
65        if (prop in emptyStyles) {
66            return prop;
67        }
68
69        var capProp = prop[0].toUpperCase() + prop.slice(1),
70            i = cssPrefixes.length;
71
72        while (i--) {
73            prop = cssPrefixes[i] + capProp;
74            if (prop in emptyStyles) {
75                return prop;
76            }
77        }
78    }
79
80    CSS_TRANSFORM = vendorPrefix('transform');
81    CSS_TRANS_ORG = vendorPrefix('transformOrigin');
82    CSS_USERSELECT = vendorPrefix('userSelect');
83
84    function getExifOffset(ornt, rotate) {
85        var arr = EXIF_NORM.indexOf(ornt) > -1 ? EXIF_NORM : EXIF_FLIP,
86            index = arr.indexOf(ornt),
87            offset = (rotate / 90) % arr.length;// 180 = 2%4 = 2 shift exif by 2 indexes
88
89        return arr[(arr.length + index + (offset % arr.length)) % arr.length];
90    }
91
92    // Credits to : Andrew Dupont - http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
93    function deepExtend(destination, source) {
94        destination = destination || {};
95        for (var property in source) {
96            if (source[property] && source[property].constructor && source[property].constructor === Object) {
97                destination[property] = destination[property] || {};
98                deepExtend(destination[property], source[property]);
99            } else {
100                destination[property] = source[property];
101            }
102        }
103        return destination;
104    }
105
106    function clone(object) {
107        return deepExtend({}, object);
108    }
109
110    function debounce(func, wait, immediate) {
111        var timeout;
112        return function () {
113            var context = this, args = arguments;
114            var later = function () {
115                timeout = null;
116                if (!immediate) func.apply(context, args);
117            };
118            var callNow = immediate && !timeout;
119            clearTimeout(timeout);
120            timeout = setTimeout(later, wait);
121            if (callNow) func.apply(context, args);
122        };
123    }
124
125    function dispatchChange(element) {
126        if ("createEvent" in document) {
127            var evt = document.createEvent("HTMLEvents");
128            evt.initEvent("change", false, true);
129            element.dispatchEvent(evt);
130        }
131        else {
132            element.fireEvent("onchange");
133        }
134    }
135
136    //http://jsperf.com/vanilla-css
137    function css(el, styles, val) {
138        if (typeof (styles) === 'string') {
139            var tmp = styles;
140            styles = {};
141            styles[tmp] = val;
142        }
143
144        for (var prop in styles) {
145            el.style[prop] = styles[prop];
146        }
147    }
148
149    function addClass(el, c) {
150        if (el.classList) {
151            el.classList.add(c);
152        }
153        else {
154            el.className += ' ' + c;
155        }
156    }
157
158    function removeClass(el, c) {
159        if (el.classList) {
160            el.classList.remove(c);
161        }
162        else {
163            el.className = el.className.replace(c, '');
164        }
165    }
166
167    function setAttributes(el, attrs) {
168        for (var key in attrs) {
169            el.setAttribute(key, attrs[key]);
170        }
171    }
172
173    function num(v) {
174        return parseInt(v, 10);
175    }
176
177    /* Utilities */
178    function loadImage(src, doExif) {
vendor: 15,047 bytes, lines 178-640
178
179        var img = new Image();
180        img.style.opacity = '0';
181        return new Promise(function (resolve, reject) {
182            function _resolve() {
183                img.style.opacity = '1';
184                setTimeout(function () {
185                    resolve(img);
186                }, 1);
187            }
188
189            img.removeAttribute('crossOrigin');
190            if (src.match(/^https?:\/\/|^\/\//)) {
191                img.setAttribute('crossOrigin', 'anonymous');
192            }
193
194            img.onload = function () {
195                if (doExif) {
196                    EXIF.getData(img, function () {
197                        _resolve();
198                    });
199                }
200                else {
201                    _resolve();
202                }
203            };
204            img.onerror = function (ev) {
205                img.style.opacity = 1;
206                setTimeout(function () {
207                    reject(ev);
208                }, 1);
209            };
210            img.src = src;
211        });
212    }
213
214    function naturalImageDimensions(img, ornt) {
215        var w = img.naturalWidth;
216        var h = img.naturalHeight;
217        var orient = ornt || getExifOrientation(img);
218        if (orient && orient >= 5) {
219            var x= w;
220            w = h;
221            h = x;
222        }
223        return { width: w, height: h };
224    }
225
226    /* CSS Transform Prototype */
227    var TRANSLATE_OPTS = {
228        'translate3d': {
229            suffix: ', 0px'
230        },
231        'translate': {
232            suffix: ''
233        }
234    };
235    var Transform = function (x, y, scale) {
236        this.x = parseFloat(x);
237        this.y = parseFloat(y);
238        this.scale = parseFloat(scale);
239    };
240
241    Transform.parse = function (v) {
242        if (v.style) {
243            return Transform.parse(v.style[CSS_TRANSFORM]);
244        }
245        else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) {
246            return Transform.fromMatrix(v);
247        }
248        else {
249            return Transform.fromString(v);
250        }
251    };
252
253    Transform.fromMatrix = function (v) {
254        var vals = v.substring(7).split(',');
255        if (!vals.length || v === 'none') {
256            vals = [1, 0, 0, 1, 0, 0];
257        }
258
259        return new Transform(num(vals[4]), num(vals[5]), parseFloat(vals[0]));
260    };
261
262    Transform.fromString = function (v) {
263        var values = v.split(') '),
264            translate = values[0].substring(Croppie.globals.translate.length + 1).split(','),
265            scale = values.length > 1 ? values[1].substring(6) : 1,
266            x = translate.length > 1 ? translate[0] : 0,
267            y = translate.length > 1 ? translate[1] : 0;
268
269        return new Transform(x, y, scale);
270    };
271
272    Transform.prototype.toString = function () {
273        var suffix = TRANSLATE_OPTS[Croppie.globals.translate].suffix || '';
274        return Croppie.globals.translate + '(' + this.x + 'px, ' + this.y + 'px' + suffix + ') scale(' + this.scale + ')';
275    };
276
277    var TransformOrigin = function (el) {
278        if (!el || !el.style[CSS_TRANS_ORG]) {
279            this.x = 0;
280            this.y = 0;
281            return;
282        }
283        var css = el.style[CSS_TRANS_ORG].split(' ');
284        this.x = parseFloat(css[0]);
285        this.y = parseFloat(css[1]);
286    };
287
288    TransformOrigin.prototype.toString = function () {
289        return this.x + 'px ' + this.y + 'px';
290    };
291
292    function getExifOrientation (img) {
293        return img.exifdata && img.exifdata.Orientation ? num(img.exifdata.Orientation) : 1;
294    }
295
296    function drawCanvas(canvas, img, orientation) {
297        var width = img.width,
298            height = img.height,
299            ctx = canvas.getContext('2d');
300
301        canvas.width = img.width;
302        canvas.height = img.height;
303
304        ctx.save();
305        switch (orientation) {
306          case 2:
307             ctx.translate(width, 0);
308             ctx.scale(-1, 1);
309             break;
310
311          case 3:
312              ctx.translate(width, height);
313              ctx.rotate(180*Math.PI/180);
314              break;
315
316          case 4:
317              ctx.translate(0, height);
318              ctx.scale(1, -1);
319              break;
320
321          case 5:
322              canvas.width = height;
323              canvas.height = width;
324              ctx.rotate(90*Math.PI/180);
325              ctx.scale(1, -1);
326              break;
327
328          case 6:
329              canvas.width = height;
330              canvas.height = width;
331              ctx.rotate(90*Math.PI/180);
332              ctx.translate(0, -height);
333              break;
334
335          case 7:
336              canvas.width = height;
337              canvas.height = width;
338              ctx.rotate(-90*Math.PI/180);
339              ctx.translate(-width, height);
340              ctx.scale(1, -1);
341              break;
342
343          case 8:
344              canvas.width = height;
345              canvas.height = width;
346              ctx.translate(0, width);
347              ctx.rotate(-90*Math.PI/180);
348              break;
349        }
350        ctx.drawImage(img, 0,0, width, height);
351        ctx.restore();
352    }
353
354    /* Private Methods */
355    function _create() {
356        var self = this,
357            contClass = 'croppie-container',
358            customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null,
359            boundary, img, viewport, overlay, bw, bh;
360
361        self.options.useCanvas = self.options.enableOrientation || _hasExif.call(self);
362        // Properties on class
363        self.data = {};
364        self.elements = {};
365
366        boundary = self.elements.boundary = document.createElement('div');
367        viewport = self.elements.viewport = document.createElement('div');
368        img = self.elements.img = document.createElement('img');
369        overlay = self.elements.overlay = document.createElement('div');
370
371        if (self.options.useCanvas) {
372            self.elements.canvas = document.createElement('canvas');
373            self.elements.preview = self.elements.canvas;
374        }
375        else {
376            self.elements.preview = img;
377        }
378
379        addClass(boundary, 'cr-boundary');
380        boundary.setAttribute('aria-dropeffect', 'none');
381        bw = self.options.boundary.width;
382        bh = self.options.boundary.height;
383        css(boundary, {
384            width: (bw + (isNaN(bw) ? '' : 'px')),
385            height: (bh + (isNaN(bh) ? '' : 'px'))
386        });
387
388        addClass(viewport, 'cr-viewport');
389        if (customViewportClass) {
390            addClass(viewport, customViewportClass);
391        }
392        css(viewport, {
393            width: self.options.viewport.width + 'px',
394            height: self.options.viewport.height + 'px'
395        });
396        viewport.setAttribute('tabindex', 0);
397
398        addClass(self.elements.preview, 'cr-image');
399        setAttributes(self.elements.preview, { 'alt': 'preview', 'aria-grabbed': 'false' });
400        addClass(overlay, 'cr-overlay');
401
402        self.element.appendChild(boundary);
403        boundary.appendChild(self.elements.preview);
404        boundary.appendChild(viewport);
405        boundary.appendChild(overlay);
406
407        addClass(self.element, contClass);
408        if (self.options.customClass) {
409            addClass(self.element, self.options.customClass);
410        }
411
412        _initDraggable.call(this);
413
414        if (self.options.enableZoom) {
415            _initializeZoom.call(self);
416        }
417
418        // if (self.options.enableOrientation) {
419        //     _initRotationControls.call(self);
420        // }
421
422        if (self.options.enableResize) {
423            _initializeResize.call(self);
424        }
425    }
426
427    // function _initRotationControls () {
428    //     var self = this,
429    //         wrap, btnLeft, btnRight, iLeft, iRight;
430
431    //     wrap = document.createElement('div');
432    //     self.elements.orientationBtnLeft = btnLeft = document.createElement('button');
433    //     self.elements.orientationBtnRight = btnRight = document.createElement('button');
434
435    //     wrap.appendChild(btnLeft);
436    //     wrap.appendChild(btnRight);
437
438    //     iLeft = document.createElement('i');
439    //     iRight = document.createElement('i');
440    //     btnLeft.appendChild(iLeft);
441    //     btnRight.appendChild(iRight);
442
443    //     addClass(wrap, 'cr-rotate-controls');
444    //     addClass(btnLeft, 'cr-rotate-l');
445    //     addClass(btnRight, 'cr-rotate-r');
446
447    //     self.elements.boundary.appendChild(wrap);
448
449    //     btnLeft.addEventListener('click', function () {
450    //         self.rotate(-90);
451    //     });
452    //     btnRight.addEventListener('click', function () {
453    //         self.rotate(90);
454    //     });
455    // }
456
457    function _hasExif() {
458        return this.options.enableExif && window.EXIF;
459    }
460
461    function _initializeResize () {
462        var self = this;
463        var wrap = document.createElement('div');
464        var isDragging = false;
465        var direction;
466        var originalX;
467        var originalY;
468        var minSize = 50;
469        var maxWidth;
470        var maxHeight;
471        var vr;
472        var hr;
473
474        addClass(wrap, 'cr-resizer');
475        css(wrap, {
476            width: this.options.viewport.width + 'px',
477            height: this.options.viewport.height + 'px'
478        });
479
480        if (this.options.resizeControls.height) {
481            vr = document.createElement('div');
482            addClass(vr, 'cr-resizer-vertical');
483            wrap.appendChild(vr);
484        }
485
486        if (this.options.resizeControls.width) {
487            hr = document.createElement('div');
488            addClass(hr, 'cr-resizer-horisontal');
489            wrap.appendChild(hr);
490        }
491
492        function mouseDown(ev) {
493            if (ev.button !== undefined && ev.button !== 0) return;
494
495            ev.preventDefault();
496            if (isDragging) {
497                return;
498            }
499
500            var overlayRect = self.elements.overlay.getBoundingClientRect();
501
502            isDragging = true;
503            originalX = ev.pageX;
504            originalY = ev.pageY;
505            direction = ev.currentTarget.className.indexOf('vertical') !== -1 ? 'v' : 'h';
506            maxWidth = overlayRect.width;
507            maxHeight = overlayRect.height;
508
509            if (ev.touches) {
510                var touches = ev.touches[0];
511                originalX = touches.pageX;
512                originalY = touches.pageY;
513            }
514
515            window.addEventListener('mousemove', mouseMove);
516            window.addEventListener('touchmove', mouseMove);
517            window.addEventListener('mouseup', mouseUp);
518            window.addEventListener('touchend', mouseUp);
519            document.body.style[CSS_USERSELECT] = 'none';
520        }
521
522        function mouseMove(ev) {
523            var pageX = ev.pageX;
524            var pageY = ev.pageY;
525
526            ev.preventDefault();
527
528            if (ev.touches) {
529                var touches = ev.touches[0];
530                pageX = touches.pageX;
531                pageY = touches.pageY;
532            }
533
534            var deltaX = pageX - originalX;
535            var deltaY = pageY - originalY;
536            var newHeight = self.options.viewport.height + deltaY;
537            var newWidth = self.options.viewport.width + deltaX;
538
539            if (direction === 'v' && newHeight >= minSize && newHeight <= maxHeight) {
540                css(wrap, {
541                    height: newHeight + 'px'
542                });
543
544                self.options.boundary.height += deltaY;
545                css(self.elements.boundary, {
546                    height: self.options.boundary.height + 'px'
547                });
548
549                self.options.viewport.height += deltaY;
550                css(self.elements.viewport, {
551                    height: self.options.viewport.height + 'px'
552                });
553            }
554            else if (direction === 'h' && newWidth >= minSize && newWidth <= maxWidth) {
555                css(wrap, {
556                    width: newWidth + 'px'
557                });
558
559                self.options.boundary.width += deltaX;
560                css(self.elements.boundary, {
561                    width: self.options.boundary.width + 'px'
562                });
563
564                self.options.viewport.width += deltaX;
565                css(self.elements.viewport, {
566                    width: self.options.viewport.width + 'px'
567                });
568            }
569
570            _updateOverlay.call(self);
571            _updateZoomLimits.call(self);
572            _updateCenterPoint.call(self);
573            _triggerUpdate.call(self);
574            originalY = pageY;
575            originalX = pageX;
576        }
577
578        function mouseUp() {
579            isDragging = false;
580            window.removeEventListener('mousemove', mouseMove);
581            window.removeEventListener('touchmove', mouseMove);
582            window.removeEventListener('mouseup', mouseUp);
583            window.removeEventListener('touchend', mouseUp);
584            document.body.style[CSS_USERSELECT] = '';
585        }
586
587        if (vr) {
588            vr.addEventListener('mousedown', mouseDown);
589            vr.addEventListener('touchstart', mouseDown);
590        }
591
592        if (hr) {
593            hr.addEventListener('mousedown', mouseDown);
594            hr.addEventListener('touchstart', mouseDown);
595        }
596
597        this.elements.boundary.appendChild(wrap);
598    }
599
600    function _setZoomerVal(v) {
601        if (this.options.enableZoom) {
602            var z = this.elements.zoomer,
603                val = fix(v, 4);
604
605            z.value = Math.max(parseFloat(z.min), Math.min(parseFloat(z.max), val)).toString();
606        }
607    }
608
609    function _initializeZoom() {
610        var self = this,
611            wrap = self.elements.zoomerWrap = document.createElement('div'),
612            zoomer = self.elements.zoomer = document.createElement('input');
613
614        addClass(wrap, 'cr-slider-wrap');
615        addClass(zoomer, 'cr-slider');
616        zoomer.type = 'range';
617        zoomer.step = '0.0001';
618        zoomer.value = '1';
619        zoomer.style.display = self.options.showZoomer ? '' : 'none';
620        zoomer.setAttribute('aria-label', 'zoom');
621
622        self.element.appendChild(wrap);
623        wrap.appendChild(zoomer);
624
625        self._currentZoom = 1;
626
627        function change() {
628            _onZoom.call(self, {
629                value: parseFloat(zoomer.value),
630                origin: new TransformOrigin(self.elements.preview),
631                viewportRect: self.elements.viewport.getBoundingClientRect(),
632                transform: Transform.parse(self.elements.preview)
633            });
634        }
635
636        function scroll(ev) {
637            var delta, targetZoom;
638
639            if(self.options.mouseWheelZoom === 'ctrl' && ev.ctrlKey !== true){
640              return 0;
640 
vendor: 14,569 bytes, lines 640-1038
640
641            } else if (ev.wheelDelta) {
642                delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2
643            } else if (ev.deltaY) {
644                delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2
645            } else if (ev.detail) {
646                delta = ev.detail / -60; //delta min: -3 max: 3 // max x 10 x 2
647            } else {
648                delta = 0;
649            }
650
651            targetZoom = self._currentZoom + (delta * self._currentZoom);
652
653            ev.preventDefault();
654            _setZoomerVal.call(self, targetZoom);
655            change.call(self);
656        }
657
658        self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress
659        self.elements.zoomer.addEventListener('change', change);
660
661        if (self.options.mouseWheelZoom) {
662            self.elements.boundary.addEventListener('mousewheel', scroll);
663            self.elements.boundary.addEventListener('DOMMouseScroll', scroll);
664        }
665    }
666
667    function _onZoom(ui) {
668        var self = this,
669            transform = ui ? ui.transform : Transform.parse(self.elements.preview),
670            vpRect = ui ? ui.viewportRect : self.elements.viewport.getBoundingClientRect(),
671            origin = ui ? ui.origin : new TransformOrigin(self.elements.preview);
672
673        function applyCss() {
674            var transCss = {};
675            transCss[CSS_TRANSFORM] = transform.toString();
676            transCss[CSS_TRANS_ORG] = origin.toString();
677            css(self.elements.preview, transCss);
678        }
679
680        self._currentZoom = ui ? ui.value : self._currentZoom;
681        transform.scale = self._currentZoom;
682        self.elements.zoomer.setAttribute('aria-valuenow', self._currentZoom);
683        applyCss();
684
685        if (self.options.enforceBoundary) {
686            var boundaries = _getVirtualBoundaries.call(self, vpRect),
687                transBoundaries = boundaries.translate,
688                oBoundaries = boundaries.origin;
689
690            if (transform.x >= transBoundaries.maxX) {
691                origin.x = oBoundaries.minX;
692                transform.x = transBoundaries.maxX;
693            }
694
695            if (transform.x <= transBoundaries.minX) {
696                origin.x = oBoundaries.maxX;
697                transform.x = transBoundaries.minX;
698            }
699
700            if (transform.y >= transBoundaries.maxY) {
701                origin.y = oBoundaries.minY;
702                transform.y = transBoundaries.maxY;
703            }
704
705            if (transform.y <= transBoundaries.minY) {
706                origin.y = oBoundaries.maxY;
707                transform.y = transBoundaries.minY;
708            }
709        }
710        applyCss();
711        _debouncedOverlay.call(self);
712        _triggerUpdate.call(self);
713    }
714
715    function _getVirtualBoundaries(viewport) {
716        var self = this,
717            scale = self._currentZoom,
718            vpWidth = viewport.width,
719            vpHeight = viewport.height,
720            centerFromBoundaryX = self.elements.boundary.clientWidth / 2,
721            centerFromBoundaryY = self.elements.boundary.clientHeight / 2,
722            imgRect = self.elements.preview.getBoundingClientRect(),
723            curImgWidth = imgRect.width,
724            curImgHeight = imgRect.height,
725            halfWidth = vpWidth / 2,
726            halfHeight = vpHeight / 2;
727
728        var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1;
729        var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale)));
730
731        var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1;
732        var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale)));
733
734        var originMinX = (1 / scale) * halfWidth;
735        var originMaxX = (curImgWidth * (1 / scale)) - originMinX;
736
737        var originMinY = (1 / scale) * halfHeight;
738        var originMaxY = (curImgHeight * (1 / scale)) - originMinY;
739
740        return {
741            translate: {
742                maxX: maxX,
743                minX: minX,
744                maxY: maxY,
745                minY: minY
746            },
747            origin: {
748                maxX: originMaxX,
749                minX: originMinX,
750                maxY: originMaxY,
751                minY: originMinY
752            }
753        };
754    }
755
756    function _updateCenterPoint(rotate) {
757        var self = this,
758            scale = self._currentZoom,
759            data = self.elements.preview.getBoundingClientRect(),
760            vpData = self.elements.viewport.getBoundingClientRect(),
761            transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]),
762            pc = new TransformOrigin(self.elements.preview),
763            top = (vpData.top - data.top) + (vpData.height / 2),
764            left = (vpData.left - data.left) + (vpData.width / 2),
765            center = {},
766            adj = {};
767
768        if (rotate) {
769            var cx = pc.x;
770            var cy = pc.y;
771            var tx = transform.x;
772            var ty = transform.y;
773
774            center.y = cx;
775            center.x = cy;
776            transform.y = tx;
777            transform.x = ty;
778        }
779        else {
780            center.y = top / scale;
781            center.x = left / scale;
782
783            adj.y = (center.y - pc.y) * (1 - scale);
784            adj.x = (center.x - pc.x) * (1 - scale);
785
786            transform.x -= adj.x;
787            transform.y -= adj.y;
788        }
789
790        var newCss = {};
791        newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px';
792        newCss[CSS_TRANSFORM] = transform.toString();
793        css(self.elements.preview, newCss);
794    }
795
796    function _initDraggable() {
797        var self = this,
798            isDragging = false,
799            originalX,
800            originalY,
801            originalDistance,
802            vpRect,
803            transform;
804
805        function assignTransformCoordinates(deltaX, deltaY) {
806            var imgRect = self.elements.preview.getBoundingClientRect(),
807                top = transform.y + deltaY,
808                left = transform.x + deltaX;
809
810            if (self.options.enforceBoundary) {
811                if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) {
812                    transform.y = top;
813                }
814
815                if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) {
816                    transform.x = left;
817                }
818            }
819            else {
820                transform.y = top;
821                transform.x = left;
822            }
823        }
824
825        function toggleGrabState(isDragging) {
826          self.elements.preview.setAttribute('aria-grabbed', isDragging);
827          self.elements.boundary.setAttribute('aria-dropeffect', isDragging? 'move': 'none');
828        }
829
830        function keyDown(ev) {
831            var LEFT_ARROW  = 37,
832                UP_ARROW    = 38,
833                RIGHT_ARROW = 39,
834                DOWN_ARROW  = 40;
835
836            if (ev.shiftKey && (ev.keyCode === UP_ARROW || ev.keyCode === DOWN_ARROW)) {
837                var zoom;
838                if (ev.keyCode === UP_ARROW) {
839                    zoom = parseFloat(self.elements.zoomer.value) + parseFloat(self.elements.zoomer.step)
840                }
841                else {
842                    zoom = parseFloat(self.elements.zoomer.value) - parseFloat(self.elements.zoomer.step)
843                }
844                self.setZoom(zoom);
845            }
846            else if (self.options.enableKeyMovement && (ev.keyCode >= 37 && ev.keyCode <= 40)) {
847                ev.preventDefault();
848                var movement = parseKeyDown(ev.keyCode);
849
850                transform = Transform.parse(self.elements.preview);
851                document.body.style[CSS_USERSELECT] = 'none';
852                vpRect = self.elements.viewport.getBoundingClientRect();
853                keyMove(movement);
854            }
855
856            function parseKeyDown(key) {
857                switch (key) {
858                    case LEFT_ARROW:
859                        return [1, 0];
860                    case UP_ARROW:
861                        return [0, 1];
862                    case RIGHT_ARROW:
863                        return [-1, 0];
864                    case DOWN_ARROW:
865                        return [0, -1];
866                }
867            }
868        }
869
870        function keyMove(movement) {
871            var deltaX = movement[0],
872                deltaY = movement[1],
873                newCss = {};
874
875            assignTransformCoordinates(deltaX, deltaY);
876
877            newCss[CSS_TRANSFORM] = transform.toString();
878            css(self.elements.preview, newCss);
879            _updateOverlay.call(self);
880            document.body.style[CSS_USERSELECT] = '';
881            _updateCenterPoint.call(self);
882            _triggerUpdate.call(self);
883            originalDistance = 0;
884        }
885
886        function mouseDown(ev) {
887            if (ev.button !== undefined && ev.button !== 0) return;
888
889            ev.preventDefault();
890            if (isDragging) return;
891            isDragging = true;
892            originalX = ev.pageX;
893            originalY = ev.pageY;
894
895            if (ev.touches) {
896                var touches = ev.touches[0];
897                originalX = touches.pageX;
898                originalY = touches.pageY;
899            }
900            toggleGrabState(isDragging);
901            transform = Transform.parse(self.elements.preview);
902            window.addEventListener('mousemove', mouseMove);
903            window.addEventListener('touchmove', mouseMove);
904            window.addEventListener('mouseup', mouseUp);
905            window.addEventListener('touchend', mouseUp);
906            document.body.style[CSS_USERSELECT] = 'none';
907            vpRect = self.elements.viewport.getBoundingClientRect();
908        }
909
910        function mouseMove(ev) {
911            ev.preventDefault();
912            var pageX = ev.pageX,
913                pageY = ev.pageY;
914
915            if (ev.touches) {
916                var touches = ev.touches[0];
917                pageX = touches.pageX;
918                pageY = touches.pageY;
919            }
920
921            var deltaX = pageX - originalX,
922                deltaY = pageY - originalY,
923                newCss = {};
924
925            if (ev.type === 'touchmove') {
926                if (ev.touches.length > 1) {
927                    var touch1 = ev.touches[0];
928                    var touch2 = ev.touches[1];
929                    var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY));
930
931                    if (!originalDistance) {
932                        originalDistance = dist / self._currentZoom;
933                    }
934
935                    var scale = dist / originalDistance;
936
937                    _setZoomerVal.call(self, scale);
938                    dispatchChange(self.elements.zoomer);
939                    return;
940                }
941            }
942
943            assignTransformCoordinates(deltaX, deltaY);
944
945            newCss[CSS_TRANSFORM] = transform.toString();
946            css(self.elements.preview, newCss);
947            _updateOverlay.call(self);
948            originalY = pageY;
949            originalX = pageX;
950        }
951
952        function mouseUp() {
953            isDragging = false;
954            toggleGrabState(isDragging);
955            window.removeEventListener('mousemove', mouseMove);
956            window.removeEventListener('touchmove', mouseMove);
957            window.removeEventListener('mouseup', mouseUp);
958            window.removeEventListener('touchend', mouseUp);
959            document.body.style[CSS_USERSELECT] = '';
960            _updateCenterPoint.call(self);
961            _triggerUpdate.call(self);
962            originalDistance = 0;
963        }
964
965        self.elements.overlay.addEventListener('mousedown', mouseDown);
966        self.elements.viewport.addEventListener('keydown', keyDown);
967        self.elements.overlay.addEventListener('touchstart', mouseDown);
968    }
969
970    function _updateOverlay() {
971        if (!this.elements) return; // since this is debounced, it can be fired after destroy
972        var self = this,
973            boundRect = self.elements.boundary.getBoundingClientRect(),
974            imgData = self.elements.preview.getBoundingClientRect();
975
976        css(self.elements.overlay, {
977            width: imgData.width + 'px',
978            height: imgData.height + 'px',
979            top: (imgData.top - boundRect.top) + 'px',
980            left: (imgData.left - boundRect.left) + 'px'
981        });
982    }
983    var _debouncedOverlay = debounce(_updateOverlay, 500);
984
985    function _triggerUpdate() {
986        var self = this,
987            data = self.get();
988
989        if (!_isVisible.call(self)) {
990            return;
991        }
992
993        self.options.update.call(self, data);
994        if (self.$ && typeof Prototype === 'undefined') {
995            self.$(self.element).trigger('update.croppie', data);
996        }
997        else {
998            var ev;
999            if (window.CustomEvent) {
1000                ev = new CustomEvent('update', { detail: data });
1001            } else {
1002                ev = document.createEvent('CustomEvent');
1003                ev.initCustomEvent('update', true, true, data);
1004            }
1005
1006            self.element.dispatchEvent(ev);
1007        }
1008    }
1009
1010    function _isVisible() {
1011        return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0;
1012    }
1013
1014    function _updatePropertiesFromImage() {
1015        var self = this,
1016            initialZoom = 1,
1017            cssReset = {},
1018            img = self.elements.preview,
1019            imgData,
1020            transformReset = new Transform(0, 0, initialZoom),
1021            originReset = new TransformOrigin(),
1022            isVisible = _isVisible.call(self);
1023
1024        if (!isVisible || self.data.bound) {// if the croppie isn't visible or it doesn't need binding
1025            return;
1026        }
1027
1028        self.data.bound = true;
1029        cssReset[CSS_TRANSFORM] = transformReset.toString();
1030        cssReset[CSS_TRANS_ORG] = originReset.toString();
1031        cssReset['opacity'] = 1;
1032        css(img, cssReset);
1033
1034        imgData = self.elements.preview.getBoundingClientRect();
1035
1036        self._originalImageWidth = imgData.width;
1037        self._originalImageHeight = imgData.height;
1038        self.data.orientation = 
vendor: 1,602 bytes, lines 1038-1087
1038getExifOrientation(self.elements.img);
1039
1040        if (self.options.enableZoom) {
1041            _updateZoomLimits.call(self, true);
1042        }
1043        else {
1044            self._currentZoom = initialZoom;
1045        }
1046
1047        transformReset.scale = self._currentZoom;
1048        cssReset[CSS_TRANSFORM] = transformReset.toString();
1049        css(img, cssReset);
1050
1051        if (self.data.points.length) {
1052            _bindPoints.call(self, self.data.points);
1053        }
1054        else {
1055            _centerImage.call(self);
1056        }
1057
1058        _updateCenterPoint.call(self);
1059        _updateOverlay.call(self);
1060    }
1061
1062    function _updateZoomLimits (initial) {
1063        var self = this,
1064            minZoom = Math.max(self.options.minZoom, 0) || 0,
1065            maxZoom = self.options.maxZoom || 1.5,
1066            initialZoom,
1067            defaultInitialZoom,
1068            zoomer = self.elements.zoomer,
1069            scale = parseFloat(zoomer.value),
1070            boundaryData = self.elements.boundary.getBoundingClientRect(),
1071            imgData = naturalImageDimensions(self.elements.img, self.data.orientation),
1072            vpData = self.elements.viewport.getBoundingClientRect(),
1073            minW,
1074            minH;
1075        if (self.options.enforceBoundary) {
1076            minW = vpData.width / imgData.width;
1077            minH = vpData.height / imgData.height;
1078            minZoom = Math.max(minW, minH);
1079        }
1080
1081        if (minZoom >= maxZoom) {
1082            maxZoom = minZoom + 1;
1083        }
1084
1085        zoomer.min = fix(minZoom, 4);
1086        zoomer.max = fix(maxZoom, 4);
1087        
vendor: 9,518 bytes, lines 1087-1345
1087
1088        if (!initial && (scale < zoomer.min || scale > zoomer.max)) {
1089            _setZoomerVal.call(self, scale < zoomer.min ? zoomer.min : zoomer.max);
1090        }
1091        else if (initial) {
1092            defaultInitialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height));
1093            initialZoom = self.data.boundZoom !== null ? self.data.boundZoom : defaultInitialZoom;
1094            _setZoomerVal.call(self, initialZoom);
1095        }
1096
1097        dispatchChange(zoomer);
1098    }
1099
1100    function _bindPoints(points) {
1101        if (points.length !== 4) {
1102            throw "Croppie - Invalid number of points supplied: " + points;
1103        }
1104        var self = this,
1105            pointsWidth = points[2] - points[0],
1106            // pointsHeight = points[3] - points[1],
1107            vpData = self.elements.viewport.getBoundingClientRect(),
1108            boundRect = self.elements.boundary.getBoundingClientRect(),
1109            vpOffset = {
1110                left: vpData.left - boundRect.left,
1111                top: vpData.top - boundRect.top
1112            },
1113            scale = vpData.width / pointsWidth,
1114            originTop = points[1],
1115            originLeft = points[0],
1116            transformTop = (-1 * points[1]) + vpOffset.top,
1117            transformLeft = (-1 * points[0]) + vpOffset.left,
1118            newCss = {};
1119
1120        newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px';
1121        newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString();
1122        css(self.elements.preview, newCss);
1123
1124        _setZoomerVal.call(self, scale);
1125        self._currentZoom = scale;
1126    }
1127
1128    function _centerImage() {
1129        var self = this,
1130            imgDim = self.elements.preview.getBoundingClientRect(),
1131            vpDim = self.elements.viewport.getBoundingClientRect(),
1132            boundDim = self.elements.boundary.getBoundingClientRect(),
1133            vpLeft = vpDim.left - boundDim.left,
1134            vpTop = vpDim.top - boundDim.top,
1135            w = vpLeft - ((imgDim.width - vpDim.width) / 2),
1136            h = vpTop - ((imgDim.height - vpDim.height) / 2),
1137            transform = new Transform(w, h, self._currentZoom);
1138
1139        css(self.elements.preview, CSS_TRANSFORM, transform.toString());
1140    }
1141
1142    function _transferImageToCanvas(customOrientation) {
1143        var self = this,
1144            canvas = self.elements.canvas,
1145            img = self.elements.img,
1146            ctx = canvas.getContext('2d');
1147
1148        ctx.clearRect(0, 0, canvas.width, canvas.height);
1149        canvas.width = img.width;
1150        canvas.height = img.height;
1151
1152        var orientation = self.options.enableOrientation && customOrientation || getExifOrientation(img);
1153        drawCanvas(canvas, img, orientation);
1154    }
1155
1156    function _getCanvas(data) {
1157        var self = this,
1158            points = data.points,
1159            left = num(points[0]),
1160            top = num(points[1]),
1161            right = num(points[2]),
1162            bottom = num(points[3]),
1163            width = right-left,
1164            height = bottom-top,
1165            circle = data.circle,
1166            canvas = document.createElement('canvas'),
1167            ctx = canvas.getContext('2d'),
1168            startX = 0,
1169            startY = 0,
1170            canvasWidth = data.outputWidth || width,
1171            canvasHeight = data.outputHeight || height;
1172
1173        canvas.width = canvasWidth;
1174        canvas.height = canvasHeight;
1175
1176        if (data.backgroundColor) {
1177            ctx.fillStyle = data.backgroundColor;
1178            ctx.fillRect(0, 0, canvasWidth, canvasHeight);
1179        }
1180
1181        // By default assume we're going to draw the entire
1182        // source image onto the destination canvas.
1183        var sx = left,
1184            sy = top,
1185            sWidth = width,
1186            sHeight = height,
1187            dx = 0,
1188            dy = 0,
1189            dWidth = canvasWidth,
1190            dHeight = canvasHeight;
1191
1192        //
1193        // Do not go outside of the original image's bounds along the x-axis.
1194        // Handle translations when projecting onto the destination canvas.
1195        //
1196
1197        // The smallest possible source x-position is 0.
1198        if (left < 0) {
1199            sx = 0;
1200            dx = (Math.abs(left) / width) * canvasWidth;
1201        }
1202
1203        // The largest possible source width is the original image's width.
1204        if (sWidth + sx > self._originalImageWidth) {
1205            sWidth = self._originalImageWidth - sx;
1206            dWidth =  (sWidth / width) * canvasWidth;
1207        }
1208
1209        //
1210        // Do not go outside of the original image's bounds along the y-axis.
1211        //
1212
1213        // The smallest possible source y-position is 0.
1214        if (top < 0) {
1215            sy = 0;
1216            dy = (Math.abs(top) / height) * canvasHeight;
1217        }
1218
1219        // The largest possible source height is the original image's height.
1220        if (sHeight + sy > self._originalImageHeight) {
1221            sHeight = self._originalImageHeight - sy;
1222            dHeight = (sHeight / height) * canvasHeight;
1223        }
1224
1225        // console.table({ left, right, top, bottom, canvasWidth, canvasHeight, width, height, startX, startY, circle, sx, sy, dx, dy, sWidth, sHeight, dWidth, dHeight });
1226
1227        ctx.drawImage(this.elements.preview, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
1228        if (circle) {
1229            ctx.fillStyle = '#fff';
1230            ctx.globalCompositeOperation = 'destination-in';
1231            ctx.beginPath();
1232            ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true);
1233            ctx.closePath();
1234            ctx.fill();
1235        }
1236        return canvas;
1237    }
1238
1239    function _getHtmlResult(data) {
1240        var points = data.points,
1241            div = document.createElement('div'),
1242            img = document.createElement('img'),
1243            width = points[2] - points[0],
1244            height = points[3] - points[1];
1245
1246        addClass(div, 'croppie-result');
1247        div.appendChild(img);
1248        css(img, {
1249            left: (-1 * points[0]) + 'px',
1250            top: (-1 * points[1]) + 'px'
1251        });
1252        img.src = data.url;
1253        css(div, {
1254            width: width + 'px',
1255            height: height + 'px'
1256        });
1257
1258        return div;
1259    }
1260
1261    function _getBase64Result(data) {
1262        return _getCanvas.call(this, data).toDataURL(data.format, data.quality);
1263    }
1264
1265    function _getBlobResult(data) {
1266        var self = this;
1267        return new Promise(function (resolve) {
1268            _getCanvas.call(self, data).toBlob(function (blob) {
1269                resolve(blob);
1270            }, data.format, data.quality);
1271        });
1272    }
1273
1274    function _replaceImage(img) {
1275        if (this.elements.img.parentNode) {
1276            Array.prototype.forEach.call(this.elements.img.classList, function(c) { img.classList.add(c); });
1277            this.elements.img.parentNode.replaceChild(img, this.elements.img);
1278            this.elements.preview = img; // if the img is attached to the DOM, they're not using the canvas
1279        }
1280        this.elements.img = img;
1281    }
1282
1283    function _bind(options, cb) {
1284        var self = this,
1285            url,
1286            points = [],
1287            zoom = null,
1288            hasExif = _hasExif.call(self);
1289
1290        if (typeof (options) === 'string') {
1291            url = options;
1292            options = {};
1293        }
1294        else if (Array.isArray(options)) {
1295            points = options.slice();
1296        }
1297        else if (typeof (options) === 'undefined' && self.data.url) { //refreshing
1298            _updatePropertiesFromImage.call(self);
1299            _triggerUpdate.call(self);
1300            return null;
1301        }
1302        else {
1303            url = options.url;
1304            points = options.points || [];
1305            zoom = typeof(options.zoom) === 'undefined' ? null : options.zoom;
1306        }
1307
1308        self.data.bound = false;
1309        self.data.url = url || self.data.url;
1310        self.data.boundZoom = zoom;
1311
1312        return loadImage(url, hasExif).then(function (img) {
1313            _replaceImage.call(self, img);
1314            if (!points.length) {
1315                var natDim = naturalImageDimensions(img);
1316                var rect = self.elements.viewport.getBoundingClientRect();
1317                var aspectRatio = rect.width / rect.height;
1318                var imgAspectRatio = natDim.width / natDim.height;
1319                var width, height;
1320
1321                if (imgAspectRatio > aspectRatio) {
1322                    height = natDim.height;
1323                    width = height * aspectRatio;
1324                }
1325                else {
1326                    width = natDim.width;
1327                    height = natDim.height / aspectRatio;
1328                }
1329
1330                var x0 = (natDim.width - width) / 2;
1331                var y0 = (natDim.height - height) / 2;
1332                var x1 = x0 + width;
1333                var y1 = y0 + height;
1334                self.data.points = [x0, y0, x1, y1];
1335            }
1336            else if (self.options.relative) {
1337                points = [
1338                    points[0] * img.naturalWidth / 100,
1339                    points[1] * img.naturalHeight / 100,
1340                    points[2] * img.naturalWidth / 100,
1341                    points[3] * img.naturalHeight / 100
1342                ];
1343            }
1344
1345            self.data.
vendor: 5,012 bytes, lines 1345-1485
1345points = points.map(function (p) {
1346                return parseFloat(p);
1347            });
1348            if (self.options.useCanvas) {
1349                _transferImageToCanvas.call(self, options.orientation);
1350            }
1351            _updatePropertiesFromImage.call(self);
1352            _triggerUpdate.call(self);
1353            cb && cb();
1354        });
1355    }
1356
1357    function fix(v, decimalPoints) {
1358        return parseFloat(v).toFixed(decimalPoints || 0);
1359    }
1360
1361    function _get() {
1362        var self = this,
1363            imgData = self.elements.preview.getBoundingClientRect(),
1364            vpData = self.elements.viewport.getBoundingClientRect(),
1365            x1 = vpData.left - imgData.left,
1366            y1 = vpData.top - imgData.top,
1367            widthDiff = (vpData.width - self.elements.viewport.offsetWidth) / 2, //border
1368            heightDiff = (vpData.height - self.elements.viewport.offsetHeight) / 2,
1369            x2 = x1 + self.elements.viewport.offsetWidth + widthDiff,
1370            y2 = y1 + self.elements.viewport.offsetHeight + heightDiff,
1371            scale = self._currentZoom;
1372
1373        if (scale === Infinity || isNaN(scale)) {
1374            scale = 1;
1375        }
1376
1377        var max = self.options.enforceBoundary ? 0 : Number.NEGATIVE_INFINITY;
1378        x1 = Math.max(max, x1 / scale);
1379        y1 = Math.max(max, y1 / scale);
1380        x2 = Math.max(max, x2 / scale);
1381        y2 = Math.max(max, y2 / scale);
1382
1383        return {
1384            points: [fix(x1), fix(y1), fix(x2), fix(y2)],
1385            zoom: scale,
1386            orientation: self.data.orientation
1387        };
1388    }
1389
1390    var RESULT_DEFAULTS = {
1391            type: 'canvas',
1392            format: 'png',
1393            quality: 1
1394        },
1395        RESULT_FORMATS = ['jpeg', 'webp', 'png'];
1396
1397    function _result(options) {
1398        var self = this,
1399            data = _get.call(self),
1400            opts = deepExtend(clone(RESULT_DEFAULTS), clone(options)),
1401            resultType = (typeof (options) === 'string' ? options : (opts.type || 'base64')),
1402            size = opts.size || 'viewport',
1403            format = opts.format,
1404            quality = opts.quality,
1405            backgroundColor = opts.backgroundColor,
1406            circle = typeof opts.circle === 'boolean' ? opts.circle : (self.options.viewport.type === 'circle'),
1407            vpRect = self.elements.viewport.getBoundingClientRect(),
1408            ratio = vpRect.width / vpRect.height,
1409            prom;
1410
1411        if (size === 'viewport') {
1412            data.outputWidth = vpRect.width;
1413            data.outputHeight = vpRect.height;
1414        } else if (typeof size === 'object') {
1415            if (size.width && size.height) {
1416                data.outputWidth = size.width;
1417                data.outputHeight = size.height;
1418            } else if (size.width) {
1419                data.outputWidth = size.width;
1420                data.outputHeight = size.width / ratio;
1421            } else if (size.height) {
1422                data.outputWidth = size.height * ratio;
1423                data.outputHeight = size.height;
1424            }
1425        }
1426
1427        if (RESULT_FORMATS.indexOf(format) > -1) {
1428            data.format = 'image/' + format;
1429            data.quality = quality;
1430        }
1431
1432        data.circle = circle;
1433        data.url = self.data.url;
1434        data.backgroundColor = backgroundColor;
1435
1436        prom = new Promise(function (resolve) {
1437            switch(resultType.toLowerCase())
1438            {
1439                case 'rawcanvas':
1440                    resolve(_getCanvas.call(self, data));
1441                    break;
1442                case 'canvas':
1443                case 'base64':
1444                    resolve(_getBase64Result.call(self, data));
1445                    break;
1446                case 'blob':
1447                    _getBlobResult.call(self, data).then(resolve);
1448                    break;
1449                default:
1450                    resolve(_getHtmlResult.call(self, data));
1451                    break;
1452            }
1453        });
1454        return prom;
1455    }
1456
1457    function _refresh() {
1458        _updatePropertiesFromImage.call(this);
1459    }
1460
1461    function _rotate(deg) {
1462        if (!this.options.useCanvas || !this.options.enableOrientation) {
1463            throw 'Croppie: Cannot rotate without enableOrientation && EXIF.js included';
1464        }
1465
1466        var self = this,
1467            canvas = self.elements.canvas;
1468
1469        self.data.orientation = getExifOffset(self.data.orientation, deg);
1470        drawCanvas(canvas, self.elements.img, self.data.orientation);
1471        _updateCenterPoint.call(self, true);
1472        _updateZoomLimits.call(self);
1473    }
1474
1475    function _destroy() {
1476        var self = this;
1477        self.element.removeChild(self.elements.boundary);
1478        removeClass(self.element, 'croppie-container');
1479        if (self.options.enableZoom) {
1480            self.element.removeChild(self.elements.zoomerWrap);
1481        }
1482        delete self.elements;
1483    }
1484
1485    if (
vendor: 4,616 bytes, lines 1485-1625
1485window.jQuery) {
1486        var $ = window.jQuery;
1487        $.fn.croppie = function (opts) {
1488            var ot = typeof opts;
1489
1490            if (ot === 'string') {
1491                var args = Array.prototype.slice.call(arguments, 1);
1492                var singleInst = $(this).data('croppie');
1493
1494                if (opts === 'get') {
1495                    return singleInst.get();
1496                }
1497                else if (opts === 'result') {
1498                    return singleInst.result.apply(singleInst, args);
1499                }
1500                else if (opts === 'bind') {
1501                    return singleInst.bind.apply(singleInst, args);
1502                }
1503
1504                return this.each(function () {
1505                    var i = $(this).data('croppie');
1506                    if (!i) return;
1507
1508                    var method = i[opts];
1509                    if ($.isFunction(method)) {
1510                        method.apply(i, args);
1511                        if (opts === 'destroy') {
1512                            $(this).removeData('croppie');
1513                        }
1514                    }
1515                    else {
1516                        throw 'Croppie ' + opts + ' method not found';
1517                    }
1518                });
1519            }
1520            else {
1521                return this.each(function () {
1522                    var i = new Croppie(this, opts);
1523                    i.$ = $;
1524                    $(this).data('croppie', i);
1525                });
1526            }
1527        };
1528    }
1529
1530    function Croppie(element, opts) {
1531        if (element.className.indexOf('croppie-container') > -1) {
1532            throw new Error("Croppie: Can't initialize croppie more than once");
1533        }
1534        this.element = element;
1535        this.options = deepExtend(clone(Croppie.defaults), opts);
1536
1537        if (this.element.tagName.toLowerCase() === 'img') {
1538            var origImage = this.element;
1539            addClass(origImage, 'cr-original-image');
1540            setAttributes(origImage, {'aria-hidden' : 'true', 'alt' : '' });
1541            var replacementDiv = document.createElement('div');
1542            this.element.parentNode.appendChild(replacementDiv);
1543            replacementDiv.appendChild(origImage);
1544            this.element = replacementDiv;
1545            this.options.url = this.options.url || origImage.src;
1546        }
1547
1548        _create.call(this);
1549        if (this.options.url) {
1550            var bindOpts = {
1551                url: this.options.url,
1552                points: this.options.points
1553            };
1554            delete this.options['url'];
1555            delete this.options['points'];
1556            _bind.call(this, bindOpts);
1557        }
1558    }
1559
1560    Croppie.defaults = {
1561        viewport: {
1562            width: 100,
1563            height: 100,
1564            type: 'square'
1565        },
1566        boundary: { },
1567        orientationControls: {
1568            enabled: true,
1569            leftClass: '',
1570            rightClass: ''
1571        },
1572        resizeControls: {
1573            width: true,
1574            height: true
1575        },
1576        customClass: '',
1577        showZoomer: true,
1578        enableZoom: true,
1579        enableResize: false,
1580        mouseWheelZoom: true,
1581        enableExif: false,
1582        enforceBoundary: true,
1583        enableOrientation: false,
1584        enableKeyMovement: true,
1585        update: function () { }
1586    };
1587
1588    Croppie.globals = {
1589        translate: 'translate3d'
1590    };
1591
1592    deepExtend(Croppie.prototype, {
1593        bind: function (options, cb) {
1594            return _bind.call(this, options, cb);
1595        },
1596        get: function () {
1597            var data = _get.call(this);
1598            var points = data.points;
1599            if (this.options.relative) {
1600                points[0] /= this.elements.img.naturalWidth / 100;
1601                points[1] /= this.elements.img.naturalHeight / 100;
1602                points[2] /= this.elements.img.naturalWidth / 100;
1603                points[3] /= this.elements.img.naturalHeight / 100;
1604            }
1605            return data;
1606        },
1607        result: function (type) {
1608            return _result.call(this, type);
1609        },
1610        refresh: function () {
1611            return _refresh.call(this);
1612        },
1613        setZoom: function (v) {
1614            _setZoomerVal.call(this, v);
1615            dispatchChange(this.elements.zoomer);
1616        },
1617        rotate: function (deg) {
1618            _rotate.call(this, deg);
1619        },
1620        destroy: function () {
1621            return _destroy.call(this);
1622        }
1623    });
1624    return Croppie;
1625}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.