├── .gitattributes
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── LICENSE
├── README.md
├── bower.json
├── croppie.css
├── croppie.js
├── croppie.min.js
├── demo
├── cat.jpg
├── demo-1.jpg
├── demo-2.jpg
├── demo-3.jpg
├── demo.css
├── demo.js
├── hero.png
├── prism.css
└── prism.js
├── deploy.js
├── index.html
├── package-lock.json
├── package.json
└── test
└── unit
├── Croppie.js
├── mocha.opts
└── stubs
├── DOMTokenList.js
├── EventTarget.js
├── HTMLElement.js
├── document.js
└── window.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | text eol=lf
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Expected Behavior
2 |
3 |
4 | ## Actual Behavior
5 |
6 |
7 | ## Steps to Reproduce the Problem
8 |
9 | 1.
10 | 1.
11 | 1.
12 |
13 | ## Example Link
14 | Please recreate your issue using [JSbin](https://www.jsbin.com), [JSFiddle](https://jsfiddle.net), or [Codepen](https://codepen.io).
15 | * Link:
16 |
17 |
18 | ## Specifications
19 |
20 | - Browser:
21 | - Version:
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | npm-debug.log
3 | node_modules/
4 | bower_components
5 | /nbproject/private/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Foliotek Inc
2 | -------------------------------
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6 | persons to whom the Software is furnished to do so, subject to the following conditions:
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
8 | Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
11 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
13 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Croppie - A Javascript Image Cropper
2 |
3 |
4 | ## To Install
5 | Bower: `bower install croppie`
6 |
7 | Npm: `npm install croppie`
8 |
9 | Download:
10 | [croppie.js](croppie.js) & [croppie.css](croppie.css)
11 |
12 | ## Adding croppie to your site
13 | ```html
14 |
15 |
16 | ```
17 |
18 | ## CDN
19 | cdnjs.com provides croppie via cdn https://cdnjs.com/libraries/croppie
20 | ```
21 | https://cdnjs.cloudflare.com/ajax/libs/croppie/{version}/croppie.min.css
22 | https://cdnjs.cloudflare.com/ajax/libs/croppie/{version}/croppie.min.js
23 | ```
24 |
25 |
26 | ## Documentation
27 | [Documentation](http://foliotek.github.io/Croppie#documentation)
28 |
29 | ## Related Libraries
30 | * [croppie-dart](https://gitlab.com/michel.werren/croppie-dart)
31 | * [ngCroppie](https://github.com/allenRoyston/ngCroppie)
32 | * [angular-croppie](https://github.com/lpsBetty/angular-croppie)
33 | * [django-croppie](https://github.com/dima-kov/django-croppie)
34 | * [vue-croppie](https://github.com/jofftiquez/vue-croppie)
35 |
36 | ## Contributing
37 | First, thanks for contributing. This project is difficult to maintain with one person. Here's a "checklist" of things to remember when contributing to croppie.
38 | * Don't forget to update the documentation.
39 | * If you're adding a new option/event/method, try adding to an example on the documentation. Or create a new example, if you feel the need.
40 | * We don't have tests for Croppie :( (if you want to create tests I'd be forever grateful), so please try to test the functionality you're changing on the demo page. I've tried to add as many use-cases as I can think of on there. Compare the functionality in your branch to the one on the official page. If they all still work, then great!
41 |
42 | If you're looking for a simple server to load the demo page, I use https://github.com/tapio/live-server.
43 |
44 | #### Minifying
45 | `uglifyjs croppie.js -c -m -r '$,require,exports' -o croppie.min.js`
46 |
47 | #### Releasing a new version
48 | For the most part, you shouldn't worry about these steps unless you're the one handling the release. Please don't bump the release and don't minify/uglify in a PR. That just creates merge conflicts when merging. Those steps will be performed when the release is created.
49 | 1. Bump version in croppie.js
50 | 2. Minify/Uglify
51 | 3. Commit
52 | 4. npm version [new version]
53 | 5. `git push && git push --tags`
54 | 6. `npm publish`
55 | 7. Draft a new release with new tag on https://github.com/Foliotek/Croppie/releases
56 | 8. Deploy to gh-pages `npm run deploy`
57 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Croppie",
3 | "homepage": "https://github.com/Foliotek/Croppie",
4 | "authors": [
5 | "Dustin Smith ",
6 | "Ethan Calvert "
7 | ],
8 | "description": "A javascript image cropper",
9 | "main": [
10 | "croppie.css",
11 | "croppie.js"
12 | ],
13 | "moduleType": [],
14 | "keywords": [
15 | "image",
16 | "cropper",
17 | "croppie"
18 | ],
19 | "license": "MIT",
20 | "ignore": [
21 | "**/.*",
22 | "node_modules",
23 | "bower_components",
24 | "demo",
25 | "test",
26 | "tests",
27 | "index.html"
28 | ],
29 | "dependencies": {},
30 | "devDependencies": {
31 | "sweetalert": "~1.1.3",
32 | "jquery": "~2.1.4",
33 | "exif-js": "~2.1.1"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/croppie.css:
--------------------------------------------------------------------------------
1 | .croppie-container {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .croppie-container .cr-image {
7 | z-index: -1;
8 | position: absolute;
9 | top: 0;
10 | left: 0;
11 | transform-origin: 0 0;
12 | max-height: none;
13 | max-width: none;
14 | }
15 |
16 | .croppie-container .cr-boundary {
17 | position: relative;
18 | overflow: hidden;
19 | margin: 0 auto;
20 | z-index: 1;
21 | width: 100%;
22 | height: 100%;
23 | }
24 |
25 | .croppie-container .cr-viewport,
26 | .croppie-container .cr-resizer {
27 | position: absolute;
28 | border: 2px solid #fff;
29 | margin: auto;
30 | top: 0;
31 | bottom: 0;
32 | right: 0;
33 | left: 0;
34 | box-shadow: 0 0 2000px 2000px rgba(0, 0, 0, 0.5);
35 | z-index: 0;
36 | }
37 |
38 | .croppie-container .cr-resizer {
39 | z-index: 2;
40 | box-shadow: none;
41 | pointer-events: none;
42 | }
43 |
44 | .croppie-container .cr-resizer-vertical,
45 | .croppie-container .cr-resizer-horisontal {
46 | position: absolute;
47 | pointer-events: all;
48 | }
49 |
50 | .croppie-container .cr-resizer-vertical::after,
51 | .croppie-container .cr-resizer-horisontal::after {
52 | display: block;
53 | position: absolute;
54 | box-sizing: border-box;
55 | border: 1px solid black;
56 | background: #fff;
57 | width: 10px;
58 | height: 10px;
59 | content: '';
60 | }
61 |
62 | .croppie-container .cr-resizer-vertical {
63 | bottom: -5px;
64 | cursor: row-resize;
65 | width: 100%;
66 | height: 10px;
67 | }
68 |
69 | .croppie-container .cr-resizer-vertical::after {
70 | left: 50%;
71 | margin-left: -5px;
72 | }
73 |
74 | .croppie-container .cr-resizer-horisontal {
75 | right: -5px;
76 | cursor: col-resize;
77 | width: 10px;
78 | height: 100%;
79 | }
80 |
81 | .croppie-container .cr-resizer-horisontal::after {
82 | top: 50%;
83 | margin-top: -5px;
84 | }
85 |
86 | .croppie-container .cr-original-image {
87 | display: none;
88 | }
89 |
90 | .croppie-container .cr-vp-circle {
91 | border-radius: 50%;
92 | }
93 |
94 | .croppie-container .cr-overlay {
95 | z-index: 1;
96 | position: absolute;
97 | cursor: move;
98 | touch-action: none;
99 | }
100 |
101 | .croppie-container .cr-slider-wrap {
102 | width: 75%;
103 | margin: 15px auto;
104 | text-align: center;
105 | }
106 |
107 | .croppie-result {
108 | position: relative;
109 | overflow: hidden;
110 | }
111 |
112 | .croppie-result img {
113 | position: absolute;
114 | }
115 |
116 | .croppie-container .cr-image,
117 | .croppie-container .cr-overlay,
118 | .croppie-container .cr-viewport {
119 | -webkit-transform: translateZ(0);
120 | -moz-transform: translateZ(0);
121 | -ms-transform: translateZ(0);
122 | transform: translateZ(0);
123 | }
124 |
125 | /*************************************/
126 | /***** STYLING RANGE INPUT ***********/
127 | /*************************************/
128 | /*http://brennaobrien.com/blog/2014/05/style-input-type-range-in-every-browser.html */
129 | /*************************************/
130 |
131 | .cr-slider {
132 | -webkit-appearance: none;
133 | /*removes default webkit styles*/
134 | /*border: 1px solid white; *//*fix for FF unable to apply focus style bug */
135 | width: 300px;
136 | /*required for proper track sizing in FF*/
137 | max-width: 100%;
138 | padding-top: 8px;
139 | padding-bottom: 8px;
140 | background-color: transparent;
141 | }
142 |
143 | .cr-slider::-webkit-slider-runnable-track {
144 | width: 100%;
145 | height: 3px;
146 | background: rgba(0, 0, 0, 0.5);
147 | border: 0;
148 | border-radius: 3px;
149 | }
150 |
151 | .cr-slider::-webkit-slider-thumb {
152 | -webkit-appearance: none;
153 | border: none;
154 | height: 16px;
155 | width: 16px;
156 | border-radius: 50%;
157 | background: #ddd;
158 | margin-top: -6px;
159 | }
160 |
161 | .cr-slider:focus {
162 | outline: none;
163 | }
164 | /*
165 | .cr-slider:focus::-webkit-slider-runnable-track {
166 | background: #ccc;
167 | }
168 | */
169 |
170 | .cr-slider::-moz-range-track {
171 | width: 100%;
172 | height: 3px;
173 | background: rgba(0, 0, 0, 0.5);
174 | border: 0;
175 | border-radius: 3px;
176 | }
177 |
178 | .cr-slider::-moz-range-thumb {
179 | border: none;
180 | height: 16px;
181 | width: 16px;
182 | border-radius: 50%;
183 | background: #ddd;
184 | margin-top: -6px;
185 | }
186 |
187 | /*hide the outline behind the border*/
188 | .cr-slider:-moz-focusring {
189 | outline: 1px solid white;
190 | outline-offset: -1px;
191 | }
192 |
193 | .cr-slider::-ms-track {
194 | width: 100%;
195 | height: 5px;
196 | background: transparent;
197 | /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
198 | border-color: transparent;/*leave room for the larger thumb to overflow with a transparent border */
199 | border-width: 6px 0;
200 | color: transparent;/*remove default tick marks*/
201 | }
202 | .cr-slider::-ms-fill-lower {
203 | background: rgba(0, 0, 0, 0.5);
204 | border-radius: 10px;
205 | }
206 | .cr-slider::-ms-fill-upper {
207 | background: rgba(0, 0, 0, 0.5);
208 | border-radius: 10px;
209 | }
210 | .cr-slider::-ms-thumb {
211 | border: none;
212 | height: 16px;
213 | width: 16px;
214 | border-radius: 50%;
215 | background: #ddd;
216 | margin-top:1px;
217 | }
218 | .cr-slider:focus::-ms-fill-lower {
219 | background: rgba(0, 0, 0, 0.5);
220 | }
221 | .cr-slider:focus::-ms-fill-upper {
222 | background: rgba(0, 0, 0, 0.5);
223 | }
224 | /*******************************************/
225 |
226 | /***********************************/
227 | /* Rotation Tools */
228 | /***********************************/
229 | .cr-rotate-controls {
230 | position: absolute;
231 | bottom: 5px;
232 | left: 5px;
233 | z-index: 1;
234 | }
235 | .cr-rotate-controls button {
236 | border: 0;
237 | background: none;
238 | }
239 | .cr-rotate-controls i:before {
240 | display: inline-block;
241 | font-style: normal;
242 | font-weight: 900;
243 | font-size: 22px;
244 | }
245 | .cr-rotate-l i:before {
246 | content: '↺';
247 | }
248 | .cr-rotate-r i:before {
249 | content: '↻';
250 | }
251 |
--------------------------------------------------------------------------------
/croppie.js:
--------------------------------------------------------------------------------
1 | /*************************
2 | * Croppie
3 | * Copyright 2019
4 | * Foliotek
5 | * Version: 2.6.5
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;fd;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 !== 'undefined' && 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 (typeof HTMLCanvasElement !== 'undefined' && !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 -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) {
179 | if (!src) { throw 'Source image missing'; }
180 |
181 | var img = new Image();
182 | img.style.opacity = '0';
183 | return new Promise(function (resolve, reject) {
184 | function _resolve() {
185 | img.style.opacity = '1';
186 | setTimeout(function () {
187 | resolve(img);
188 | }, 1);
189 | }
190 |
191 | img.removeAttribute('crossOrigin');
192 | if (src.match(/^https?:\/\/|^\/\//)) {
193 | img.setAttribute('crossOrigin', 'anonymous');
194 | }
195 |
196 | img.onload = function () {
197 | if (doExif) {
198 | EXIF.getData(img, function () {
199 | _resolve();
200 | });
201 | }
202 | else {
203 | _resolve();
204 | }
205 | };
206 | img.onerror = function (ev) {
207 | img.style.opacity = 1;
208 | setTimeout(function () {
209 | reject(ev);
210 | }, 1);
211 | };
212 | img.src = src;
213 | });
214 | }
215 |
216 | function naturalImageDimensions(img, ornt) {
217 | var w = img.naturalWidth;
218 | var h = img.naturalHeight;
219 | var orient = ornt || getExifOrientation(img);
220 | if (orient && orient >= 5) {
221 | var x= w;
222 | w = h;
223 | h = x;
224 | }
225 | return { width: w, height: h };
226 | }
227 |
228 | /* CSS Transform Prototype */
229 | var TRANSLATE_OPTS = {
230 | 'translate3d': {
231 | suffix: ', 0px'
232 | },
233 | 'translate': {
234 | suffix: ''
235 | }
236 | };
237 | var Transform = function (x, y, scale) {
238 | this.x = parseFloat(x);
239 | this.y = parseFloat(y);
240 | this.scale = parseFloat(scale);
241 | };
242 |
243 | Transform.parse = function (v) {
244 | if (v.style) {
245 | return Transform.parse(v.style[CSS_TRANSFORM]);
246 | }
247 | else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) {
248 | return Transform.fromMatrix(v);
249 | }
250 | else {
251 | return Transform.fromString(v);
252 | }
253 | };
254 |
255 | Transform.fromMatrix = function (v) {
256 | var vals = v.substring(7).split(',');
257 | if (!vals.length || v === 'none') {
258 | vals = [1, 0, 0, 1, 0, 0];
259 | }
260 |
261 | return new Transform(num(vals[4]), num(vals[5]), parseFloat(vals[0]));
262 | };
263 |
264 | Transform.fromString = function (v) {
265 | var values = v.split(') '),
266 | translate = values[0].substring(Croppie.globals.translate.length + 1).split(','),
267 | scale = values.length > 1 ? values[1].substring(6) : 1,
268 | x = translate.length > 1 ? translate[0] : 0,
269 | y = translate.length > 1 ? translate[1] : 0;
270 |
271 | return new Transform(x, y, scale);
272 | };
273 |
274 | Transform.prototype.toString = function () {
275 | var suffix = TRANSLATE_OPTS[Croppie.globals.translate].suffix || '';
276 | return Croppie.globals.translate + '(' + this.x + 'px, ' + this.y + 'px' + suffix + ') scale(' + this.scale + ')';
277 | };
278 |
279 | var TransformOrigin = function (el) {
280 | if (!el || !el.style[CSS_TRANS_ORG]) {
281 | this.x = 0;
282 | this.y = 0;
283 | return;
284 | }
285 | var css = el.style[CSS_TRANS_ORG].split(' ');
286 | this.x = parseFloat(css[0]);
287 | this.y = parseFloat(css[1]);
288 | };
289 |
290 | TransformOrigin.prototype.toString = function () {
291 | return this.x + 'px ' + this.y + 'px';
292 | };
293 |
294 | function getExifOrientation (img) {
295 | return img.exifdata && img.exifdata.Orientation ? num(img.exifdata.Orientation) : 1;
296 | }
297 |
298 | function drawCanvas(canvas, img, orientation) {
299 | var width = img.width,
300 | height = img.height,
301 | ctx = canvas.getContext('2d');
302 |
303 | canvas.width = img.width;
304 | canvas.height = img.height;
305 |
306 | ctx.save();
307 | switch (orientation) {
308 | case 2:
309 | ctx.translate(width, 0);
310 | ctx.scale(-1, 1);
311 | break;
312 |
313 | case 3:
314 | ctx.translate(width, height);
315 | ctx.rotate(180*Math.PI/180);
316 | break;
317 |
318 | case 4:
319 | ctx.translate(0, height);
320 | ctx.scale(1, -1);
321 | break;
322 |
323 | case 5:
324 | canvas.width = height;
325 | canvas.height = width;
326 | ctx.rotate(90*Math.PI/180);
327 | ctx.scale(1, -1);
328 | break;
329 |
330 | case 6:
331 | canvas.width = height;
332 | canvas.height = width;
333 | ctx.rotate(90*Math.PI/180);
334 | ctx.translate(0, -height);
335 | break;
336 |
337 | case 7:
338 | canvas.width = height;
339 | canvas.height = width;
340 | ctx.rotate(-90*Math.PI/180);
341 | ctx.translate(-width, height);
342 | ctx.scale(1, -1);
343 | break;
344 |
345 | case 8:
346 | canvas.width = height;
347 | canvas.height = width;
348 | ctx.translate(0, width);
349 | ctx.rotate(-90*Math.PI/180);
350 | break;
351 | }
352 | ctx.drawImage(img, 0,0, width, height);
353 | ctx.restore();
354 | }
355 |
356 | /* Private Methods */
357 | function _create() {
358 | var self = this,
359 | contClass = 'croppie-container',
360 | customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null,
361 | boundary, img, viewport, overlay, bw, bh;
362 |
363 | self.options.useCanvas = self.options.enableOrientation || _hasExif.call(self);
364 | // Properties on class
365 | self.data = {};
366 | self.elements = {};
367 |
368 | boundary = self.elements.boundary = document.createElement('div');
369 | viewport = self.elements.viewport = document.createElement('div');
370 | img = self.elements.img = document.createElement('img');
371 | overlay = self.elements.overlay = document.createElement('div');
372 |
373 | if (self.options.useCanvas) {
374 | self.elements.canvas = document.createElement('canvas');
375 | self.elements.preview = self.elements.canvas;
376 | }
377 | else {
378 | self.elements.preview = img;
379 | }
380 |
381 | addClass(boundary, 'cr-boundary');
382 | boundary.setAttribute('aria-dropeffect', 'none');
383 | bw = self.options.boundary.width;
384 | bh = self.options.boundary.height;
385 | css(boundary, {
386 | width: (bw + (isNaN(bw) ? '' : 'px')),
387 | height: (bh + (isNaN(bh) ? '' : 'px'))
388 | });
389 |
390 | addClass(viewport, 'cr-viewport');
391 | if (customViewportClass) {
392 | addClass(viewport, customViewportClass);
393 | }
394 | css(viewport, {
395 | width: self.options.viewport.width + 'px',
396 | height: self.options.viewport.height + 'px'
397 | });
398 | viewport.setAttribute('tabindex', 0);
399 |
400 | addClass(self.elements.preview, 'cr-image');
401 | setAttributes(self.elements.preview, { 'alt': 'preview', 'aria-grabbed': 'false' });
402 | addClass(overlay, 'cr-overlay');
403 |
404 | self.element.appendChild(boundary);
405 | boundary.appendChild(self.elements.preview);
406 | boundary.appendChild(viewport);
407 | boundary.appendChild(overlay);
408 |
409 | addClass(self.element, contClass);
410 | if (self.options.customClass) {
411 | addClass(self.element, self.options.customClass);
412 | }
413 |
414 | _initDraggable.call(this);
415 |
416 | if (self.options.enableZoom) {
417 | _initializeZoom.call(self);
418 | }
419 |
420 | // if (self.options.enableOrientation) {
421 | // _initRotationControls.call(self);
422 | // }
423 |
424 | if (self.options.enableResize) {
425 | _initializeResize.call(self);
426 | }
427 | }
428 |
429 | // function _initRotationControls () {
430 | // var self = this,
431 | // wrap, btnLeft, btnRight, iLeft, iRight;
432 |
433 | // wrap = document.createElement('div');
434 | // self.elements.orientationBtnLeft = btnLeft = document.createElement('button');
435 | // self.elements.orientationBtnRight = btnRight = document.createElement('button');
436 |
437 | // wrap.appendChild(btnLeft);
438 | // wrap.appendChild(btnRight);
439 |
440 | // iLeft = document.createElement('i');
441 | // iRight = document.createElement('i');
442 | // btnLeft.appendChild(iLeft);
443 | // btnRight.appendChild(iRight);
444 |
445 | // addClass(wrap, 'cr-rotate-controls');
446 | // addClass(btnLeft, 'cr-rotate-l');
447 | // addClass(btnRight, 'cr-rotate-r');
448 |
449 | // self.elements.boundary.appendChild(wrap);
450 |
451 | // btnLeft.addEventListener('click', function () {
452 | // self.rotate(-90);
453 | // });
454 | // btnRight.addEventListener('click', function () {
455 | // self.rotate(90);
456 | // });
457 | // }
458 |
459 | function _hasExif() {
460 | return this.options.enableExif && window.EXIF;
461 | }
462 |
463 | function _initializeResize () {
464 | var self = this;
465 | var wrap = document.createElement('div');
466 | var isDragging = false;
467 | var direction;
468 | var originalX;
469 | var originalY;
470 | var minSize = 50;
471 | var maxWidth;
472 | var maxHeight;
473 | var vr;
474 | var hr;
475 |
476 | addClass(wrap, 'cr-resizer');
477 | css(wrap, {
478 | width: this.options.viewport.width + 'px',
479 | height: this.options.viewport.height + 'px'
480 | });
481 |
482 | if (this.options.resizeControls.height) {
483 | vr = document.createElement('div');
484 | addClass(vr, 'cr-resizer-vertical');
485 | wrap.appendChild(vr);
486 | }
487 |
488 | if (this.options.resizeControls.width) {
489 | hr = document.createElement('div');
490 | addClass(hr, 'cr-resizer-horisontal');
491 | wrap.appendChild(hr);
492 | }
493 |
494 | function mouseDown(ev) {
495 | if (ev.button !== undefined && ev.button !== 0) return;
496 |
497 | ev.preventDefault();
498 | if (isDragging) {
499 | return;
500 | }
501 |
502 | var overlayRect = self.elements.overlay.getBoundingClientRect();
503 |
504 | isDragging = true;
505 | originalX = ev.pageX;
506 | originalY = ev.pageY;
507 | direction = ev.currentTarget.className.indexOf('vertical') !== -1 ? 'v' : 'h';
508 | maxWidth = overlayRect.width;
509 | maxHeight = overlayRect.height;
510 |
511 | if (ev.touches) {
512 | var touches = ev.touches[0];
513 | originalX = touches.pageX;
514 | originalY = touches.pageY;
515 | }
516 |
517 | window.addEventListener('mousemove', mouseMove);
518 | window.addEventListener('touchmove', mouseMove);
519 | window.addEventListener('mouseup', mouseUp);
520 | window.addEventListener('touchend', mouseUp);
521 | document.body.style[CSS_USERSELECT] = 'none';
522 | }
523 |
524 | function mouseMove(ev) {
525 | var pageX = ev.pageX;
526 | var pageY = ev.pageY;
527 |
528 | ev.preventDefault();
529 |
530 | if (ev.touches) {
531 | var touches = ev.touches[0];
532 | pageX = touches.pageX;
533 | pageY = touches.pageY;
534 | }
535 |
536 | var deltaX = pageX - originalX;
537 | var deltaY = pageY - originalY;
538 | var newHeight = self.options.viewport.height + deltaY;
539 | var newWidth = self.options.viewport.width + deltaX;
540 |
541 | if (direction === 'v' && newHeight >= minSize && newHeight <= maxHeight) {
542 | css(wrap, {
543 | height: newHeight + 'px'
544 | });
545 |
546 | self.options.boundary.height += deltaY;
547 | css(self.elements.boundary, {
548 | height: self.options.boundary.height + 'px'
549 | });
550 |
551 | self.options.viewport.height += deltaY;
552 | css(self.elements.viewport, {
553 | height: self.options.viewport.height + 'px'
554 | });
555 | }
556 | else if (direction === 'h' && newWidth >= minSize && newWidth <= maxWidth) {
557 | css(wrap, {
558 | width: newWidth + 'px'
559 | });
560 |
561 | self.options.boundary.width += deltaX;
562 | css(self.elements.boundary, {
563 | width: self.options.boundary.width + 'px'
564 | });
565 |
566 | self.options.viewport.width += deltaX;
567 | css(self.elements.viewport, {
568 | width: self.options.viewport.width + 'px'
569 | });
570 | }
571 |
572 | _updateOverlay.call(self);
573 | _updateZoomLimits.call(self);
574 | _updateCenterPoint.call(self);
575 | _triggerUpdate.call(self);
576 | originalY = pageY;
577 | originalX = pageX;
578 | }
579 |
580 | function mouseUp() {
581 | isDragging = false;
582 | window.removeEventListener('mousemove', mouseMove);
583 | window.removeEventListener('touchmove', mouseMove);
584 | window.removeEventListener('mouseup', mouseUp);
585 | window.removeEventListener('touchend', mouseUp);
586 | document.body.style[CSS_USERSELECT] = '';
587 | }
588 |
589 | if (vr) {
590 | vr.addEventListener('mousedown', mouseDown);
591 | vr.addEventListener('touchstart', mouseDown);
592 | }
593 |
594 | if (hr) {
595 | hr.addEventListener('mousedown', mouseDown);
596 | hr.addEventListener('touchstart', mouseDown);
597 | }
598 |
599 | this.elements.boundary.appendChild(wrap);
600 | }
601 |
602 | function _setZoomerVal(v) {
603 | if (this.options.enableZoom) {
604 | var z = this.elements.zoomer,
605 | val = fix(v, 4);
606 |
607 | z.value = Math.max(parseFloat(z.min), Math.min(parseFloat(z.max), val)).toString();
608 | }
609 | }
610 |
611 | function _initializeZoom() {
612 | var self = this,
613 | wrap = self.elements.zoomerWrap = document.createElement('div'),
614 | zoomer = self.elements.zoomer = document.createElement('input');
615 |
616 | addClass(wrap, 'cr-slider-wrap');
617 | addClass(zoomer, 'cr-slider');
618 | zoomer.type = 'range';
619 | zoomer.step = '0.0001';
620 | zoomer.value = '1';
621 | zoomer.style.display = self.options.showZoomer ? '' : 'none';
622 | zoomer.setAttribute('aria-label', 'zoom');
623 |
624 | self.element.appendChild(wrap);
625 | wrap.appendChild(zoomer);
626 |
627 | self._currentZoom = 1;
628 |
629 | function change() {
630 | _onZoom.call(self, {
631 | value: parseFloat(zoomer.value),
632 | origin: new TransformOrigin(self.elements.preview),
633 | viewportRect: self.elements.viewport.getBoundingClientRect(),
634 | transform: Transform.parse(self.elements.preview)
635 | });
636 | }
637 |
638 | function scroll(ev) {
639 | var delta, targetZoom;
640 |
641 | if(self.options.mouseWheelZoom === 'ctrl' && ev.ctrlKey !== true){
642 | return 0;
643 | } else if (ev.wheelDelta) {
644 | delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2
645 | } else if (ev.deltaY) {
646 | delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2
647 | } else if (ev.detail) {
648 | delta = ev.detail / -60; //delta min: -3 max: 3 // max x 10 x 2
649 | } else {
650 | delta = 0;
651 | }
652 |
653 | targetZoom = self._currentZoom + (delta * self._currentZoom);
654 |
655 | ev.preventDefault();
656 | _setZoomerVal.call(self, targetZoom);
657 | change.call(self);
658 | }
659 |
660 | self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress
661 | self.elements.zoomer.addEventListener('change', change);
662 |
663 | if (self.options.mouseWheelZoom) {
664 | self.elements.boundary.addEventListener('mousewheel', scroll);
665 | self.elements.boundary.addEventListener('DOMMouseScroll', scroll);
666 | }
667 | }
668 |
669 | function _onZoom(ui) {
670 | var self = this,
671 | transform = ui ? ui.transform : Transform.parse(self.elements.preview),
672 | vpRect = ui ? ui.viewportRect : self.elements.viewport.getBoundingClientRect(),
673 | origin = ui ? ui.origin : new TransformOrigin(self.elements.preview);
674 |
675 | function applyCss() {
676 | var transCss = {};
677 | transCss[CSS_TRANSFORM] = transform.toString();
678 | transCss[CSS_TRANS_ORG] = origin.toString();
679 | css(self.elements.preview, transCss);
680 | }
681 |
682 | self._currentZoom = ui ? ui.value : self._currentZoom;
683 | transform.scale = self._currentZoom;
684 | self.elements.zoomer.setAttribute('aria-valuenow', self._currentZoom);
685 | applyCss();
686 |
687 | if (self.options.enforceBoundary) {
688 | var boundaries = _getVirtualBoundaries.call(self, vpRect),
689 | transBoundaries = boundaries.translate,
690 | oBoundaries = boundaries.origin;
691 |
692 | if (transform.x >= transBoundaries.maxX) {
693 | origin.x = oBoundaries.minX;
694 | transform.x = transBoundaries.maxX;
695 | }
696 |
697 | if (transform.x <= transBoundaries.minX) {
698 | origin.x = oBoundaries.maxX;
699 | transform.x = transBoundaries.minX;
700 | }
701 |
702 | if (transform.y >= transBoundaries.maxY) {
703 | origin.y = oBoundaries.minY;
704 | transform.y = transBoundaries.maxY;
705 | }
706 |
707 | if (transform.y <= transBoundaries.minY) {
708 | origin.y = oBoundaries.maxY;
709 | transform.y = transBoundaries.minY;
710 | }
711 | }
712 | applyCss();
713 | _debouncedOverlay.call(self);
714 | _triggerUpdate.call(self);
715 | }
716 |
717 | function _getVirtualBoundaries(viewport) {
718 | var self = this,
719 | scale = self._currentZoom,
720 | vpWidth = viewport.width,
721 | vpHeight = viewport.height,
722 | centerFromBoundaryX = self.elements.boundary.clientWidth / 2,
723 | centerFromBoundaryY = self.elements.boundary.clientHeight / 2,
724 | imgRect = self.elements.preview.getBoundingClientRect(),
725 | curImgWidth = imgRect.width,
726 | curImgHeight = imgRect.height,
727 | halfWidth = vpWidth / 2,
728 | halfHeight = vpHeight / 2;
729 |
730 | var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1;
731 | var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale)));
732 |
733 | var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1;
734 | var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale)));
735 |
736 | var originMinX = (1 / scale) * halfWidth;
737 | var originMaxX = (curImgWidth * (1 / scale)) - originMinX;
738 |
739 | var originMinY = (1 / scale) * halfHeight;
740 | var originMaxY = (curImgHeight * (1 / scale)) - originMinY;
741 |
742 | return {
743 | translate: {
744 | maxX: maxX,
745 | minX: minX,
746 | maxY: maxY,
747 | minY: minY
748 | },
749 | origin: {
750 | maxX: originMaxX,
751 | minX: originMinX,
752 | maxY: originMaxY,
753 | minY: originMinY
754 | }
755 | };
756 | }
757 |
758 | function _updateCenterPoint(rotate) {
759 | var self = this,
760 | scale = self._currentZoom,
761 | data = self.elements.preview.getBoundingClientRect(),
762 | vpData = self.elements.viewport.getBoundingClientRect(),
763 | transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]),
764 | pc = new TransformOrigin(self.elements.preview),
765 | top = (vpData.top - data.top) + (vpData.height / 2),
766 | left = (vpData.left - data.left) + (vpData.width / 2),
767 | center = {},
768 | adj = {};
769 |
770 | if (rotate) {
771 | var cx = pc.x;
772 | var cy = pc.y;
773 | var tx = transform.x;
774 | var ty = transform.y;
775 |
776 | center.y = cx;
777 | center.x = cy;
778 | transform.y = tx;
779 | transform.x = ty;
780 | }
781 | else {
782 | center.y = top / scale;
783 | center.x = left / scale;
784 |
785 | adj.y = (center.y - pc.y) * (1 - scale);
786 | adj.x = (center.x - pc.x) * (1 - scale);
787 |
788 | transform.x -= adj.x;
789 | transform.y -= adj.y;
790 | }
791 |
792 | var newCss = {};
793 | newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px';
794 | newCss[CSS_TRANSFORM] = transform.toString();
795 | css(self.elements.preview, newCss);
796 | }
797 |
798 | function _initDraggable() {
799 | var self = this,
800 | isDragging = false,
801 | originalX,
802 | originalY,
803 | originalDistance,
804 | vpRect,
805 | transform;
806 |
807 | function assignTransformCoordinates(deltaX, deltaY) {
808 | var imgRect = self.elements.preview.getBoundingClientRect(),
809 | top = transform.y + deltaY,
810 | left = transform.x + deltaX;
811 |
812 | if (self.options.enforceBoundary) {
813 | if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) {
814 | transform.y = top;
815 | }
816 |
817 | if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) {
818 | transform.x = left;
819 | }
820 | }
821 | else {
822 | transform.y = top;
823 | transform.x = left;
824 | }
825 | }
826 |
827 | function toggleGrabState(isDragging) {
828 | self.elements.preview.setAttribute('aria-grabbed', isDragging);
829 | self.elements.boundary.setAttribute('aria-dropeffect', isDragging? 'move': 'none');
830 | }
831 |
832 | function keyDown(ev) {
833 | var LEFT_ARROW = 37,
834 | UP_ARROW = 38,
835 | RIGHT_ARROW = 39,
836 | DOWN_ARROW = 40;
837 |
838 | if (ev.shiftKey && (ev.keyCode === UP_ARROW || ev.keyCode === DOWN_ARROW)) {
839 | var zoom;
840 | if (ev.keyCode === UP_ARROW) {
841 | zoom = parseFloat(self.elements.zoomer.value) + parseFloat(self.elements.zoomer.step)
842 | }
843 | else {
844 | zoom = parseFloat(self.elements.zoomer.value) - parseFloat(self.elements.zoomer.step)
845 | }
846 | self.setZoom(zoom);
847 | }
848 | else if (self.options.enableKeyMovement && (ev.keyCode >= 37 && ev.keyCode <= 40)) {
849 | ev.preventDefault();
850 | var movement = parseKeyDown(ev.keyCode);
851 |
852 | transform = Transform.parse(self.elements.preview);
853 | document.body.style[CSS_USERSELECT] = 'none';
854 | vpRect = self.elements.viewport.getBoundingClientRect();
855 | keyMove(movement);
856 | }
857 |
858 | function parseKeyDown(key) {
859 | switch (key) {
860 | case LEFT_ARROW:
861 | return [1, 0];
862 | case UP_ARROW:
863 | return [0, 1];
864 | case RIGHT_ARROW:
865 | return [-1, 0];
866 | case DOWN_ARROW:
867 | return [0, -1];
868 | }
869 | }
870 | }
871 |
872 | function keyMove(movement) {
873 | var deltaX = movement[0],
874 | deltaY = movement[1],
875 | newCss = {};
876 |
877 | assignTransformCoordinates(deltaX, deltaY);
878 |
879 | newCss[CSS_TRANSFORM] = transform.toString();
880 | css(self.elements.preview, newCss);
881 | _updateOverlay.call(self);
882 | document.body.style[CSS_USERSELECT] = '';
883 | _updateCenterPoint.call(self);
884 | _triggerUpdate.call(self);
885 | originalDistance = 0;
886 | }
887 |
888 | function mouseDown(ev) {
889 | if (ev.button !== undefined && ev.button !== 0) return;
890 |
891 | ev.preventDefault();
892 | if (isDragging) return;
893 | isDragging = true;
894 | originalX = ev.pageX;
895 | originalY = ev.pageY;
896 |
897 | if (ev.touches) {
898 | var touches = ev.touches[0];
899 | originalX = touches.pageX;
900 | originalY = touches.pageY;
901 | }
902 | toggleGrabState(isDragging);
903 | transform = Transform.parse(self.elements.preview);
904 | window.addEventListener('mousemove', mouseMove);
905 | window.addEventListener('touchmove', mouseMove);
906 | window.addEventListener('mouseup', mouseUp);
907 | window.addEventListener('touchend', mouseUp);
908 | document.body.style[CSS_USERSELECT] = 'none';
909 | vpRect = self.elements.viewport.getBoundingClientRect();
910 | }
911 |
912 | function mouseMove(ev) {
913 | ev.preventDefault();
914 | var pageX = ev.pageX,
915 | pageY = ev.pageY;
916 |
917 | if (ev.touches) {
918 | var touches = ev.touches[0];
919 | pageX = touches.pageX;
920 | pageY = touches.pageY;
921 | }
922 |
923 | var deltaX = pageX - originalX,
924 | deltaY = pageY - originalY,
925 | newCss = {};
926 |
927 | if (ev.type === 'touchmove') {
928 | if (ev.touches.length > 1) {
929 | var touch1 = ev.touches[0];
930 | var touch2 = ev.touches[1];
931 | var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY));
932 |
933 | if (!originalDistance) {
934 | originalDistance = dist / self._currentZoom;
935 | }
936 |
937 | var scale = dist / originalDistance;
938 |
939 | _setZoomerVal.call(self, scale);
940 | dispatchChange(self.elements.zoomer);
941 | return;
942 | }
943 | }
944 |
945 | assignTransformCoordinates(deltaX, deltaY);
946 |
947 | newCss[CSS_TRANSFORM] = transform.toString();
948 | css(self.elements.preview, newCss);
949 | _updateOverlay.call(self);
950 | originalY = pageY;
951 | originalX = pageX;
952 | }
953 |
954 | function mouseUp() {
955 | isDragging = false;
956 | toggleGrabState(isDragging);
957 | window.removeEventListener('mousemove', mouseMove);
958 | window.removeEventListener('touchmove', mouseMove);
959 | window.removeEventListener('mouseup', mouseUp);
960 | window.removeEventListener('touchend', mouseUp);
961 | document.body.style[CSS_USERSELECT] = '';
962 | _updateCenterPoint.call(self);
963 | _triggerUpdate.call(self);
964 | originalDistance = 0;
965 | }
966 |
967 | self.elements.overlay.addEventListener('mousedown', mouseDown);
968 | self.elements.viewport.addEventListener('keydown', keyDown);
969 | self.elements.overlay.addEventListener('touchstart', mouseDown);
970 | }
971 |
972 | function _updateOverlay() {
973 | if (!this.elements) return; // since this is debounced, it can be fired after destroy
974 | var self = this,
975 | boundRect = self.elements.boundary.getBoundingClientRect(),
976 | imgData = self.elements.preview.getBoundingClientRect();
977 |
978 | css(self.elements.overlay, {
979 | width: imgData.width + 'px',
980 | height: imgData.height + 'px',
981 | top: (imgData.top - boundRect.top) + 'px',
982 | left: (imgData.left - boundRect.left) + 'px'
983 | });
984 | }
985 | var _debouncedOverlay = debounce(_updateOverlay, 500);
986 |
987 | function _triggerUpdate() {
988 | var self = this,
989 | data = self.get();
990 |
991 | if (!_isVisible.call(self)) {
992 | return;
993 | }
994 |
995 | self.options.update.call(self, data);
996 | if (self.$ && typeof Prototype === 'undefined') {
997 | self.$(self.element).trigger('update.croppie', data);
998 | }
999 | else {
1000 | var ev;
1001 | if (window.CustomEvent) {
1002 | ev = new CustomEvent('update', { detail: data });
1003 | } else {
1004 | ev = document.createEvent('CustomEvent');
1005 | ev.initCustomEvent('update', true, true, data);
1006 | }
1007 |
1008 | self.element.dispatchEvent(ev);
1009 | }
1010 | }
1011 |
1012 | function _isVisible() {
1013 | return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0;
1014 | }
1015 |
1016 | function _updatePropertiesFromImage() {
1017 | var self = this,
1018 | initialZoom = 1,
1019 | cssReset = {},
1020 | img = self.elements.preview,
1021 | imgData,
1022 | transformReset = new Transform(0, 0, initialZoom),
1023 | originReset = new TransformOrigin(),
1024 | isVisible = _isVisible.call(self);
1025 |
1026 | if (!isVisible || self.data.bound) {// if the croppie isn't visible or it doesn't need binding
1027 | return;
1028 | }
1029 |
1030 | self.data.bound = true;
1031 | cssReset[CSS_TRANSFORM] = transformReset.toString();
1032 | cssReset[CSS_TRANS_ORG] = originReset.toString();
1033 | cssReset['opacity'] = 1;
1034 | css(img, cssReset);
1035 |
1036 | imgData = self.elements.preview.getBoundingClientRect();
1037 |
1038 | self._originalImageWidth = imgData.width;
1039 | self._originalImageHeight = imgData.height;
1040 | self.data.orientation = _hasExif.call(self) ? getExifOrientation(self.elements.img) : self.data.orientation;
1041 |
1042 | if (self.options.enableZoom) {
1043 | _updateZoomLimits.call(self, true);
1044 | }
1045 | else {
1046 | self._currentZoom = initialZoom;
1047 | }
1048 |
1049 | transformReset.scale = self._currentZoom;
1050 | cssReset[CSS_TRANSFORM] = transformReset.toString();
1051 | css(img, cssReset);
1052 |
1053 | if (self.data.points.length) {
1054 | _bindPoints.call(self, self.data.points);
1055 | }
1056 | else {
1057 | _centerImage.call(self);
1058 | }
1059 |
1060 | _updateCenterPoint.call(self);
1061 | _updateOverlay.call(self);
1062 | }
1063 |
1064 | function _updateZoomLimits (initial) {
1065 | var self = this,
1066 | minZoom = Math.max(self.options.minZoom, 0) || 0,
1067 | maxZoom = self.options.maxZoom || 1.5,
1068 | initialZoom,
1069 | defaultInitialZoom,
1070 | zoomer = self.elements.zoomer,
1071 | scale = parseFloat(zoomer.value),
1072 | boundaryData = self.elements.boundary.getBoundingClientRect(),
1073 | imgData = naturalImageDimensions(self.elements.img, self.data.orientation),
1074 | vpData = self.elements.viewport.getBoundingClientRect(),
1075 | minW,
1076 | minH;
1077 | if (self.options.enforceBoundary) {
1078 | minW = vpData.width / imgData.width;
1079 | minH = vpData.height / imgData.height;
1080 | minZoom = Math.max(minW, minH);
1081 | }
1082 |
1083 | if (minZoom >= maxZoom) {
1084 | maxZoom = minZoom + 1;
1085 | }
1086 |
1087 | zoomer.min = fix(minZoom, 4);
1088 | zoomer.max = fix(maxZoom, 4);
1089 |
1090 | if (!initial && (scale < zoomer.min || scale > zoomer.max)) {
1091 | _setZoomerVal.call(self, scale < zoomer.min ? zoomer.min : zoomer.max);
1092 | }
1093 | else if (initial) {
1094 | defaultInitialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height));
1095 | initialZoom = self.data.boundZoom !== null ? self.data.boundZoom : defaultInitialZoom;
1096 | _setZoomerVal.call(self, initialZoom);
1097 | }
1098 |
1099 | dispatchChange(zoomer);
1100 | }
1101 |
1102 | function _bindPoints(points) {
1103 | if (points.length !== 4) {
1104 | throw "Croppie - Invalid number of points supplied: " + points;
1105 | }
1106 | var self = this,
1107 | pointsWidth = points[2] - points[0],
1108 | // pointsHeight = points[3] - points[1],
1109 | vpData = self.elements.viewport.getBoundingClientRect(),
1110 | boundRect = self.elements.boundary.getBoundingClientRect(),
1111 | vpOffset = {
1112 | left: vpData.left - boundRect.left,
1113 | top: vpData.top - boundRect.top
1114 | },
1115 | scale = vpData.width / pointsWidth,
1116 | originTop = points[1],
1117 | originLeft = points[0],
1118 | transformTop = (-1 * points[1]) + vpOffset.top,
1119 | transformLeft = (-1 * points[0]) + vpOffset.left,
1120 | newCss = {};
1121 |
1122 | newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px';
1123 | newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString();
1124 | css(self.elements.preview, newCss);
1125 |
1126 | _setZoomerVal.call(self, scale);
1127 | self._currentZoom = scale;
1128 | }
1129 |
1130 | function _centerImage() {
1131 | var self = this,
1132 | imgDim = self.elements.preview.getBoundingClientRect(),
1133 | vpDim = self.elements.viewport.getBoundingClientRect(),
1134 | boundDim = self.elements.boundary.getBoundingClientRect(),
1135 | vpLeft = vpDim.left - boundDim.left,
1136 | vpTop = vpDim.top - boundDim.top,
1137 | w = vpLeft - ((imgDim.width - vpDim.width) / 2),
1138 | h = vpTop - ((imgDim.height - vpDim.height) / 2),
1139 | transform = new Transform(w, h, self._currentZoom);
1140 |
1141 | css(self.elements.preview, CSS_TRANSFORM, transform.toString());
1142 | }
1143 |
1144 | function _transferImageToCanvas(customOrientation) {
1145 | var self = this,
1146 | canvas = self.elements.canvas,
1147 | img = self.elements.img,
1148 | ctx = canvas.getContext('2d');
1149 |
1150 | ctx.clearRect(0, 0, canvas.width, canvas.height);
1151 | canvas.width = img.width;
1152 | canvas.height = img.height;
1153 |
1154 | var orientation = self.options.enableOrientation && customOrientation || getExifOrientation(img);
1155 | drawCanvas(canvas, img, orientation);
1156 | }
1157 |
1158 | function _getCanvas(data) {
1159 | var self = this,
1160 | points = data.points,
1161 | left = num(points[0]),
1162 | top = num(points[1]),
1163 | right = num(points[2]),
1164 | bottom = num(points[3]),
1165 | width = right-left,
1166 | height = bottom-top,
1167 | circle = data.circle,
1168 | canvas = document.createElement('canvas'),
1169 | ctx = canvas.getContext('2d'),
1170 | startX = 0,
1171 | startY = 0,
1172 | canvasWidth = data.outputWidth || width,
1173 | canvasHeight = data.outputHeight || height;
1174 |
1175 | canvas.width = canvasWidth;
1176 | canvas.height = canvasHeight;
1177 |
1178 | if (data.backgroundColor) {
1179 | ctx.fillStyle = data.backgroundColor;
1180 | ctx.fillRect(0, 0, canvasWidth, canvasHeight);
1181 | }
1182 |
1183 | // By default assume we're going to draw the entire
1184 | // source image onto the destination canvas.
1185 | var sx = left,
1186 | sy = top,
1187 | sWidth = width,
1188 | sHeight = height,
1189 | dx = 0,
1190 | dy = 0,
1191 | dWidth = canvasWidth,
1192 | dHeight = canvasHeight;
1193 |
1194 | //
1195 | // Do not go outside of the original image's bounds along the x-axis.
1196 | // Handle translations when projecting onto the destination canvas.
1197 | //
1198 |
1199 | // The smallest possible source x-position is 0.
1200 | if (left < 0) {
1201 | sx = 0;
1202 | dx = (Math.abs(left) / width) * canvasWidth;
1203 | }
1204 |
1205 | // The largest possible source width is the original image's width.
1206 | if (sWidth + sx > self._originalImageWidth) {
1207 | sWidth = self._originalImageWidth - sx;
1208 | dWidth = (sWidth / width) * canvasWidth;
1209 | }
1210 |
1211 | //
1212 | // Do not go outside of the original image's bounds along the y-axis.
1213 | //
1214 |
1215 | // The smallest possible source y-position is 0.
1216 | if (top < 0) {
1217 | sy = 0;
1218 | dy = (Math.abs(top) / height) * canvasHeight;
1219 | }
1220 |
1221 | // The largest possible source height is the original image's height.
1222 | if (sHeight + sy > self._originalImageHeight) {
1223 | sHeight = self._originalImageHeight - sy;
1224 | dHeight = (sHeight / height) * canvasHeight;
1225 | }
1226 |
1227 | // console.table({ left, right, top, bottom, canvasWidth, canvasHeight, width, height, startX, startY, circle, sx, sy, dx, dy, sWidth, sHeight, dWidth, dHeight });
1228 |
1229 | ctx.drawImage(this.elements.preview, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
1230 | if (circle) {
1231 | ctx.fillStyle = '#fff';
1232 | ctx.globalCompositeOperation = 'destination-in';
1233 | ctx.beginPath();
1234 | ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true);
1235 | ctx.closePath();
1236 | ctx.fill();
1237 | }
1238 | return canvas;
1239 | }
1240 |
1241 | function _getHtmlResult(data) {
1242 | var points = data.points,
1243 | div = document.createElement('div'),
1244 | img = document.createElement('img'),
1245 | width = points[2] - points[0],
1246 | height = points[3] - points[1];
1247 |
1248 | addClass(div, 'croppie-result');
1249 | div.appendChild(img);
1250 | css(img, {
1251 | left: (-1 * points[0]) + 'px',
1252 | top: (-1 * points[1]) + 'px'
1253 | });
1254 | img.src = data.url;
1255 | css(div, {
1256 | width: width + 'px',
1257 | height: height + 'px'
1258 | });
1259 |
1260 | return div;
1261 | }
1262 |
1263 | function _getBase64Result(data) {
1264 | return _getCanvas.call(this, data).toDataURL(data.format, data.quality);
1265 | }
1266 |
1267 | function _getBlobResult(data) {
1268 | var self = this;
1269 | return new Promise(function (resolve) {
1270 | _getCanvas.call(self, data).toBlob(function (blob) {
1271 | resolve(blob);
1272 | }, data.format, data.quality);
1273 | });
1274 | }
1275 |
1276 | function _replaceImage(img) {
1277 | if (this.elements.img.parentNode) {
1278 | Array.prototype.forEach.call(this.elements.img.classList, function(c) { img.classList.add(c); });
1279 | this.elements.img.parentNode.replaceChild(img, this.elements.img);
1280 | this.elements.preview = img; // if the img is attached to the DOM, they're not using the canvas
1281 | }
1282 | this.elements.img = img;
1283 | }
1284 |
1285 | function _bind(options, cb) {
1286 | var self = this,
1287 | url,
1288 | points = [],
1289 | zoom = null,
1290 | hasExif = _hasExif.call(self);
1291 |
1292 | if (typeof (options) === 'string') {
1293 | url = options;
1294 | options = {};
1295 | }
1296 | else if (Array.isArray(options)) {
1297 | points = options.slice();
1298 | }
1299 | else if (typeof (options) === 'undefined' && self.data.url) { //refreshing
1300 | _updatePropertiesFromImage.call(self);
1301 | _triggerUpdate.call(self);
1302 | return null;
1303 | }
1304 | else {
1305 | url = options.url;
1306 | points = options.points || [];
1307 | zoom = typeof(options.zoom) === 'undefined' ? null : options.zoom;
1308 | }
1309 |
1310 | self.data.bound = false;
1311 | self.data.url = url || self.data.url;
1312 | self.data.boundZoom = zoom;
1313 |
1314 | return loadImage(url, hasExif).then(function (img) {
1315 | _replaceImage.call(self, img);
1316 | if (!points.length) {
1317 | var natDim = naturalImageDimensions(img);
1318 | var rect = self.elements.viewport.getBoundingClientRect();
1319 | var aspectRatio = rect.width / rect.height;
1320 | var imgAspectRatio = natDim.width / natDim.height;
1321 | var width, height;
1322 |
1323 | if (imgAspectRatio > aspectRatio) {
1324 | height = natDim.height;
1325 | width = height * aspectRatio;
1326 | }
1327 | else {
1328 | width = natDim.width;
1329 | height = natDim.height / aspectRatio;
1330 | }
1331 |
1332 | var x0 = (natDim.width - width) / 2;
1333 | var y0 = (natDim.height - height) / 2;
1334 | var x1 = x0 + width;
1335 | var y1 = y0 + height;
1336 | self.data.points = [x0, y0, x1, y1];
1337 | }
1338 | else if (self.options.relative) {
1339 | points = [
1340 | points[0] * img.naturalWidth / 100,
1341 | points[1] * img.naturalHeight / 100,
1342 | points[2] * img.naturalWidth / 100,
1343 | points[3] * img.naturalHeight / 100
1344 | ];
1345 | }
1346 |
1347 | self.data.orientation = options.orientation || 1;
1348 | self.data.points = points.map(function (p) {
1349 | return parseFloat(p);
1350 | });
1351 | if (self.options.useCanvas) {
1352 | _transferImageToCanvas.call(self, self.data.orientation);
1353 | }
1354 | _updatePropertiesFromImage.call(self);
1355 | _triggerUpdate.call(self);
1356 | cb && cb();
1357 | });
1358 | }
1359 |
1360 | function fix(v, decimalPoints) {
1361 | return parseFloat(v).toFixed(decimalPoints || 0);
1362 | }
1363 |
1364 | function _get() {
1365 | var self = this,
1366 | imgData = self.elements.preview.getBoundingClientRect(),
1367 | vpData = self.elements.viewport.getBoundingClientRect(),
1368 | x1 = vpData.left - imgData.left,
1369 | y1 = vpData.top - imgData.top,
1370 | widthDiff = (vpData.width - self.elements.viewport.offsetWidth) / 2, //border
1371 | heightDiff = (vpData.height - self.elements.viewport.offsetHeight) / 2,
1372 | x2 = x1 + self.elements.viewport.offsetWidth + widthDiff,
1373 | y2 = y1 + self.elements.viewport.offsetHeight + heightDiff,
1374 | scale = self._currentZoom;
1375 |
1376 | if (scale === Infinity || isNaN(scale)) {
1377 | scale = 1;
1378 | }
1379 |
1380 | var max = self.options.enforceBoundary ? 0 : Number.NEGATIVE_INFINITY;
1381 | x1 = Math.max(max, x1 / scale);
1382 | y1 = Math.max(max, y1 / scale);
1383 | x2 = Math.max(max, x2 / scale);
1384 | y2 = Math.max(max, y2 / scale);
1385 |
1386 | return {
1387 | points: [fix(x1), fix(y1), fix(x2), fix(y2)],
1388 | zoom: scale,
1389 | orientation: self.data.orientation
1390 | };
1391 | }
1392 |
1393 | var RESULT_DEFAULTS = {
1394 | type: 'canvas',
1395 | format: 'png',
1396 | quality: 1
1397 | },
1398 | RESULT_FORMATS = ['jpeg', 'webp', 'png'];
1399 |
1400 | function _result(options) {
1401 | var self = this,
1402 | data = _get.call(self),
1403 | opts = deepExtend(clone(RESULT_DEFAULTS), clone(options)),
1404 | resultType = (typeof (options) === 'string' ? options : (opts.type || 'base64')),
1405 | size = opts.size || 'viewport',
1406 | format = opts.format,
1407 | quality = opts.quality,
1408 | backgroundColor = opts.backgroundColor,
1409 | circle = typeof opts.circle === 'boolean' ? opts.circle : (self.options.viewport.type === 'circle'),
1410 | vpRect = self.elements.viewport.getBoundingClientRect(),
1411 | ratio = vpRect.width / vpRect.height,
1412 | prom;
1413 |
1414 | if (size === 'viewport') {
1415 | data.outputWidth = vpRect.width;
1416 | data.outputHeight = vpRect.height;
1417 | } else if (typeof size === 'object') {
1418 | if (size.width && size.height) {
1419 | data.outputWidth = size.width;
1420 | data.outputHeight = size.height;
1421 | } else if (size.width) {
1422 | data.outputWidth = size.width;
1423 | data.outputHeight = size.width / ratio;
1424 | } else if (size.height) {
1425 | data.outputWidth = size.height * ratio;
1426 | data.outputHeight = size.height;
1427 | }
1428 | }
1429 |
1430 | if (RESULT_FORMATS.indexOf(format) > -1) {
1431 | data.format = 'image/' + format;
1432 | data.quality = quality;
1433 | }
1434 |
1435 | data.circle = circle;
1436 | data.url = self.data.url;
1437 | data.backgroundColor = backgroundColor;
1438 |
1439 | prom = new Promise(function (resolve) {
1440 | switch(resultType.toLowerCase())
1441 | {
1442 | case 'rawcanvas':
1443 | resolve(_getCanvas.call(self, data));
1444 | break;
1445 | case 'canvas':
1446 | case 'base64':
1447 | resolve(_getBase64Result.call(self, data));
1448 | break;
1449 | case 'blob':
1450 | _getBlobResult.call(self, data).then(resolve);
1451 | break;
1452 | default:
1453 | resolve(_getHtmlResult.call(self, data));
1454 | break;
1455 | }
1456 | });
1457 | return prom;
1458 | }
1459 |
1460 | function _refresh() {
1461 | _updatePropertiesFromImage.call(this);
1462 | }
1463 |
1464 | function _rotate(deg) {
1465 | if (!this.options.useCanvas || !this.options.enableOrientation) {
1466 | throw 'Croppie: Cannot rotate without enableOrientation && EXIF.js included';
1467 | }
1468 |
1469 | var self = this,
1470 | canvas = self.elements.canvas;
1471 |
1472 | self.data.orientation = getExifOffset(self.data.orientation, deg);
1473 | drawCanvas(canvas, self.elements.img, self.data.orientation);
1474 | _updateCenterPoint.call(self, true);
1475 | _updateZoomLimits.call(self);
1476 |
1477 | // Reverses image dimensions if the degrees of rotation is not divisible by 180.
1478 | if ((Math.abs(deg) / 90) % 2 === 1) {
1479 | var oldHeight = self._originalImageHeight;
1480 | var oldWidth = self._originalImageWidth;
1481 | self._originalImageWidth = oldHeight;
1482 | self._originalImageHeight = oldWidth;
1483 | }
1484 | }
1485 |
1486 | function _destroy() {
1487 | var self = this;
1488 | self.element.removeChild(self.elements.boundary);
1489 | removeClass(self.element, 'croppie-container');
1490 | if (self.options.enableZoom) {
1491 | self.element.removeChild(self.elements.zoomerWrap);
1492 | }
1493 | delete self.elements;
1494 | }
1495 |
1496 | if (typeof window !== 'undefined' && window.jQuery) {
1497 | var $ = window.jQuery;
1498 | $.fn.croppie = function (opts) {
1499 | var ot = typeof opts;
1500 |
1501 | if (ot === 'string') {
1502 | var args = Array.prototype.slice.call(arguments, 1);
1503 | var singleInst = $(this).data('croppie');
1504 |
1505 | if (opts === 'get') {
1506 | return singleInst.get();
1507 | }
1508 | else if (opts === 'result') {
1509 | return singleInst.result.apply(singleInst, args);
1510 | }
1511 | else if (opts === 'bind') {
1512 | return singleInst.bind.apply(singleInst, args);
1513 | }
1514 |
1515 | return this.each(function () {
1516 | var i = $(this).data('croppie');
1517 | if (!i) return;
1518 |
1519 | var method = i[opts];
1520 | if ($.isFunction(method)) {
1521 | method.apply(i, args);
1522 | if (opts === 'destroy') {
1523 | $(this).removeData('croppie');
1524 | }
1525 | }
1526 | else {
1527 | throw 'Croppie ' + opts + ' method not found';
1528 | }
1529 | });
1530 | }
1531 | else {
1532 | return this.each(function () {
1533 | var i = new Croppie(this, opts);
1534 | i.$ = $;
1535 | $(this).data('croppie', i);
1536 | });
1537 | }
1538 | };
1539 | }
1540 |
1541 | function Croppie(element, opts) {
1542 | if (element.className.indexOf('croppie-container') > -1) {
1543 | throw new Error("Croppie: Can't initialize croppie more than once");
1544 | }
1545 | this.element = element;
1546 | this.options = deepExtend(clone(Croppie.defaults), opts);
1547 |
1548 | if (this.element.tagName.toLowerCase() === 'img') {
1549 | var origImage = this.element;
1550 | addClass(origImage, 'cr-original-image');
1551 | setAttributes(origImage, {'aria-hidden' : 'true', 'alt' : '' });
1552 | var replacementDiv = document.createElement('div');
1553 | this.element.parentNode.appendChild(replacementDiv);
1554 | replacementDiv.appendChild(origImage);
1555 | this.element = replacementDiv;
1556 | this.options.url = this.options.url || origImage.src;
1557 | }
1558 |
1559 | _create.call(this);
1560 | if (this.options.url) {
1561 | var bindOpts = {
1562 | url: this.options.url,
1563 | points: this.options.points
1564 | };
1565 | delete this.options['url'];
1566 | delete this.options['points'];
1567 | _bind.call(this, bindOpts);
1568 | }
1569 | }
1570 |
1571 | Croppie.defaults = {
1572 | viewport: {
1573 | width: 100,
1574 | height: 100,
1575 | type: 'square'
1576 | },
1577 | boundary: { },
1578 | orientationControls: {
1579 | enabled: true,
1580 | leftClass: '',
1581 | rightClass: ''
1582 | },
1583 | resizeControls: {
1584 | width: true,
1585 | height: true
1586 | },
1587 | customClass: '',
1588 | showZoomer: true,
1589 | enableZoom: true,
1590 | enableResize: false,
1591 | mouseWheelZoom: true,
1592 | enableExif: false,
1593 | enforceBoundary: true,
1594 | enableOrientation: false,
1595 | enableKeyMovement: true,
1596 | update: function () { }
1597 | };
1598 |
1599 | Croppie.globals = {
1600 | translate: 'translate3d'
1601 | };
1602 |
1603 | deepExtend(Croppie.prototype, {
1604 | bind: function (options, cb) {
1605 | return _bind.call(this, options, cb);
1606 | },
1607 | get: function () {
1608 | var data = _get.call(this);
1609 | var points = data.points;
1610 | if (this.options.relative) {
1611 | points[0] /= this.elements.img.naturalWidth / 100;
1612 | points[1] /= this.elements.img.naturalHeight / 100;
1613 | points[2] /= this.elements.img.naturalWidth / 100;
1614 | points[3] /= this.elements.img.naturalHeight / 100;
1615 | }
1616 | return data;
1617 | },
1618 | result: function (type) {
1619 | return _result.call(this, type);
1620 | },
1621 | refresh: function () {
1622 | return _refresh.call(this);
1623 | },
1624 | setZoom: function (v) {
1625 | _setZoomerVal.call(this, v);
1626 | dispatchChange(this.elements.zoomer);
1627 | },
1628 | rotate: function (deg) {
1629 | _rotate.call(this, deg);
1630 | },
1631 | destroy: function () {
1632 | return _destroy.call(this);
1633 | }
1634 | });
1635 | return Croppie;
1636 | }));
1637 |
--------------------------------------------------------------------------------
/croppie.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports&&"string"!=typeof exports.nodeName?module.exports=t():e.Croppie=t()}("undefined"!=typeof self?self:this,function(){"function"!=typeof Promise&&function(e){function t(e,t){return function(){e.apply(t,arguments)}}function i(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],s(e,t(o,this),t(r,this))}function n(e){var t=this;return null===this._state?void this._deferreds.push(e):void h(function(){var i=t._state?e.onFulfilled:e.onRejected;if(null!==i){var n;try{n=i(t._value)}catch(t){return void e.reject(t)}e.resolve(n)}else(t._state?e.resolve:e.reject)(t._value)})}function o(e){try{if(e===this)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var i=e.then;if("function"==typeof i)return void s(t(i,e),t(o,this),t(r,this))}this._state=!0,this._value=e,a.call(this)}catch(e){r.call(this,e)}}function r(e){this._state=!1,this._value=e,a.call(this)}function a(){for(var e=0,t=this._deferreds.length;t>e;e++)n.call(this,this._deferreds[e]);this._deferreds=null}function s(e,t,i){var n=!1;try{e(function(e){n||(n=!0,t(e))},function(e){n||(n=!0,i(e))})}catch(e){if(n)return;n=!0,i(e)}}var l=setTimeout,h="function"==typeof setImmediate&&setImmediate||function(e){l(e,1)},u=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};i.prototype.catch=function(e){return this.then(null,e)},i.prototype.then=function(e,t){var o=this;return new i(function(i,r){n.call(o,new function(e,t,i,n){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof t?t:null,this.resolve=i,this.reject=n}(e,t,i,r))})},i.all=function(){var e=Array.prototype.slice.call(1===arguments.length&&u(arguments[0])?arguments[0]:arguments);return new i(function(t,i){function n(r,a){try{if(a&&("object"==typeof a||"function"==typeof a)){var s=a.then;if("function"==typeof s)return void s.call(a,function(e){n(r,e)},i)}e[r]=a,0==--o&&t(e)}catch(e){i(e)}}if(0===e.length)return t([]);for(var o=e.length,r=0;rn;n++)e[n].then(t,i)})},i._setImmediateFn=function(e){h=e},"undefined"!=typeof module&&module.exports?module.exports=i:e.Promise||(e.Promise=i)}(this),"undefined"!=typeof window&&"function"!=typeof window.CustomEvent&&function(){function e(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var i=document.createEvent("CustomEvent");return i.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),i}e.prototype=window.Event.prototype,window.CustomEvent=e}(),"undefined"==typeof HTMLCanvasElement||HTMLCanvasElement.prototype.toBlob||Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(e,t,i){for(var n=atob(this.toDataURL(t,i).split(",")[1]),o=n.length,r=new Uint8Array(o),a=0;a=5){var r=i;i=n,n=r}return{width:i,height:n}}t=s("transform"),e=s("transformOrigin"),i=s("userSelect");var v={translate3d:{suffix:", 0px"},translate:{suffix:""}},g=function(e,t,i){this.x=parseFloat(e),this.y=parseFloat(t),this.scale=parseFloat(i)};g.parse=function(e){return e.style?g.parse(e.style[t]):e.indexOf("matrix")>-1||e.indexOf("none")>-1?g.fromMatrix(e):g.fromString(e)},g.fromMatrix=function(e){var t=e.substring(7).split(",");return t.length&&"none"!==e||(t=[1,0,0,1,0,0]),new g(m(t[4]),m(t[5]),parseFloat(t[0]))},g.fromString=function(e){var t=e.split(") "),i=t[0].substring(T.globals.translate.length+1).split(","),n=t.length>1?t[1].substring(6):1,o=i.length>1?i[0]:0,r=i.length>1?i[1]:0;return new g(o,r,n)},g.prototype.toString=function(){var e=v[T.globals.translate].suffix||"";return T.globals.translate+"("+this.x+"px, "+this.y+"px"+e+") scale("+this.scale+")"};var w=function(t){if(!t||!t.style[e])return this.x=0,void(this.y=0);var i=t.style[e].split(" ");this.x=parseFloat(i[0]),this.y=parseFloat(i[1])};function y(e){return e.exifdata&&e.exifdata.Orientation?m(e.exifdata.Orientation):1}function b(e,t,i){var n=t.width,o=t.height,r=e.getContext("2d");switch(e.width=t.width,e.height=t.height,r.save(),i){case 2:r.translate(n,0),r.scale(-1,1);break;case 3:r.translate(n,o),r.rotate(180*Math.PI/180);break;case 4:r.translate(0,o),r.scale(1,-1);break;case 5:e.width=o,e.height=n,r.rotate(90*Math.PI/180),r.scale(1,-1);break;case 6:e.width=o,e.height=n,r.rotate(90*Math.PI/180),r.translate(0,-o);break;case 7:e.width=o,e.height=n,r.rotate(-90*Math.PI/180),r.translate(-n,o),r.scale(1,-1);break;case 8:e.width=o,e.height=n,r.translate(0,n),r.rotate(-90*Math.PI/180)}r.drawImage(t,0,0,n,o),r.restore()}function x(){var n,o,r,a,s,l,h=this.options.viewport.type?"cr-vp-"+this.options.viewport.type:null;this.options.useCanvas=this.options.enableOrientation||C.call(this),this.data={},this.elements={},n=this.elements.boundary=document.createElement("div"),r=this.elements.viewport=document.createElement("div"),o=this.elements.img=document.createElement("img"),a=this.elements.overlay=document.createElement("div"),this.options.useCanvas?(this.elements.canvas=document.createElement("canvas"),this.elements.preview=this.elements.canvas):this.elements.preview=o,p(n,"cr-boundary"),n.setAttribute("aria-dropeffect","none"),s=this.options.boundary.width,l=this.options.boundary.height,c(n,{width:s+(isNaN(s)?"":"px"),height:l+(isNaN(l)?"":"px")}),p(r,"cr-viewport"),h&&p(r,h),c(r,{width:this.options.viewport.width+"px",height:this.options.viewport.height+"px"}),r.setAttribute("tabindex",0),p(this.elements.preview,"cr-image"),d(this.elements.preview,{alt:"preview","aria-grabbed":"false"}),p(a,"cr-overlay"),this.element.appendChild(n),n.appendChild(this.elements.preview),n.appendChild(r),n.appendChild(a),p(this.element,"croppie-container"),this.options.customClass&&p(this.element,this.options.customClass),function(){var e,n,o,r,a,s=this,l=!1;function h(e,t){var i=s.elements.preview.getBoundingClientRect(),n=a.y+t,o=a.x+e;s.options.enforceBoundary?(r.top>i.top+t&&r.bottomi.left+e&&r.right1){var v=i.touches[0],g=i.touches[1],w=Math.sqrt((v.pageX-g.pageX)*(v.pageX-g.pageX)+(v.pageY-g.pageY)*(v.pageY-g.pageY));o||(o=w/s._currentZoom);var y=w/o;return E.call(s,y),void u(s.elements.zoomer)}h(d,m),f[t]=a.toString(),c(s.elements.preview,f),L.call(s),n=l,e=r}function f(){p(l=!1),window.removeEventListener("mousemove",m),window.removeEventListener("touchmove",m),window.removeEventListener("mouseup",f),window.removeEventListener("touchend",f),document.body.style[i]="",_.call(s),z.call(s),o=0}s.elements.overlay.addEventListener("mousedown",d),s.elements.viewport.addEventListener("keydown",function(e){var n=37,l=38,u=39,p=40;if(!e.shiftKey||e.keyCode!==l&&e.keyCode!==p){if(s.options.enableKeyMovement&&e.keyCode>=37&&e.keyCode<=40){e.preventDefault();var d=function(e){switch(e){case n:return[1,0];case l:return[0,1];case u:return[-1,0];case p:return[0,-1]}}(e.keyCode);a=g.parse(s.elements.preview),document.body.style[i]="none",r=s.elements.viewport.getBoundingClientRect(),function(e){var n=e[0],r=e[1],l={};h(n,r),l[t]=a.toString(),c(s.elements.preview,l),L.call(s),document.body.style[i]="",_.call(s),z.call(s),o=0}(d)}}else{var m;m=e.keyCode===l?parseFloat(s.elements.zoomer.value)+parseFloat(s.elements.zoomer.step):parseFloat(s.elements.zoomer.value)-parseFloat(s.elements.zoomer.step),s.setZoom(m)}}),s.elements.overlay.addEventListener("touchstart",d)}.call(this),this.options.enableZoom&&function(){var i=this,n=i.elements.zoomerWrap=document.createElement("div"),o=i.elements.zoomer=document.createElement("input");function r(){(function(i){var n=this,o=i?i.transform:g.parse(n.elements.preview),r=i?i.viewportRect:n.elements.viewport.getBoundingClientRect(),a=i?i.origin:new w(n.elements.preview);function s(){var i={};i[t]=o.toString(),i[e]=a.toString(),c(n.elements.preview,i)}if(n._currentZoom=i?i.value:n._currentZoom,o.scale=n._currentZoom,n.elements.zoomer.setAttribute("aria-valuenow",n._currentZoom),s(),n.options.enforceBoundary){var l=function(e){var t=this._currentZoom,i=e.width,n=e.height,o=this.elements.boundary.clientWidth/2,r=this.elements.boundary.clientHeight/2,a=this.elements.preview.getBoundingClientRect(),s=a.width,l=a.height,h=i/2,u=n/2,c=-1*(h/t-o),p=-1*(u/t-r),d=1/t*h,m=1/t*u;return{translate:{maxX:c,minX:c-(s*(1/t)-i*(1/t)),maxY:p,minY:p-(l*(1/t)-n*(1/t))},origin:{maxX:s*(1/t)-d,minX:d,maxY:l*(1/t)-m,minY:m}}}.call(n,r),h=l.translate,u=l.origin;o.x>=h.maxX&&(a.x=u.minX,o.x=h.maxX),o.x<=h.minX&&(a.x=u.maxX,o.x=h.minX),o.y>=h.maxY&&(a.y=u.minY,o.y=h.maxY),o.y<=h.minY&&(a.y=u.maxY,o.y=h.minY)}s(),M.call(n),z.call(n)}).call(i,{value:parseFloat(o.value),origin:new w(i.elements.preview),viewportRect:i.elements.viewport.getBoundingClientRect(),transform:g.parse(i.elements.preview)})}function a(e){var t,n;if("ctrl"===i.options.mouseWheelZoom&&!0!==e.ctrlKey)return 0;t=e.wheelDelta?e.wheelDelta/1200:e.deltaY?e.deltaY/1060:e.detail?e.detail/-60:0,n=i._currentZoom+t*i._currentZoom,e.preventDefault(),E.call(i,n),r.call(i)}p(n,"cr-slider-wrap"),p(o,"cr-slider"),o.type="range",o.step="0.0001",o.value="1",o.style.display=i.options.showZoomer?"":"none",o.setAttribute("aria-label","zoom"),i.element.appendChild(n),n.appendChild(o),i._currentZoom=1,i.elements.zoomer.addEventListener("input",r),i.elements.zoomer.addEventListener("change",r),i.options.mouseWheelZoom&&(i.elements.boundary.addEventListener("mousewheel",a),i.elements.boundary.addEventListener("DOMMouseScroll",a))}.call(this),this.options.enableResize&&function(){var e,t,n,o,r,a,s,l=this,h=document.createElement("div"),u=!1,d=50;p(h,"cr-resizer"),c(h,{width:this.options.viewport.width+"px",height:this.options.viewport.height+"px"}),this.options.resizeControls.height&&(p(a=document.createElement("div"),"cr-resizer-vertical"),h.appendChild(a));this.options.resizeControls.width&&(p(s=document.createElement("div"),"cr-resizer-horisontal"),h.appendChild(s));function m(a){if((void 0===a.button||0===a.button)&&(a.preventDefault(),!u)){var s=l.elements.overlay.getBoundingClientRect();if(u=!0,t=a.pageX,n=a.pageY,e=-1!==a.currentTarget.className.indexOf("vertical")?"v":"h",o=s.width,r=s.height,a.touches){var h=a.touches[0];t=h.pageX,n=h.pageY}window.addEventListener("mousemove",f),window.addEventListener("touchmove",f),window.addEventListener("mouseup",v),window.addEventListener("touchend",v),document.body.style[i]="none"}}function f(i){var a=i.pageX,s=i.pageY;if(i.preventDefault(),i.touches){var u=i.touches[0];a=u.pageX,s=u.pageY}var p=a-t,m=s-n,f=l.options.viewport.height+m,v=l.options.viewport.width+p;"v"===e&&f>=d&&f<=r?(c(h,{height:f+"px"}),l.options.boundary.height+=m,c(l.elements.boundary,{height:l.options.boundary.height+"px"}),l.options.viewport.height+=m,c(l.elements.viewport,{height:l.options.viewport.height+"px"})):"h"===e&&v>=d&&v<=o&&(c(h,{width:v+"px"}),l.options.boundary.width+=p,c(l.elements.boundary,{width:l.options.boundary.width+"px"}),l.options.viewport.width+=p,c(l.elements.viewport,{width:l.options.viewport.width+"px"})),L.call(l),X.call(l),_.call(l),z.call(l),n=s,t=a}function v(){u=!1,window.removeEventListener("mousemove",f),window.removeEventListener("touchmove",f),window.removeEventListener("mouseup",v),window.removeEventListener("touchend",v),document.body.style[i]=""}a&&(a.addEventListener("mousedown",m),a.addEventListener("touchstart",m));s&&(s.addEventListener("mousedown",m),s.addEventListener("touchstart",m));this.elements.boundary.appendChild(h)}.call(this)}function C(){return this.options.enableExif&&window.EXIF}function E(e){if(this.options.enableZoom){var t=this.elements.zoomer,i=O(e,4);t.value=Math.max(parseFloat(t.min),Math.min(parseFloat(t.max),i)).toString()}}function _(i){var n=this._currentZoom,o=this.elements.preview.getBoundingClientRect(),r=this.elements.viewport.getBoundingClientRect(),a=g.parse(this.elements.preview.style[t]),s=new w(this.elements.preview),l=r.top-o.top+r.height/2,h=r.left-o.left+r.width/2,u={},p={};if(i){var d=s.x,m=s.y,f=a.x,v=a.y;u.y=d,u.x=m,a.y=f,a.x=v}else u.y=l/n,u.x=h/n,p.y=(u.y-s.y)*(1-n),p.x=(u.x-s.x)*(1-n),a.x-=p.x,a.y-=p.y;var y={};y[e]=u.x+"px "+u.y+"px",y[t]=a.toString(),c(this.elements.preview,y)}function L(){if(this.elements){var e=this.elements.boundary.getBoundingClientRect(),t=this.elements.preview.getBoundingClientRect();c(this.elements.overlay,{width:t.width+"px",height:t.height+"px",top:t.top-e.top+"px",left:t.left-e.left+"px"})}}w.prototype.toString=function(){return this.x+"px "+this.y+"px"};var R,B,Z,I,M=(R=L,B=500,function(){var e=this,t=arguments,i=Z&&!I;clearTimeout(I),I=setTimeout(function(){I=null,Z||R.apply(e,t)},B),i&&R.apply(e,t)});function z(){var e,t=this.get();F.call(this)&&(this.options.update.call(this,t),this.$&&"undefined"==typeof Prototype?this.$(this.element).trigger("update.croppie",t):(window.CustomEvent?e=new CustomEvent("update",{detail:t}):(e=document.createEvent("CustomEvent")).initCustomEvent("update",!0,!0,t),this.element.dispatchEvent(e)))}function F(){return this.elements.preview.offsetHeight>0&&this.elements.preview.offsetWidth>0}function W(){var i,n={},o=this.elements.preview,r=new g(0,0,1),a=new w;F.call(this)&&!this.data.bound&&(this.data.bound=!0,n[t]=r.toString(),n[e]=a.toString(),n.opacity=1,c(o,n),i=this.elements.preview.getBoundingClientRect(),this._originalImageWidth=i.width,this._originalImageHeight=i.height,this.data.orientation=C.call(this)?y(this.elements.img):this.data.orientation,this.options.enableZoom?X.call(this,!0):this._currentZoom=1,r.scale=this._currentZoom,n[t]=r.toString(),c(o,n),this.data.points.length?function(i){if(4!==i.length)throw"Croppie - Invalid number of points supplied: "+i;var n=i[2]-i[0],o=this.elements.viewport.getBoundingClientRect(),r=this.elements.boundary.getBoundingClientRect(),a={left:o.left-r.left,top:o.top-r.top},s=o.width/n,l=i[1],h=i[0],u=-1*i[1]+a.top,p=-1*i[0]+a.left,d={};d[e]=h+"px "+l+"px",d[t]=new g(p,u,s).toString(),c(this.elements.preview,d),E.call(this,s),this._currentZoom=s}.call(this,this.data.points):function(){var e=this.elements.preview.getBoundingClientRect(),i=this.elements.viewport.getBoundingClientRect(),n=this.elements.boundary.getBoundingClientRect(),o=i.left-n.left,r=i.top-n.top,a=o-(e.width-i.width)/2,s=r-(e.height-i.height)/2,l=new g(a,s,this._currentZoom);c(this.elements.preview,t,l.toString())}.call(this),_.call(this),L.call(this))}function X(e){var t,i,n,o,r=Math.max(this.options.minZoom,0)||0,a=this.options.maxZoom||1.5,s=this.elements.zoomer,l=parseFloat(s.value),h=this.elements.boundary.getBoundingClientRect(),c=f(this.elements.img,this.data.orientation),p=this.elements.viewport.getBoundingClientRect();this.options.enforceBoundary&&(n=p.width/c.width,o=p.height/c.height,r=Math.max(n,o)),r>=a&&(a=r+1),s.min=O(r,4),s.max=O(a,4),!e&&(ls.max)?E.call(this,lthis._originalImageWidth&&(w=(d=this._originalImageWidth-c)/o*h),n<0&&(p=0,g=Math.abs(n)/r*u),f+p>this._originalImageHeight&&(y=(f=this._originalImageHeight-p)/r*u),l.drawImage(this.elements.preview,c,p,d,f,v,g,w,y),a&&(l.fillStyle="#fff",l.globalCompositeOperation="destination-in",l.beginPath(),l.arc(s.width/2,s.height/2,s.width/2,0,2*Math.PI,!0),l.closePath(),l.fill()),s}function H(e,t){var i,n=this,o=[],r=null,a=C.call(n);if("string"==typeof e)i=e,e={};else if(Array.isArray(e))o=e.slice();else{if(void 0===e&&n.data.url)return W.call(n),z.call(n),null;i=e.url,o=e.points||[],r=void 0===e.zoom?null:e.zoom}return n.data.bound=!1,n.data.url=i||n.data.url,n.data.boundZoom=r,function(e,t){if(!e)throw"Source image missing";var i=new Image;return i.style.opacity="0",new Promise(function(n,o){function r(){i.style.opacity="1",setTimeout(function(){n(i)},1)}i.removeAttribute("crossOrigin"),e.match(/^https?:\/\/|^\/\//)&&i.setAttribute("crossOrigin","anonymous"),i.onload=function(){t?EXIF.getData(i,function(){r()}):r()},i.onerror=function(e){i.style.opacity=1,setTimeout(function(){o(e)},1)},i.src=e})}(i,a).then(function(i){if(function(e){this.elements.img.parentNode&&(Array.prototype.forEach.call(this.elements.img.classList,function(t){e.classList.add(t)}),this.elements.img.parentNode.replaceChild(e,this.elements.img),this.elements.preview=e),this.elements.img=e}.call(n,i),o.length)n.options.relative&&(o=[o[0]*i.naturalWidth/100,o[1]*i.naturalHeight/100,o[2]*i.naturalWidth/100,o[3]*i.naturalHeight/100]);else{var r,a,s=f(i),l=n.elements.viewport.getBoundingClientRect(),h=l.width/l.height;s.width/s.height>h?r=(a=s.height)*h:(r=s.width,a=s.height/h);var u=(s.width-r)/2,c=(s.height-a)/2,p=u+r,d=c+a;n.data.points=[u,c,p,d]}n.data.orientation=e.orientation||1,n.data.points=o.map(function(e){return parseFloat(e)}),n.options.useCanvas&&function(e){var t=this.elements.canvas,i=this.elements.img;t.getContext("2d").clearRect(0,0,t.width,t.height),t.width=i.width,t.height=i.height,b(t,i,this.options.enableOrientation&&e||y(i))}.call(n,n.data.orientation),W.call(n),z.call(n),t&&t()})}function O(e,t){return parseFloat(e).toFixed(t||0)}function k(){var e=this.elements.preview.getBoundingClientRect(),t=this.elements.viewport.getBoundingClientRect(),i=t.left-e.left,n=t.top-e.top,o=(t.width-this.elements.viewport.offsetWidth)/2,r=(t.height-this.elements.viewport.offsetHeight)/2,a=i+this.elements.viewport.offsetWidth+o,s=n+this.elements.viewport.offsetHeight+r,l=this._currentZoom;(l===1/0||isNaN(l))&&(l=1);var h=this.options.enforceBoundary?0:Number.NEGATIVE_INFINITY;return i=Math.max(h,i/l),n=Math.max(h,n/l),a=Math.max(h,a/l),s=Math.max(h,s/l),{points:[O(i),O(n),O(a),O(s)],zoom:l,orientation:this.data.orientation}}var A={type:"canvas",format:"png",quality:1},S=["jpeg","webp","png"];function j(e){var t=this,i=k.call(t),n=l(h(A),h(e)),o="string"==typeof e?e:n.type||"base64",r=n.size||"viewport",a=n.format,s=n.quality,u=n.backgroundColor,d="boolean"==typeof n.circle?n.circle:"circle"===t.options.viewport.type,m=t.elements.viewport.getBoundingClientRect(),f=m.width/m.height;return"viewport"===r?(i.outputWidth=m.width,i.outputHeight=m.height):"object"==typeof r&&(r.width&&r.height?(i.outputWidth=r.width,i.outputHeight=r.height):r.width?(i.outputWidth=r.width,i.outputHeight=r.width/f):r.height&&(i.outputWidth=r.height*f,i.outputHeight=r.height)),S.indexOf(a)>-1&&(i.format="image/"+a,i.quality=s),i.circle=d,i.url=t.data.url,i.backgroundColor=u,new Promise(function(e){switch(o.toLowerCase()){case"rawcanvas":e(Y.call(t,i));break;case"canvas":case"base64":e(function(e){return Y.call(this,e).toDataURL(e.format,e.quality)}.call(t,i));break;case"blob":(function(e){var t=this;return new Promise(function(i){Y.call(t,e).toBlob(function(e){i(e)},e.format,e.quality)})}).call(t,i).then(e);break;default:e(function(e){var t=e.points,i=document.createElement("div"),n=document.createElement("img"),o=t[2]-t[0],r=t[3]-t[1];return p(i,"croppie-result"),i.appendChild(n),c(n,{left:-1*t[0]+"px",top:-1*t[1]+"px"}),n.src=e.url,c(i,{width:o+"px",height:r+"px"}),i}.call(t,i))}})}function N(e){if(!this.options.useCanvas||!this.options.enableOrientation)throw"Croppie: Cannot rotate without enableOrientation && EXIF.js included";var t,i,n,o,s,l=this.elements.canvas;if(this.data.orientation=(t=this.data.orientation,i=e,n=r.indexOf(t)>-1?r:a,o=n.indexOf(t),s=i/90%n.length,n[(n.length+o+s%n.length)%n.length]),b(l,this.elements.img,this.data.orientation),_.call(this,!0),X.call(this),Math.abs(e)/90%2==1){var h=this._originalImageHeight,u=this._originalImageWidth;this._originalImageWidth=h,this._originalImageHeight=u}}if("undefined"!=typeof window&&window.jQuery){var P=window.jQuery;P.fn.croppie=function(e){if("string"===typeof e){var t=Array.prototype.slice.call(arguments,1),i=P(this).data("croppie");return"get"===e?i.get():"result"===e?i.result.apply(i,t):"bind"===e?i.bind.apply(i,t):this.each(function(){var i=P(this).data("croppie");if(i){var n=i[e];if(!P.isFunction(n))throw"Croppie "+e+" method not found";n.apply(i,t),"destroy"===e&&P(this).removeData("croppie")}})}return this.each(function(){var t=new T(this,e);t.$=P,P(this).data("croppie",t)})}}function T(e,t){if(e.className.indexOf("croppie-container")>-1)throw new Error("Croppie: Can't initialize croppie more than once");if(this.element=e,this.options=l(h(T.defaults),t),"img"===this.element.tagName.toLowerCase()){var i=this.element;p(i,"cr-original-image"),d(i,{"aria-hidden":"true",alt:""});var n=document.createElement("div");this.element.parentNode.appendChild(n),n.appendChild(i),this.element=n,this.options.url=this.options.url||i.src}if(x.call(this),this.options.url){var o={url:this.options.url,points:this.options.points};delete this.options.url,delete this.options.points,H.call(this,o)}}return T.defaults={viewport:{width:100,height:100,type:"square"},boundary:{},orientationControls:{enabled:!0,leftClass:"",rightClass:""},resizeControls:{width:!0,height:!0},customClass:"",showZoomer:!0,enableZoom:!0,enableResize:!1,mouseWheelZoom:!0,enableExif:!1,enforceBoundary:!0,enableOrientation:!1,enableKeyMovement:!0,update:function(){}},T.globals={translate:"translate3d"},l(T.prototype,{bind:function(e,t){return H.call(this,e,t)},get:function(){var e=k.call(this),t=e.points;return this.options.relative&&(t[0]/=this.elements.img.naturalWidth/100,t[1]/=this.elements.img.naturalHeight/100,t[2]/=this.elements.img.naturalWidth/100,t[3]/=this.elements.img.naturalHeight/100),e},result:function(e){return j.call(this,e)},refresh:function(){return function(){W.call(this)}.call(this)},setZoom:function(e){E.call(this,e),u(this.elements.zoomer)},rotate:function(e){N.call(this,e)},destroy:function(){return function(){var e,t;this.element.removeChild(this.elements.boundary),e=this.element,t="croppie-container",e.classList?e.classList.remove(t):e.className=e.className.replace(t,""),this.options.enableZoom&&this.element.removeChild(this.elements.zoomerWrap),delete this.elements}.call(this)}}),T});
--------------------------------------------------------------------------------
/demo/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foliotek/Croppie/8998b1e35a79f5c8f920e7fa76f72523bffc8df5/demo/cat.jpg
--------------------------------------------------------------------------------
/demo/demo-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foliotek/Croppie/8998b1e35a79f5c8f920e7fa76f72523bffc8df5/demo/demo-1.jpg
--------------------------------------------------------------------------------
/demo/demo-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foliotek/Croppie/8998b1e35a79f5c8f920e7fa76f72523bffc8df5/demo/demo-2.jpg
--------------------------------------------------------------------------------
/demo/demo-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foliotek/Croppie/8998b1e35a79f5c8f920e7fa76f72523bffc8df5/demo/demo-3.jpg
--------------------------------------------------------------------------------
/demo/demo.css:
--------------------------------------------------------------------------------
1 | /*
2 | Colors
3 | #20C1C7
4 | #204648
5 | #189094
6 | #61CED2
7 | #0C4648
8 | */
9 | html,
10 | body {
11 | height: 100%;
12 | padding: 0;
13 | margin: 0;
14 | }
15 |
16 | body {
17 | font-size: 14px;
18 | color: #222;
19 | min-height: 100%;
20 | height: auto;
21 | }
22 |
23 | body,
24 | button,
25 | input {
26 | font-family: 'Open Sans', sans-serif;
27 | }
28 |
29 | h1 {
30 | font-size: 42px;
31 | font-weight: 300;
32 | padding-top: 30px;
33 | margin: 15px 0;
34 | }
35 | h3 {
36 | font-size: 18px;
37 | font-weight: 400;
38 | border-bottom: 1px solid #0C4648;
39 | margin: 15px 0 10px;
40 | }
41 | nav {
42 | position: absolute;
43 | top: 0;
44 | right: 0;
45 | padding:15px;
46 | }
47 |
48 | nav a {
49 | color: white;
50 | text-decoration: none;
51 | padding: 0 10px;
52 | }
53 |
54 | footer {
55 | text-align: center;
56 | color: #555;
57 | font-size: 12px;
58 | padding: 5px;
59 | }
60 |
61 | section {
62 | margin-bottom: 25px;
63 | }
64 |
65 | section.hero {
66 | background: #20C1C7;
67 | background: linear-gradient(#189094, #20C1C7);
68 | color: white;
69 | text-shadow: 0 1px 1px rgba(20,20,20,0.6);
70 | margin-bottom: 0;
71 | min-height: 450px;
72 | }
73 | .hero h2 {
74 | font-size: 16px;
75 | font-weight: 400;
76 | }
77 |
78 | section.who {
79 | margin-bottom: 30px;
80 | }
81 | .section-header {
82 | background: #204648;
83 | padding: 5px 0;
84 | }
85 |
86 | input[type="number"],
87 | input[type="text"] {
88 | border: 1px solid #aaa;
89 | padding: 5px;
90 | font-size: 18px;
91 | width: 100px;
92 | }
93 |
94 | button,
95 | a.btn {
96 | background-color: #189094;
97 | color: white;
98 | padding: 10px 15px;
99 | border-radius: 3px;
100 | border: 1px solid rgba(255, 255, 255, 0.5);
101 | font-size: 16px;
102 | cursor: pointer;
103 | text-decoration: none;
104 | text-shadow: none;
105 | display: inline-block;
106 | cursor: pointer;
107 | }
108 | input[type="file"] {
109 | cursor: pointer;
110 | }
111 | button:focus {
112 | outline: 0;
113 | }
114 |
115 | .file-btn {
116 | position: relative;
117 | }
118 | .file-btn input[type="file"] {
119 | position: absolute;
120 | top: 0;
121 | left: 0;
122 | width: 100%;
123 | height: 100%;
124 | opacity: 0;
125 | }
126 |
127 | .actions {
128 | padding: 5px 0;
129 | }
130 | .actions button {
131 | margin-right: 5px;
132 | }
133 |
134 | pre[class*="language"] {
135 | margin: 10px 0;
136 | padding-top: 0;
137 | border-left-color: #189094;
138 | }
139 |
140 | .container,
141 | .section-header h2 {
142 | position: relative;
143 | max-width: 1000px;
144 | margin: 0 auto;
145 | min-width: 500px;
146 | padding: 0 10px;
147 | }
148 |
149 | .hero p {
150 | font-size: 16px;
151 | }
152 |
153 | .hero .grid {
154 | padding-top: 50px;
155 | }
156 |
157 | h2 {
158 | color: white;
159 | font-size: 23px;
160 | font-weight: 300;
161 | }
162 |
163 | .demo-wrap {
164 | border-bottom: 1px solid #ddd;
165 | padding-top: 20px;
166 | }
167 |
168 | .demo-wrap .container {
169 | padding-bottom: 10px;
170 | }
171 |
172 | .demo-wrap strong {
173 | font-size: 16px;
174 | display: block;
175 | font-weight: 400;
176 | color: #aaa;
177 | margin: 0 0 5px 0;
178 | }
179 |
180 | .documentation ul {
181 | list-style: none;
182 | padding: 0;
183 | margin: 0;
184 | }
185 |
186 | .documentation section > ul > li {
187 | margin-bottom: 1.5em;
188 | }
189 |
190 | .documentation p {
191 | margin: 5px 0 10px;
192 | }
193 |
194 | .documentation .parameter-list li {
195 | padding-left: 5px;
196 | line-height: 28px;
197 | }
198 | .documentation .parameter-list li.values {
199 | padding-left: 20px;
200 | }
201 | .documentation em {
202 | color: #aaa;
203 | font-style: normal;
204 | padding: 0 10px;
205 | }
206 | .documentation i {
207 | color: #666;
208 | }
209 |
210 | .documentation strong.focus {
211 | font-size: 18px;
212 | color: #189094;
213 | font-weight: 700;
214 | }
215 | .documentation span.default {
216 | padding-right: 10px;
217 | font-weight: 600;
218 | color: #777;
219 | }
220 |
221 | .important-notes article {
222 | margin-bottom: 2em;
223 | }
224 |
225 | .upload-demo .upload-demo-wrap,
226 | .upload-demo .upload-result,
227 | .upload-demo.ready .upload-msg {
228 | display: none;
229 | }
230 | .upload-demo.ready .upload-demo-wrap {
231 | display: block;
232 | }
233 | .upload-demo.ready .upload-result {
234 | display: inline-block;
235 | }
236 | .upload-demo-wrap {
237 | width: 300px;
238 | height: 300px;
239 | margin: 0 auto;
240 | }
241 |
242 | .upload-msg {
243 | text-align: center;
244 | padding: 50px;
245 | font-size: 22px;
246 | color: #aaa;
247 | width: 260px;
248 | margin: 50px auto;
249 | border: 1px solid #aaa;
250 | }
251 |
252 | /* Sweet alert modifications */
253 | .sweet-alert {
254 | width: auto;
255 | max-width: 85%;
256 | }
257 |
258 | /* Grid - subset */
259 | *, *:after, *:before {
260 | -webkit-box-sizing: border-box;
261 | -moz-box-sizing: border-box;
262 | box-sizing: border-box;
263 | }
264 | [class*='col-'] {
265 | float: left;
266 | padding-right: 20px; /* column-space */
267 | }
268 |
269 | .grid {
270 | width: 100%;
271 | max-width: 1140px;
272 | min-width: 755px;
273 | margin: 0 auto;
274 | overflow: hidden;
275 | }
276 | .grid:after {
277 | content: "";
278 | display: table;
279 | clear: both;
280 | }
281 |
282 | .col-1-2 {
283 | width: 50%;
284 | }
285 |
286 | .col-1-3 {
287 | width: 33.33%;
288 | }
289 | .col-2-3 {
290 | width: 66.66%;
291 | }
292 | .col-1-4 {
293 | width: 25%;
294 | }
295 | .col-3-4 {
296 | width: 75%;
297 | }
298 |
299 | @media handheld, only screen and (max-width: 767px) {
300 | .grid {
301 | width: 100%;
302 | min-width: 0;
303 | margin-left: 0;
304 | margin-right: 0;
305 | padding-left: 20px; /* grid-space to left */
306 | padding-right: 10px; /* grid-space to right: (grid-space-left - column-space) e.g. 20px-10px=10px */
307 | }
308 |
309 | [class*='col-'] {
310 | width: auto;
311 | float: none;
312 | margin: 10px 0;
313 | padding-left: 0;
314 | padding-right: 10px; /* column-space */
315 | }
316 | .container,
317 | .section-header h2 {
318 | min-width: 0;
319 | }
320 |
321 | .croppie-container {
322 | padding: 30px 0;
323 | }
324 | }
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | var Demo = (function() {
2 |
3 | function output(node) {
4 | var existing = $('#result .croppie-result');
5 | if (existing.length > 0) {
6 | existing[0].parentNode.replaceChild(node, existing[0]);
7 | }
8 | else {
9 | $('#result')[0].appendChild(node);
10 | }
11 | }
12 |
13 | function popupResult(result) {
14 | var html;
15 | if (result.html) {
16 | html = result.html;
17 | }
18 | if (result.src) {
19 | html = '
';
20 | }
21 | swal({
22 | title: '',
23 | html: true,
24 | text: html,
25 | allowOutsideClick: true
26 | });
27 | setTimeout(function(){
28 | $('.sweet-alert').css('margin', function() {
29 | var top = -1 * ($(this).height() / 2),
30 | left = -1 * ($(this).width() / 2);
31 |
32 | return top + 'px 0 0 ' + left + 'px';
33 | });
34 | }, 1);
35 | }
36 |
37 | function demoMain () {
38 | var mc = $('#cropper-1');
39 | mc.croppie({
40 | viewport: {
41 | width: 150,
42 | height: 150,
43 | type: 'circle'
44 | },
45 | boundary: {
46 | width: 300,
47 | height: 300
48 | },
49 | // url: 'demo/demo-1.jpg',
50 | // enforceBoundary: false
51 | // mouseWheelZoom: false
52 | });
53 | mc.on('update.croppie', function (ev, data) {
54 | // console.log('jquery update', ev, data);
55 | });
56 | $('.js-main-image').on('click', function (ev) {
57 | mc.croppie('result', {
58 | type: 'rawcanvas',
59 | circle: true,
60 | // size: { width: 300, height: 300 },
61 | format: 'png'
62 | }).then(function (canvas) {
63 | popupResult({
64 | src: canvas.toDataURL()
65 | });
66 | });
67 | });
68 | }
69 |
70 | function demoBasic() {
71 | var $w = $('.basic-width'),
72 | $h = $('.basic-height'),
73 | basic = $('#demo-basic').croppie({
74 | viewport: {
75 | width: 150,
76 | height: 200
77 | },
78 | boundary: {
79 | width: 300,
80 | height: 300
81 | }
82 | });
83 | basic.croppie('bind', {
84 | url: 'demo/cat.jpg',
85 | points: [77,469,280,739]
86 | });
87 |
88 | $('.basic-result').on('click', function() {
89 | var w = parseInt($w.val(), 10),
90 | h = parseInt($h.val(), 10),s
91 | size = 'viewport';
92 | if (w || h) {
93 | size = { width: w, height: h };
94 | }
95 | basic.croppie('result', {
96 | type: 'canvas',
97 | size: size,
98 | resultSize: {
99 | width: 50,
100 | height: 50
101 | }
102 | }).then(function (resp) {
103 | popupResult({
104 | src: resp
105 | });
106 | });
107 | });
108 | }
109 |
110 | function demoVanilla() {
111 | var vEl = document.getElementById('vanilla-demo'),
112 | vanilla = new Croppie(vEl, {
113 | viewport: { width: 200, height: 100 },
114 | boundary: { width: 300, height: 300 },
115 | showZoomer: false,
116 | enableOrientation: true
117 | });
118 | vanilla.bind({
119 | url: 'demo/demo-2.jpg',
120 | orientation: 4,
121 | zoom: 0
122 | });
123 | vEl.addEventListener('update', function (ev) {
124 | // console.log('vanilla update', ev);
125 | });
126 | document.querySelector('.vanilla-result').addEventListener('click', function (ev) {
127 | vanilla.result({
128 | type: 'blob'
129 | }).then(function (blob) {
130 | popupResult({
131 | src: window.URL.createObjectURL(blob)
132 | });
133 | });
134 | });
135 |
136 | $('.vanilla-rotate').on('click', function(ev) {
137 | vanilla.rotate(parseInt($(this).data('deg')));
138 | });
139 | }
140 |
141 | function demoResizer() {
142 | var vEl = document.getElementById('resizer-demo'),
143 | resize = new Croppie(vEl, {
144 | viewport: { width: 100, height: 100 },
145 | boundary: { width: 300, height: 300 },
146 | showZoomer: false,
147 | enableResize: true,
148 | enableOrientation: true,
149 | mouseWheelZoom: 'ctrl'
150 | });
151 | resize.bind({
152 | url: 'demo/demo-2.jpg',
153 | zoom: 0
154 | });
155 | vEl.addEventListener('update', function (ev) {
156 | console.log('resize update', ev);
157 | });
158 | document.querySelector('.resizer-result').addEventListener('click', function (ev) {
159 | resize.result({
160 | type: 'blob'
161 | }).then(function (blob) {
162 | popupResult({
163 | src: window.URL.createObjectURL(blob)
164 | });
165 | });
166 | });
167 | }
168 |
169 | function demoUpload() {
170 | var $uploadCrop;
171 |
172 | function readFile(input) {
173 | if (input.files && input.files[0]) {
174 | var reader = new FileReader();
175 |
176 | reader.onload = function (e) {
177 | $('.upload-demo').addClass('ready');
178 | $uploadCrop.croppie('bind', {
179 | url: e.target.result
180 | }).then(function(){
181 | console.log('jQuery bind complete');
182 | });
183 |
184 | }
185 |
186 | reader.readAsDataURL(input.files[0]);
187 | }
188 | else {
189 | swal("Sorry - you're browser doesn't support the FileReader API");
190 | }
191 | }
192 |
193 | $uploadCrop = $('#upload-demo').croppie({
194 | viewport: {
195 | width: 100,
196 | height: 100,
197 | type: 'circle'
198 | },
199 | enableExif: true
200 | });
201 |
202 | $('#upload').on('change', function () { readFile(this); });
203 | $('.upload-result').on('click', function (ev) {
204 | $uploadCrop.croppie('result', {
205 | type: 'canvas',
206 | size: 'viewport'
207 | }).then(function (resp) {
208 | popupResult({
209 | src: resp
210 | });
211 | });
212 | });
213 | }
214 |
215 | function demoHidden() {
216 | var $hid = $('#hidden-demo');
217 |
218 | $hid.croppie({
219 | viewport: {
220 | width: 175,
221 | height: 175,
222 | type: 'circle'
223 | },
224 | boundary: {
225 | width: 200,
226 | height: 200
227 | }
228 | });
229 | $hid.croppie('bind', 'demo/demo-3.jpg');
230 | $('.show-hidden').on('click', function () {
231 | $hid.toggle();
232 | $hid.croppie('bind');
233 | });
234 | }
235 |
236 | function bindNavigation () {
237 | var $html = $('html');
238 | $('nav a').on('click', function (ev) {
239 | var lnk = $(ev.currentTarget),
240 | href = lnk.attr('href'),
241 | targetTop = $('a[name=' + href.substring(1) + ']').offset().top;
242 |
243 | $html.animate({ scrollTop: targetTop });
244 | ev.preventDefault();
245 | });
246 | }
247 |
248 | function init() {
249 | bindNavigation();
250 | demoMain();
251 | demoBasic();
252 | demoVanilla();
253 | demoResizer();
254 | demoUpload();
255 | demoHidden();
256 | }
257 |
258 | return {
259 | init: init
260 | };
261 | })();
262 |
263 |
264 | // Full version of `log` that:
265 | // * Prevents errors on console methods when no console present.
266 | // * Exposes a global 'log' function that preserves line numbering and formatting.
267 | (function () {
268 | var method;
269 | var noop = function () { };
270 | var methods = [
271 | 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
272 | 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
273 | 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
274 | 'timeStamp', 'trace', 'warn'
275 | ];
276 | var length = methods.length;
277 | var console = (window.console = window.console || {});
278 |
279 | while (length--) {
280 | method = methods[length];
281 |
282 | // Only stub undefined methods.
283 | if (!console[method]) {
284 | console[method] = noop;
285 | }
286 | }
287 |
288 |
289 | if (Function.prototype.bind) {
290 | window.log = Function.prototype.bind.call(console.log, console);
291 | }
292 | else {
293 | window.log = function() {
294 | Function.prototype.apply.call(console.log, console, arguments);
295 | };
296 | }
297 | })();
298 |
--------------------------------------------------------------------------------
/demo/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Foliotek/Croppie/8998b1e35a79f5c8f920e7fa76f72523bffc8df5/demo/hero.png
--------------------------------------------------------------------------------
/demo/prism.css:
--------------------------------------------------------------------------------
1 | /* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+clike+javascript&plugins=line-highlight+line-numbers */
2 | /**
3 | * prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
4 | * Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
5 | * @author Tim Shedor
6 | */
7 |
8 | code[class*="language-"],
9 | pre[class*="language-"] {
10 | color: black;
11 | background: none;
12 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
13 | direction: ltr;
14 | text-align: left;
15 | white-space: pre;
16 | word-spacing: normal;
17 | word-break: normal;
18 | word-wrap: normal;
19 | line-height: 1.5;
20 |
21 | -moz-tab-size: 4;
22 | -o-tab-size: 4;
23 | tab-size: 4;
24 |
25 | -webkit-hyphens: none;
26 | -moz-hyphens: none;
27 | -ms-hyphens: none;
28 | hyphens: none;
29 | }
30 |
31 | /* Code blocks */
32 | pre[class*="language-"] {
33 | position: relative;
34 | margin: .5em 0;
35 | -webkit-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
36 | -moz-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
37 | box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
38 | border-left: 10px solid #358ccb;
39 | background-color: #fdfdfd;
40 | background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
41 | background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
42 | background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
43 | background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
44 | background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
45 | background-size: 3em 3em;
46 | background-origin: content-box;
47 | overflow: visible;
48 | padding: 0;
49 | }
50 |
51 | code[class*="language"] {
52 | max-height: inherit;
53 | height: 100%;
54 | padding: 0 1em;
55 | display: block;
56 | overflow: auto;
57 | }
58 |
59 | /* Margin bottom to accomodate shadow */
60 | :not(pre) > code[class*="language-"],
61 | pre[class*="language-"] {
62 | background-color: #fdfdfd;
63 | -webkit-box-sizing: border-box;
64 | -moz-box-sizing: border-box;
65 | box-sizing: border-box;
66 | margin-bottom: 1em;
67 | }
68 |
69 | /* Inline code */
70 | :not(pre) > code[class*="language-"] {
71 | position: relative;
72 | padding: .2em;
73 | -webkit-border-radius: 0.3em;
74 | -moz-border-radius: 0.3em;
75 | -ms-border-radius: 0.3em;
76 | -o-border-radius: 0.3em;
77 | border-radius: 0.3em;
78 | color: #c92c2c;
79 | border: 1px solid rgba(0, 0, 0, 0.1);
80 | display: inline;
81 | white-space: normal;
82 | }
83 |
84 | pre[class*="language-"]:before,
85 | pre[class*="language-"]:after {
86 | content: '';
87 | z-index: -2;
88 | display: block;
89 | position: absolute;
90 | bottom: 0.75em;
91 | left: 0.18em;
92 | width: 40%;
93 | height: 20%;
94 | max-height: 13em;
95 | -webkit-box-shadow: 0px 13px 8px #979797;
96 | -moz-box-shadow: 0px 13px 8px #979797;
97 | box-shadow: 0px 13px 8px #979797;
98 | -webkit-transform: rotate(-2deg);
99 | -moz-transform: rotate(-2deg);
100 | -ms-transform: rotate(-2deg);
101 | -o-transform: rotate(-2deg);
102 | transform: rotate(-2deg);
103 | }
104 |
105 | :not(pre) > code[class*="language-"]:after,
106 | pre[class*="language-"]:after {
107 | right: 0.75em;
108 | left: auto;
109 | -webkit-transform: rotate(2deg);
110 | -moz-transform: rotate(2deg);
111 | -ms-transform: rotate(2deg);
112 | -o-transform: rotate(2deg);
113 | transform: rotate(2deg);
114 | }
115 |
116 | .token.comment,
117 | .token.block-comment,
118 | .token.prolog,
119 | .token.doctype,
120 | .token.cdata {
121 | color: #7D8B99;
122 | }
123 |
124 | .token.punctuation {
125 | color: #5F6364;
126 | }
127 |
128 | .token.property,
129 | .token.tag,
130 | .token.boolean,
131 | .token.number,
132 | .token.function-name,
133 | .token.constant,
134 | .token.symbol,
135 | .token.deleted {
136 | color: #c92c2c;
137 | }
138 |
139 | .token.selector,
140 | .token.attr-name,
141 | .token.string,
142 | .token.char,
143 | .token.function,
144 | .token.builtin,
145 | .token.inserted {
146 | color: #2f9c0a;
147 | }
148 |
149 | .token.operator,
150 | .token.entity,
151 | .token.url,
152 | .token.variable {
153 | color: #a67f59;
154 | background: rgba(255, 255, 255, 0.5);
155 | }
156 |
157 | .token.atrule,
158 | .token.attr-value,
159 | .token.keyword,
160 | .token.class-name {
161 | color: #1990b8;
162 | }
163 |
164 | .token.regex,
165 | .token.important {
166 | color: #e90;
167 | }
168 |
169 | .language-css .token.string,
170 | .style .token.string {
171 | color: #a67f59;
172 | background: rgba(255, 255, 255, 0.5);
173 | }
174 |
175 | .token.important {
176 | font-weight: normal;
177 | }
178 |
179 | .token.bold {
180 | font-weight: bold;
181 | }
182 | .token.italic {
183 | font-style: italic;
184 | }
185 |
186 | .token.entity {
187 | cursor: help;
188 | }
189 |
190 | .namespace {
191 | opacity: .7;
192 | }
193 |
194 | @media screen and (max-width: 767px) {
195 | pre[class*="language-"]:before,
196 | pre[class*="language-"]:after {
197 | bottom: 14px;
198 | -webkit-box-shadow: none;
199 | -moz-box-shadow: none;
200 | box-shadow: none;
201 | }
202 |
203 | }
204 |
205 | /* Plugin styles */
206 | .token.tab:not(:empty):before,
207 | .token.cr:before,
208 | .token.lf:before {
209 | color: #e0d7d1;
210 | }
211 |
212 | /* Plugin styles: Line Numbers */
213 | pre[class*="language-"].line-numbers {
214 | padding-left: 0;
215 | }
216 |
217 | pre[class*="language-"].line-numbers code {
218 | padding-left: 3.8em;
219 | }
220 |
221 | pre[class*="language-"].line-numbers .line-numbers-rows {
222 | left: 0;
223 | }
224 |
225 | /* Plugin styles: Line Highlight */
226 | pre[class*="language-"][data-line] {
227 | padding-top: 0;
228 | padding-bottom: 0;
229 | padding-left: 0;
230 | }
231 | pre[data-line] code {
232 | position: relative;
233 | padding-left: 4em;
234 | }
235 | pre .line-highlight {
236 | margin-top: 0;
237 | }
238 |
239 | pre[data-line] {
240 | position: relative;
241 | padding: 1em 0 1em 3em;
242 | }
243 |
244 | .line-highlight {
245 | position: absolute;
246 | left: 0;
247 | right: 0;
248 | padding: inherit 0;
249 | margin-top: 1em; /* Same as .prism’s padding-top */
250 |
251 | background: hsla(24, 20%, 50%,.08);
252 | background: -moz-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
253 | background: -webkit-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
254 | background: -o-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
255 | background: linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
256 |
257 | pointer-events: none;
258 |
259 | line-height: inherit;
260 | white-space: pre;
261 | }
262 |
263 | .line-highlight:before,
264 | .line-highlight[data-end]:after {
265 | content: attr(data-start);
266 | position: absolute;
267 | top: .4em;
268 | left: .6em;
269 | min-width: 1em;
270 | padding: 0 .5em;
271 | background-color: hsla(24, 20%, 50%,.4);
272 | color: hsl(24, 20%, 95%);
273 | font: bold 65%/1.5 sans-serif;
274 | text-align: center;
275 | vertical-align: .3em;
276 | border-radius: 999px;
277 | text-shadow: none;
278 | box-shadow: 0 1px white;
279 | }
280 |
281 | .line-highlight[data-end]:after {
282 | content: attr(data-end);
283 | top: auto;
284 | bottom: .4em;
285 | }
286 | pre.line-numbers {
287 | position: relative;
288 | padding-left: 3.8em;
289 | counter-reset: linenumber;
290 | }
291 |
292 | pre.line-numbers > code {
293 | position: relative;
294 | }
295 |
296 | .line-numbers .line-numbers-rows {
297 | position: absolute;
298 | pointer-events: none;
299 | top: 0;
300 | font-size: 100%;
301 | left: -3.8em;
302 | width: 3em; /* works for line-numbers below 1000 lines */
303 | letter-spacing: -1px;
304 | border-right: 1px solid #999;
305 |
306 | -webkit-user-select: none;
307 | -moz-user-select: none;
308 | -ms-user-select: none;
309 | user-select: none;
310 |
311 | }
312 |
313 | .line-numbers-rows > span {
314 | pointer-events: none;
315 | display: block;
316 | counter-increment: linenumber;
317 | }
318 |
319 | .line-numbers-rows > span:before {
320 | content: counter(linenumber);
321 | color: #999;
322 | display: block;
323 | padding-right: 0.8em;
324 | text-align: right;
325 | }
--------------------------------------------------------------------------------
/demo/prism.js:
--------------------------------------------------------------------------------
1 | /* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+clike+javascript&plugins=line-highlight+line-numbers */
2 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){g&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,b=y+v,k=d.slice(0,y+1),w=d.slice(b+1),_=[p,1];k&&_.push(k);var P=new a(l,c?n.tokenize(m,c):m,h);_.push(P),w&&_.push(w),Array.prototype.splice.apply(r,_)}}}}}return r},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(t)}}},a=n.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var i={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}n.hooks.run("wrap",i);var o="";for(var s in i.attributes)o+=(o?" ":"")+s+'="'+(i.attributes[s]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+o+">"+i.content+""+i.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,i=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),i&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",n.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
3 | Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(
544 |