rails_cropit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,637 @@
1
+ /*
2
+ * cropit - v0.2.0
3
+ * Customizable crop and zoom.
4
+ * https://github.com/scottcheng/cropit
5
+ *
6
+ * Made by Scott Cheng
7
+ * Based on https://github.com/yufeiliu/simple_image_uploader
8
+ * Under MIT License
9
+ */
10
+ (function($) {
11
+ var Zoomer;
12
+ Zoomer = function() {
13
+ function Zoomer() {}
14
+ Zoomer.prototype.setup = function(imageSize, previewSize, exportZoom, options) {
15
+ var heightRatio, widthRatio;
16
+ if (exportZoom == null) {
17
+ exportZoom = 1;
18
+ }
19
+ widthRatio = previewSize.w / imageSize.w;
20
+ heightRatio = previewSize.h / imageSize.h;
21
+ if ((options != null ? options.minZoom : void 0) === "fit") {
22
+ this.minZoom = widthRatio < heightRatio ? widthRatio : heightRatio;
23
+ } else {
24
+ this.minZoom = widthRatio < heightRatio ? heightRatio : widthRatio;
25
+ }
26
+ return this.maxZoom = this.minZoom < 1 / exportZoom ? 1 / exportZoom : this.minZoom;
27
+ };
28
+ Zoomer.prototype.getZoom = function(sliderPos) {
29
+ if (!(this.minZoom && this.maxZoom)) {
30
+ return null;
31
+ }
32
+ return sliderPos * (this.maxZoom - this.minZoom) + this.minZoom;
33
+ };
34
+ Zoomer.prototype.getSliderPos = function(zoom) {
35
+ if (!(this.minZoom && this.maxZoom)) {
36
+ return null;
37
+ }
38
+ if (this.minZoom === this.maxZoom) {
39
+ return 0;
40
+ } else {
41
+ return (zoom - this.minZoom) / (this.maxZoom - this.minZoom);
42
+ }
43
+ };
44
+ Zoomer.prototype.isZoomable = function() {
45
+ if (!(this.minZoom && this.maxZoom)) {
46
+ return null;
47
+ }
48
+ return this.minZoom !== this.maxZoom;
49
+ };
50
+ Zoomer.prototype.fixZoom = function(zoom) {
51
+ if (zoom < this.minZoom) {
52
+ return this.minZoom;
53
+ }
54
+ if (zoom > this.maxZoom) {
55
+ return this.maxZoom;
56
+ }
57
+ return zoom;
58
+ };
59
+ return Zoomer;
60
+ }();
61
+ var Cropit;
62
+ Cropit = function() {
63
+ Cropit._DEFAULTS = {
64
+ exportZoom: 1,
65
+ imageBackground: false,
66
+ imageBackgroundBorderWidth: 0,
67
+ imageState: null,
68
+ allowCrossOrigin: false,
69
+ allowDragNDrop: true,
70
+ freeMove: false,
71
+ minZoom: "fill"
72
+ };
73
+ Cropit.PREVIEW_EVENTS = function() {
74
+ return [ "mousedown", "mouseup", "mouseleave", "touchstart", "touchend", "touchcancel", "touchleave" ].map(function(type) {
75
+ return "" + type + ".cropit";
76
+ }).join(" ");
77
+ }();
78
+ Cropit.PREVIEW_MOVE_EVENTS = "mousemove.cropit touchmove.cropit";
79
+ Cropit.ZOOM_INPUT_EVENTS = function() {
80
+ return [ "mousemove", "touchmove", "change" ].map(function(type) {
81
+ return "" + type + ".cropit";
82
+ }).join(" ");
83
+ }();
84
+ function Cropit(element, options) {
85
+ var dynamicDefaults;
86
+ this.element = element;
87
+ this.$el = $(this.element);
88
+ dynamicDefaults = {
89
+ $fileInput: this.$("input.cropit-image-input"),
90
+ $preview: this.$(".cropit-image-preview"),
91
+ $zoomSlider: this.$("input.cropit-image-zoom-input"),
92
+ $previewContainer: this.$(".cropit-image-preview-container")
93
+ };
94
+ this.options = $.extend({}, Cropit._DEFAULTS, dynamicDefaults, options);
95
+ this.init();
96
+ }
97
+ Cropit.prototype.init = function() {
98
+ var $previewContainer, _ref, _ref1, _ref2;
99
+ this.image = new Image();
100
+ if (this.options.allowCrossOrigin) {
101
+ this.image.crossOrigin = "Anonymous";
102
+ }
103
+ this.$fileInput = this.options.$fileInput.attr({
104
+ accept: "image/*"
105
+ });
106
+ this.$preview = this.options.$preview.css({
107
+ backgroundRepeat: "no-repeat"
108
+ });
109
+ this.$zoomSlider = this.options.$zoomSlider.attr({
110
+ min: 0,
111
+ max: 1,
112
+ step: .01
113
+ });
114
+ this.previewSize = {
115
+ w: this.options.width || this.$preview.width(),
116
+ h: this.options.height || this.$preview.height()
117
+ };
118
+ if (this.options.width) {
119
+ this.$preview.width(this.previewSize.w);
120
+ }
121
+ if (this.options.height) {
122
+ this.$preview.height(this.previewSize.h);
123
+ }
124
+ if (this.options.imageBackground) {
125
+ if ($.isArray(this.options.imageBackgroundBorderWidth)) {
126
+ this.imageBgBorderWidthArray = this.options.imageBackgroundBorderWidth;
127
+ } else {
128
+ this.imageBgBorderWidthArray = [];
129
+ [ 0, 1, 2, 3 ].forEach(function(_this) {
130
+ return function(i) {
131
+ return _this.imageBgBorderWidthArray[i] = _this.options.imageBackgroundBorderWidth;
132
+ };
133
+ }(this));
134
+ }
135
+ $previewContainer = this.options.$previewContainer;
136
+ this.$imageBg = $("<img />").addClass("cropit-image-background").attr("alt", "").css("position", "absolute");
137
+ this.$imageBgContainer = $("<div />").addClass("cropit-image-background-container").css({
138
+ position: "absolute",
139
+ zIndex: 0,
140
+ left: -this.imageBgBorderWidthArray[3] + window.parseInt(this.$preview.css("border-left-width")),
141
+ top: -this.imageBgBorderWidthArray[0] + window.parseInt(this.$preview.css("border-top-width")),
142
+ width: this.previewSize.w + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
143
+ height: this.previewSize.h + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
144
+ }).append(this.$imageBg);
145
+ if (this.imageBgBorderWidthArray[0] > 0) {
146
+ this.$imageBgContainer.css({
147
+ overflow: "hidden"
148
+ });
149
+ }
150
+ $previewContainer.css("position", "relative").prepend(this.$imageBgContainer);
151
+ this.$preview.css("position", "relative");
152
+ this.$preview.hover(function(_this) {
153
+ return function() {
154
+ return _this.$imageBg.addClass("cropit-preview-hovered");
155
+ };
156
+ }(this), function(_this) {
157
+ return function() {
158
+ return _this.$imageBg.removeClass("cropit-preview-hovered");
159
+ };
160
+ }(this));
161
+ }
162
+ this.initialOffset = {
163
+ x: 0,
164
+ y: 0
165
+ };
166
+ this.initialZoom = 0;
167
+ this.initialZoomSliderPos = 0;
168
+ this.imageLoaded = false;
169
+ this.moveContinue = false;
170
+ this.zoomer = new Zoomer();
171
+ if (this.options.allowDragNDrop) {
172
+ jQuery.event.props.push("dataTransfer");
173
+ }
174
+ this.bindListeners();
175
+ this.$zoomSlider.val(this.initialZoomSliderPos);
176
+ this.setOffset(((_ref = this.options.imageState) != null ? _ref.offset : void 0) || this.initialOffset);
177
+ this.zoom = ((_ref1 = this.options.imageState) != null ? _ref1.zoom : void 0) || this.initialZoom;
178
+ return this.loadImage(((_ref2 = this.options.imageState) != null ? _ref2.src : void 0) || null);
179
+ };
180
+ Cropit.prototype.bindListeners = function() {
181
+ this.$fileInput.on("change.cropit", this.onFileChange.bind(this));
182
+ this.$preview.on(Cropit.PREVIEW_EVENTS, this.onPreviewEvent.bind(this));
183
+ this.$zoomSlider.on(Cropit.ZOOM_INPUT_EVENTS, this.onZoomSliderChange.bind(this));
184
+ if (this.options.allowDragNDrop) {
185
+ this.$preview.on("dragover.cropit dragleave.cropit", this.onDragOver.bind(this));
186
+ return this.$preview.on("drop.cropit", this.onDrop.bind(this));
187
+ }
188
+ };
189
+ Cropit.prototype.unbindListeners = function() {
190
+ this.$fileInput.off("change.cropit");
191
+ this.$preview.off(Cropit.PREVIEW_EVENTS);
192
+ this.$preview.off("dragover.cropit dragleave.cropit drop.cropit");
193
+ return this.$zoomSlider.off(Cropit.ZOOM_INPUT_EVENTS);
194
+ };
195
+ Cropit.prototype.reset = function() {
196
+ this.zoom = this.initialZoom;
197
+ return this.offset = this.initialOffset;
198
+ };
199
+ Cropit.prototype.onFileChange = function() {
200
+ var _base;
201
+ if (typeof (_base = this.options).onFileChange === "function") {
202
+ _base.onFileChange();
203
+ }
204
+ return this.loadFileReader(this.$fileInput.get(0).files[0]);
205
+ };
206
+ Cropit.prototype.loadFileReader = function(file) {
207
+ var fileReader;
208
+ fileReader = new FileReader();
209
+ if (file != null ? file.type.match("image") : void 0) {
210
+ this.setImageLoadingClass();
211
+ fileReader.readAsDataURL(file);
212
+ fileReader.onload = this.onFileReaderLoaded.bind(this);
213
+ return fileReader.onerror = this.onFileReaderError.bind(this);
214
+ } else if (file != null) {
215
+ return this.onFileReaderError();
216
+ }
217
+ };
218
+ Cropit.prototype.onFileReaderLoaded = function(e) {
219
+ this.reset();
220
+ return this.loadImage(e.target.result);
221
+ };
222
+ Cropit.prototype.onFileReaderError = function() {
223
+ var _base;
224
+ return typeof (_base = this.options).onFileReaderError === "function" ? _base.onFileReaderError() : void 0;
225
+ };
226
+ Cropit.prototype.onDragOver = function(e) {
227
+ e.preventDefault();
228
+ e.dataTransfer.dropEffect = "copy";
229
+ return this.$preview.toggleClass("cropit-drag-hovered", e.type === "dragover");
230
+ };
231
+ Cropit.prototype.onDrop = function(e) {
232
+ var files;
233
+ e.preventDefault();
234
+ e.stopPropagation();
235
+ files = Array.prototype.slice.call(e.dataTransfer.files, 0);
236
+ files.some(function(_this) {
237
+ return function(file) {
238
+ if (file.type.match("image")) {
239
+ _this.loadFileReader(file);
240
+ return true;
241
+ }
242
+ };
243
+ }(this));
244
+ return this.$preview.removeClass("cropit-drag-hovered");
245
+ };
246
+ Cropit.prototype.loadImage = function(imageSrc) {
247
+ var _base;
248
+ this.imageSrc = imageSrc;
249
+ if (!this.imageSrc) {
250
+ return;
251
+ }
252
+ if (typeof (_base = this.options).onImageLoading === "function") {
253
+ _base.onImageLoading();
254
+ }
255
+ this.setImageLoadingClass();
256
+ this.image.onload = this.onImageLoaded.bind(this);
257
+ this.image.onerror = this.onImageError.bind(this);
258
+ return this.image.src = this.imageSrc;
259
+ };
260
+ Cropit.prototype.onImageLoaded = function() {
261
+ var _base;
262
+ this.setImageLoadedClass();
263
+ this.setOffset(this.offset);
264
+ this.$preview.css("background-image", "url(" + this.imageSrc + ")");
265
+ if (this.options.imageBackground) {
266
+ this.$imageBg.attr("src", this.imageSrc);
267
+ }
268
+ this.imageSize = {
269
+ w: this.image.width,
270
+ h: this.image.height
271
+ };
272
+ this.setupZoomer();
273
+ this.imageLoaded = true;
274
+ return typeof (_base = this.options).onImageLoaded === "function" ? _base.onImageLoaded() : void 0;
275
+ };
276
+ Cropit.prototype.onImageError = function() {
277
+ var _base;
278
+ return typeof (_base = this.options).onImageError === "function" ? _base.onImageError() : void 0;
279
+ };
280
+ Cropit.prototype.setImageLoadingClass = function() {
281
+ return this.$preview.removeClass("cropit-image-loaded").addClass("cropit-image-loading");
282
+ };
283
+ Cropit.prototype.setImageLoadedClass = function() {
284
+ return this.$preview.removeClass("cropit-image-loading").addClass("cropit-image-loaded");
285
+ };
286
+ Cropit.prototype.getEventPosition = function(e) {
287
+ var _ref, _ref1, _ref2, _ref3;
288
+ if ((_ref = e.originalEvent) != null ? (_ref1 = _ref.touches) != null ? _ref1[0] : void 0 : void 0) {
289
+ e = (_ref2 = e.originalEvent) != null ? (_ref3 = _ref2.touches) != null ? _ref3[0] : void 0 : void 0;
290
+ }
291
+ if (e.clientX && e.clientY) {
292
+ return {
293
+ x: e.clientX,
294
+ y: e.clientY
295
+ };
296
+ }
297
+ };
298
+ Cropit.prototype.onPreviewEvent = function(e) {
299
+ if (!this.imageLoaded) {
300
+ return;
301
+ }
302
+ this.moveContinue = false;
303
+ this.$preview.off(Cropit.PREVIEW_MOVE_EVENTS);
304
+ if (e.type === "mousedown" || e.type === "touchstart") {
305
+ this.origin = this.getEventPosition(e);
306
+ this.moveContinue = true;
307
+ this.$preview.on(Cropit.PREVIEW_MOVE_EVENTS, this.onMove.bind(this));
308
+ } else {
309
+ $(document.body).focus();
310
+ }
311
+ e.stopPropagation();
312
+ return false;
313
+ };
314
+ Cropit.prototype.onMove = function(e) {
315
+ var eventPosition;
316
+ eventPosition = this.getEventPosition(e);
317
+ if (this.moveContinue && eventPosition) {
318
+ this.setOffset({
319
+ x: this.offset.x + eventPosition.x - this.origin.x,
320
+ y: this.offset.y + eventPosition.y - this.origin.y
321
+ });
322
+ }
323
+ this.origin = eventPosition;
324
+ e.stopPropagation();
325
+ return false;
326
+ };
327
+ Cropit.prototype.setOffset = function(position) {
328
+ this.offset = this.fixOffset(position);
329
+ this.$preview.css("background-position", "" + this.offset.x + "px " + this.offset.y + "px");
330
+ if (this.options.imageBackground) {
331
+ return this.$imageBg.css({
332
+ left: this.offset.x + this.imageBgBorderWidthArray[3],
333
+ top: this.offset.y + this.imageBgBorderWidthArray[0]
334
+ });
335
+ }
336
+ };
337
+ Cropit.prototype.fixOffset = function(offset) {
338
+ var ret;
339
+ if (!this.imageLoaded) {
340
+ return offset;
341
+ }
342
+ ret = {
343
+ x: offset.x,
344
+ y: offset.y
345
+ };
346
+ if (!this.options.freeMove) {
347
+ if (this.imageSize.w * this.zoom >= this.previewSize.w) {
348
+ ret.x = Math.min(0, Math.max(ret.x, this.previewSize.w - this.imageSize.w * this.zoom));
349
+ } else {
350
+ ret.x = Math.max(0, Math.min(ret.x, this.previewSize.w - this.imageSize.w * this.zoom));
351
+ }
352
+ if (this.imageSize.h * this.zoom >= this.previewSize.h) {
353
+ ret.y = Math.min(0, Math.max(ret.y, this.previewSize.h - this.imageSize.h * this.zoom));
354
+ } else {
355
+ ret.y = Math.max(0, Math.min(ret.y, this.previewSize.h - this.imageSize.h * this.zoom));
356
+ }
357
+ }
358
+ ret.x = this.round(ret.x);
359
+ ret.y = this.round(ret.y);
360
+ return ret;
361
+ };
362
+ Cropit.prototype.onZoomSliderChange = function() {
363
+ var newZoom;
364
+ if (!this.imageLoaded) {
365
+ return;
366
+ }
367
+ this.zoomSliderPos = Number(this.$zoomSlider.val());
368
+ newZoom = this.zoomer.getZoom(this.zoomSliderPos);
369
+ return this.setZoom(newZoom);
370
+ };
371
+ Cropit.prototype.enableZoomSlider = function() {
372
+ var _base;
373
+ this.$zoomSlider.removeAttr("disabled");
374
+ return typeof (_base = this.options).onZoomEnabled === "function" ? _base.onZoomEnabled() : void 0;
375
+ };
376
+ Cropit.prototype.disableZoomSlider = function() {
377
+ var _base;
378
+ this.$zoomSlider.attr("disabled", true);
379
+ return typeof (_base = this.options).onZoomDisabled === "function" ? _base.onZoomDisabled() : void 0;
380
+ };
381
+ Cropit.prototype.setupZoomer = function() {
382
+ this.zoomer.setup(this.imageSize, this.previewSize, this.options.exportZoom, this.options);
383
+ this.zoom = this.fixZoom(this.zoom);
384
+ this.setZoom(this.zoom);
385
+ if (this.isZoomable()) {
386
+ return this.enableZoomSlider();
387
+ } else {
388
+ return this.disableZoomSlider();
389
+ }
390
+ };
391
+ Cropit.prototype.setZoom = function(newZoom) {
392
+ var newX, newY, oldZoom, updatedHeight, updatedWidth;
393
+ newZoom = this.fixZoom(newZoom);
394
+ updatedWidth = this.round(this.imageSize.w * newZoom);
395
+ updatedHeight = this.round(this.imageSize.h * newZoom);
396
+ oldZoom = this.zoom;
397
+ newX = this.previewSize.w / 2 - (this.previewSize.w / 2 - this.offset.x) * newZoom / oldZoom;
398
+ newY = this.previewSize.h / 2 - (this.previewSize.h / 2 - this.offset.y) * newZoom / oldZoom;
399
+ this.zoom = newZoom;
400
+ this.setOffset({
401
+ x: newX,
402
+ y: newY
403
+ });
404
+ this.zoomSliderPos = this.zoomer.getSliderPos(this.zoom);
405
+ this.$zoomSlider.val(this.zoomSliderPos);
406
+ this.$preview.css("background-size", "" + updatedWidth + "px " + updatedHeight + "px");
407
+ if (this.options.imageBackground) {
408
+ return this.$imageBg.css({
409
+ width: updatedWidth,
410
+ height: updatedHeight
411
+ });
412
+ }
413
+ };
414
+ Cropit.prototype.fixZoom = function(zoom) {
415
+ return this.zoomer.fixZoom(zoom);
416
+ };
417
+ Cropit.prototype.isZoomable = function() {
418
+ return this.zoomer.isZoomable();
419
+ };
420
+ Cropit.prototype.getCroppedImageData = function(exportOptions) {
421
+ var canvas, canvasContext, croppedSize, exportDefaults, exportZoom;
422
+ if (!this.imageSrc) {
423
+ return null;
424
+ }
425
+ exportDefaults = {
426
+ type: "image/png",
427
+ quality: .75,
428
+ originalSize: false,
429
+ fillBg: "#fff"
430
+ };
431
+ exportOptions = $.extend({}, exportDefaults, exportOptions);
432
+ croppedSize = {
433
+ w: this.previewSize.w,
434
+ h: this.previewSize.h
435
+ };
436
+ exportZoom = exportOptions.originalSize ? 1 / this.zoom : this.options.exportZoom;
437
+ canvas = $("<canvas />").attr({
438
+ width: croppedSize.w * exportZoom,
439
+ height: croppedSize.h * exportZoom
440
+ }).get(0);
441
+ canvasContext = canvas.getContext("2d");
442
+ if (exportOptions.type === "image/jpeg") {
443
+ canvasContext.fillStyle = exportOptions.fillBg;
444
+ canvasContext.fillRect(0, 0, canvas.width, canvas.height);
445
+ }
446
+ canvasContext.drawImage(this.image, this.offset.x * exportZoom, this.offset.y * exportZoom, this.zoom * exportZoom * this.imageSize.w, this.zoom * exportZoom * this.imageSize.h);
447
+ return canvas.toDataURL(exportOptions.type, exportOptions.quality);
448
+ };
449
+ Cropit.prototype.getImageState = function() {
450
+ return {
451
+ src: this.imageSrc,
452
+ offset: this.offset,
453
+ zoom: this.zoom
454
+ };
455
+ };
456
+ Cropit.prototype.getImageSrc = function() {
457
+ return this.imageSrc;
458
+ };
459
+ Cropit.prototype.getOffset = function() {
460
+ return this.offset;
461
+ };
462
+ Cropit.prototype.getZoom = function() {
463
+ return this.zoom;
464
+ };
465
+ Cropit.prototype.getImageSize = function() {
466
+ if (!this.imageSize) {
467
+ return null;
468
+ }
469
+ return {
470
+ width: this.imageSize.w,
471
+ height: this.imageSize.h
472
+ };
473
+ };
474
+ Cropit.prototype.getPreviewSize = function() {
475
+ return {
476
+ width: this.previewSize.w,
477
+ height: this.previewSize.h
478
+ };
479
+ };
480
+ Cropit.prototype.setPreviewSize = function(size) {
481
+ if (!((size != null ? size.width : void 0) > 0 && (size != null ? size.height : void 0) > 0)) {
482
+ return;
483
+ }
484
+ this.previewSize = {
485
+ w: size.width,
486
+ h: size.height
487
+ };
488
+ this.$preview.css({
489
+ width: this.previewSize.w,
490
+ height: this.previewSize.h
491
+ });
492
+ if (this.options.imageBackground) {
493
+ this.$imageBgContainer.css({
494
+ width: this.previewSize.w + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
495
+ height: this.previewSize.h + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
496
+ });
497
+ }
498
+ if (this.imageLoaded) {
499
+ return this.setupZoomer();
500
+ }
501
+ };
502
+ Cropit.prototype.disable = function() {
503
+ this.unbindListeners();
504
+ this.disableZoomSlider();
505
+ return this.$el.addClass("cropit-disabled");
506
+ };
507
+ Cropit.prototype.reenable = function() {
508
+ this.bindListeners();
509
+ this.enableZoomSlider();
510
+ return this.$el.removeClass("cropit-disabled");
511
+ };
512
+ Cropit.prototype.round = function(x) {
513
+ return +(Math.round(x * 100) + "e-2");
514
+ };
515
+ Cropit.prototype.$ = function(selector) {
516
+ if (!this.$el) {
517
+ return null;
518
+ }
519
+ return this.$el.find(selector);
520
+ };
521
+ return Cropit;
522
+ }();
523
+ var dataKey, methods;
524
+ dataKey = "cropit";
525
+ methods = {
526
+ init: function(options) {
527
+ return this.each(function() {
528
+ var cropit;
529
+ if (!$.data(this, dataKey)) {
530
+ cropit = new Cropit(this, options);
531
+ return $.data(this, dataKey, cropit);
532
+ }
533
+ });
534
+ },
535
+ destroy: function() {
536
+ return this.each(function() {
537
+ return $.removeData(this, dataKey);
538
+ });
539
+ },
540
+ isZoomable: function() {
541
+ var cropit;
542
+ cropit = this.first().data(dataKey);
543
+ return cropit != null ? cropit.isZoomable() : void 0;
544
+ },
545
+ "export": function(options) {
546
+ var cropit;
547
+ cropit = this.first().data(dataKey);
548
+ return cropit != null ? cropit.getCroppedImageData(options) : void 0;
549
+ },
550
+ imageState: function() {
551
+ var cropit;
552
+ cropit = this.first().data(dataKey);
553
+ return cropit != null ? cropit.getImageState() : void 0;
554
+ },
555
+ imageSrc: function(newImageSrc) {
556
+ var cropit;
557
+ if (newImageSrc != null) {
558
+ return this.each(function() {
559
+ var cropit;
560
+ cropit = $.data(this, dataKey);
561
+ if (cropit != null) {
562
+ cropit.reset();
563
+ }
564
+ return cropit != null ? cropit.loadImage(newImageSrc) : void 0;
565
+ });
566
+ } else {
567
+ cropit = this.first().data(dataKey);
568
+ return cropit != null ? cropit.getImageSrc() : void 0;
569
+ }
570
+ },
571
+ offset: function(newOffset) {
572
+ var cropit;
573
+ if (newOffset != null && newOffset.x != null && newOffset.y != null) {
574
+ return this.each(function() {
575
+ var cropit;
576
+ cropit = $.data(this, dataKey);
577
+ return cropit != null ? cropit.setOffset(newOffset) : void 0;
578
+ });
579
+ } else {
580
+ cropit = this.first().data(dataKey);
581
+ return cropit != null ? cropit.getOffset() : void 0;
582
+ }
583
+ },
584
+ zoom: function(newZoom) {
585
+ var cropit;
586
+ if (newZoom != null) {
587
+ return this.each(function() {
588
+ var cropit;
589
+ cropit = $.data(this, dataKey);
590
+ return cropit != null ? cropit.setZoom(newZoom) : void 0;
591
+ });
592
+ } else {
593
+ cropit = this.first().data(dataKey);
594
+ return cropit != null ? cropit.getZoom() : void 0;
595
+ }
596
+ },
597
+ imageSize: function() {
598
+ var cropit;
599
+ cropit = this.first().data(dataKey);
600
+ return cropit != null ? cropit.getImageSize() : void 0;
601
+ },
602
+ previewSize: function(newSize) {
603
+ var cropit;
604
+ if (newSize != null) {
605
+ return this.each(function() {
606
+ var cropit;
607
+ cropit = $.data(this, dataKey);
608
+ return cropit != null ? cropit.setPreviewSize(newSize) : void 0;
609
+ });
610
+ } else {
611
+ cropit = this.first().data(dataKey);
612
+ return cropit != null ? cropit.getPreviewSize() : void 0;
613
+ }
614
+ },
615
+ disable: function() {
616
+ return this.each(function() {
617
+ var cropit;
618
+ cropit = $.data(this, dataKey);
619
+ return cropit.disable();
620
+ });
621
+ },
622
+ reenable: function() {
623
+ return this.each(function() {
624
+ var cropit;
625
+ cropit = $.data(this, dataKey);
626
+ return cropit.reenable();
627
+ });
628
+ }
629
+ };
630
+ $.fn.cropit = function(method) {
631
+ if (methods[method]) {
632
+ return methods[method].apply(this, [].slice.call(arguments, 1));
633
+ } else {
634
+ return methods.init.apply(this, arguments);
635
+ }
636
+ };
637
+ })(window.jQuery);
@@ -0,0 +1,10 @@
1
+ /*
2
+ * cropit - v0.2.0
3
+ * Customizable crop and zoom.
4
+ * https://github.com/scottcheng/cropit
5
+ *
6
+ * Made by Scott Cheng
7
+ * Based on https://github.com/yufeiliu/simple_image_uploader
8
+ * Under MIT License
9
+ */
10
+ !function(a){var b;b=function(){function a(){}return a.prototype.setup=function(a,b,c,d){var e,f;return null==c&&(c=1),f=b.w/a.w,e=b.h/a.h,this.minZoom="fit"===(null!=d?d.minZoom:void 0)?e>f?f:e:e>f?e:f,this.maxZoom=this.minZoom<1/c?1/c:this.minZoom},a.prototype.getZoom=function(a){return this.minZoom&&this.maxZoom?a*(this.maxZoom-this.minZoom)+this.minZoom:null},a.prototype.getSliderPos=function(a){return this.minZoom&&this.maxZoom?this.minZoom===this.maxZoom?0:(a-this.minZoom)/(this.maxZoom-this.minZoom):null},a.prototype.isZoomable=function(){return this.minZoom&&this.maxZoom?this.minZoom!==this.maxZoom:null},a.prototype.fixZoom=function(a){return a<this.minZoom?this.minZoom:a>this.maxZoom?this.maxZoom:a},a}();var c;c=function(){function c(b,d){var e;this.element=b,this.$el=a(this.element),e={$fileInput:this.$("input.cropit-image-input"),$preview:this.$(".cropit-image-preview"),$zoomSlider:this.$("input.cropit-image-zoom-input"),$previewContainer:this.$(".cropit-image-preview-container")},this.options=a.extend({},c._DEFAULTS,e,d),this.init()}return c._DEFAULTS={exportZoom:1,imageBackground:!1,imageBackgroundBorderWidth:0,imageState:null,allowCrossOrigin:!1,allowDragNDrop:!0,freeMove:!1,minZoom:"fill"},c.PREVIEW_EVENTS=function(){return["mousedown","mouseup","mouseleave","touchstart","touchend","touchcancel","touchleave"].map(function(a){return""+a+".cropit"}).join(" ")}(),c.PREVIEW_MOVE_EVENTS="mousemove.cropit touchmove.cropit",c.ZOOM_INPUT_EVENTS=function(){return["mousemove","touchmove","change"].map(function(a){return""+a+".cropit"}).join(" ")}(),c.prototype.init=function(){var c,d,e,f;return this.image=new Image,this.options.allowCrossOrigin&&(this.image.crossOrigin="Anonymous"),this.$fileInput=this.options.$fileInput.attr({accept:"image/*"}),this.$preview=this.options.$preview.css({backgroundRepeat:"no-repeat"}),this.$zoomSlider=this.options.$zoomSlider.attr({min:0,max:1,step:.01}),this.previewSize={w:this.options.width||this.$preview.width(),h:this.options.height||this.$preview.height()},this.options.width&&this.$preview.width(this.previewSize.w),this.options.height&&this.$preview.height(this.previewSize.h),this.options.imageBackground&&(a.isArray(this.options.imageBackgroundBorderWidth)?this.imageBgBorderWidthArray=this.options.imageBackgroundBorderWidth:(this.imageBgBorderWidthArray=[],[0,1,2,3].forEach(function(a){return function(b){return a.imageBgBorderWidthArray[b]=a.options.imageBackgroundBorderWidth}}(this))),c=this.options.$previewContainer,this.$imageBg=a("<img />").addClass("cropit-image-background").attr("alt","").css("position","absolute"),this.$imageBgContainer=a("<div />").addClass("cropit-image-background-container").css({position:"absolute",zIndex:0,left:-this.imageBgBorderWidthArray[3]+window.parseInt(this.$preview.css("border-left-width")),top:-this.imageBgBorderWidthArray[0]+window.parseInt(this.$preview.css("border-top-width")),width:this.previewSize.w+this.imageBgBorderWidthArray[1]+this.imageBgBorderWidthArray[3],height:this.previewSize.h+this.imageBgBorderWidthArray[0]+this.imageBgBorderWidthArray[2]}).append(this.$imageBg),this.imageBgBorderWidthArray[0]>0&&this.$imageBgContainer.css({overflow:"hidden"}),c.css("position","relative").prepend(this.$imageBgContainer),this.$preview.css("position","relative"),this.$preview.hover(function(a){return function(){return a.$imageBg.addClass("cropit-preview-hovered")}}(this),function(a){return function(){return a.$imageBg.removeClass("cropit-preview-hovered")}}(this))),this.initialOffset={x:0,y:0},this.initialZoom=0,this.initialZoomSliderPos=0,this.imageLoaded=!1,this.moveContinue=!1,this.zoomer=new b,this.options.allowDragNDrop&&jQuery.event.props.push("dataTransfer"),this.bindListeners(),this.$zoomSlider.val(this.initialZoomSliderPos),this.setOffset((null!=(d=this.options.imageState)?d.offset:void 0)||this.initialOffset),this.zoom=(null!=(e=this.options.imageState)?e.zoom:void 0)||this.initialZoom,this.loadImage((null!=(f=this.options.imageState)?f.src:void 0)||null)},c.prototype.bindListeners=function(){return this.$fileInput.on("change.cropit",this.onFileChange.bind(this)),this.$preview.on(c.PREVIEW_EVENTS,this.onPreviewEvent.bind(this)),this.$zoomSlider.on(c.ZOOM_INPUT_EVENTS,this.onZoomSliderChange.bind(this)),this.options.allowDragNDrop?(this.$preview.on("dragover.cropit dragleave.cropit",this.onDragOver.bind(this)),this.$preview.on("drop.cropit",this.onDrop.bind(this))):void 0},c.prototype.unbindListeners=function(){return this.$fileInput.off("change.cropit"),this.$preview.off(c.PREVIEW_EVENTS),this.$preview.off("dragover.cropit dragleave.cropit drop.cropit"),this.$zoomSlider.off(c.ZOOM_INPUT_EVENTS)},c.prototype.reset=function(){return this.zoom=this.initialZoom,this.offset=this.initialOffset},c.prototype.onFileChange=function(){var a;return"function"==typeof(a=this.options).onFileChange&&a.onFileChange(),this.loadFileReader(this.$fileInput.get(0).files[0])},c.prototype.loadFileReader=function(a){var b;return b=new FileReader,(null!=a?a.type.match("image"):void 0)?(this.setImageLoadingClass(),b.readAsDataURL(a),b.onload=this.onFileReaderLoaded.bind(this),b.onerror=this.onFileReaderError.bind(this)):null!=a?this.onFileReaderError():void 0},c.prototype.onFileReaderLoaded=function(a){return this.reset(),this.loadImage(a.target.result)},c.prototype.onFileReaderError=function(){var a;return"function"==typeof(a=this.options).onFileReaderError?a.onFileReaderError():void 0},c.prototype.onDragOver=function(a){return a.preventDefault(),a.dataTransfer.dropEffect="copy",this.$preview.toggleClass("cropit-drag-hovered","dragover"===a.type)},c.prototype.onDrop=function(a){var b;return a.preventDefault(),a.stopPropagation(),b=Array.prototype.slice.call(a.dataTransfer.files,0),b.some(function(a){return function(b){return b.type.match("image")?(a.loadFileReader(b),!0):void 0}}(this)),this.$preview.removeClass("cropit-drag-hovered")},c.prototype.loadImage=function(a){var b;return this.imageSrc=a,this.imageSrc?("function"==typeof(b=this.options).onImageLoading&&b.onImageLoading(),this.setImageLoadingClass(),this.image.onload=this.onImageLoaded.bind(this),this.image.onerror=this.onImageError.bind(this),this.image.src=this.imageSrc):void 0},c.prototype.onImageLoaded=function(){var a;return this.setImageLoadedClass(),this.setOffset(this.offset),this.$preview.css("background-image","url("+this.imageSrc+")"),this.options.imageBackground&&this.$imageBg.attr("src",this.imageSrc),this.imageSize={w:this.image.width,h:this.image.height},this.setupZoomer(),this.imageLoaded=!0,"function"==typeof(a=this.options).onImageLoaded?a.onImageLoaded():void 0},c.prototype.onImageError=function(){var a;return"function"==typeof(a=this.options).onImageError?a.onImageError():void 0},c.prototype.setImageLoadingClass=function(){return this.$preview.removeClass("cropit-image-loaded").addClass("cropit-image-loading")},c.prototype.setImageLoadedClass=function(){return this.$preview.removeClass("cropit-image-loading").addClass("cropit-image-loaded")},c.prototype.getEventPosition=function(a){var b,c,d,e;return(null!=(b=a.originalEvent)&&null!=(c=b.touches)?c[0]:void 0)&&(a=null!=(d=a.originalEvent)&&null!=(e=d.touches)?e[0]:void 0),a.clientX&&a.clientY?{x:a.clientX,y:a.clientY}:void 0},c.prototype.onPreviewEvent=function(b){return this.imageLoaded?(this.moveContinue=!1,this.$preview.off(c.PREVIEW_MOVE_EVENTS),"mousedown"===b.type||"touchstart"===b.type?(this.origin=this.getEventPosition(b),this.moveContinue=!0,this.$preview.on(c.PREVIEW_MOVE_EVENTS,this.onMove.bind(this))):a(document.body).focus(),b.stopPropagation(),!1):void 0},c.prototype.onMove=function(a){var b;return b=this.getEventPosition(a),this.moveContinue&&b&&this.setOffset({x:this.offset.x+b.x-this.origin.x,y:this.offset.y+b.y-this.origin.y}),this.origin=b,a.stopPropagation(),!1},c.prototype.setOffset=function(a){return this.offset=this.fixOffset(a),this.$preview.css("background-position",""+this.offset.x+"px "+this.offset.y+"px"),this.options.imageBackground?this.$imageBg.css({left:this.offset.x+this.imageBgBorderWidthArray[3],top:this.offset.y+this.imageBgBorderWidthArray[0]}):void 0},c.prototype.fixOffset=function(a){var b;return this.imageLoaded?(b={x:a.x,y:a.y},this.options.freeMove||(b.x=this.imageSize.w*this.zoom>=this.previewSize.w?Math.min(0,Math.max(b.x,this.previewSize.w-this.imageSize.w*this.zoom)):Math.max(0,Math.min(b.x,this.previewSize.w-this.imageSize.w*this.zoom)),b.y=this.imageSize.h*this.zoom>=this.previewSize.h?Math.min(0,Math.max(b.y,this.previewSize.h-this.imageSize.h*this.zoom)):Math.max(0,Math.min(b.y,this.previewSize.h-this.imageSize.h*this.zoom))),b.x=this.round(b.x),b.y=this.round(b.y),b):a},c.prototype.onZoomSliderChange=function(){var a;if(this.imageLoaded)return this.zoomSliderPos=Number(this.$zoomSlider.val()),a=this.zoomer.getZoom(this.zoomSliderPos),this.setZoom(a)},c.prototype.enableZoomSlider=function(){var a;return this.$zoomSlider.removeAttr("disabled"),"function"==typeof(a=this.options).onZoomEnabled?a.onZoomEnabled():void 0},c.prototype.disableZoomSlider=function(){var a;return this.$zoomSlider.attr("disabled",!0),"function"==typeof(a=this.options).onZoomDisabled?a.onZoomDisabled():void 0},c.prototype.setupZoomer=function(){return this.zoomer.setup(this.imageSize,this.previewSize,this.options.exportZoom,this.options),this.zoom=this.fixZoom(this.zoom),this.setZoom(this.zoom),this.isZoomable()?this.enableZoomSlider():this.disableZoomSlider()},c.prototype.setZoom=function(a){var b,c,d,e,f;return a=this.fixZoom(a),f=this.round(this.imageSize.w*a),e=this.round(this.imageSize.h*a),d=this.zoom,b=this.previewSize.w/2-(this.previewSize.w/2-this.offset.x)*a/d,c=this.previewSize.h/2-(this.previewSize.h/2-this.offset.y)*a/d,this.zoom=a,this.setOffset({x:b,y:c}),this.zoomSliderPos=this.zoomer.getSliderPos(this.zoom),this.$zoomSlider.val(this.zoomSliderPos),this.$preview.css("background-size",""+f+"px "+e+"px"),this.options.imageBackground?this.$imageBg.css({width:f,height:e}):void 0},c.prototype.fixZoom=function(a){return this.zoomer.fixZoom(a)},c.prototype.isZoomable=function(){return this.zoomer.isZoomable()},c.prototype.getCroppedImageData=function(b){var c,d,e,f,g;return this.imageSrc?(f={type:"image/png",quality:.75,originalSize:!1,fillBg:"#fff"},b=a.extend({},f,b),e={w:this.previewSize.w,h:this.previewSize.h},g=b.originalSize?1/this.zoom:this.options.exportZoom,c=a("<canvas />").attr({width:e.w*g,height:e.h*g}).get(0),d=c.getContext("2d"),"image/jpeg"===b.type&&(d.fillStyle=b.fillBg,d.fillRect(0,0,c.width,c.height)),d.drawImage(this.image,this.offset.x*g,this.offset.y*g,this.zoom*g*this.imageSize.w,this.zoom*g*this.imageSize.h),c.toDataURL(b.type,b.quality)):null},c.prototype.getImageState=function(){return{src:this.imageSrc,offset:this.offset,zoom:this.zoom}},c.prototype.getImageSrc=function(){return this.imageSrc},c.prototype.getOffset=function(){return this.offset},c.prototype.getZoom=function(){return this.zoom},c.prototype.getImageSize=function(){return this.imageSize?{width:this.imageSize.w,height:this.imageSize.h}:null},c.prototype.getPreviewSize=function(){return{width:this.previewSize.w,height:this.previewSize.h}},c.prototype.setPreviewSize=function(a){return(null!=a?a.width:void 0)>0&&(null!=a?a.height:void 0)>0?(this.previewSize={w:a.width,h:a.height},this.$preview.css({width:this.previewSize.w,height:this.previewSize.h}),this.options.imageBackground&&this.$imageBgContainer.css({width:this.previewSize.w+this.imageBgBorderWidthArray[1]+this.imageBgBorderWidthArray[3],height:this.previewSize.h+this.imageBgBorderWidthArray[0]+this.imageBgBorderWidthArray[2]}),this.imageLoaded?this.setupZoomer():void 0):void 0},c.prototype.disable=function(){return this.unbindListeners(),this.disableZoomSlider(),this.$el.addClass("cropit-disabled")},c.prototype.reenable=function(){return this.bindListeners(),this.enableZoomSlider(),this.$el.removeClass("cropit-disabled")},c.prototype.round=function(a){return+(Math.round(100*a)+"e-2")},c.prototype.$=function(a){return this.$el?this.$el.find(a):null},c}();var d,e;d="cropit",e={init:function(b){return this.each(function(){var e;return a.data(this,d)?void 0:(e=new c(this,b),a.data(this,d,e))})},destroy:function(){return this.each(function(){return a.removeData(this,d)})},isZoomable:function(){var a;return a=this.first().data(d),null!=a?a.isZoomable():void 0},"export":function(a){var b;return b=this.first().data(d),null!=b?b.getCroppedImageData(a):void 0},imageState:function(){var a;return a=this.first().data(d),null!=a?a.getImageState():void 0},imageSrc:function(b){var c;return null!=b?this.each(function(){var c;return c=a.data(this,d),null!=c&&c.reset(),null!=c?c.loadImage(b):void 0}):(c=this.first().data(d),null!=c?c.getImageSrc():void 0)},offset:function(b){var c;return null!=b&&null!=b.x&&null!=b.y?this.each(function(){var c;return c=a.data(this,d),null!=c?c.setOffset(b):void 0}):(c=this.first().data(d),null!=c?c.getOffset():void 0)},zoom:function(b){var c;return null!=b?this.each(function(){var c;return c=a.data(this,d),null!=c?c.setZoom(b):void 0}):(c=this.first().data(d),null!=c?c.getZoom():void 0)},imageSize:function(){var a;return a=this.first().data(d),null!=a?a.getImageSize():void 0},previewSize:function(b){var c;return null!=b?this.each(function(){var c;return c=a.data(this,d),null!=c?c.setPreviewSize(b):void 0}):(c=this.first().data(d),null!=c?c.getPreviewSize():void 0)},disable:function(){return this.each(function(){var b;return b=a.data(this,d),b.disable()})},reenable:function(){return this.each(function(){var b;return b=a.data(this,d),b.reenable()})}},a.fn.cropit=function(a){return e[a]?e[a].apply(this,[].slice.call(arguments,1)):e.init.apply(this,arguments)}}(window.jQuery);