voltron-crop 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aa0b2ed35e7274922caf416da52fb672edcb9714a9e7bb990abf15e91f59070f
4
+ data.tar.gz: 01e44206dbf45b0e28e5e917c5f71e3b7067845a0a01742bdce061892187651c
5
+ SHA512:
6
+ metadata.gz: edfc87008365ed1b36a29e45c307c467b56c249e28b2ddadc346a3af88b3a0d3e17f9e1b59fb7b1296e3f8fa77326a2d2b377c7132487389ff73225511cd3441
7
+ data.tar.gz: 8b0b1d73756f34754f6273fa473e36322dbf3fa326595955b833ba3c974d301d466131a15c1e75820102e2a6b1c8ac53474e8aea3276997e3f2e35f224172933
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ tmp/
10
+ log/
11
+ voltron-*.gem
12
+ *.bak
13
+ database.yml
14
+ public/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.3
5
+ - 2.3.1
6
+ - 2.3.3
7
+ - 2.4.1
8
+ before_install: gem install bundler -v 1.12.5
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at eric.hainer@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+ source 'https://gem.minow.io'
3
+
4
+ # Specify your gem's dependencies in voltron-crop.gemspec
5
+ gemspec
6
+
7
+ group :test do
8
+ gem 'coveralls', require: false
9
+ gem 'simplecov', '0.11.0'
10
+ end
11
+
12
+ group :development, :test do
13
+ gem 'jquery-rails', '~> 4'
14
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Eric Hainer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ [![Coverage Status](https://coveralls.io/repos/github/ehainer/voltron-crop/badge.svg?branch=master)](https://coveralls.io/github/ehainer/voltron-crop?branch=master)
2
+ [![Build Status](https://travis-ci.org/ehainer/voltron-crop.svg?branch=master)](https://travis-ci.org/ehainer/voltron-crop)
3
+ [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0)
4
+
5
+ # Voltron::Crop
6
+
7
+ Trying to bring a little sanity to the process of cropping images in ruby utilizing Scott Cheng's [cropit](http://scottcheng.github.io/cropit/) plugin and the [CarrierWave](https://github.com/carrierwaveuploader/carrierwave) file uploader.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'voltron-crop', '~> 0.1.3'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle install
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install voltron-crop
24
+
25
+ Then run the following to create the voltron.rb initializer (if not existing already) and add the upload config:
26
+
27
+ $ rails g voltron:crop:install
28
+
29
+ Then, include the necessary js and css by adding the following to your application.js and application.css respectively
30
+
31
+ ```javascript
32
+ //= require voltron-crop
33
+ ```
34
+
35
+ ```css
36
+ /*
37
+ *= require voltron-crop
38
+ */
39
+ ```
40
+
41
+ If you want to customize the out-of-the-box functionality or styles, you can copy the assets (javascript/css) to your app assets directory by running:
42
+
43
+ $ rails g voltron:crop:install:assets
44
+
45
+ ## Usage
46
+
47
+ Voltron Crop exposes a new form builder method, `crop_field`, that is essentially just an extension of FormBuilder's [file_field](https://apidock.com/rails/ActionView/Helpers/FormBuilder/file_field) method, but automatically handles the creation of necessary data-* attributes on the generated input field that are utilitzed by the crop js module to generate the crop interface.
48
+
49
+ Given a user model with the following (using [CarrierWave's](https://github.com/carrierwaveuploader/carrierwave) `mount_uploader` method)
50
+
51
+ ```ruby
52
+ class User < ActiveRecord::Base
53
+ mount_uploader :avatar, AvatarUploader
54
+ end
55
+ ```
56
+
57
+ ```ruby
58
+ <%= form_for @user do |f| %>
59
+ <%= f.crop_field :avatar %>
60
+ <% end %>
61
+ ```
62
+
63
+ Optionally, any cropit option listed on the [cropit site](http://scottcheng.github.io/cropit/) can be passed as a part of the `data-crop-options` attribute (you would need to modify the js module to change options whose value is a callback function, see Installation above for instructions on extracting the assets for modification):
64
+
65
+ ```ruby
66
+ <%= form_for @user do |f| %>
67
+ <%= f.crop_field :avatar, data: { crop_options: { width: 300, height: 300 } } %>
68
+ <% end %>
69
+ ```
70
+
71
+ ## Configuration
72
+
73
+ After running the installer (see: Installation), configuration options should appear within `config/initializers/voltron.rb`
74
+
75
+ | Option | Default | Comment |
76
+ |------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
77
+ | min_width | 300 (pixels) | The minimum width of the cropped image. This does not affect the preview crop size, it only makes a difference when the image itself is cropped. If the cropped image width is less than this value, the image is automatically scaled up proportionally to match this minimum width. |
78
+ | min_height | 300 (pixels) | The minimum height of the cropped image. This does not affect the preview crop size, it only makes a difference when the image itself is cropped. If the cropped image height is less than this value, the image is automatically scaled up proportionally to match this minimum height. |
79
+
80
+ ## Integration
81
+
82
+ Voltron Crop is designed to work seamlessly with [Voltron Upload](https://github.com/ehainer/voltron-upload), to the point that no changes are necessary to use both together. If Voltron Upload is installed it will still have an effect on file upload fields, even those generated via the `crop_field` method. The built in event observer methods found in the Crop js module (`onBeforeModuleInitializeUpload`, `onUploadComplete`) handles tying the upload module to the crop interface. There is also a built-in upload preview template in the Upload gem that is designed to work well with the crop interface, the `progress` template. If using the Crop and Upload gem together, the following is at the very least a good start for a simple user interface, as the upload container will take the form of a one-off file upload progress bar that changes the crop image when uploaded:
83
+
84
+ ```ruby
85
+ <%= form_for @user do |f| %>
86
+ <%= f.crop_field :avatar, preview: :progress %>
87
+ <% end %>
88
+ ```
89
+
90
+ ## Development
91
+
92
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
93
+
94
+ ## Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ehainer/voltron-crop. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
97
+
98
+
99
+ ## License
100
+
101
+ The gem is available as open source under the terms of the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.en.html).
102
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,1234 @@
1
+ /*! cropit - v0.5.1 <https://github.com/scottcheng/cropit> */
2
+ (function webpackUniversalModuleDefinition(root, factory) {
3
+ if(typeof exports === 'object' && typeof module === 'object')
4
+ module.exports = factory(require("jquery"));
5
+ else if(typeof define === 'function' && define.amd)
6
+ define(["jquery"], factory);
7
+ else if(typeof exports === 'object')
8
+ exports["cropit"] = factory(require("jquery"));
9
+ else
10
+ root["cropit"] = factory(root["jQuery"]);
11
+ })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
12
+ return /******/ (function(modules) { // webpackBootstrap
13
+ /******/ // The module cache
14
+ /******/ var installedModules = {};
15
+
16
+ /******/ // The require function
17
+ /******/ function __webpack_require__(moduleId) {
18
+
19
+ /******/ // Check if module is in cache
20
+ /******/ if(installedModules[moduleId])
21
+ /******/ return installedModules[moduleId].exports;
22
+
23
+ /******/ // Create a new module (and put it into the cache)
24
+ /******/ var module = installedModules[moduleId] = {
25
+ /******/ exports: {},
26
+ /******/ id: moduleId,
27
+ /******/ loaded: false
28
+ /******/ };
29
+
30
+ /******/ // Execute the module function
31
+ /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
32
+
33
+ /******/ // Flag the module as loaded
34
+ /******/ module.loaded = true;
35
+
36
+ /******/ // Return the exports of the module
37
+ /******/ return module.exports;
38
+ /******/ }
39
+
40
+
41
+ /******/ // expose the modules object (__webpack_modules__)
42
+ /******/ __webpack_require__.m = modules;
43
+
44
+ /******/ // expose the module cache
45
+ /******/ __webpack_require__.c = installedModules;
46
+
47
+ /******/ // __webpack_public_path__
48
+ /******/ __webpack_require__.p = "";
49
+
50
+ /******/ // Load entry module and return exports
51
+ /******/ return __webpack_require__(0);
52
+ /******/ })
53
+ /************************************************************************/
54
+ /******/ ([
55
+ /* 0 */
56
+ /***/ function(module, exports, __webpack_require__) {
57
+
58
+ var _slice = Array.prototype.slice;
59
+
60
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
61
+
62
+ var _jquery = __webpack_require__(1);
63
+
64
+ var _jquery2 = _interopRequireDefault(_jquery);
65
+
66
+ var _cropit = __webpack_require__(2);
67
+
68
+ var _cropit2 = _interopRequireDefault(_cropit);
69
+
70
+ var _constants = __webpack_require__(4);
71
+
72
+ var _utils = __webpack_require__(6);
73
+
74
+ var applyOnEach = function applyOnEach($el, callback) {
75
+ return $el.each(function () {
76
+ var cropit = _jquery2['default'].data(this, _constants.PLUGIN_KEY);
77
+
78
+ if (!cropit) {
79
+ return;
80
+ }
81
+ callback(cropit);
82
+ });
83
+ };
84
+
85
+ var callOnFirst = function callOnFirst($el, method, options) {
86
+ var cropit = $el.first().data(_constants.PLUGIN_KEY);
87
+
88
+ if (!cropit || !_jquery2['default'].isFunction(cropit[method])) {
89
+ return null;
90
+ }
91
+ return cropit[method](options);
92
+ };
93
+
94
+ var methods = {
95
+ init: function init(options) {
96
+ return this.each(function () {
97
+ // Only instantiate once per element
98
+ if (_jquery2['default'].data(this, _constants.PLUGIN_KEY)) {
99
+ return;
100
+ }
101
+
102
+ var cropit = new _cropit2['default'](_jquery2['default'], this, options);
103
+ _jquery2['default'].data(this, _constants.PLUGIN_KEY, cropit);
104
+ });
105
+ },
106
+
107
+ destroy: function destroy() {
108
+ return this.each(function () {
109
+ _jquery2['default'].removeData(this, _constants.PLUGIN_KEY);
110
+ });
111
+ },
112
+
113
+ isZoomable: function isZoomable() {
114
+ return callOnFirst(this, 'isZoomable');
115
+ },
116
+
117
+ 'export': function _export(options) {
118
+ return callOnFirst(this, 'getCroppedImageData', options);
119
+ }
120
+ };
121
+
122
+ var delegate = function delegate($el, fnName) {
123
+ return applyOnEach($el, function (cropit) {
124
+ cropit[fnName]();
125
+ });
126
+ };
127
+
128
+ var prop = function prop($el, name, value) {
129
+ if ((0, _utils.exists)(value)) {
130
+ return applyOnEach($el, function (cropit) {
131
+ cropit[name] = value;
132
+ });
133
+ } else {
134
+ var cropit = $el.first().data(_constants.PLUGIN_KEY);
135
+ return cropit[name];
136
+ }
137
+ };
138
+
139
+ _jquery2['default'].fn.cropit = function (method) {
140
+ if (methods[method]) {
141
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
142
+ } else if (['imageState', 'imageSrc', 'offset', 'previewSize', 'imageSize', 'zoom', 'initialZoom', 'exportZoom', 'minZoom', 'maxZoom'].indexOf(method) >= 0) {
143
+ return prop.apply(undefined, [this].concat(_slice.call(arguments)));
144
+ } else if (['rotateCW', 'rotateCCW', 'disable', 'reenable'].indexOf(method) >= 0) {
145
+ return delegate.apply(undefined, [this].concat(_slice.call(arguments)));
146
+ } else {
147
+ return methods.init.apply(this, arguments);
148
+ }
149
+ };
150
+
151
+ /***/ },
152
+ /* 1 */
153
+ /***/ function(module, exports) {
154
+
155
+ module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
156
+
157
+ /***/ },
158
+ /* 2 */
159
+ /***/ function(module, exports, __webpack_require__) {
160
+
161
+ Object.defineProperty(exports, '__esModule', {
162
+ value: true
163
+ });
164
+
165
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
166
+
167
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
168
+
169
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
170
+
171
+ var _jquery = __webpack_require__(1);
172
+
173
+ var _jquery2 = _interopRequireDefault(_jquery);
174
+
175
+ var _Zoomer = __webpack_require__(3);
176
+
177
+ var _Zoomer2 = _interopRequireDefault(_Zoomer);
178
+
179
+ var _constants = __webpack_require__(4);
180
+
181
+ var _options = __webpack_require__(5);
182
+
183
+ var _utils = __webpack_require__(6);
184
+
185
+ var Cropit = (function () {
186
+ function Cropit(jQuery, element, options) {
187
+ _classCallCheck(this, Cropit);
188
+
189
+ this.$el = (0, _jquery2['default'])(element);
190
+
191
+ var defaults = (0, _options.loadDefaults)(this.$el);
192
+ this.options = _jquery2['default'].extend({}, defaults, options);
193
+
194
+ this.init();
195
+ }
196
+
197
+ _createClass(Cropit, [{
198
+ key: 'init',
199
+ value: function init() {
200
+ var _this = this;
201
+
202
+ this.image = new Image();
203
+ this.preImage = new Image();
204
+ this.image.onload = this.onImageLoaded.bind(this);
205
+ this.preImage.onload = this.onPreImageLoaded.bind(this);
206
+ this.image.onerror = this.preImage.onerror = function () {
207
+ _this.onImageError.call(_this, _constants.ERRORS.IMAGE_FAILED_TO_LOAD);
208
+ };
209
+
210
+ this.$preview = this.options.$preview.css('position', 'relative');
211
+ this.$fileInput = this.options.$fileInput.attr({ accept: 'image/*' });
212
+ this.$zoomSlider = this.options.$zoomSlider.attr({ min: 0, max: 1, step: 0.01 });
213
+
214
+ this.previewSize = {
215
+ width: this.options.width || this.$preview.width(),
216
+ height: this.options.height || this.$preview.height()
217
+ };
218
+
219
+ this.$image = (0, _jquery2['default'])('<img />').addClass(_constants.CLASS_NAMES.PREVIEW_IMAGE).attr('alt', '').css({
220
+ transformOrigin: 'top left',
221
+ webkitTransformOrigin: 'top left',
222
+ willChange: 'transform'
223
+ });
224
+ this.$imageContainer = (0, _jquery2['default'])('<div />').addClass(_constants.CLASS_NAMES.PREVIEW_IMAGE_CONTAINER).css({
225
+ position: 'absolute',
226
+ overflow: 'hidden',
227
+ left: 0,
228
+ top: 0,
229
+ width: '100%',
230
+ height: '100%'
231
+ }).append(this.$image);
232
+ this.$preview.append(this.$imageContainer);
233
+
234
+ if (this.options.imageBackground) {
235
+ if (_jquery2['default'].isArray(this.options.imageBackgroundBorderWidth)) {
236
+ this.bgBorderWidthArray = this.options.imageBackgroundBorderWidth;
237
+ } else {
238
+ this.bgBorderWidthArray = [0, 1, 2, 3].map(function () {
239
+ return _this.options.imageBackgroundBorderWidth;
240
+ });
241
+ }
242
+
243
+ this.$bg = (0, _jquery2['default'])('<img />').addClass(_constants.CLASS_NAMES.PREVIEW_BACKGROUND).attr('alt', '').css({
244
+ position: 'relative',
245
+ left: this.bgBorderWidthArray[3],
246
+ top: this.bgBorderWidthArray[0],
247
+ transformOrigin: 'top left',
248
+ webkitTransformOrigin: 'top left',
249
+ willChange: 'transform'
250
+ });
251
+ this.$bgContainer = (0, _jquery2['default'])('<div />').addClass(_constants.CLASS_NAMES.PREVIEW_BACKGROUND_CONTAINER).css({
252
+ position: 'absolute',
253
+ zIndex: 0,
254
+ top: -this.bgBorderWidthArray[0],
255
+ right: -this.bgBorderWidthArray[1],
256
+ bottom: -this.bgBorderWidthArray[2],
257
+ left: -this.bgBorderWidthArray[3]
258
+ }).append(this.$bg);
259
+ if (this.bgBorderWidthArray[0] > 0) {
260
+ this.$bgContainer.css('overflow', 'hidden');
261
+ }
262
+ this.$preview.prepend(this.$bgContainer);
263
+ }
264
+
265
+ this.initialZoom = this.options.initialZoom;
266
+
267
+ this.imageLoaded = false;
268
+
269
+ this.moveContinue = false;
270
+
271
+ this.zoomer = new _Zoomer2['default']();
272
+
273
+ if (this.options.allowDragNDrop) {
274
+ _jquery2['default'].event.props.push('dataTransfer');
275
+ }
276
+
277
+ this.bindListeners();
278
+
279
+ if (this.options.imageState && this.options.imageState.src) {
280
+ this.loadImage(this.options.imageState.src);
281
+ }
282
+ }
283
+ }, {
284
+ key: 'bindListeners',
285
+ value: function bindListeners() {
286
+ this.$fileInput.on('change.cropit', this.onFileChange.bind(this));
287
+ this.$imageContainer.on(_constants.EVENTS.PREVIEW, this.onPreviewEvent.bind(this));
288
+ this.$zoomSlider.on(_constants.EVENTS.ZOOM_INPUT, this.onZoomSliderChange.bind(this));
289
+
290
+ if (this.options.allowDragNDrop) {
291
+ this.$imageContainer.on('dragover.cropit dragleave.cropit', this.onDragOver.bind(this));
292
+ this.$imageContainer.on('drop.cropit', this.onDrop.bind(this));
293
+ }
294
+ }
295
+ }, {
296
+ key: 'unbindListeners',
297
+ value: function unbindListeners() {
298
+ this.$fileInput.off('change.cropit');
299
+ this.$imageContainer.off(_constants.EVENTS.PREVIEW);
300
+ this.$imageContainer.off('dragover.cropit dragleave.cropit drop.cropit');
301
+ this.$zoomSlider.off(_constants.EVENTS.ZOOM_INPUT);
302
+ }
303
+ }, {
304
+ key: 'onFileChange',
305
+ value: function onFileChange(e) {
306
+ this.options.onFileChange(e);
307
+
308
+ if (this.$fileInput.get(0).files) {
309
+ this.loadFile(this.$fileInput.get(0).files[0]);
310
+ }
311
+ }
312
+ }, {
313
+ key: 'loadFile',
314
+ value: function loadFile(file) {
315
+ var fileReader = new FileReader();
316
+ if (file && file.type.match('image')) {
317
+ fileReader.readAsDataURL(file);
318
+ fileReader.onload = this.onFileReaderLoaded.bind(this);
319
+ fileReader.onerror = this.onFileReaderError.bind(this);
320
+ } else if (file) {
321
+ this.onFileReaderError();
322
+ }
323
+ }
324
+ }, {
325
+ key: 'onFileReaderLoaded',
326
+ value: function onFileReaderLoaded(e) {
327
+ this.loadImage(e.target.result);
328
+ }
329
+ }, {
330
+ key: 'onFileReaderError',
331
+ value: function onFileReaderError() {
332
+ this.options.onFileReaderError();
333
+ }
334
+ }, {
335
+ key: 'onDragOver',
336
+ value: function onDragOver(e) {
337
+ e.preventDefault();
338
+ e.dataTransfer.dropEffect = 'copy';
339
+ this.$preview.toggleClass(_constants.CLASS_NAMES.DRAG_HOVERED, e.type === 'dragover');
340
+ }
341
+ }, {
342
+ key: 'onDrop',
343
+ value: function onDrop(e) {
344
+ var _this2 = this;
345
+
346
+ e.preventDefault();
347
+ e.stopPropagation();
348
+
349
+ var files = Array.prototype.slice.call(e.dataTransfer.files, 0);
350
+ files.some(function (file) {
351
+ if (!file.type.match('image')) {
352
+ return false;
353
+ }
354
+
355
+ _this2.loadFile(file);
356
+ return true;
357
+ });
358
+
359
+ this.$preview.removeClass(_constants.CLASS_NAMES.DRAG_HOVERED);
360
+ }
361
+ }, {
362
+ key: 'loadImage',
363
+ value: function loadImage(imageSrc) {
364
+ var _this3 = this;
365
+
366
+ if (!imageSrc) {
367
+ return;
368
+ }
369
+
370
+ this.options.onImageLoading();
371
+ this.setImageLoadingClass();
372
+
373
+ if (imageSrc.indexOf('data') === 0) {
374
+ this.preImage.src = imageSrc;
375
+ } else {
376
+ var xhr = new XMLHttpRequest();
377
+ xhr.onload = function (e) {
378
+ if (e.target.status >= 300) {
379
+ _this3.onImageError.call(_this3, _constants.ERRORS.IMAGE_FAILED_TO_LOAD);
380
+ return;
381
+ }
382
+
383
+ _this3.loadFile(e.target.response);
384
+ };
385
+ xhr.open('GET', imageSrc);
386
+ xhr.responseType = 'blob';
387
+ xhr.send();
388
+ }
389
+ }
390
+ }, {
391
+ key: 'onPreImageLoaded',
392
+ value: function onPreImageLoaded() {
393
+ if (this.shouldRejectImage({
394
+ imageWidth: this.preImage.width,
395
+ imageHeight: this.preImage.height,
396
+ previewSize: this.previewSize,
397
+ maxZoom: this.options.maxZoom,
398
+ exportZoom: this.options.exportZoom,
399
+ smallImage: this.options.smallImage
400
+ })) {
401
+ this.onImageError(_constants.ERRORS.SMALL_IMAGE);
402
+ if (this.image.src) {
403
+ this.setImageLoadedClass();
404
+ }
405
+ return;
406
+ }
407
+
408
+ this.image.src = this.preImage.src;
409
+ }
410
+ }, {
411
+ key: 'onImageLoaded',
412
+ value: function onImageLoaded() {
413
+ this.rotation = 0;
414
+ this.setupZoomer(this.options.imageState && this.options.imageState.zoom || this._initialZoom);
415
+ if (this.options.imageState && this.options.imageState.offset) {
416
+ this.offset = this.options.imageState.offset;
417
+ } else {
418
+ this.centerImage();
419
+ }
420
+
421
+ this.options.imageState = {};
422
+
423
+ this.$image.attr('src', this.image.src);
424
+ if (this.options.imageBackground) {
425
+ this.$bg.attr('src', this.image.src);
426
+ }
427
+
428
+ this.setImageLoadedClass();
429
+
430
+ this.imageLoaded = true;
431
+
432
+ this.options.onImageLoaded();
433
+ }
434
+ }, {
435
+ key: 'onImageError',
436
+ value: function onImageError() {
437
+ this.options.onImageError.apply(this, arguments);
438
+ this.removeImageLoadingClass();
439
+ }
440
+ }, {
441
+ key: 'setImageLoadingClass',
442
+ value: function setImageLoadingClass() {
443
+ this.$preview.removeClass(_constants.CLASS_NAMES.IMAGE_LOADED).addClass(_constants.CLASS_NAMES.IMAGE_LOADING);
444
+ }
445
+ }, {
446
+ key: 'setImageLoadedClass',
447
+ value: function setImageLoadedClass() {
448
+ this.$preview.removeClass(_constants.CLASS_NAMES.IMAGE_LOADING).addClass(_constants.CLASS_NAMES.IMAGE_LOADED);
449
+ }
450
+ }, {
451
+ key: 'removeImageLoadingClass',
452
+ value: function removeImageLoadingClass() {
453
+ this.$preview.removeClass(_constants.CLASS_NAMES.IMAGE_LOADING);
454
+ }
455
+ }, {
456
+ key: 'getEventPosition',
457
+ value: function getEventPosition(e) {
458
+ if (e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0]) {
459
+ e = e.originalEvent.touches[0];
460
+ }
461
+ if (e.clientX && e.clientY) {
462
+ return { x: e.clientX, y: e.clientY };
463
+ }
464
+ }
465
+ }, {
466
+ key: 'onPreviewEvent',
467
+ value: function onPreviewEvent(e) {
468
+ if (!this.imageLoaded) {
469
+ return;
470
+ }
471
+
472
+ /*
473
+ this.moveContinue = false;
474
+ this.$imageContainer.off(_constants.EVENTS.PREVIEW_MOVE);
475
+
476
+ if (e.type === 'mousedown' || e.type === 'touchstart') {
477
+ this.origin = this.getEventPosition(e);
478
+ this.moveContinue = true;
479
+ this.$imageContainer.on(_constants.EVENTS.PREVIEW_MOVE, this.onMove.bind(this));
480
+ } else {
481
+ (0, _jquery2['default'])(document.body).focus();
482
+ }
483
+ */
484
+
485
+ // Start new cropit logic to allow dragging outside of the container
486
+ if (e.type === 'mouseup' || e.type === 'touchend') {
487
+ this.moveContinue = false;
488
+ this.$preview.off(_constants.EVENTS.PREVIEW_MOVE);
489
+ this.$imageContainer.off(_constants.EVENTS.PREVIEW_MOVE);
490
+ $('body').off(_constants.EVENTS.PREVIEW);
491
+ $('body').off(_constants.EVENTS.PREVIEW_MOVE);
492
+ $('.dragger').trigger('mouseup');
493
+ }
494
+
495
+ if (e.type === 'mousedown' || e.type === 'touchstart') {
496
+ this.origin = this.getEventPosition(e);
497
+ this.moveContinue = true;
498
+ this.$preview.on(_constants.EVENTS.PREVIEW_MOVE, this.onMove.bind(this));
499
+ this.$imageContainer.on(_constants.EVENTS.PREVIEW_MOVE, this.onMove.bind(this));
500
+ $('body').on(_constants.EVENTS.PREVIEW, this.onPreviewEvent.bind(this));
501
+ $('body').on(_constants.EVENTS.PREVIEW_MOVE, this.onMove.bind(this));
502
+ } else {
503
+ (0, _jquery2['default'])(document.body).focus();
504
+ }
505
+ // Stop new cropit logic
506
+
507
+ e.stopPropagation();
508
+ return false;
509
+ }
510
+ }, {
511
+ key: 'onMove',
512
+ value: function onMove(e) {
513
+ var eventPosition = this.getEventPosition(e);
514
+
515
+ if (this.moveContinue && eventPosition) {
516
+ this.offset = {
517
+ x: this.offset.x + eventPosition.x - this.origin.x,
518
+ y: this.offset.y + eventPosition.y - this.origin.y
519
+ };
520
+ }
521
+
522
+ this.origin = eventPosition;
523
+
524
+ e.stopPropagation();
525
+ return false;
526
+ }
527
+ }, {
528
+ key: 'fixOffset',
529
+ value: function fixOffset(offset) {
530
+ if (!this.imageLoaded) {
531
+ return offset;
532
+ }
533
+
534
+ var ret = { x: offset.x, y: offset.y };
535
+
536
+ if (!this.options.freeMove) {
537
+ if (this.imageWidth * this.zoom >= this.previewSize.width) {
538
+ ret.x = Math.min(0, Math.max(ret.x, this.previewSize.width - this.imageWidth * this.zoom));
539
+ } else {
540
+ ret.x = Math.max(0, Math.min(ret.x, this.previewSize.width - this.imageWidth * this.zoom));
541
+ }
542
+
543
+ if (this.imageHeight * this.zoom >= this.previewSize.height) {
544
+ ret.y = Math.min(0, Math.max(ret.y, this.previewSize.height - this.imageHeight * this.zoom));
545
+ } else {
546
+ ret.y = Math.max(0, Math.min(ret.y, this.previewSize.height - this.imageHeight * this.zoom));
547
+ }
548
+ }
549
+
550
+ ret.x = (0, _utils.round)(ret.x);
551
+ ret.y = (0, _utils.round)(ret.y);
552
+
553
+ return ret;
554
+ }
555
+ }, {
556
+ key: 'centerImage',
557
+ value: function centerImage() {
558
+ if (!this.image.width || !this.image.height || !this.zoom) {
559
+ return;
560
+ }
561
+
562
+ this.offset = {
563
+ x: (this.previewSize.width - this.imageWidth * this.zoom) / 2,
564
+ y: (this.previewSize.height - this.imageHeight * this.zoom) / 2
565
+ };
566
+ }
567
+ }, {
568
+ key: 'onZoomSliderChange',
569
+ value: function onZoomSliderChange() {
570
+ if (!this.imageLoaded) {
571
+ return;
572
+ }
573
+
574
+ this.zoomSliderPos = Number(this.$zoomSlider.val());
575
+ var newZoom = this.zoomer.getZoom(this.zoomSliderPos);
576
+ if (newZoom === this.zoom) {
577
+ return;
578
+ }
579
+ this.zoom = newZoom;
580
+ }
581
+ }, {
582
+ key: 'enableZoomSlider',
583
+ value: function enableZoomSlider() {
584
+ this.$zoomSlider.removeAttr('disabled');
585
+ this.options.onZoomEnabled();
586
+ }
587
+ }, {
588
+ key: 'disableZoomSlider',
589
+ value: function disableZoomSlider() {
590
+ this.$zoomSlider.attr('disabled', true);
591
+ this.options.onZoomDisabled();
592
+ }
593
+ }, {
594
+ key: 'setupZoomer',
595
+ value: function setupZoomer(zoom) {
596
+ this.zoomer.setup({
597
+ imageSize: this.imageSize,
598
+ previewSize: this.previewSize,
599
+ exportZoom: this.options.exportZoom,
600
+ maxZoom: this.options.maxZoom,
601
+ minZoom: this.options.minZoom,
602
+ smallImage: this.options.smallImage
603
+ });
604
+ this.zoom = (0, _utils.exists)(zoom) ? zoom : this._zoom;
605
+
606
+ if (this.isZoomable()) {
607
+ this.enableZoomSlider();
608
+ } else {
609
+ this.disableZoomSlider();
610
+ }
611
+ }
612
+ }, {
613
+ key: 'fixZoom',
614
+ value: function fixZoom(zoom) {
615
+ return this.zoomer.fixZoom(zoom);
616
+ }
617
+ }, {
618
+ key: 'isZoomable',
619
+ value: function isZoomable() {
620
+ return this.zoomer.isZoomable();
621
+ }
622
+ }, {
623
+ key: 'renderImage',
624
+ value: function renderImage() {
625
+ var transformation = '\n translate(' + this.rotatedOffset.x + 'px, ' + this.rotatedOffset.y + 'px)\n scale(' + this.zoom + ')\n rotate(' + this.rotation + 'deg)';
626
+
627
+ this.$image.css({
628
+ transform: transformation,
629
+ webkitTransform: transformation
630
+ });
631
+ if (this.options.imageBackground) {
632
+ this.$bg.css({
633
+ transform: transformation,
634
+ webkitTransform: transformation
635
+ });
636
+ }
637
+ }
638
+ }, {
639
+ key: 'rotateCW',
640
+ value: function rotateCW() {
641
+ if (this.shouldRejectImage({
642
+ imageWidth: this.image.height,
643
+ imageHeight: this.image.width,
644
+ previewSize: this.previewSize,
645
+ maxZoom: this.options.maxZoom,
646
+ exportZoom: this.options.exportZoom,
647
+ smallImage: this.options.smallImage
648
+ })) {
649
+ this.rotation = (this.rotation + 180) % 360;
650
+ } else {
651
+ this.rotation = (this.rotation + 90) % 360;
652
+ }
653
+ }
654
+ }, {
655
+ key: 'rotateCCW',
656
+ value: function rotateCCW() {
657
+ if (this.shouldRejectImage({
658
+ imageWidth: this.image.height,
659
+ imageHeight: this.image.width,
660
+ previewSize: this.previewSize,
661
+ maxZoom: this.options.maxZoom,
662
+ exportZoom: this.options.exportZoom,
663
+ smallImage: this.options.smallImage
664
+ })) {
665
+ this.rotation = (this.rotation + 180) % 360;
666
+ } else {
667
+ this.rotation = (this.rotation + 270) % 360;
668
+ }
669
+ }
670
+ }, {
671
+ key: 'shouldRejectImage',
672
+ value: function shouldRejectImage(_ref) {
673
+ var imageWidth = _ref.imageWidth;
674
+ var imageHeight = _ref.imageHeight;
675
+ var previewSize = _ref.previewSize;
676
+ var maxZoom = _ref.maxZoom;
677
+ var exportZoom = _ref.exportZoom;
678
+ var smallImage = _ref.smallImage;
679
+
680
+ if (smallImage !== 'reject') {
681
+ return false;
682
+ }
683
+
684
+ return imageWidth * maxZoom < previewSize.width * exportZoom || imageHeight * maxZoom < previewSize.height * exportZoom;
685
+ }
686
+ }, {
687
+ key: 'getCroppedImageData',
688
+ value: function getCroppedImageData(exportOptions) {
689
+ if (!this.image.src) {
690
+ return;
691
+ }
692
+
693
+ var exportDefaults = {
694
+ type: 'image/png',
695
+ quality: 0.75,
696
+ originalSize: false,
697
+ fillBg: '#fff'
698
+ };
699
+ exportOptions = _jquery2['default'].extend({}, exportDefaults, exportOptions);
700
+
701
+ var exportZoom = exportOptions.originalSize ? 1 / this.zoom : this.options.exportZoom;
702
+
703
+ var zoomedSize = {
704
+ width: this.zoom * exportZoom * this.image.width,
705
+ height: this.zoom * exportZoom * this.image.height
706
+ };
707
+
708
+ var canvas = (0, _jquery2['default'])('<canvas />').attr({
709
+ width: this.previewSize.width * exportZoom,
710
+ height: this.previewSize.height * exportZoom
711
+ }).get(0);
712
+ var canvasContext = canvas.getContext('2d');
713
+
714
+ if (exportOptions.type === 'image/jpeg') {
715
+ canvasContext.fillStyle = exportOptions.fillBg;
716
+ canvasContext.fillRect(0, 0, canvas.width, canvas.height);
717
+ }
718
+
719
+ canvasContext.translate(this.rotatedOffset.x * exportZoom, this.rotatedOffset.y * exportZoom);
720
+ canvasContext.rotate(this.rotation * Math.PI / 180);
721
+ canvasContext.drawImage(this.image, 0, 0, zoomedSize.width, zoomedSize.height);
722
+
723
+ return canvas.toDataURL(exportOptions.type, exportOptions.quality);
724
+ }
725
+ }, {
726
+ key: 'disable',
727
+ value: function disable() {
728
+ this.unbindListeners();
729
+ this.disableZoomSlider();
730
+ this.$el.addClass(_constants.CLASS_NAMES.DISABLED);
731
+ }
732
+ }, {
733
+ key: 'reenable',
734
+ value: function reenable() {
735
+ this.bindListeners();
736
+ this.enableZoomSlider();
737
+ this.$el.removeClass(_constants.CLASS_NAMES.DISABLED);
738
+ }
739
+ }, {
740
+ key: '$',
741
+ value: function $(selector) {
742
+ if (!this.$el) {
743
+ return null;
744
+ }
745
+ return this.$el.find(selector);
746
+ }
747
+ }, {
748
+ key: 'offset',
749
+ set: function (position) {
750
+ if (!position || !(0, _utils.exists)(position.x) || !(0, _utils.exists)(position.y)) {
751
+ return;
752
+ }
753
+
754
+ this._offset = this.fixOffset(position);
755
+ this.renderImage();
756
+
757
+ this.options.onOffsetChange(position);
758
+ },
759
+ get: function () {
760
+ return this._offset;
761
+ }
762
+ }, {
763
+ key: 'zoom',
764
+ set: function (newZoom) {
765
+ newZoom = this.fixZoom(newZoom);
766
+
767
+ if (this.imageLoaded) {
768
+ var oldZoom = this.zoom;
769
+
770
+ var newX = this.previewSize.width / 2 - (this.previewSize.width / 2 - this.offset.x) * newZoom / oldZoom;
771
+ var newY = this.previewSize.height / 2 - (this.previewSize.height / 2 - this.offset.y) * newZoom / oldZoom;
772
+
773
+ this._zoom = newZoom;
774
+ this.offset = { x: newX, y: newY }; // Triggers renderImage()
775
+ } else {
776
+ this._zoom = newZoom;
777
+ }
778
+
779
+ this.zoomSliderPos = this.zoomer.getSliderPos(this.zoom);
780
+ this.$zoomSlider.val(this.zoomSliderPos);
781
+
782
+ this.options.onZoomChange(newZoom);
783
+ },
784
+ get: function () {
785
+ return this._zoom;
786
+ }
787
+ }, {
788
+ key: 'rotatedOffset',
789
+ get: function () {
790
+ return {
791
+ x: this.offset.x + (this.rotation === 90 ? this.image.height * this.zoom : 0) + (this.rotation === 180 ? this.image.width * this.zoom : 0),
792
+ y: this.offset.y + (this.rotation === 180 ? this.image.height * this.zoom : 0) + (this.rotation === 270 ? this.image.width * this.zoom : 0)
793
+ };
794
+ }
795
+ }, {
796
+ key: 'rotation',
797
+ set: function (newRotation) {
798
+ this._rotation = newRotation;
799
+
800
+ if (this.imageLoaded) {
801
+ // Change in image size may lead to change in zoom range
802
+ this.setupZoomer();
803
+ }
804
+ },
805
+ get: function () {
806
+ return this._rotation;
807
+ }
808
+ }, {
809
+ key: 'imageState',
810
+ get: function () {
811
+ return {
812
+ src: this.image.src,
813
+ offset: this.offset,
814
+ zoom: this.zoom
815
+ };
816
+ }
817
+ }, {
818
+ key: 'imageSrc',
819
+ get: function () {
820
+ return this.image.src;
821
+ },
822
+ set: function (imageSrc) {
823
+ this.loadImage(imageSrc);
824
+ }
825
+ }, {
826
+ key: 'imageWidth',
827
+ get: function () {
828
+ return this.rotation % 180 === 0 ? this.image.width : this.image.height;
829
+ }
830
+ }, {
831
+ key: 'imageHeight',
832
+ get: function () {
833
+ return this.rotation % 180 === 0 ? this.image.height : this.image.width;
834
+ }
835
+ }, {
836
+ key: 'imageSize',
837
+ get: function () {
838
+ return {
839
+ width: this.imageWidth,
840
+ height: this.imageHeight
841
+ };
842
+ }
843
+ }, {
844
+ key: 'initialZoom',
845
+ get: function () {
846
+ return this.options.initialZoom;
847
+ },
848
+ set: function (initialZoomOption) {
849
+ this.options.initialZoom = initialZoomOption;
850
+ if (initialZoomOption === 'min') {
851
+ this._initialZoom = 0; // Will be fixed when image loads
852
+ } else if (initialZoomOption === 'image') {
853
+ this._initialZoom = 1;
854
+ } else {
855
+ this._initialZoom = 0;
856
+ }
857
+ }
858
+ }, {
859
+ key: 'exportZoom',
860
+ get: function () {
861
+ return this.options.exportZoom;
862
+ },
863
+ set: function (exportZoom) {
864
+ this.options.exportZoom = exportZoom;
865
+ this.setupZoomer();
866
+ }
867
+ }, {
868
+ key: 'minZoom',
869
+ get: function () {
870
+ return this.options.minZoom;
871
+ },
872
+ set: function (minZoom) {
873
+ this.options.minZoom = minZoom;
874
+ this.setupZoomer();
875
+ }
876
+ }, {
877
+ key: 'maxZoom',
878
+ get: function () {
879
+ return this.options.maxZoom;
880
+ },
881
+ set: function (maxZoom) {
882
+ this.options.maxZoom = maxZoom;
883
+ this.setupZoomer();
884
+ }
885
+ }, {
886
+ key: 'previewSize',
887
+ get: function () {
888
+ return this._previewSize;
889
+ },
890
+ set: function (size) {
891
+ if (!size || size.width <= 0 || size.height <= 0) {
892
+ return;
893
+ }
894
+
895
+ this._previewSize = {
896
+ width: size.width,
897
+ height: size.height
898
+ };
899
+ this.$preview.css({
900
+ width: this.previewSize.width,
901
+ height: this.previewSize.height
902
+ });
903
+
904
+ if (this.imageLoaded) {
905
+ this.setupZoomer();
906
+ }
907
+ }
908
+ }]);
909
+
910
+ return Cropit;
911
+ })();
912
+
913
+ exports['default'] = Cropit;
914
+ module.exports = exports['default'];
915
+
916
+ /***/ },
917
+ /* 3 */
918
+ /***/ function(module, exports) {
919
+
920
+ Object.defineProperty(exports, '__esModule', {
921
+ value: true
922
+ });
923
+
924
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
925
+
926
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
927
+
928
+ var Zoomer = (function () {
929
+ function Zoomer() {
930
+ _classCallCheck(this, Zoomer);
931
+
932
+ this.minZoom = this.maxZoom = 1;
933
+ }
934
+
935
+ _createClass(Zoomer, [{
936
+ key: 'setup',
937
+ value: function setup(_ref) {
938
+ var imageSize = _ref.imageSize;
939
+ var previewSize = _ref.previewSize;
940
+ var exportZoom = _ref.exportZoom;
941
+ var maxZoom = _ref.maxZoom;
942
+ var minZoom = _ref.minZoom;
943
+ var smallImage = _ref.smallImage;
944
+
945
+ var widthRatio = previewSize.width / imageSize.width;
946
+ var heightRatio = previewSize.height / imageSize.height;
947
+
948
+ if (minZoom === 'fit') {
949
+ this.minZoom = Math.min(widthRatio, heightRatio);
950
+ } else {
951
+ this.minZoom = Math.max(widthRatio, heightRatio);
952
+ }
953
+
954
+ if (smallImage === 'allow') {
955
+ this.minZoom = Math.min(this.minZoom, 1);
956
+ }
957
+
958
+ this.maxZoom = Math.max(this.minZoom, maxZoom / exportZoom);
959
+ }
960
+ }, {
961
+ key: 'getZoom',
962
+ value: function getZoom(sliderPos) {
963
+ if (!this.minZoom || !this.maxZoom) {
964
+ return null;
965
+ }
966
+
967
+ return sliderPos * (this.maxZoom - this.minZoom) + this.minZoom;
968
+ }
969
+ }, {
970
+ key: 'getSliderPos',
971
+ value: function getSliderPos(zoom) {
972
+ if (!this.minZoom || !this.maxZoom) {
973
+ return null;
974
+ }
975
+
976
+ if (this.minZoom === this.maxZoom) {
977
+ return 0;
978
+ } else {
979
+ return (zoom - this.minZoom) / (this.maxZoom - this.minZoom);
980
+ }
981
+ }
982
+ }, {
983
+ key: 'isZoomable',
984
+ value: function isZoomable() {
985
+ if (!this.minZoom || !this.maxZoom) {
986
+ return null;
987
+ }
988
+
989
+ return this.minZoom !== this.maxZoom;
990
+ }
991
+ }, {
992
+ key: 'fixZoom',
993
+ value: function fixZoom(zoom) {
994
+ return Math.max(this.minZoom, Math.min(this.maxZoom, zoom));
995
+ }
996
+ }]);
997
+
998
+ return Zoomer;
999
+ })();
1000
+
1001
+ exports['default'] = Zoomer;
1002
+ module.exports = exports['default'];
1003
+
1004
+ /***/ },
1005
+ /* 4 */
1006
+ /***/ function(module, exports) {
1007
+
1008
+ Object.defineProperty(exports, '__esModule', {
1009
+ value: true
1010
+ });
1011
+ var PLUGIN_KEY = 'cropit';
1012
+
1013
+ exports.PLUGIN_KEY = PLUGIN_KEY;
1014
+ var CLASS_NAMES = {
1015
+ PREVIEW: 'cropit-preview',
1016
+ PREVIEW_IMAGE_CONTAINER: 'cropit-preview-image-container',
1017
+ PREVIEW_IMAGE: 'cropit-preview-image',
1018
+ PREVIEW_BACKGROUND_CONTAINER: 'cropit-preview-background-container',
1019
+ PREVIEW_BACKGROUND: 'cropit-preview-background',
1020
+ FILE_INPUT: 'cropit-image-input',
1021
+ ZOOM_SLIDER: 'cropit-image-zoom-input',
1022
+
1023
+ DRAG_HOVERED: 'cropit-drag-hovered',
1024
+ IMAGE_LOADING: 'cropit-image-loading',
1025
+ IMAGE_LOADED: 'cropit-image-loaded',
1026
+ DISABLED: 'cropit-disabled'
1027
+ };
1028
+
1029
+ exports.CLASS_NAMES = CLASS_NAMES;
1030
+ var ERRORS = {
1031
+ IMAGE_FAILED_TO_LOAD: { code: 0, message: 'Image failed to load.' },
1032
+ SMALL_IMAGE: { code: 1, message: 'Image is too small.' }
1033
+ };
1034
+
1035
+ exports.ERRORS = ERRORS;
1036
+ var eventName = function eventName(events) {
1037
+ return events.map(function (e) {
1038
+ return '' + e + '.cropit';
1039
+ }).join(' ');
1040
+ };
1041
+ var EVENTS = {
1042
+ PREVIEW: eventName(['mousedown', 'mouseup', 'mouseleave', 'touchstart', 'touchend', 'touchcancel', 'touchleave']),
1043
+ PREVIEW_MOVE: eventName(['mousemove', 'touchmove']),
1044
+ ZOOM_INPUT: eventName(['mousemove', 'touchmove', 'change'])
1045
+ };
1046
+ exports.EVENTS = EVENTS;
1047
+
1048
+ /***/ },
1049
+ /* 5 */
1050
+ /***/ function(module, exports, __webpack_require__) {
1051
+
1052
+ Object.defineProperty(exports, '__esModule', {
1053
+ value: true
1054
+ });
1055
+
1056
+ var _constants = __webpack_require__(4);
1057
+
1058
+ var options = {
1059
+ elements: [{
1060
+ name: '$preview',
1061
+ description: 'The HTML element that displays image preview.',
1062
+ defaultSelector: '.' + _constants.CLASS_NAMES.PREVIEW
1063
+ }, {
1064
+ name: '$fileInput',
1065
+ description: 'File input element.',
1066
+ defaultSelector: 'input.' + _constants.CLASS_NAMES.FILE_INPUT
1067
+ }, {
1068
+ name: '$zoomSlider',
1069
+ description: 'Range input element that controls image zoom.',
1070
+ defaultSelector: 'input.' + _constants.CLASS_NAMES.ZOOM_SLIDER
1071
+ }].map(function (o) {
1072
+ o.type = 'jQuery element';
1073
+ o['default'] = '$imageCropper.find(\'' + o.defaultSelector + '\')';
1074
+ return o;
1075
+ }),
1076
+
1077
+ values: [{
1078
+ name: 'width',
1079
+ type: 'number',
1080
+ description: 'Width of image preview in pixels. If set, it will override the CSS property.',
1081
+ 'default': null
1082
+ }, {
1083
+ name: 'height',
1084
+ type: 'number',
1085
+ description: 'Height of image preview in pixels. If set, it will override the CSS property.',
1086
+ 'default': null
1087
+ }, {
1088
+ name: 'imageBackground',
1089
+ type: 'boolean',
1090
+ description: 'Whether or not to display the background image beyond the preview area.',
1091
+ 'default': false
1092
+ }, {
1093
+ name: 'imageBackgroundBorderWidth',
1094
+ type: 'array or number',
1095
+ description: 'Width of background image border in pixels.\n The four array elements specify the width of background image width on the top, right, bottom, left side respectively.\n The background image beyond the width will be hidden.\n If specified as a number, border with uniform width on all sides will be applied.',
1096
+ 'default': [0, 0, 0, 0]
1097
+ }, {
1098
+ name: 'exportZoom',
1099
+ type: 'number',
1100
+ description: 'The ratio between the desired image size to export and the preview size.\n For example, if the preview size is `300px * 200px`, and `exportZoom = 2`, then\n the exported image size will be `600px * 400px`.\n This also affects the maximum zoom level, since the exported image cannot be zoomed to larger than its original size.',
1101
+ 'default': 1
1102
+ }, {
1103
+ name: 'allowDragNDrop',
1104
+ type: 'boolean',
1105
+ description: 'When set to true, you can load an image by dragging it from local file browser onto the preview area.',
1106
+ 'default': true
1107
+ }, {
1108
+ name: 'minZoom',
1109
+ type: 'string',
1110
+ description: 'This options decides the minimal zoom level of the image.\n If set to `\'fill\'`, the image has to fill the preview area, i.e. both width and height must not go smaller than the preview area.\n If set to `\'fit\'`, the image can shrink further to fit the preview area, i.e. at least one of its edges must not go smaller than the preview area.',
1111
+ 'default': 'fill'
1112
+ }, {
1113
+ name: 'maxZoom',
1114
+ type: 'number',
1115
+ description: 'Determines how big the image can be zoomed. E.g. if set to 1.5, the image can be zoomed to 150% of its original size.',
1116
+ 'default': 1
1117
+ }, {
1118
+ name: 'initialZoom',
1119
+ type: 'string',
1120
+ description: 'Determines the zoom when an image is loaded.\n When set to `\'min\'`, image is zoomed to the smallest when loaded.\n When set to `\'image\'`, image is zoomed to 100% when loaded.',
1121
+ 'default': 'min'
1122
+ }, {
1123
+ name: 'freeMove',
1124
+ type: 'boolean',
1125
+ description: 'When set to true, you can freely move the image instead of being bound to the container borders',
1126
+ 'default': false
1127
+ }, {
1128
+ name: 'smallImage',
1129
+ type: 'string',
1130
+ description: 'When set to `\'reject\'`, `onImageError` would be called when cropit loads an image that is smaller than the container.\n When set to `\'allow\'`, images smaller than the container can be zoomed down to its original size, overiding `minZoom` option.\n When set to `\'stretch\'`, the minimum zoom of small images would follow `minZoom` option.',
1131
+ 'default': 'reject'
1132
+ }],
1133
+
1134
+ callbacks: [{
1135
+ name: 'onFileChange',
1136
+ description: 'Called when user selects a file in the select file input.',
1137
+ params: [{
1138
+ name: 'event',
1139
+ type: 'object',
1140
+ description: 'File change event object'
1141
+ }]
1142
+ }, {
1143
+ name: 'onFileReaderError',
1144
+ description: 'Called when `FileReader` encounters an error while loading the image file.'
1145
+ }, {
1146
+ name: 'onImageLoading',
1147
+ description: 'Called when image starts to be loaded.'
1148
+ }, {
1149
+ name: 'onImageLoaded',
1150
+ description: 'Called when image is loaded.'
1151
+ }, {
1152
+ name: 'onImageError',
1153
+ description: 'Called when image cannot be loaded.',
1154
+ params: [{
1155
+ name: 'error',
1156
+ type: 'object',
1157
+ description: 'Error object.'
1158
+ }, {
1159
+ name: 'error.code',
1160
+ type: 'number',
1161
+ description: 'Error code. `0` means generic image loading failure. `1` means image is too small.'
1162
+ }, {
1163
+ name: 'error.message',
1164
+ type: 'string',
1165
+ description: 'A message explaining the error.'
1166
+ }]
1167
+ }, {
1168
+ name: 'onZoomEnabled',
1169
+ description: 'Called when image the zoom slider is enabled.'
1170
+ }, {
1171
+ name: 'onZoomDisabled',
1172
+ description: 'Called when image the zoom slider is disabled.'
1173
+ }, {
1174
+ name: 'onZoomChange',
1175
+ description: 'Called when zoom changes.',
1176
+ params: [{
1177
+ name: 'zoom',
1178
+ type: 'number',
1179
+ description: 'New zoom.'
1180
+ }]
1181
+ }, {
1182
+ name: 'onOffsetChange',
1183
+ description: 'Called when image offset changes.',
1184
+ params: [{
1185
+ name: 'offset',
1186
+ type: 'object',
1187
+ description: 'New offset, with `x` and `y` values.'
1188
+ }]
1189
+ }].map(function (o) {
1190
+ o.type = 'function';return o;
1191
+ })
1192
+ };
1193
+
1194
+ var loadDefaults = function loadDefaults($el) {
1195
+ var defaults = {};
1196
+ if ($el) {
1197
+ options.elements.forEach(function (o) {
1198
+ defaults[o.name] = $el.find(o.defaultSelector);
1199
+ });
1200
+ }
1201
+ options.values.forEach(function (o) {
1202
+ defaults[o.name] = o['default'];
1203
+ });
1204
+ options.callbacks.forEach(function (o) {
1205
+ defaults[o.name] = function () {};
1206
+ });
1207
+
1208
+ return defaults;
1209
+ };
1210
+
1211
+ exports.loadDefaults = loadDefaults;
1212
+ exports['default'] = options;
1213
+
1214
+ /***/ },
1215
+ /* 6 */
1216
+ /***/ function(module, exports) {
1217
+
1218
+ Object.defineProperty(exports, '__esModule', {
1219
+ value: true
1220
+ });
1221
+ var exists = function exists(v) {
1222
+ return typeof v !== 'undefined';
1223
+ };
1224
+
1225
+ exports.exists = exists;
1226
+ var round = function round(x) {
1227
+ return +(Math.round(x * 100) + 'e-2');
1228
+ };
1229
+ exports.round = round;
1230
+
1231
+ /***/ }
1232
+ /******/ ])
1233
+ });
1234
+ ;