NextCellent Gallery – NextGEN Legacy - Version 1.9.31

Version Description

  • 2016-09-05
Download this release

Release Info

Developer WPReady
Plugin Icon NextCellent Gallery – NextGEN Legacy
Version 1.9.31
Comparing to
See all releases

Code changes from version 1.9.30 to 1.9.31

admin/ajax.php CHANGED
@@ -96,6 +96,7 @@ add_action('wp_ajax_createNewThumb', 'createNewThumb');
96
  function new_thumbnail() {
97
 
98
  global $ngg;
 
99
 
100
  // check for correct capability
101
  if ( !(is_user_logged_in() && current_user_can('NextGEN Manage gallery')) ) {
@@ -124,6 +125,19 @@ function new_thumbnail() {
124
 
125
  $thumb->crop($x, $y, $w, $h);
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  if ( $thumb->save($picture->thumbPath, 100)) {
128
 
129
  //read the new sizes
96
  function new_thumbnail() {
97
 
98
  global $ngg;
99
+ $ngg_options = get_option('ngg_options');
100
 
101
  // check for correct capability
102
  if ( !(is_user_logged_in() && current_user_can('NextGEN Manage gallery')) ) {
125
 
126
  $thumb->crop($x, $y, $w, $h);
127
 
128
+ $differentSizes = false;
129
+ if(isset($ngg_options['thumbDifferentSize'])) {
130
+ $differentSizes = (bool) $ngg_options['thumbDifferentSize'];
131
+ }
132
+
133
+ if(!$differentSizes) {
134
+ if($ngg_options['thumbfix']) {
135
+ $thumb->resizeFix((int) $ngg_options['thumbwidth'], (int) $ngg_options['thumbheight']);
136
+ } else {
137
+ $thumb->resize((int) $ngg_options['thumbwidth'], (int) $ngg_options['thumbheight']);
138
+ }
139
+ }
140
+
141
  if ( $thumb->save($picture->thumbPath, 100)) {
142
 
143
  //read the new sizes
admin/class-ngg-admin-launcher.php CHANGED
@@ -262,7 +262,7 @@ class NGG_Admin_Launcher {
262
  return;
263
  }
264
 
265
- wp_register_script( 'ngg-ajax', NGGALLERY_URLPATH . 'admin/js/ngg.ajax.js', array( 'jquery' ), '1.4.1' );
266
  wp_localize_script( 'ngg-ajax', 'nggAjaxSetup', array(
267
  'url' => admin_url( 'admin-ajax.php' ),
268
  'action' => 'ngg_ajax_operation',
@@ -271,8 +271,7 @@ class NGG_Admin_Launcher {
271
  'error' => __( 'Unexpected Error', 'nggallery' ),
272
  'failure' => __( 'A failure occurred', 'nggallery' )
273
  ) );
274
- wp_register_script( 'ngg-plupload-handler', NGGALLERY_URLPATH . 'admin/js/plupload.handler.js',
275
- array( 'plupload-all' ), '0.0.1' );
276
  wp_localize_script( 'ngg-plupload-handler', 'pluploadL10n', array(
277
  'queue_limit_exceeded' => __( 'You have attempted to queue too many files.' ),
278
  'file_exceeds_size_limit' => __( 'This file exceeds the maximum upload size for this site.' ),
@@ -296,10 +295,9 @@ class NGG_Admin_Launcher {
296
  'error_uploading' => __( '“%s” has failed to upload due to an error' ),
297
  'no_gallery' => __( 'You didn\'t select a gallery!', 'nggallery' )
298
  ) );
299
- wp_register_script( 'ngg-progressbar', NGGALLERY_URLPATH . 'admin/js/ngg.progressbar.js', array( 'jquery' ),
300
  '2.0.1' );
301
- wp_register_script( 'ngg-autocomplete', NGGALLERY_URLPATH . 'admin/js/ngg.autocomplete.js',
302
- array( 'jquery-ui-autocomplete' ), '1.1' );
303
 
304
  switch ( $_GET['page'] ) {
305
  case NGGFOLDER :
@@ -314,8 +312,8 @@ class NGG_Admin_Launcher {
314
  wp_enqueue_script( 'jquery-ui-sortable' );
315
  wp_enqueue_script( 'jquery-ui-datepicker' );
316
  wp_enqueue_script( 'ngg-autocomplete' );
317
- wp_enqueue_script( 'ngg-cropper', NGGALLERY_URLPATH . 'admin/js/cropper/cropper.js', '0.10.0' );
318
- wp_register_script( 'shutter', NGGALLERY_URLPATH . 'shutter/shutter-reloaded.js', false, '1.3.2' );
319
  wp_localize_script( 'shutter', 'shutterSettings', array(
320
  'msgLoading' => __( 'L O A D I N G', 'nggallery' ),
321
  'msgClose' => __( 'Click to Close', 'nggallery' ),
@@ -339,8 +337,7 @@ class NGG_Admin_Launcher {
339
  wp_enqueue_script( 'ngg-ajax' );
340
  wp_enqueue_script( 'ngg-progressbar' );
341
  wp_enqueue_script( 'jquery-ui-dialog' );
342
- wp_enqueue_script( 'jqueryFileTree', NGGALLERY_URLPATH . 'admin/js/jqueryFileTree/jqueryFileTree.js',
343
- array( 'jquery' ), '1.0.1' );
344
  break;
345
  case "nggallery-style" :
346
  wp_enqueue_script( 'codepress' );
@@ -353,8 +350,8 @@ class NGG_Admin_Launcher {
353
  * Load the CSS files.
354
  */
355
  public function load_styles() {
356
- wp_register_style( 'nggadmin', NGGALLERY_URLPATH . 'admin/css/nggadmin.css', false, '2.8.1', 'screen' );
357
- wp_register_style( 'ngg-jqueryui', NGGALLERY_URLPATH . 'admin/css/jquery.ui.css', false, '1.8.5', 'screen' );
358
 
359
  // no need to go on if it's not a plugin page
360
  if ( ! isset( $_GET['page'] ) ) {
@@ -368,20 +365,19 @@ class NGG_Admin_Launcher {
368
  break;
369
  case "nggallery-add-gallery" :
370
  wp_enqueue_style( 'ngg-jqueryui' );
371
- wp_enqueue_style( 'jqueryFileTree', NGGALLERY_URLPATH . 'admin/js/jqueryFileTree/jqueryFileTree.css',
372
- false, '1.0.1', 'screen' );
373
  case "nggallery-options" :
374
- wp_enqueue_style( 'nggtabs', NGGALLERY_URLPATH . 'admin/css/jquery.ui.tabs.css', false, '2.5.0',
375
  'screen' );
376
  wp_enqueue_style( 'nggadmin' );
377
  wp_enqueue_style( 'wp-color-picker' );
378
  wp_enqueue_style( 'ngg-jqueryui' );
379
  break;
380
  case "nggallery-manage":
381
- wp_enqueue_style( 'ngg-cropper', NGGALLERY_URLPATH . 'admin/js/cropper/cropper.min.css', '0.10.0' );
382
- wp_enqueue_style( 'shutter', NGGALLERY_URLPATH . 'shutter/shutter-reloaded.css', false, '1.3.2',
383
  'screen' );
384
- wp_enqueue_style( 'datepicker', NGGALLERY_URLPATH . 'admin/css/jquery.ui.datepicker.css', false,
385
  '1.8.2', 'screen' );
386
  case "nggallery-roles" :
387
  case "nggallery-manage-album" :
@@ -524,18 +520,73 @@ class NGG_Admin_Launcher {
524
  'default' => 50,
525
  'option' => 'ngg_images_per_page'
526
  );
527
- }
528
 
529
- $screen->add_option( $option, $args );
530
 
 
 
 
 
 
531
 
532
- $help = '<p>' . __( 'Manage your images and galleries.', 'nggallery' ) . '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
 
534
- $screen->add_help_tab( array(
535
- 'id' => $screen->id . '-general',
536
- 'title' => 'Manage everything',
537
- 'content' => $help
538
- ) );
539
  break;
540
  case "{$i18n}_page_nggallery-manage-album" :
541
  $help = '<p>' . __( 'Organize your galleries into albums.',
262
  return;
263
  }
264
 
265
+ wp_register_script( 'ngg-ajax', plugins_url( 'js/ngg.ajax.js', __FILE__), array( 'jquery' ), '1.4.1' );
266
  wp_localize_script( 'ngg-ajax', 'nggAjaxSetup', array(
267
  'url' => admin_url( 'admin-ajax.php' ),
268
  'action' => 'ngg_ajax_operation',
271
  'error' => __( 'Unexpected Error', 'nggallery' ),
272
  'failure' => __( 'A failure occurred', 'nggallery' )
273
  ) );
274
+ wp_register_script( 'ngg-plupload-handler', plugins_url( 'js/plupload.handler.js', __FILE__), array( 'plupload-all' ), '0.0.1' );
 
275
  wp_localize_script( 'ngg-plupload-handler', 'pluploadL10n', array(
276
  'queue_limit_exceeded' => __( 'You have attempted to queue too many files.' ),
277
  'file_exceeds_size_limit' => __( 'This file exceeds the maximum upload size for this site.' ),
295
  'error_uploading' => __( '&#8220;%s&#8221; has failed to upload due to an error' ),
296
  'no_gallery' => __( 'You didn\'t select a gallery!', 'nggallery' )
297
  ) );
298
+ wp_register_script( 'ngg-progressbar', plugins_url( 'js/ngg.progressbar.js', __FILE__), array( 'jquery' ),
299
  '2.0.1' );
300
+ wp_register_script( 'ngg-autocomplete', plugins_url( 'js/ngg.autocomplete.js', __FILE__ ), array( 'jquery-ui-autocomplete' ), '1.1' );
 
301
 
302
  switch ( $_GET['page'] ) {
303
  case NGGFOLDER :
312
  wp_enqueue_script( 'jquery-ui-sortable' );
313
  wp_enqueue_script( 'jquery-ui-datepicker' );
314
  wp_enqueue_script( 'ngg-autocomplete' );
315
+ wp_enqueue_script( 'ngg-cropper', plugins_url('js/cropper/cropper.min.js', __FILE__), '2.2.5' );
316
+ wp_register_script( 'shutter', plugins_url('shutter/shutter-reloaded.js', __DIR__), false, '1.3.2' );
317
  wp_localize_script( 'shutter', 'shutterSettings', array(
318
  'msgLoading' => __( 'L O A D I N G', 'nggallery' ),
319
  'msgClose' => __( 'Click to Close', 'nggallery' ),
337
  wp_enqueue_script( 'ngg-ajax' );
338
  wp_enqueue_script( 'ngg-progressbar' );
339
  wp_enqueue_script( 'jquery-ui-dialog' );
340
+ wp_enqueue_script( 'jqueryFileTree', plugins_url( 'js/jqueryFileTree/jqueryFileTree.js', __FILE__), array( 'jquery' ), '1.0.1' );
 
341
  break;
342
  case "nggallery-style" :
343
  wp_enqueue_script( 'codepress' );
350
  * Load the CSS files.
351
  */
352
  public function load_styles() {
353
+ wp_register_style( 'nggadmin', plugins_url( 'css/nggadmin.css', __FILE__), false, '2.8.1', 'screen' );
354
+ wp_register_style( 'ngg-jqueryui', plugins_url( 'css/jquery.ui.css', __FILE__), false, '1.8.5', 'screen' );
355
 
356
  // no need to go on if it's not a plugin page
357
  if ( ! isset( $_GET['page'] ) ) {
365
  break;
366
  case "nggallery-add-gallery" :
367
  wp_enqueue_style( 'ngg-jqueryui' );
368
+ wp_enqueue_style( 'jqueryFileTree', plugins_url( 'js/jqueryFileTree/jqueryFileTree.css', __FILE__), false, '1.0.1', 'screen' );
 
369
  case "nggallery-options" :
370
+ wp_enqueue_style( 'nggtabs', plugins_url( 'css/jquery.ui.tabs.css', __FILE__), false, '2.5.0',
371
  'screen' );
372
  wp_enqueue_style( 'nggadmin' );
373
  wp_enqueue_style( 'wp-color-picker' );
374
  wp_enqueue_style( 'ngg-jqueryui' );
375
  break;
376
  case "nggallery-manage":
377
+ wp_enqueue_style( 'ngg-cropper', plugins_url( 'js/cropper/cropper.min.css', __FILE__), '2.2.5' );
378
+ wp_enqueue_style( 'shutter', plugins_url('shutter/shutter-reloaded.css', __DIR__), false, '1.3.2',
379
  'screen' );
380
+ wp_enqueue_style( 'datepicker', plugins_url('css/jquery.ui.datepicker.css', __FILE__), false,
381
  '1.8.2', 'screen' );
382
  case "nggallery-roles" :
383
  case "nggallery-manage-album" :
520
  'default' => 50,
521
  'option' => 'ngg_images_per_page'
522
  );
 
523
 
524
+ $help = '<p>' . __( 'This box contains information and the various options a gallery had.', 'nggallery') . '</p>';
525
 
526
+ $screen->add_help_tab( array(
527
+ 'id' => $screen->id . '-general',
528
+ 'title' => __( 'Overview', 'nggallery'),
529
+ 'content' => $help
530
+ ) );
531
 
532
+ $help = '<p>' . __( 'Manage a single gallery and the images it contains:', 'nggallery' ) . '</p>';
533
+ $help .= '<dl class="ncg-dl">';
534
+
535
+ $help .= '<dt>' . __( 'Title', 'ngallery') . '</dt>';
536
+ $help .= '<dd>' . __( 'The title of the gallery. This can be visible to the users of the website. This has no effect on the gallery path.', 'nggallery') .'</dd>';
537
+
538
+ $help .= '<dt>' . __( 'Description', 'ngallery') . '</dt>';
539
+ $help .= '<dd>' . __( 'The description of the gallery. Albums using the "extend" template may display this on the website. The description cannot contain HTML.', 'nggallery') .'</dd>';
540
+
541
+ $help .= '<dt>' . __( 'Path', 'ngallery') . '</dt>';
542
+ $help .= '<dd>' . __( 'The path on the server to the folder containing this gallery. If you change this, NextCellent will not move the gallery for you.', 'nggallery') .'</dd>';
543
+
544
+ $help .= '<dt>' . __( 'Gallery ID', 'ngallery') . '</dt>';
545
+ $help .= '<dd>' . __( 'The internal ID used by NextCellent to represent this gallery. This information can be useful for developers. A gallery ID should never change.', 'nggallery') .'</dd>';
546
+
547
+ $help .= '<dt>' . __( 'Page Link', 'ngallery') . '</dt>';
548
+ $help .= '<dd>' . __( 'With this option you can select the behavior when an user clicks on a gallery in an album. If the option is set to "not linked", the gallery will be displayed on the same page. If you do select a page, the user will be redirected to that page.', 'nggallery');
549
+ $help .= ' '. sprintf( __( 'More information about this is available on this webpage: %s', 'nggallery'), '<a target="_blank" href="http://www.nextgen-gallery.com/link-to-page/">' . __('page', 'nggallery') . '</a>') . '</dd>';
550
+
551
+ $help .= '<dt>' . __( 'Preview image', 'ngallery') . '</dt>';
552
+ $help .= '<dd>' . __( 'This image will be shown when the gallery is shown on the website and it needs a preview, e.g. an album. If you do not select a preview image, NextCellent will use the last uploaded image of the gallery.', 'nggallery') .'</dd>';
553
+
554
+ $help .= '<dt>' . __( 'Author', 'ngallery') . '</dt>';
555
+ $help .= '<dd>' . __( 'The user who created this gallery.', 'nggallery') .'</dd>';
556
+
557
+ $help .= '<dt>' . __( 'Create new page', 'ngallery') . '</dt>';
558
+ $help .= '<dd>' . __( 'This will create a new page with the same name as the gallery, and include a shortcode for this gallery in it.', 'nggallery') .'</dd>';
559
+ $help .= '</dl>';
560
+
561
+ $screen->add_help_tab( array(
562
+ 'id' => $screen->id . '-options',
563
+ 'title' => __( 'Gallery settings', 'nggallery'),
564
+ 'content' => $help
565
+ ) );
566
+
567
+ $help = '<p>' . __( 'There are three buttons:', 'nggallery') . '</p>';
568
+ $help .= '<dl class="ncg-dl">';
569
+
570
+ $help .= '<dt>' . __( 'Sort gallery', 'ngallery') . '</dt>';
571
+ $help .= '<dd>' . __( 'Allows you to manually set the order of the images in the gallery. This will only be enabled if you have selected the option "Custom sort order" in the NextCellent settings.', 'nggallery') .'</dd>';
572
+
573
+ $help .= '<dt>' . __( 'Scan folder for new images', 'ngallery') . '</dt>';
574
+ $help .= '<dd>' . __( 'Scan the folder (the path of the gallery) for new images and add them to the gallery. <strong>Warning!</strong> This will normalize and rename the images that are added, e.g. spaces are removed.', 'nggallery') .'</dd>';
575
+
576
+ $help .= '<dt>' . __( 'Save', 'ngallery') . '</dt>';
577
+ $help .= '<dd>' . __( 'Save changes you have made to the gallery options.', 'nggallery') .'</dd>';
578
+
579
+ $help .= '</dl>';
580
+
581
+ $screen->add_help_tab( array(
582
+ 'id' => $screen->id . '-buttons',
583
+ 'title' => __( 'Buttons', 'nggallery'),
584
+ 'content' => $help
585
+ ) );
586
+ }
587
+
588
+ $screen->add_option( $option, $args );
589
 
 
 
 
 
 
590
  break;
591
  case "{$i18n}_page_nggallery-manage-album" :
592
  $help = '<p>' . __( 'Organize your galleries into albums.',
admin/class-ngg-options.php CHANGED
@@ -357,7 +357,7 @@ class NGG_Options extends NGG_Post_Admin_Page {
357
  <h3><?php _e('Image settings','nggallery'); ?></h3>
358
  <form name="imagesettings" method="POST" action="<?php echo $this->page.'#images'; ?>">
359
  <?php wp_nonce_field('ngg_settings') ?>
360
- <input type="hidden" name="page_options" value="imgResize,imgWidth,imgHeight,imgQuality,imgBackup,imgAutoResize,thumbwidth,thumbheight,thumbfix,thumbquality">
361
  <table class="form-table ngg-options">
362
  <tr>
363
  <th><?php _e('Resize images','nggallery') ?></th>
@@ -393,7 +393,16 @@ class NGG_Options extends NGG_Post_Admin_Page {
393
  </tr>
394
  </table>
395
  <h3><?php _e('Thumbnail settings','nggallery'); ?></h3>
396
- <p><?php _e('Please note: if you change these settings, you need to recreate the thumbnails under -> Manage Gallery .', 'nggallery') ?></p>
 
 
 
 
 
 
 
 
 
397
  <table class="form-table ngg-options">
398
  <tr>
399
  <th><?php _e('Thumbnail size','nggallery'); ?></th>
357
  <h3><?php _e('Image settings','nggallery'); ?></h3>
358
  <form name="imagesettings" method="POST" action="<?php echo $this->page.'#images'; ?>">
359
  <?php wp_nonce_field('ngg_settings') ?>
360
+ <input type="hidden" name="page_options" value="imgResize,imgWidth,imgHeight,imgQuality,imgBackup,imgAutoResize,thumbwidth,thumbheight,thumbfix,thumbquality,thumbDifferentSize">
361
  <table class="form-table ngg-options">
362
  <tr>
363
  <th><?php _e('Resize images','nggallery') ?></th>
393
  </tr>
394
  </table>
395
  <h3><?php _e('Thumbnail settings','nggallery'); ?></h3>
396
+ <table class="form-table ngg-options">
397
+ <tr>
398
+ <th><?php _e('Different sizes','nggallery'); ?></th>
399
+ <td>
400
+ <input type="checkbox" name="thumbDifferentSize" id="thumbDifferentSize" value="true" <?php checked( $options['thumbDifferentSize']); ?>>
401
+ <label for="thumbDifferentSize"><?php _e('Allows you to make thubnails with dimensions that differ from the rest of the gallery.','nggallery') ?></label>
402
+ </td>
403
+ </tr>
404
+ </table>
405
+ <p><?php _e('Please note: if you change the settings below settings, you need to recreate the thumbnails under -> Manage Gallery .', 'nggallery') ?></p>
406
  <table class="form-table ngg-options">
407
  <tr>
408
  <th><?php _e('Thumbnail size','nggallery'); ?></th>
admin/css/jquery.ui.tabs.css CHANGED
@@ -14,7 +14,7 @@
14
 
15
  /* Skin */
16
  #slider ul.ui-tabs-nav {
17
- height: 33px;
18
  border-bottom: 1px solid #CCCCCC;
19
  padding: 9px 15px 0 10px;
20
  }
14
 
15
  /* Skin */
16
  #slider ul.ui-tabs-nav {
17
+ height: 37px;
18
  border-bottom: 1px solid #CCCCCC;
19
  padding: 9px 15px 0 10px;
20
  }
admin/css/nggadmin.css CHANGED
@@ -589,4 +589,9 @@ p#sortButton {
589
  .ngg-tag-wrap #ajax_area_tagslist {}
590
  .ngg-tag-wrap #ajax_area_tagslist ul{list-style:square;margin:10px 0 10px 20px;padding:0;}
591
  .ngg-tag-wrap #ajax_area_tagslist ul li{margin:0;padding:0;line-height:1.4;}
592
- .ngg-tag-wrap #ajax_area_tagslist ul li span{cursor:pointer;}
 
 
 
 
 
589
  .ngg-tag-wrap #ajax_area_tagslist {}
590
  .ngg-tag-wrap #ajax_area_tagslist ul{list-style:square;margin:10px 0 10px 20px;padding:0;}
591
  .ngg-tag-wrap #ajax_area_tagslist ul li{margin:0;padding:0;line-height:1.4;}
592
+ .ngg-tag-wrap #ajax_area_tagslist ul li span{cursor:pointer;}
593
+
594
+ /* This is for the NextCellent help */
595
+ .contextual-help-tabs-wrap .ncg-dl dt {
596
+ font-weight: bold;
597
+ }
admin/js/cropper/cropper.css CHANGED
@@ -1,25 +1,33 @@
1
  /*!
2
- * Cropper v0.10.0
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
- * Copyright (c) 2014-2015 Fengyuan Chen and other contributors
6
  * Released under the MIT license
7
  *
8
- * Date: 2015-06-08T14:57:26.353Z
9
  */
10
  .cropper-container {
 
 
 
11
  position: relative;
12
- overflow: hidden;
13
  -webkit-user-select: none;
14
  -moz-user-select: none;
15
  -ms-user-select: none;
16
  user-select: none;
17
 
 
 
 
18
  -webkit-tap-highlight-color: transparent;
19
  -webkit-touch-callout: none;
20
  }
 
21
  .cropper-container img {
22
  display: block;
 
23
  width: 100%;
24
  min-width: 0 !important;
25
  max-width: none !important;
@@ -29,6 +37,8 @@
29
 
30
  image-orientation: 0deg !important;
31
  }
 
 
32
  .cropper-canvas,
33
  .cropper-drag-box,
34
  .cropper-crop-box,
@@ -39,206 +49,328 @@
39
  bottom: 0;
40
  left: 0;
41
  }
 
 
 
 
 
42
  .cropper-drag-box {
 
43
  background-color: #fff;
 
44
  filter: alpha(opacity=0);
45
- opacity: 0;
46
  }
 
47
  .cropper-modal {
 
48
  background-color: #000;
 
49
  filter: alpha(opacity=50);
50
- opacity: .5;
51
  }
 
52
  .cropper-view-box {
53
  display: block;
 
 
54
  width: 100%;
55
  height: 100%;
56
- overflow: hidden;
57
- outline: 1px solid #69f;
58
- outline-color: rgba(102, 153, 255, .75);
59
  }
 
60
  .cropper-dashed {
61
  position: absolute;
 
62
  display: block;
63
- filter: alpha(opacity=50);
64
- border: 0 dashed #fff;
65
  opacity: .5;
 
 
 
66
  }
 
67
  .cropper-dashed.dashed-h {
68
- top: 33.33333333%;
69
  left: 0;
 
70
  width: 100%;
71
- height: 33.33333333%;
 
72
  border-top-width: 1px;
73
  border-bottom-width: 1px;
74
  }
 
75
  .cropper-dashed.dashed-v {
76
  top: 0;
77
- left: 33.33333333%;
78
- width: 33.33333333%;
 
79
  height: 100%;
 
80
  border-right-width: 1px;
81
  border-left-width: 1px;
82
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  .cropper-face,
84
  .cropper-line,
85
  .cropper-point {
86
  position: absolute;
 
87
  display: block;
 
88
  width: 100%;
89
  height: 100%;
90
- filter: alpha(opacity=10);
91
  opacity: .1;
 
 
92
  }
 
93
  .cropper-face {
94
  top: 0;
95
  left: 0;
 
96
  background-color: #fff;
97
  }
 
98
  .cropper-line {
99
- background-color: #69f;
100
  }
 
101
  .cropper-line.line-e {
102
  top: 0;
103
  right: -3px;
 
104
  width: 5px;
 
105
  cursor: e-resize;
106
  }
 
107
  .cropper-line.line-n {
108
  top: -3px;
109
  left: 0;
 
110
  height: 5px;
 
111
  cursor: n-resize;
112
  }
 
113
  .cropper-line.line-w {
114
  top: 0;
115
  left: -3px;
 
116
  width: 5px;
 
117
  cursor: w-resize;
118
  }
 
119
  .cropper-line.line-s {
120
  bottom: -3px;
121
  left: 0;
 
122
  height: 5px;
 
123
  cursor: s-resize;
124
  }
 
125
  .cropper-point {
126
  width: 5px;
127
  height: 5px;
128
- background-color: #69f;
129
- filter: alpha(opacity=75);
130
  opacity: .75;
 
 
 
131
  }
 
132
  .cropper-point.point-e {
133
  top: 50%;
134
  right: -3px;
 
135
  margin-top: -3px;
 
136
  cursor: e-resize;
137
  }
 
138
  .cropper-point.point-n {
139
  top: -3px;
140
  left: 50%;
 
141
  margin-left: -3px;
 
142
  cursor: n-resize;
143
  }
 
144
  .cropper-point.point-w {
145
  top: 50%;
146
  left: -3px;
 
147
  margin-top: -3px;
 
148
  cursor: w-resize;
149
  }
 
150
  .cropper-point.point-s {
151
  bottom: -3px;
152
  left: 50%;
 
153
  margin-left: -3px;
 
154
  cursor: s-resize;
155
  }
 
156
  .cropper-point.point-ne {
157
  top: -3px;
158
  right: -3px;
 
159
  cursor: ne-resize;
160
  }
 
161
  .cropper-point.point-nw {
162
  top: -3px;
163
  left: -3px;
 
164
  cursor: nw-resize;
165
  }
 
166
  .cropper-point.point-sw {
167
  bottom: -3px;
168
  left: -3px;
 
169
  cursor: sw-resize;
170
  }
 
171
  .cropper-point.point-se {
172
  right: -3px;
173
  bottom: -3px;
 
174
  width: 20px;
175
  height: 20px;
 
176
  cursor: se-resize;
177
- filter: alpha(opacity=100);
178
  opacity: 1;
 
 
179
  }
 
180
  .cropper-point.point-se:before {
181
  position: absolute;
182
  right: -50%;
183
  bottom: -50%;
 
184
  display: block;
 
185
  width: 200%;
186
  height: 200%;
187
- content: " ";
188
- background-color: #69f;
189
- filter: alpha(opacity=0);
190
  opacity: 0;
 
 
 
191
  }
 
192
  @media (min-width: 768px) {
193
  .cropper-point.point-se {
194
  width: 15px;
195
  height: 15px;
196
  }
197
  }
 
198
  @media (min-width: 992px) {
199
  .cropper-point.point-se {
200
  width: 10px;
201
  height: 10px;
202
  }
203
  }
 
204
  @media (min-width: 1200px) {
205
  .cropper-point.point-se {
206
  width: 5px;
207
  height: 5px;
208
- filter: alpha(opacity=75);
209
  opacity: .75;
 
 
210
  }
211
  }
212
- .cropper-bg {
213
- background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
214
- }
215
  .cropper-invisible {
216
- filter: alpha(opacity=0);
217
  opacity: 0;
 
 
 
 
 
 
218
  }
 
219
  .cropper-hide {
220
- position: fixed;
221
- top: 0;
222
- left: 0;
223
- z-index: -1;
224
- width: auto!important;
225
- min-width: 0!important;
226
- max-width: none!important;
227
- height: auto!important;
228
- min-height: 0!important;
229
- max-height: none!important;
230
- filter: alpha(opacity=0);
231
- opacity: 0;
232
  }
 
233
  .cropper-hidden {
234
  display: none !important;
235
  }
 
236
  .cropper-move {
237
  cursor: move;
238
  }
 
239
  .cropper-crop {
240
  cursor: crosshair;
241
  }
 
242
  .cropper-disabled .cropper-drag-box,
243
  .cropper-disabled .cropper-face,
244
  .cropper-disabled .cropper-line,
1
  /*!
2
+ * Cropper v2.2.5
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
+ * Copyright (c) 2014-2016 Fengyuan Chen and contributors
6
  * Released under the MIT license
7
  *
8
+ * Date: 2016-01-18T05:42:29.639Z
9
  */
10
  .cropper-container {
11
+ font-size: 0;
12
+ line-height: 0;
13
+
14
  position: relative;
15
+
16
  -webkit-user-select: none;
17
  -moz-user-select: none;
18
  -ms-user-select: none;
19
  user-select: none;
20
 
21
+ direction: ltr !important;
22
+ -ms-touch-action: none;
23
+ touch-action: none;
24
  -webkit-tap-highlight-color: transparent;
25
  -webkit-touch-callout: none;
26
  }
27
+
28
  .cropper-container img {
29
  display: block;
30
+
31
  width: 100%;
32
  min-width: 0 !important;
33
  max-width: none !important;
37
 
38
  image-orientation: 0deg !important;
39
  }
40
+
41
+ .cropper-wrap-box,
42
  .cropper-canvas,
43
  .cropper-drag-box,
44
  .cropper-crop-box,
49
  bottom: 0;
50
  left: 0;
51
  }
52
+
53
+ .cropper-wrap-box {
54
+ overflow: hidden;
55
+ }
56
+
57
  .cropper-drag-box {
58
+ opacity: 0;
59
  background-color: #fff;
60
+
61
  filter: alpha(opacity=0);
 
62
  }
63
+
64
  .cropper-modal {
65
+ opacity: .5;
66
  background-color: #000;
67
+
68
  filter: alpha(opacity=50);
 
69
  }
70
+
71
  .cropper-view-box {
72
  display: block;
73
+ overflow: hidden;
74
+
75
  width: 100%;
76
  height: 100%;
77
+
78
+ outline: 1px solid #39f;
79
+ outline-color: rgba(51, 153, 255, .75);
80
  }
81
+
82
  .cropper-dashed {
83
  position: absolute;
84
+
85
  display: block;
86
+
 
87
  opacity: .5;
88
+ border: 0 dashed #eee;
89
+
90
+ filter: alpha(opacity=50);
91
  }
92
+
93
  .cropper-dashed.dashed-h {
94
+ top: 33.33333%;
95
  left: 0;
96
+
97
  width: 100%;
98
+ height: 33.33333%;
99
+
100
  border-top-width: 1px;
101
  border-bottom-width: 1px;
102
  }
103
+
104
  .cropper-dashed.dashed-v {
105
  top: 0;
106
+ left: 33.33333%;
107
+
108
+ width: 33.33333%;
109
  height: 100%;
110
+
111
  border-right-width: 1px;
112
  border-left-width: 1px;
113
  }
114
+
115
+ .cropper-center {
116
+ position: absolute;
117
+ top: 50%;
118
+ left: 50%;
119
+
120
+ display: block;
121
+
122
+ width: 0;
123
+ height: 0;
124
+
125
+ opacity: .75;
126
+
127
+ filter: alpha(opacity=75);
128
+ }
129
+
130
+ .cropper-center:before,
131
+ .cropper-center:after {
132
+ position: absolute;
133
+
134
+ display: block;
135
+
136
+ content: ' ';
137
+
138
+ background-color: #eee;
139
+ }
140
+
141
+ .cropper-center:before {
142
+ top: 0;
143
+ left: -3px;
144
+
145
+ width: 7px;
146
+ height: 1px;
147
+ }
148
+
149
+ .cropper-center:after {
150
+ top: -3px;
151
+ left: 0;
152
+
153
+ width: 1px;
154
+ height: 7px;
155
+ }
156
+
157
  .cropper-face,
158
  .cropper-line,
159
  .cropper-point {
160
  position: absolute;
161
+
162
  display: block;
163
+
164
  width: 100%;
165
  height: 100%;
166
+
167
  opacity: .1;
168
+
169
+ filter: alpha(opacity=10);
170
  }
171
+
172
  .cropper-face {
173
  top: 0;
174
  left: 0;
175
+
176
  background-color: #fff;
177
  }
178
+
179
  .cropper-line {
180
+ background-color: #39f;
181
  }
182
+
183
  .cropper-line.line-e {
184
  top: 0;
185
  right: -3px;
186
+
187
  width: 5px;
188
+
189
  cursor: e-resize;
190
  }
191
+
192
  .cropper-line.line-n {
193
  top: -3px;
194
  left: 0;
195
+
196
  height: 5px;
197
+
198
  cursor: n-resize;
199
  }
200
+
201
  .cropper-line.line-w {
202
  top: 0;
203
  left: -3px;
204
+
205
  width: 5px;
206
+
207
  cursor: w-resize;
208
  }
209
+
210
  .cropper-line.line-s {
211
  bottom: -3px;
212
  left: 0;
213
+
214
  height: 5px;
215
+
216
  cursor: s-resize;
217
  }
218
+
219
  .cropper-point {
220
  width: 5px;
221
  height: 5px;
222
+
 
223
  opacity: .75;
224
+ background-color: #39f;
225
+
226
+ filter: alpha(opacity=75);
227
  }
228
+
229
  .cropper-point.point-e {
230
  top: 50%;
231
  right: -3px;
232
+
233
  margin-top: -3px;
234
+
235
  cursor: e-resize;
236
  }
237
+
238
  .cropper-point.point-n {
239
  top: -3px;
240
  left: 50%;
241
+
242
  margin-left: -3px;
243
+
244
  cursor: n-resize;
245
  }
246
+
247
  .cropper-point.point-w {
248
  top: 50%;
249
  left: -3px;
250
+
251
  margin-top: -3px;
252
+
253
  cursor: w-resize;
254
  }
255
+
256
  .cropper-point.point-s {
257
  bottom: -3px;
258
  left: 50%;
259
+
260
  margin-left: -3px;
261
+
262
  cursor: s-resize;
263
  }
264
+
265
  .cropper-point.point-ne {
266
  top: -3px;
267
  right: -3px;
268
+
269
  cursor: ne-resize;
270
  }
271
+
272
  .cropper-point.point-nw {
273
  top: -3px;
274
  left: -3px;
275
+
276
  cursor: nw-resize;
277
  }
278
+
279
  .cropper-point.point-sw {
280
  bottom: -3px;
281
  left: -3px;
282
+
283
  cursor: sw-resize;
284
  }
285
+
286
  .cropper-point.point-se {
287
  right: -3px;
288
  bottom: -3px;
289
+
290
  width: 20px;
291
  height: 20px;
292
+
293
  cursor: se-resize;
294
+
295
  opacity: 1;
296
+
297
+ filter: alpha(opacity=100);
298
  }
299
+
300
  .cropper-point.point-se:before {
301
  position: absolute;
302
  right: -50%;
303
  bottom: -50%;
304
+
305
  display: block;
306
+
307
  width: 200%;
308
  height: 200%;
309
+
310
+ content: ' ';
311
+
312
  opacity: 0;
313
+ background-color: #39f;
314
+
315
+ filter: alpha(opacity=0);
316
  }
317
+
318
  @media (min-width: 768px) {
319
  .cropper-point.point-se {
320
  width: 15px;
321
  height: 15px;
322
  }
323
  }
324
+
325
  @media (min-width: 992px) {
326
  .cropper-point.point-se {
327
  width: 10px;
328
  height: 10px;
329
  }
330
  }
331
+
332
  @media (min-width: 1200px) {
333
  .cropper-point.point-se {
334
  width: 5px;
335
  height: 5px;
336
+
337
  opacity: .75;
338
+
339
+ filter: alpha(opacity=75);
340
  }
341
  }
342
+
 
 
343
  .cropper-invisible {
 
344
  opacity: 0;
345
+
346
+ filter: alpha(opacity=0);
347
+ }
348
+
349
+ .cropper-bg {
350
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
351
  }
352
+
353
  .cropper-hide {
354
+ position: absolute;
355
+
356
+ display: block;
357
+
358
+ width: 0;
359
+ height: 0;
 
 
 
 
 
 
360
  }
361
+
362
  .cropper-hidden {
363
  display: none !important;
364
  }
365
+
366
  .cropper-move {
367
  cursor: move;
368
  }
369
+
370
  .cropper-crop {
371
  cursor: crosshair;
372
  }
373
+
374
  .cropper-disabled .cropper-drag-box,
375
  .cropper-disabled .cropper-face,
376
  .cropper-disabled .cropper-line,
admin/js/cropper/cropper.js CHANGED
@@ -1,11 +1,11 @@
1
  /*!
2
- * Cropper v0.10.0
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
- * Copyright (c) 2014-2015 Fengyuan Chen and other contributors
6
  * Released under the MIT license
7
  *
8
- * Date: 2015-06-08T14:57:26.353Z
9
  */
10
 
11
  (function (factory) {
@@ -23,57 +23,86 @@
23
 
24
  'use strict';
25
 
26
- var $window = $(window),
27
- $document = $(document),
28
- location = window.location,
29
-
30
- // Constants
31
- CROPPER_NAMESPACE = '.cropper',
32
- CROPPER_PREVIEW = 'preview' + CROPPER_NAMESPACE,
33
-
34
- // RegExps
35
- REGEXP_DRAG_TYPES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,
36
-
37
- // Classes
38
- CLASS_MODAL = 'cropper-modal',
39
- CLASS_HIDE = 'cropper-hide',
40
- CLASS_HIDDEN = 'cropper-hidden',
41
- CLASS_INVISIBLE = 'cropper-invisible',
42
- CLASS_MOVE = 'cropper-move',
43
- CLASS_CROP = 'cropper-crop',
44
- CLASS_DISABLED = 'cropper-disabled',
45
- CLASS_BG = 'cropper-bg',
46
-
47
- // Events
48
- EVENT_MOUSE_DOWN = 'mousedown touchstart',
49
- EVENT_MOUSE_MOVE = 'mousemove touchmove',
50
- EVENT_MOUSE_UP = 'mouseup mouseleave touchend touchleave touchcancel',
51
- EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll',
52
- EVENT_DBLCLICK = 'dblclick',
53
- EVENT_RESIZE = 'resize' + CROPPER_NAMESPACE, // Bind to window with namespace
54
- EVENT_BUILD = 'build' + CROPPER_NAMESPACE,
55
- EVENT_BUILT = 'built' + CROPPER_NAMESPACE,
56
- EVENT_DRAG_START = 'dragstart' + CROPPER_NAMESPACE,
57
- EVENT_DRAG_MOVE = 'dragmove' + CROPPER_NAMESPACE,
58
- EVENT_DRAG_END = 'dragend' + CROPPER_NAMESPACE,
59
- EVENT_ZOOM_IN = 'zoomin' + CROPPER_NAMESPACE,
60
- EVENT_ZOOM_OUT = 'zoomout' + CROPPER_NAMESPACE,
61
- EVENT_CHANGE = 'change' + CROPPER_NAMESPACE,
62
-
63
- // Supports
64
- SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext),
65
-
66
- // Others
67
- sqrt = Math.sqrt,
68
- min = Math.min,
69
- max = Math.max,
70
- abs = Math.abs,
71
- sin = Math.sin,
72
- cos = Math.cos,
73
- num = parseFloat,
74
-
75
- // Prototype
76
- prototype = {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  function isNumber(n) {
79
  return typeof n === 'number' && !isNaN(n);
@@ -86,7 +115,8 @@
86
  function toArray(obj, offset) {
87
  var args = [];
88
 
89
- if (isNumber(offset)) { // It's necessary for IE8
 
90
  args.push(offset);
91
  }
92
 
@@ -105,7 +135,11 @@
105
  function isCrossOriginURL(url) {
106
  var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
107
 
108
- return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
 
 
 
 
109
  }
110
 
111
  function addTimestamp(url) {
@@ -114,22 +148,57 @@
114
  return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
115
  }
116
 
117
- function getRotateValue(degree) {
118
- return degree ? 'rotate(' + degree + 'deg)' : 'none';
119
  }
120
 
121
- function getRotatedSizes(data, reverse) {
122
- var deg = abs(data.degree) % 180,
123
- arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180,
124
- sinArc = sin(arc),
125
- cosArc = cos(arc),
126
- width = data.width,
127
- height = data.height,
128
- aspectRatio = data.aspectRatio,
129
- newWidth,
130
- newHeight;
131
-
132
- if (!reverse) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  newWidth = width * cosArc + height * sinArc;
134
  newHeight = width * sinArc + height * cosArc;
135
  } else {
@@ -144,218 +213,556 @@
144
  }
145
 
146
  function getSourceCanvas(image, data) {
147
- var canvas = $('<canvas>')[0],
148
- context = canvas.getContext('2d'),
149
- width = data.naturalWidth,
150
- height = data.naturalHeight,
151
- rotate = data.rotate,
152
- rotated = getRotatedSizes({
153
- width: width,
154
- height: height,
155
- degree: rotate
156
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- if (rotate) {
159
- canvas.width = rotated.width;
160
- canvas.height = rotated.height;
161
  context.save();
162
- context.translate(rotated.width / 2, rotated.height / 2);
 
 
 
163
  context.rotate(rotate * Math.PI / 180);
164
- context.drawImage(image, -width / 2, -height / 2, width, height);
 
 
 
 
 
 
 
 
 
165
  context.restore();
166
- } else {
167
- canvas.width = width;
168
- canvas.height = height;
169
- context.drawImage(image, 0, 0, width, height);
170
  }
171
 
172
  return canvas;
173
  }
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  function Cropper(element, options) {
176
  this.$element = $(element);
177
  this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
178
-
179
- this.ready = false;
180
- this.built = false;
181
- this.rotated = false;
182
- this.cropped = false;
183
- this.disabled = false;
 
 
 
 
 
184
  this.canvas = null;
185
  this.cropBox = null;
186
-
187
- this.load();
188
  }
189
 
190
- prototype.load = function (url) {
191
- var options = this.options,
192
- $this = this.$element,
193
- crossOrigin,
194
- bustCacheUrl,
195
- buildEvent,
196
- $clone;
197
 
198
- if (!url) {
199
  if ($this.is('img')) {
200
- if (!$this.attr('src')) {
 
 
 
 
 
 
201
  return;
202
  }
203
 
 
204
  url = $this.prop('src');
205
  } else if ($this.is('canvas') && SUPPORT_CANVAS) {
206
  url = $this[0].toDataURL();
207
  }
208
- }
209
 
210
- if (!url) {
211
- return;
212
- }
213
 
214
- buildEvent = $.Event(EVENT_BUILD);
215
- $this.one(EVENT_BUILD, options.build).trigger(buildEvent); // Only trigger once
 
216
 
217
- if (buildEvent.isDefaultPrevented()) {
218
- return;
219
- }
 
220
 
221
- if (options.checkImageOrigin && isCrossOriginURL(url)) {
222
- crossOrigin = ' crossOrigin="anonymous"';
 
 
 
223
 
224
- if (!$this.prop('crossOrigin')) { // Only when there was not a "crossOrigin" property
225
- bustCacheUrl = addTimestamp(url); // Bust cache (#148)
226
  }
227
- }
228
 
229
- // IE8 compatibility: Don't use "$().attr()" to set "src"
230
- this.$clone = $clone = $('<img' + (crossOrigin || '') + ' src="' + (bustCacheUrl || url) + '">');
231
 
232
- $clone.one('load', $.proxy(function () {
233
- var image = $clone[0],
234
- naturalWidth = image.naturalWidth || image.width,
235
- naturalHeight = image.naturalHeight || image.height; // $clone.width() and $clone.height() will return 0 in IE8 (#319)
236
 
237
- this.image = {
238
- naturalWidth: naturalWidth,
239
- naturalHeight: naturalHeight,
240
- aspectRatio: naturalWidth / naturalHeight,
241
- rotate: 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  };
243
 
244
- this.url = url;
245
- this.ready = true;
246
- this.build();
247
- }, this)).one('error', function () {
248
- $clone.remove();
249
- });
250
 
251
- // Hide and insert into the document
252
- $clone.addClass(CLASS_HIDE).insertAfter($this);
253
- };
 
 
 
 
254
 
255
- prototype.build = function () {
256
- var $this = this.$element,
257
- $clone = this.$clone,
258
- options = this.options,
259
- $cropper,
260
- $cropBox,
261
- $face;
262
 
263
- if (!this.ready) {
264
- return;
265
- }
266
 
267
- if (this.built) {
268
- this.unbuild();
269
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
 
271
- // Create cropper elements
272
- this.$cropper = $cropper = $(Cropper.TEMPLATE);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
- // Hide the original image
275
- $this.addClass(CLASS_HIDDEN);
 
276
 
277
- // Show the clone iamge
278
- $clone.removeClass(CLASS_HIDE);
 
 
279
 
280
- this.$container = $this.parent().append($cropper);
281
- this.$canvas = $cropper.find('.cropper-canvas').append($clone);
282
- this.$dragBox = $cropper.find('.cropper-drag-box');
283
- this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
284
- this.$viewBox = $cropper.find('.cropper-view-box');
285
- this.$face = $face = $cropBox.find('.cropper-face');
286
 
287
- this.addListeners();
288
- this.initPreview();
 
 
 
 
 
289
 
290
- // Format aspect ratio
291
- options.aspectRatio = num(options.aspectRatio) || NaN; // 0 -> NaN
292
 
293
- if (options.autoCrop) {
294
- this.cropped = true;
 
 
295
 
296
- if (options.modal) {
297
- this.$dragBox.addClass(CLASS_MODAL);
 
298
  }
299
- } else {
300
- $cropBox.addClass(CLASS_HIDDEN);
301
- }
302
 
303
- if (options.background) {
304
- $cropper.addClass(CLASS_BG);
305
- }
306
 
307
- if (!options.highlight) {
308
- $face.addClass(CLASS_INVISIBLE);
309
- }
 
 
 
 
 
 
 
 
 
 
 
310
 
311
- if (!options.guides) {
312
- $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
313
- }
314
 
315
- if (options.cropBoxMovable) {
316
- $face.addClass(CLASS_MOVE).data('drag', 'all');
317
- }
 
318
 
319
- if (!options.cropBoxResizable) {
320
- $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
321
- }
 
 
 
322
 
323
- this.setDragMode(options.dragCrop ? 'crop' : options.movable ? 'move' : 'none');
 
 
 
324
 
325
- this.built = true;
326
- this.render();
327
- this.setData(options.data);
328
- $this.one(EVENT_BUILT, options.built).trigger(EVENT_BUILT); // Only trigger once
329
- };
330
 
331
- prototype.unbuild = function () {
332
- if (!this.built) {
333
- return;
334
- }
 
 
 
335
 
336
- this.built = false;
337
- this.initialImage = null;
338
- this.initialCanvas = null; // This is necessary when replace
339
- this.initialCropBox = null;
340
- this.container = null;
341
- this.canvas = null;
342
- this.cropBox = null; // This is necessary when replace
343
- this.removeListeners();
344
 
345
- this.resetPreview();
346
- this.$preview = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
 
348
- this.$viewBox = null;
349
- this.$cropBox = null;
350
- this.$dragBox = null;
351
- this.$canvas = null;
352
- this.$container = null;
353
 
354
- this.$cropper.remove();
355
- this.$cropper = null;
356
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
- $.extend(prototype, {
359
  render: function () {
360
  this.initContainer();
361
  this.initCanvas();
@@ -363,16 +770,16 @@
363
 
364
  this.renderCanvas();
365
 
366
- if (this.cropped) {
367
  this.renderCropBox();
368
  }
369
  },
370
 
371
  initContainer: function () {
372
- var $this = this.$element,
373
- $container = this.$container,
374
- $cropper = this.$cropper,
375
- options = this.options;
376
 
377
  $cropper.addClass(CLASS_HIDDEN);
378
  $this.removeClass(CLASS_HIDDEN);
@@ -386,102 +793,155 @@
386
  $cropper.removeClass(CLASS_HIDDEN);
387
  },
388
 
389
- // image box (wrapper)
390
  initCanvas: function () {
391
- var container = this.container,
392
- containerWidth = container.width,
393
- containerHeight = container.height,
394
- image = this.image,
395
- aspectRatio = image.aspectRatio,
396
- canvas = {
397
- aspectRatio: aspectRatio,
398
- width: containerWidth,
399
- height: containerHeight
400
- };
 
 
 
 
401
 
402
  if (containerHeight * aspectRatio > containerWidth) {
403
- canvas.height = containerWidth / aspectRatio;
 
 
 
 
404
  } else {
405
- canvas.width = containerHeight * aspectRatio;
 
 
 
 
406
  }
407
 
408
- canvas.oldLeft = canvas.left = (containerWidth - canvas.width) / 2;
409
- canvas.oldTop = canvas.top = (containerHeight - canvas.height) / 2;
 
 
 
 
 
 
 
 
410
 
411
  this.canvas = canvas;
 
412
  this.limitCanvas(true, true);
413
  this.initialImage = $.extend({}, image);
414
  this.initialCanvas = $.extend({}, canvas);
415
  },
416
 
417
- limitCanvas: function (size, position) {
418
- var options = this.options,
419
- strict = options.strict,
420
- container = this.container,
421
- containerWidth = container.width,
422
- containerHeight = container.height,
423
- canvas = this.canvas,
424
- aspectRatio = canvas.aspectRatio,
425
- cropBox = this.cropBox,
426
- cropped = this.cropped && cropBox,
427
- initialCanvas = this.initialCanvas || canvas,
428
- initialCanvasWidth = initialCanvas.width,
429
- initialCanvasHeight = initialCanvas.height,
430
- minCanvasWidth,
431
- minCanvasHeight;
432
-
433
- if (size) {
434
  minCanvasWidth = num(options.minCanvasWidth) || 0;
435
  minCanvasHeight = num(options.minCanvasHeight) || 0;
436
 
437
- if (minCanvasWidth) {
438
- if (strict) {
439
- minCanvasWidth = max(cropped ? cropBox.width : initialCanvasWidth, minCanvasWidth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  }
 
441
 
 
 
 
 
 
 
 
442
  minCanvasHeight = minCanvasWidth / aspectRatio;
443
  } else if (minCanvasHeight) {
444
- if (strict) {
445
- minCanvasHeight = max(cropped ? cropBox.height : initialCanvasHeight, minCanvasHeight);
446
- }
447
-
448
  minCanvasWidth = minCanvasHeight * aspectRatio;
449
- } else if (strict) {
450
- if (cropped) {
451
- minCanvasWidth = cropBox.width;
452
- minCanvasHeight = cropBox.height;
453
-
454
- if (minCanvasHeight * aspectRatio > minCanvasWidth) {
455
- minCanvasWidth = minCanvasHeight * aspectRatio;
456
- } else {
457
- minCanvasHeight = minCanvasWidth / aspectRatio;
458
- }
459
- } else {
460
- minCanvasWidth = initialCanvasWidth;
461
- minCanvasHeight = initialCanvasHeight;
462
- }
463
  }
464
 
465
- $.extend(canvas, {
466
- minWidth: minCanvasWidth,
467
- minHeight: minCanvasHeight,
468
- maxWidth: Infinity,
469
- maxHeight: Infinity
470
- });
471
  }
472
 
473
- if (position) {
474
- if (strict) {
475
- if (cropped) {
476
- canvas.minLeft = min(cropBox.left, (cropBox.left + cropBox.width) - canvas.width);
477
- canvas.minTop = min(cropBox.top, (cropBox.top + cropBox.height) - canvas.height);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  canvas.maxLeft = cropBox.left;
479
  canvas.maxTop = cropBox.top;
480
- } else {
481
- canvas.minLeft = min(0, containerWidth - canvas.width);
482
- canvas.minTop = min(0, containerHeight - canvas.height);
483
- canvas.maxLeft = max(0, containerWidth - canvas.width);
484
- canvas.maxTop = max(0, containerHeight - canvas.height);
 
 
 
 
 
 
 
485
  }
486
  } else {
487
  canvas.minLeft = -canvas.width;
@@ -492,21 +952,23 @@
492
  }
493
  },
494
 
495
- renderCanvas: function (changed) {
496
- var options = this.options,
497
- canvas = this.canvas,
498
- image = this.image,
499
- aspectRatio,
500
- rotated;
 
 
501
 
502
- if (this.rotated) {
503
- this.rotated = false;
504
 
505
- // Computes rotatation sizes with image sizes
506
  rotated = getRotatedSizes({
507
  width: image.width,
508
  height: image.height,
509
- degree: image.rotate
510
  });
511
 
512
  aspectRatio = rotated.width / rotated.height;
@@ -517,6 +979,21 @@
517
  canvas.width = rotated.width;
518
  canvas.height = rotated.height;
519
  canvas.aspectRatio = aspectRatio;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  this.limitCanvas(true, false);
521
  }
522
  }
@@ -546,19 +1023,19 @@
546
 
547
  this.renderImage();
548
 
549
- if (this.cropped && options.strict) {
550
  this.limitCropBox(true, true);
551
  }
552
 
553
- if (changed) {
554
  this.output();
555
  }
556
  },
557
 
558
- renderImage: function () {
559
- var canvas = this.canvas,
560
- image = this.image,
561
- reversed;
562
 
563
  if (image.rotate) {
564
  reversed = getRotatedSizes({
@@ -586,16 +1063,20 @@
586
  height: image.height,
587
  marginLeft: image.left,
588
  marginTop: image.top,
589
- transform: getRotateValue(image.rotate)
590
  });
 
 
 
 
591
  },
592
 
593
  initCropBox: function () {
594
- var options = this.options,
595
- canvas = this.canvas,
596
- aspectRatio = options.aspectRatio,
597
- autoCropArea = num(options.autoCropArea) || 0.8,
598
- cropBox = {
599
  width: canvas.width,
600
  height: canvas.height
601
  };
@@ -624,46 +1105,59 @@
624
  this.initialCropBox = $.extend({}, cropBox);
625
  },
626
 
627
- limitCropBox: function (size, position) {
628
- var options = this.options,
629
- strict = options.strict,
630
- container = this.container,
631
- containerWidth = container.width,
632
- containerHeight = container.height,
633
- canvas = this.canvas,
634
- cropBox = this.cropBox,
635
- aspectRatio = options.aspectRatio,
636
- minCropBoxWidth,
637
- minCropBoxHeight;
638
-
639
- if (size) {
 
 
640
  minCropBoxWidth = num(options.minCropBoxWidth) || 0;
641
  minCropBoxHeight = num(options.minCropBoxHeight) || 0;
642
 
643
- // min/maxCropBoxWidth/Height must less than conatiner width/height
644
- cropBox.minWidth = min(containerWidth, minCropBoxWidth);
645
- cropBox.minHeight = min(containerHeight, minCropBoxHeight);
646
- cropBox.maxWidth = min(containerWidth, strict ? canvas.width : containerWidth);
647
- cropBox.maxHeight = min(containerHeight, strict ? canvas.height : containerHeight);
648
 
649
  if (aspectRatio) {
650
- // compare crop box size with container first
651
- if (cropBox.maxHeight * aspectRatio > cropBox.maxWidth) {
652
- cropBox.minHeight = cropBox.minWidth / aspectRatio;
653
- cropBox.maxHeight = cropBox.maxWidth / aspectRatio;
 
 
 
 
 
 
 
 
 
 
654
  } else {
655
- cropBox.minWidth = cropBox.minHeight * aspectRatio;
656
- cropBox.maxWidth = cropBox.maxHeight * aspectRatio;
657
  }
658
  }
659
 
660
- // The "minWidth" must be less than "maxWidth", and the "minHeight" too.
661
- cropBox.minWidth = min(cropBox.maxWidth, cropBox.minWidth);
662
- cropBox.minHeight = min(cropBox.maxHeight, cropBox.minHeight);
 
 
663
  }
664
 
665
- if (position) {
666
- if (strict) {
667
  cropBox.minLeft = max(0, canvas.left);
668
  cropBox.minTop = max(0, canvas.top);
669
  cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
@@ -678,11 +1172,11 @@
678
  },
679
 
680
  renderCropBox: function () {
681
- var options = this.options,
682
- container = this.container,
683
- containerWidth = container.width,
684
- containerHeight = container.height,
685
- cropBox = this.cropBox;
686
 
687
  if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
688
  cropBox.left = cropBox.oldLeft;
@@ -701,8 +1195,9 @@
701
  cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);
702
 
703
  if (options.movable && options.cropBoxMovable) {
 
704
  // Turn to move the canvas when the crop box is equal to the container
705
- this.$face.data('drag', (cropBox.width === containerWidth && cropBox.height === containerHeight) ? 'move' : 'all');
706
  }
707
 
708
  this.$cropBox.css({
@@ -712,243 +1207,285 @@
712
  top: cropBox.top
713
  });
714
 
715
- if (this.cropped && options.strict) {
716
  this.limitCanvas(true, true);
717
  }
718
 
719
- if (!this.disabled) {
720
  this.output();
721
  }
722
  },
723
 
724
  output: function () {
725
- var options = this.options,
726
- $this = this.$element;
727
-
728
  this.preview();
729
 
730
- if (options.crop) {
731
- options.crop.call($this, this.getData());
 
 
 
 
 
 
732
  }
 
733
 
734
- $this.trigger(EVENT_CHANGE);
735
- }
736
- });
737
 
738
- prototype.initPreview = function () {
739
- var url = this.url;
 
 
740
 
741
- this.$preview = $(this.options.preview);
742
- this.$viewBox.html('<img src="' + url + '">');
743
-
744
- // Override img element styles
745
- // Add `display:block` to avoid margin top issue (Occur only when margin-top <= -height)
746
- this.$preview.each(function () {
747
- var $this = $(this);
748
-
749
- $this.data(CROPPER_PREVIEW, {
750
- width: $this.width(),
751
- height: $this.height(),
752
- original: $this.html()
753
- }).html('<img src="' + url + '" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation: 0deg!important">');
754
- });
755
- };
756
 
757
- prototype.resetPreview = function () {
758
- this.$preview.each(function () {
759
- var $this = $(this);
 
 
 
 
 
 
 
 
 
 
 
760
 
761
- $this.html($this.data(CROPPER_PREVIEW).original).removeData(CROPPER_PREVIEW);
762
- });
763
- };
 
764
 
765
- prototype.preview = function () {
766
- var image = this.image,
767
- canvas = this.canvas,
768
- cropBox = this.cropBox,
769
- width = image.width,
770
- height = image.height,
771
- left = cropBox.left - canvas.left - image.left,
772
- top = cropBox.top - canvas.top - image.top,
773
- rotate = image.rotate;
774
-
775
- if (!this.cropped || this.disabled) {
776
- return;
777
- }
778
 
779
- this.$viewBox.find('img').css({
780
- width: width,
781
- height: height,
782
- marginLeft: -left,
783
- marginTop: -top,
784
- transform: getRotateValue(rotate)
785
- });
 
 
 
 
 
 
 
786
 
787
- this.$preview.each(function () {
788
- var $this = $(this),
789
- data = $this.data(CROPPER_PREVIEW),
790
- ratio = data.width / cropBox.width,
791
- newWidth = data.width,
792
- newHeight = cropBox.height * ratio;
793
-
794
- if (newHeight > data.height) {
795
- ratio = data.height / cropBox.height;
796
- newWidth = cropBox.width * ratio;
797
- newHeight = data.height;
798
- }
799
-
800
- $this.width(newWidth).height(newHeight).find('img').css({
801
- width: width * ratio,
802
- height: height * ratio,
803
- marginLeft: -left * ratio,
804
- marginTop: -top * ratio,
805
- transform: getRotateValue(rotate)
806
  });
807
- });
808
- };
809
 
810
- prototype.addListeners = function () {
811
- var options = this.options,
812
- $this = this.$element,
813
- $cropper = this.$cropper;
 
 
 
 
 
 
 
 
 
814
 
815
- if ($.isFunction(options.dragstart)) {
816
- $this.on(EVENT_DRAG_START, options.dragstart);
817
- }
 
 
818
 
819
- if ($.isFunction(options.dragmove)) {
820
- $this.on(EVENT_DRAG_MOVE, options.dragmove);
821
- }
 
 
 
 
 
 
 
 
 
822
 
823
- if ($.isFunction(options.dragend)) {
824
- $this.on(EVENT_DRAG_END, options.dragend);
825
- }
 
826
 
827
- if ($.isFunction(options.zoomin)) {
828
- $this.on(EVENT_ZOOM_IN, options.zoomin);
829
- }
830
 
831
- if ($.isFunction(options.zoomout)) {
832
- $this.on(EVENT_ZOOM_OUT, options.zoomout);
833
- }
834
 
835
- if ($.isFunction(options.change)) {
836
- $this.on(EVENT_CHANGE, options.change);
837
- }
838
 
839
- $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this));
 
 
840
 
841
- if (options.zoomable && options.mouseWheelZoom) {
842
- $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
843
- }
844
 
845
- if (options.doubleClickToggle) {
846
- $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
847
- }
848
 
849
- $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this)));
 
 
850
 
851
- if (options.responsive) {
852
- $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
853
- }
854
- };
855
 
856
- prototype.removeListeners = function () {
857
- var options = this.options,
858
- $this = this.$element,
859
- $cropper = this.$cropper;
860
 
861
- if ($.isFunction(options.dragstart)) {
862
- $this.off(EVENT_DRAG_START, options.dragstart);
863
- }
 
864
 
865
- if ($.isFunction(options.dragmove)) {
866
- $this.off(EVENT_DRAG_MOVE, options.dragmove);
867
- }
 
868
 
869
- if ($.isFunction(options.dragend)) {
870
- $this.off(EVENT_DRAG_END, options.dragend);
871
- }
872
 
873
- if ($.isFunction(options.zoomin)) {
874
- $this.off(EVENT_ZOOM_IN, options.zoomin);
875
- }
876
 
877
- if ($.isFunction(options.zoomout)) {
878
- $this.off(EVENT_ZOOM_OUT, options.zoomout);
879
- }
880
 
881
- if ($.isFunction(options.change)) {
882
- $this.off(EVENT_CHANGE, options.change);
883
- }
884
 
885
- $cropper.off(EVENT_MOUSE_DOWN, this.dragstart);
 
 
886
 
887
- if (options.zoomable && options.mouseWheelZoom) {
888
- $cropper.off(EVENT_WHEEL, this.wheel);
889
- }
890
 
891
- if (options.doubleClickToggle) {
892
- $cropper.off(EVENT_DBLCLICK, this.dblclick);
893
- }
894
 
895
- $document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend);
 
 
896
 
897
- if (options.responsive) {
898
- $window.off(EVENT_RESIZE, this._resize);
899
- }
900
- };
901
 
902
- $.extend(prototype, {
903
- resize: function () {
904
- var $container = this.$container,
905
- container = this.container,
906
- canvasData,
907
- cropBoxData,
908
- ratio;
909
 
910
- if (this.disabled || !container) { // Check "container" for IE8
 
 
 
 
 
 
 
 
 
911
  return;
912
  }
913
 
914
  ratio = $container.width() / container.width;
915
 
 
916
  if (ratio !== 1 || $container.height() !== container.height) {
917
- canvasData = this.getCanvasData();
918
- cropBoxData = this.getCropBoxData();
 
 
919
 
920
  this.render();
921
- this.setCanvasData($.each(canvasData, function (i, n) {
922
- canvasData[i] = n * ratio;
923
- }));
924
- this.setCropBoxData($.each(cropBoxData, function (i, n) {
925
- cropBoxData[i] = n * ratio;
926
- }));
 
 
 
927
  }
928
  },
929
 
930
  dblclick: function () {
931
- if (this.disabled) {
932
  return;
933
  }
934
 
935
  if (this.$dragBox.hasClass(CLASS_CROP)) {
936
- this.setDragMode('move');
937
  } else {
938
- this.setDragMode('crop');
939
  }
940
  },
941
 
942
  wheel: function (event) {
943
- var e = event.originalEvent,
944
- delta = 1;
 
945
 
946
- if (this.disabled) {
947
  return;
948
  }
949
 
950
  event.preventDefault();
951
 
 
 
 
 
 
 
 
 
 
 
 
952
  if (e.deltaY) {
953
  delta = e.deltaY > 0 ? 1 : -1;
954
  } else if (e.wheelDelta) {
@@ -957,19 +1494,18 @@
957
  delta = e.detail > 0 ? 1 : -1;
958
  }
959
 
960
- this.zoom(-delta * 0.1);
961
  },
962
 
963
- dragstart: function (event) {
964
- var options = this.options,
965
- originalEvent = event.originalEvent,
966
- touches = originalEvent && originalEvent.touches,
967
- e = event,
968
- dragType,
969
- dragStartEvent,
970
- touchesLength;
971
 
972
- if (this.disabled) {
973
  return;
974
  }
975
 
@@ -977,11 +1513,11 @@
977
  touchesLength = touches.length;
978
 
979
  if (touchesLength > 1) {
980
- if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
981
  e = touches[1];
982
  this.startX2 = e.pageX;
983
  this.startY2 = e.pageY;
984
- dragType = 'zoom';
985
  } else {
986
  return;
987
  }
@@ -990,44 +1526,42 @@
990
  e = touches[0];
991
  }
992
 
993
- dragType = dragType || $(e.target).data('drag');
994
-
995
- if (REGEXP_DRAG_TYPES.test(dragType)) {
996
- event.preventDefault();
997
 
998
- dragStartEvent = $.Event(EVENT_DRAG_START, {
 
999
  originalEvent: originalEvent,
1000
- dragType: dragType
1001
- });
1002
-
1003
- this.$element.trigger(dragStartEvent);
1004
-
1005
- if (dragStartEvent.isDefaultPrevented()) {
1006
  return;
1007
  }
1008
 
1009
- this.dragType = dragType;
 
 
1010
  this.cropping = false;
1011
- this.startX = e.pageX;
1012
- this.startY = e.pageY;
1013
 
1014
- if (dragType === 'crop') {
 
 
 
 
 
1015
  this.cropping = true;
1016
  this.$dragBox.addClass(CLASS_MODAL);
1017
  }
1018
  }
1019
  },
1020
 
1021
- dragmove: function (event) {
1022
- var options = this.options,
1023
- originalEvent = event.originalEvent,
1024
- touches = originalEvent && originalEvent.touches,
1025
- e = event,
1026
- dragType = this.dragType,
1027
- dragMoveEvent,
1028
- touchesLength;
1029
 
1030
- if (this.disabled) {
1031
  return;
1032
  }
1033
 
@@ -1035,7 +1569,7 @@
1035
  touchesLength = touches.length;
1036
 
1037
  if (touchesLength > 1) {
1038
- if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
1039
  e = touches[1];
1040
  this.endX2 = e.pageX;
1041
  this.endY2 = e.pageY;
@@ -1047,67 +1581,459 @@
1047
  e = touches[0];
1048
  }
1049
 
1050
- if (dragType) {
1051
- event.preventDefault();
1052
-
1053
- dragMoveEvent = $.Event(EVENT_DRAG_MOVE, {
1054
  originalEvent: originalEvent,
1055
- dragType: dragType
1056
- });
1057
-
1058
- this.$element.trigger(dragMoveEvent);
1059
-
1060
- if (dragMoveEvent.isDefaultPrevented()) {
1061
  return;
1062
  }
1063
 
1064
- this.endX = e.pageX;
1065
- this.endY = e.pageY;
1066
 
1067
- this.change(e.shiftKey);
 
 
 
1068
  }
1069
  },
1070
 
1071
- dragend: function (event) {
1072
- var dragType = this.dragType,
1073
- dragEndEvent;
1074
 
1075
- if (this.disabled) {
1076
  return;
1077
  }
1078
 
1079
- if (dragType) {
1080
  event.preventDefault();
1081
 
1082
- dragEndEvent = $.Event(EVENT_DRAG_END, {
1083
- originalEvent: event.originalEvent,
1084
- dragType: dragType
 
 
 
 
 
 
 
1085
  });
 
 
1086
 
1087
- this.$element.trigger(dragEndEvent);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1088
 
1089
- if (dragEndEvent.isDefaultPrevented()) {
1090
- return;
1091
- }
 
 
 
1092
 
1093
- if (this.cropping) {
1094
- this.cropping = false;
1095
- this.$dragBox.toggleClass(CLASS_MODAL, this.cropped && this.options.modal);
1096
- }
1097
 
1098
- this.dragType = '';
 
 
1099
  }
1100
- }
1101
- });
1102
 
1103
- $.extend(prototype, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1104
  crop: function () {
1105
- if (!this.built || this.disabled) {
1106
  return;
1107
  }
1108
 
1109
- if (!this.cropped) {
1110
- this.cropped = true;
1111
  this.limitCropBox(true, true);
1112
 
1113
  if (this.options.modal) {
@@ -1120,24 +2046,26 @@
1120
  this.setCropBoxData(this.initialCropBox);
1121
  },
1122
 
 
1123
  reset: function () {
1124
- if (!this.built || this.disabled) {
1125
  return;
1126
  }
1127
 
1128
  this.image = $.extend({}, this.initialImage);
1129
  this.canvas = $.extend({}, this.initialCanvas);
1130
- this.cropBox = $.extend({}, this.initialCropBox); // required for strict mode
1131
 
1132
  this.renderCanvas();
1133
 
1134
- if (this.cropped) {
1135
  this.renderCropBox();
1136
  }
1137
  },
1138
 
 
1139
  clear: function () {
1140
- if (!this.cropped || this.disabled) {
1141
  return;
1142
  }
1143
 
@@ -1148,108 +2076,306 @@
1148
  height: 0
1149
  });
1150
 
1151
- this.cropped = false;
1152
  this.renderCropBox();
1153
 
1154
- this.limitCanvas();
1155
- this.renderCanvas(); // Render canvas after render crop box
 
 
1156
 
1157
  this.$dragBox.removeClass(CLASS_MODAL);
1158
  this.$cropBox.addClass(CLASS_HIDDEN);
1159
  },
1160
 
1161
- destroy: function () {
1162
- var $this = this.$element;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1163
 
1164
- if (this.ready) {
1165
- this.unbuild();
1166
- $this.removeClass(CLASS_HIDDEN);
1167
- } else if (this.$clone) {
1168
- this.$clone.remove();
1169
- }
1170
 
1171
- $this.removeData('cropper');
1172
- },
 
 
 
 
 
 
1173
 
1174
- replace: function (url) {
1175
- if (!this.disabled && url) {
1176
- this.options.data = null; // Remove previous data
1177
- this.load(url);
1178
- }
1179
- },
1180
 
1181
- enable: function () {
1182
- if (this.built) {
1183
- this.disabled = false;
1184
- this.$cropper.removeClass(CLASS_DISABLED);
1185
  }
1186
  },
1187
 
1188
- disable: function () {
1189
- if (this.built) {
1190
- this.disabled = true;
1191
- this.$cropper.addClass(CLASS_DISABLED);
1192
- }
 
 
1193
  },
1194
 
1195
- move: function (offsetX, offsetY) {
1196
- var canvas = this.canvas;
 
 
 
 
 
 
1197
 
1198
- if (this.built && !this.disabled && this.options.movable && isNumber(offsetX) && isNumber(offsetY)) {
1199
- canvas.left += offsetX;
1200
- canvas.top += offsetY;
1201
  this.renderCanvas(true);
1202
  }
1203
  },
1204
 
1205
- zoom: function (delta) {
1206
- var canvas = this.canvas,
1207
- zoomEvent,
1208
- width,
1209
- height;
 
 
 
 
 
1210
 
1211
- delta = num(delta);
 
 
 
1212
 
1213
- if (delta && this.built && !this.disabled && this.options.zoomable) {
1214
- zoomEvent = delta > 0 ? $.Event(EVENT_ZOOM_IN) : $.Event(EVENT_ZOOM_OUT);
1215
- this.$element.trigger(zoomEvent);
1216
 
1217
- if (zoomEvent.isDefaultPrevented()) {
1218
- return;
 
 
1219
  }
1220
 
1221
- delta = delta <= -1 ? 1 / (1 - delta) : delta <= 1 ? (1 + delta) : delta;
1222
- width = canvas.width * delta;
1223
- height = canvas.height * delta;
1224
- canvas.left -= (width - canvas.width) / 2;
1225
- canvas.top -= (height - canvas.height) / 2;
1226
- canvas.width = width;
1227
- canvas.height = height;
1228
- this.renderCanvas(true);
1229
- this.setDragMode('move');
1230
  }
1231
  },
1232
 
1233
- rotate: function (degree) {
1234
- var image = this.image;
 
 
 
 
 
1235
 
1236
- degree = num(degree);
 
1237
 
1238
- if (degree && this.built && !this.disabled && this.options.rotatable) {
1239
- image.rotate = (image.rotate + degree) % 360;
1240
- this.rotated = true;
1241
- this.renderCanvas(true);
1242
- }
 
 
 
 
1243
  },
1244
 
1245
- getData: function (rounded) {
1246
- var cropBox = this.cropBox,
1247
- canvas = this.canvas,
1248
- image = this.image,
1249
- ratio,
1250
- data;
 
 
 
 
 
 
 
1251
 
1252
- if (this.built && this.cropped) {
1253
  data = {
1254
  x: cropBox.left - canvas.left,
1255
  y: cropBox.top - canvas.top,
@@ -1261,7 +2387,7 @@
1261
 
1262
  $.each(data, function (i, n) {
1263
  n = n / ratio;
1264
- data[i] = rounded ? Math.round(n) : n;
1265
  });
1266
 
1267
  } else {
@@ -1273,22 +2399,60 @@
1273
  };
1274
  }
1275
 
1276
- data.rotate = this.ready ? image.rotate : 0;
 
 
 
 
 
 
 
1277
 
1278
  return data;
1279
  },
1280
 
 
 
 
 
 
1281
  setData: function (data) {
1282
- var image = this.image,
1283
- canvas = this.canvas,
1284
- cropBoxData = {},
1285
- ratio;
1286
-
1287
- if (this.built && !this.disabled && $.isPlainObject(data)) {
1288
- if (isNumber(data.rotate) && data.rotate !== image.rotate && this.options.rotatable) {
1289
- image.rotate = data.rotate;
1290
- this.rotated = true;
1291
- this.renderCanvas(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1292
  }
1293
 
1294
  ratio = image.width / image.naturalWidth;
@@ -1313,35 +2477,63 @@
1313
  }
1314
  },
1315
 
 
 
 
 
 
1316
  getContainerData: function () {
1317
- return this.built ? this.container : {};
1318
  },
1319
 
 
 
 
 
 
1320
  getImageData: function () {
1321
- return this.ready ? this.image : {};
1322
  },
1323
 
 
 
 
 
 
1324
  getCanvasData: function () {
1325
- var canvas = this.canvas,
1326
- data;
1327
-
1328
- if (this.built) {
1329
- data = {
1330
- left: canvas.left,
1331
- top: canvas.top,
1332
- width: canvas.width,
1333
- height: canvas.height
1334
- };
 
 
 
 
1335
  }
1336
 
1337
- return data || {};
1338
  },
1339
 
 
 
 
 
 
1340
  setCanvasData: function (data) {
1341
- var canvas = this.canvas,
1342
- aspectRatio = canvas.aspectRatio;
 
 
 
 
1343
 
1344
- if (this.built && !this.disabled && $.isPlainObject(data)) {
1345
  if (isNumber(data.left)) {
1346
  canvas.left = data.left;
1347
  }
@@ -1362,11 +2554,16 @@
1362
  }
1363
  },
1364
 
 
 
 
 
 
1365
  getCropBoxData: function () {
1366
- var cropBox = this.cropBox,
1367
- data;
1368
 
1369
- if (this.built && this.cropped) {
1370
  data = {
1371
  left: cropBox.left,
1372
  top: cropBox.top,
@@ -1378,11 +2575,22 @@
1378
  return data || {};
1379
  },
1380
 
 
 
 
 
 
1381
  setCropBoxData: function (data) {
1382
- var cropBox = this.cropBox,
1383
- aspectRatio = this.options.aspectRatio;
 
 
 
 
 
 
1384
 
1385
- if (this.built && this.cropped && !this.disabled && $.isPlainObject(data)) {
1386
 
1387
  if (isNumber(data.left)) {
1388
  cropBox.left = data.left;
@@ -1393,17 +2601,19 @@
1393
  }
1394
 
1395
  if (isNumber(data.width)) {
 
1396
  cropBox.width = data.width;
1397
  }
1398
 
1399
  if (isNumber(data.height)) {
 
1400
  cropBox.height = data.height;
1401
  }
1402
 
1403
  if (aspectRatio) {
1404
- if (isNumber(data.width)) {
1405
  cropBox.height = cropBox.width / aspectRatio;
1406
- } else if (isNumber(data.height)) {
1407
  cropBox.width = cropBox.height * aspectRatio;
1408
  }
1409
  }
@@ -1412,20 +2622,26 @@
1412
  }
1413
  },
1414
 
 
 
 
 
 
 
1415
  getCroppedCanvas: function (options) {
1416
- var originalWidth,
1417
- originalHeight,
1418
- canvasWidth,
1419
- canvasHeight,
1420
- scaledWidth,
1421
- scaledHeight,
1422
- scaledRatio,
1423
- aspectRatio,
1424
- canvas,
1425
- context,
1426
- data;
1427
-
1428
- if (!this.built || !this.cropped || !SUPPORT_CANVAS) {
1429
  return;
1430
  }
1431
 
@@ -1451,8 +2667,9 @@
1451
  }
1452
  }
1453
 
1454
- canvasWidth = scaledWidth || originalWidth;
1455
- canvasHeight = scaledHeight || originalHeight;
 
1456
 
1457
  canvas = $('<canvas>')[0];
1458
  canvas.width = canvasWidth;
@@ -1466,18 +2683,22 @@
1466
 
1467
  // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
1468
  context.drawImage.apply(context, (function () {
1469
- var source = getSourceCanvas(this.$clone[0], this.image),
1470
- sourceWidth = source.width,
1471
- sourceHeight = source.height,
1472
- args = [source],
1473
- srcX = data.x, // source canvas
1474
- srcY = data.y,
1475
- srcWidth,
1476
- srcHeight,
1477
- dstX, // destination canvas
1478
- dstY,
1479
- dstWidth,
1480
- dstHeight;
 
 
 
 
1481
 
1482
  if (srcX <= -originalWidth || srcX > sourceWidth) {
1483
  srcX = srcWidth = dstX = dstWidth = 0;
@@ -1501,7 +2722,8 @@
1501
  srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
1502
  }
1503
 
1504
- args.push(srcX, srcY, srcWidth, srcHeight);
 
1505
 
1506
  // Scale destination sizes
1507
  if (scaledRatio) {
@@ -1513,7 +2735,7 @@
1513
 
1514
  // Avoid "IndexSizeError" in IE and Firefox
1515
  if (dstWidth > 0 && dstHeight > 0) {
1516
- args.push(dstX, dstY, dstWidth, dstHeight);
1517
  }
1518
 
1519
  return args;
@@ -1522,483 +2744,142 @@
1522
  return canvas;
1523
  },
1524
 
 
 
 
 
 
1525
  setAspectRatio: function (aspectRatio) {
1526
  var options = this.options;
1527
 
1528
- if (!this.disabled && !isUndefined(aspectRatio)) {
1529
- options.aspectRatio = num(aspectRatio) || NaN; // 0 -> NaN
 
 
1530
 
1531
- if (this.built) {
1532
  this.initCropBox();
1533
 
1534
- if (this.cropped) {
1535
  this.renderCropBox();
1536
  }
1537
  }
1538
  }
1539
  },
1540
 
 
 
 
 
 
1541
  setDragMode: function (mode) {
1542
- var options = this.options,
1543
- croppable,
1544
- movable;
1545
 
1546
- if (this.ready && !this.disabled) {
1547
- croppable = options.dragCrop && mode === 'crop';
1548
- movable = options.movable && mode === 'move';
1549
- mode = (croppable || movable) ? mode : 'none';
1550
 
1551
- this.$dragBox.data('drag', mode).toggleClass(CLASS_CROP, croppable).toggleClass(CLASS_MOVE, movable);
 
 
 
1552
 
1553
  if (!options.cropBoxMovable) {
 
1554
  // Sync drag mode to crop box when it is not movable(#300)
1555
- this.$face.data('drag', mode).toggleClass(CLASS_CROP, croppable).toggleClass(CLASS_MOVE, movable);
 
 
 
1556
  }
1557
  }
1558
  }
1559
- });
1560
-
1561
- prototype.change = function (shiftKey) {
1562
- var dragType = this.dragType,
1563
- options = this.options,
1564
- canvas = this.canvas,
1565
- container = this.container,
1566
- cropBox = this.cropBox,
1567
- width = cropBox.width,
1568
- height = cropBox.height,
1569
- left = cropBox.left,
1570
- top = cropBox.top,
1571
- right = left + width,
1572
- bottom = top + height,
1573
- minLeft = 0,
1574
- minTop = 0,
1575
- maxWidth = container.width,
1576
- maxHeight = container.height,
1577
- renderable = true,
1578
- aspectRatio = options.aspectRatio,
1579
- range = {
1580
- x: this.endX - this.startX,
1581
- y: this.endY - this.startY
1582
- },
1583
- offset;
1584
-
1585
- // Locking aspect ratio in "free mode" by holding shift key (#259)
1586
- if (!aspectRatio && shiftKey) {
1587
- aspectRatio = width && height ? width / height : 1;
1588
- }
1589
-
1590
- if (options.strict) {
1591
- minLeft = cropBox.minLeft;
1592
- minTop = cropBox.minTop;
1593
- maxWidth = minLeft + min(container.width, canvas.width);
1594
- maxHeight = minTop + min(container.height, canvas.height);
1595
- }
1596
-
1597
- if (aspectRatio) {
1598
- range.X = range.y * aspectRatio;
1599
- range.Y = range.x / aspectRatio;
1600
- }
1601
-
1602
- switch (dragType) {
1603
- // Move cropBox
1604
- case 'all':
1605
- left += range.x;
1606
- top += range.y;
1607
- break;
1608
-
1609
- // Resize cropBox
1610
- case 'e':
1611
- if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
1612
- renderable = false;
1613
- break;
1614
- }
1615
-
1616
- width += range.x;
1617
-
1618
- if (aspectRatio) {
1619
- height = width / aspectRatio;
1620
- top -= range.Y / 2;
1621
- }
1622
-
1623
- if (width < 0) {
1624
- dragType = 'w';
1625
- width = 0;
1626
- }
1627
-
1628
- break;
1629
-
1630
- case 'n':
1631
- if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) {
1632
- renderable = false;
1633
- break;
1634
- }
1635
-
1636
- height -= range.y;
1637
- top += range.y;
1638
-
1639
- if (aspectRatio) {
1640
- width = height * aspectRatio;
1641
- left += range.X / 2;
1642
- }
1643
-
1644
- if (height < 0) {
1645
- dragType = 's';
1646
- height = 0;
1647
- }
1648
-
1649
- break;
1650
-
1651
- case 'w':
1652
- if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
1653
- renderable = false;
1654
- break;
1655
- }
1656
-
1657
- width -= range.x;
1658
- left += range.x;
1659
-
1660
- if (aspectRatio) {
1661
- height = width / aspectRatio;
1662
- top += range.Y / 2;
1663
- }
1664
-
1665
- if (width < 0) {
1666
- dragType = 'e';
1667
- width = 0;
1668
- }
1669
-
1670
- break;
1671
-
1672
- case 's':
1673
- if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) {
1674
- renderable = false;
1675
- break;
1676
- }
1677
-
1678
- height += range.y;
1679
-
1680
- if (aspectRatio) {
1681
- width = height * aspectRatio;
1682
- left -= range.X / 2;
1683
- }
1684
-
1685
- if (height < 0) {
1686
- dragType = 'n';
1687
- height = 0;
1688
- }
1689
-
1690
- break;
1691
-
1692
- case 'ne':
1693
- if (aspectRatio) {
1694
- if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
1695
- renderable = false;
1696
- break;
1697
- }
1698
-
1699
- height -= range.y;
1700
- top += range.y;
1701
- width = height * aspectRatio;
1702
- } else {
1703
- if (range.x >= 0) {
1704
- if (right < maxWidth) {
1705
- width += range.x;
1706
- } else if (range.y <= 0 && top <= minTop) {
1707
- renderable = false;
1708
- }
1709
- } else {
1710
- width += range.x;
1711
- }
1712
-
1713
- if (range.y <= 0) {
1714
- if (top > minTop) {
1715
- height -= range.y;
1716
- top += range.y;
1717
- }
1718
- } else {
1719
- height -= range.y;
1720
- top += range.y;
1721
- }
1722
- }
1723
-
1724
- if (width < 0 && height < 0) {
1725
- dragType = 'sw';
1726
- height = 0;
1727
- width = 0;
1728
- } else if (width < 0) {
1729
- dragType = 'nw';
1730
- width = 0;
1731
- } else if (height < 0) {
1732
- dragType = 'se';
1733
- height = 0;
1734
- }
1735
-
1736
- break;
1737
-
1738
- case 'nw':
1739
- if (aspectRatio) {
1740
- if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
1741
- renderable = false;
1742
- break;
1743
- }
1744
-
1745
- height -= range.y;
1746
- top += range.y;
1747
- width = height * aspectRatio;
1748
- left += range.X;
1749
- } else {
1750
- if (range.x <= 0) {
1751
- if (left > minLeft) {
1752
- width -= range.x;
1753
- left += range.x;
1754
- } else if (range.y <= 0 && top <= minTop) {
1755
- renderable = false;
1756
- }
1757
- } else {
1758
- width -= range.x;
1759
- left += range.x;
1760
- }
1761
 
1762
- if (range.y <= 0) {
1763
- if (top > minTop) {
1764
- height -= range.y;
1765
- top += range.y;
1766
- }
1767
- } else {
1768
- height -= range.y;
1769
- top += range.y;
1770
- }
1771
- }
1772
 
1773
- if (width < 0 && height < 0) {
1774
- dragType = 'se';
1775
- height = 0;
1776
- width = 0;
1777
- } else if (width < 0) {
1778
- dragType = 'ne';
1779
- width = 0;
1780
- } else if (height < 0) {
1781
- dragType = 'sw';
1782
- height = 0;
1783
- }
1784
 
1785
- break;
 
1786
 
1787
- case 'sw':
1788
- if (aspectRatio) {
1789
- if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
1790
- renderable = false;
1791
- break;
1792
- }
1793
 
1794
- width -= range.x;
1795
- left += range.x;
1796
- height = width / aspectRatio;
1797
- } else {
1798
- if (range.x <= 0) {
1799
- if (left > minLeft) {
1800
- width -= range.x;
1801
- left += range.x;
1802
- } else if (range.y >= 0 && bottom >= maxHeight) {
1803
- renderable = false;
1804
- }
1805
- } else {
1806
- width -= range.x;
1807
- left += range.x;
1808
- }
1809
 
1810
- if (range.y >= 0) {
1811
- if (bottom < maxHeight) {
1812
- height += range.y;
1813
- }
1814
- } else {
1815
- height += range.y;
1816
- }
1817
- }
1818
 
1819
- if (width < 0 && height < 0) {
1820
- dragType = 'ne';
1821
- height = 0;
1822
- width = 0;
1823
- } else if (width < 0) {
1824
- dragType = 'se';
1825
- width = 0;
1826
- } else if (height < 0) {
1827
- dragType = 'nw';
1828
- height = 0;
1829
- }
1830
 
1831
- break;
 
1832
 
1833
- case 'se':
1834
- if (aspectRatio) {
1835
- if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
1836
- renderable = false;
1837
- break;
1838
- }
1839
 
1840
- width += range.x;
1841
- height = width / aspectRatio;
1842
- } else {
1843
- if (range.x >= 0) {
1844
- if (right < maxWidth) {
1845
- width += range.x;
1846
- } else if (range.y >= 0 && bottom >= maxHeight) {
1847
- renderable = false;
1848
- }
1849
- } else {
1850
- width += range.x;
1851
- }
1852
 
1853
- if (range.y >= 0) {
1854
- if (bottom < maxHeight) {
1855
- height += range.y;
1856
- }
1857
- } else {
1858
- height += range.y;
1859
- }
1860
- }
1861
 
1862
- if (width < 0 && height < 0) {
1863
- dragType = 'nw';
1864
- height = 0;
1865
- width = 0;
1866
- } else if (width < 0) {
1867
- dragType = 'sw';
1868
- width = 0;
1869
- } else if (height < 0) {
1870
- dragType = 'ne';
1871
- height = 0;
1872
- }
1873
 
1874
- break;
 
1875
 
1876
- // Move image
1877
- case 'move':
1878
- canvas.left += range.x;
1879
- canvas.top += range.y;
1880
- this.renderCanvas(true);
1881
- renderable = false;
1882
- break;
1883
-
1884
- // Scale image
1885
- case 'zoom':
1886
- this.zoom(function (x1, y1, x2, y2) {
1887
- var z1 = sqrt(x1 * x1 + y1 * y1),
1888
- z2 = sqrt(x2 * x2 + y2 * y2);
1889
-
1890
- return (z2 - z1) / z1;
1891
- }(
1892
- abs(this.startX - this.startX2),
1893
- abs(this.startY - this.startY2),
1894
- abs(this.endX - this.endX2),
1895
- abs(this.endY - this.endY2)
1896
- ));
1897
-
1898
- this.startX2 = this.endX2;
1899
- this.startY2 = this.endY2;
1900
- renderable = false;
1901
- break;
1902
-
1903
- // Crop image
1904
- case 'crop':
1905
- if (range.x && range.y) {
1906
- offset = this.$cropper.offset();
1907
- left = this.startX - offset.left;
1908
- top = this.startY - offset.top;
1909
- width = cropBox.minWidth;
1910
- height = cropBox.minHeight;
1911
 
1912
- if (range.x > 0) {
1913
- if (range.y > 0) {
1914
- dragType = 'se';
1915
- } else {
1916
- dragType = 'ne';
1917
- top -= height;
1918
- }
1919
- } else {
1920
- if (range.y > 0) {
1921
- dragType = 'sw';
1922
- left -= width;
1923
- } else {
1924
- dragType = 'nw';
1925
- left -= width;
1926
- top -= height;
1927
- }
1928
- }
1929
 
1930
- // Show the cropBox if is hidden
1931
- if (!this.cropped) {
1932
- this.cropped = true;
1933
- this.$cropBox.removeClass(CLASS_HIDDEN);
1934
- }
1935
- }
1936
 
1937
- break;
 
1938
 
1939
- // No default
1940
- }
1941
 
1942
- if (renderable) {
1943
- cropBox.width = width;
1944
- cropBox.height = height;
1945
- cropBox.left = left;
1946
- cropBox.top = top;
1947
- this.dragType = dragType;
1948
 
1949
- this.renderCropBox();
1950
- }
1951
 
1952
- // Override
1953
- this.startX = this.endX;
1954
- this.startY = this.endY;
1955
- };
1956
 
1957
- $.extend(Cropper.prototype, prototype);
 
1958
 
1959
- Cropper.DEFAULTS = {
1960
- // Defines the aspect ratio of the crop box
1961
- // Type: Number
1962
- aspectRatio: NaN,
1963
 
1964
- // Defines the percentage of automatic cropping area when initializes
1965
- // Type: Number (Must large than 0 and less than 1)
1966
- autoCropArea: 0.8, // 80%
1967
 
1968
- // Outputs the cropping results.
1969
- // Type: Function
1970
- crop: null,
1971
 
1972
- // Previous/latest crop data
1973
- // Type: Object
1974
- data: null,
1975
 
1976
- // Add extra containers for previewing
1977
- // Type: String (jQuery selector)
1978
- preview: '',
1979
 
1980
- // Toggles
1981
- strict: true, // strict mode, the image cannot zoom out less than the container
1982
- responsive: true, // Rebuild when resize the window
1983
- checkImageOrigin: true, // Check if the target image is cross origin
1984
-
1985
- modal: true, // Show the black modal
1986
- guides: true, // Show the dashed lines for guiding
1987
- highlight: true, // Show the white modal to highlight the crop box
1988
- background: true, // Show the grid background
1989
-
1990
- autoCrop: true, // Enable to crop the image automatically when initialize
1991
- dragCrop: true, // Enable to create new crop box by dragging over the image
1992
- movable: true, // Enable to move the image
1993
- rotatable: true, // Enable to rotate the image
1994
- zoomable: true, // Enable to zoom the image
1995
- touchDragZoom: true, // Enable to zoom the image by wheeling mouse
1996
- mouseWheelZoom: true, // Enable to zoom the image by dragging touch
1997
- cropBoxMovable: true, // Enable to move the crop box
1998
- cropBoxResizable: true, // Enable to resize the crop box
1999
- doubleClickToggle: true, // Toggle drag mode between "crop" and "move" when double click on the cropper
2000
-
2001
- // Dimensions
2002
  minCanvasWidth: 0,
2003
  minCanvasHeight: 0,
2004
  minCropBoxWidth: 0,
@@ -2006,72 +2887,72 @@
2006
  minContainerWidth: 200,
2007
  minContainerHeight: 100,
2008
 
2009
- // Events
2010
- build: null, // Function
2011
- built: null, // Function
2012
- dragstart: null, // Function
2013
- dragmove: null, // Function
2014
- dragend: null, // Function
2015
- zoomin: null, // Function
2016
- zoomout: null, // Function
2017
- change: null // Function
2018
  };
2019
 
2020
  Cropper.setDefaults = function (options) {
2021
  $.extend(Cropper.DEFAULTS, options);
2022
  };
2023
 
2024
- // Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin)
2025
- Cropper.TEMPLATE = (function (source, words) {
2026
- words = words.split(',');
2027
- return source.replace(/\d+/g, function (i) {
2028
- return words[i];
2029
- });
2030
- })('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-2-9"></0><0 6="5-crop-9"><1 6="5-view-9"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>', 'div,span,drag,data,point,cropper,class,line,dashed,box');
2031
-
2032
- /* Template source:
2033
- <div class="cropper-container">
2034
- <div class="cropper-canvas"></div>
2035
- <div class="cropper-drag-box"></div>
2036
- <div class="cropper-crop-box">
2037
- <span class="cropper-view-box"></span>
2038
- <span class="cropper-dashed dashed-h"></span>
2039
- <span class="cropper-dashed dashed-v"></span>
2040
- <span class="cropper-face"></span>
2041
- <span class="cropper-line line-e" data-drag="e"></span>
2042
- <span class="cropper-line line-n" data-drag="n"></span>
2043
- <span class="cropper-line line-w" data-drag="w"></span>
2044
- <span class="cropper-line line-s" data-drag="s"></span>
2045
- <span class="cropper-point point-e" data-drag="e"></span>
2046
- <span class="cropper-point point-n" data-drag="n"></span>
2047
- <span class="cropper-point point-w" data-drag="w"></span>
2048
- <span class="cropper-point point-s" data-drag="s"></span>
2049
- <span class="cropper-point point-ne" data-drag="ne"></span>
2050
- <span class="cropper-point point-nw" data-drag="nw"></span>
2051
- <span class="cropper-point point-sw" data-drag="sw"></span>
2052
- <span class="cropper-point point-se" data-drag="se"></span>
2053
- </div>
2054
- </div>
2055
- */
2056
 
2057
  // Save the other cropper
2058
  Cropper.other = $.fn.cropper;
2059
 
2060
  // Register as jQuery plugin
2061
- $.fn.cropper = function (options) {
2062
- var args = toArray(arguments, 1),
2063
- result;
2064
 
2065
  this.each(function () {
2066
- var $this = $(this),
2067
- data = $this.data('cropper'),
2068
- fn;
 
2069
 
2070
  if (!data) {
2071
- $this.data('cropper', (data = new Cropper(this, options)));
 
 
 
 
 
2072
  }
2073
 
2074
- if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
2075
  result = fn.apply(data, args);
2076
  }
2077
  });
1
  /*!
2
+ * Cropper v2.2.5
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
+ * Copyright (c) 2014-2016 Fengyuan Chen and contributors
6
  * Released under the MIT license
7
  *
8
+ * Date: 2016-01-18T05:42:50.800Z
9
  */
10
 
11
  (function (factory) {
23
 
24
  'use strict';
25
 
26
+ // Globals
27
+ var $window = $(window);
28
+ var $document = $(document);
29
+ var location = window.location;
30
+ var ArrayBuffer = window.ArrayBuffer;
31
+ var Uint8Array = window.Uint8Array;
32
+ var DataView = window.DataView;
33
+ var btoa = window.btoa;
34
+
35
+ // Constants
36
+ var NAMESPACE = 'cropper';
37
+
38
+ // Classes
39
+ var CLASS_MODAL = 'cropper-modal';
40
+ var CLASS_HIDE = 'cropper-hide';
41
+ var CLASS_HIDDEN = 'cropper-hidden';
42
+ var CLASS_INVISIBLE = 'cropper-invisible';
43
+ var CLASS_MOVE = 'cropper-move';
44
+ var CLASS_CROP = 'cropper-crop';
45
+ var CLASS_DISABLED = 'cropper-disabled';
46
+ var CLASS_BG = 'cropper-bg';
47
+
48
+ // Events
49
+ var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown';
50
+ var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove';
51
+ var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel';
52
+ var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
53
+ var EVENT_DBLCLICK = 'dblclick';
54
+ var EVENT_LOAD = 'load.' + NAMESPACE;
55
+ var EVENT_ERROR = 'error.' + NAMESPACE;
56
+ var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace
57
+ var EVENT_BUILD = 'build.' + NAMESPACE;
58
+ var EVENT_BUILT = 'built.' + NAMESPACE;
59
+ var EVENT_CROP_START = 'cropstart.' + NAMESPACE;
60
+ var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE;
61
+ var EVENT_CROP_END = 'cropend.' + NAMESPACE;
62
+ var EVENT_CROP = 'crop.' + NAMESPACE;
63
+ var EVENT_ZOOM = 'zoom.' + NAMESPACE;
64
+
65
+ // RegExps
66
+ var REGEXP_ACTIONS = /e|w|s|n|se|sw|ne|nw|all|crop|move|zoom/;
67
+ var REGEXP_DATA_URL = /^data\:/;
68
+ var REGEXP_DATA_URL_HEAD = /^data\:([^\;]+)\;base64,/;
69
+ var REGEXP_DATA_URL_JPEG = /^data\:image\/jpeg.*;base64,/;
70
+
71
+ // Data keys
72
+ var DATA_PREVIEW = 'preview';
73
+ var DATA_ACTION = 'action';
74
+
75
+ // Actions
76
+ var ACTION_EAST = 'e';
77
+ var ACTION_WEST = 'w';
78
+ var ACTION_SOUTH = 's';
79
+ var ACTION_NORTH = 'n';
80
+ var ACTION_SOUTH_EAST = 'se';
81
+ var ACTION_SOUTH_WEST = 'sw';
82
+ var ACTION_NORTH_EAST = 'ne';
83
+ var ACTION_NORTH_WEST = 'nw';
84
+ var ACTION_ALL = 'all';
85
+ var ACTION_CROP = 'crop';
86
+ var ACTION_MOVE = 'move';
87
+ var ACTION_ZOOM = 'zoom';
88
+ var ACTION_NONE = 'none';
89
+
90
+ // Supports
91
+ var SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext);
92
+
93
+ // Maths
94
+ var num = Number;
95
+ var min = Math.min;
96
+ var max = Math.max;
97
+ var abs = Math.abs;
98
+ var sin = Math.sin;
99
+ var cos = Math.cos;
100
+ var sqrt = Math.sqrt;
101
+ var round = Math.round;
102
+ var floor = Math.floor;
103
+
104
+ // Utilities
105
+ var fromCharCode = String.fromCharCode;
106
 
107
  function isNumber(n) {
108
  return typeof n === 'number' && !isNaN(n);
115
  function toArray(obj, offset) {
116
  var args = [];
117
 
118
+ // This is necessary for IE8
119
+ if (isNumber(offset)) {
120
  args.push(offset);
121
  }
122
 
135
  function isCrossOriginURL(url) {
136
  var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
137
 
138
+ return parts && (
139
+ parts[1] !== location.protocol ||
140
+ parts[2] !== location.hostname ||
141
+ parts[3] !== location.port
142
+ );
143
  }
144
 
145
  function addTimestamp(url) {
148
  return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
149
  }
150
 
151
+ function getCrossOrigin(crossOrigin) {
152
+ return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : '';
153
  }
154
 
155
+ function getImageSize(image, callback) {
156
+ var newImage;
157
+
158
+ // Modern browsers
159
+ if (image.naturalWidth) {
160
+ return callback(image.naturalWidth, image.naturalHeight);
161
+ }
162
+
163
+ // IE8: Don't use `new Image()` here (#319)
164
+ newImage = document.createElement('img');
165
+
166
+ newImage.onload = function () {
167
+ callback(this.width, this.height);
168
+ };
169
+
170
+ newImage.src = image.src;
171
+ }
172
+
173
+ function getTransform(options) {
174
+ var transforms = [];
175
+ var rotate = options.rotate;
176
+ var scaleX = options.scaleX;
177
+ var scaleY = options.scaleY;
178
+
179
+ if (isNumber(rotate)) {
180
+ transforms.push('rotate(' + rotate + 'deg)');
181
+ }
182
+
183
+ if (isNumber(scaleX) && isNumber(scaleY)) {
184
+ transforms.push('scale(' + scaleX + ',' + scaleY + ')');
185
+ }
186
+
187
+ return transforms.length ? transforms.join(' ') : 'none';
188
+ }
189
+
190
+ function getRotatedSizes(data, isReversed) {
191
+ var deg = abs(data.degree) % 180;
192
+ var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180;
193
+ var sinArc = sin(arc);
194
+ var cosArc = cos(arc);
195
+ var width = data.width;
196
+ var height = data.height;
197
+ var aspectRatio = data.aspectRatio;
198
+ var newWidth;
199
+ var newHeight;
200
+
201
+ if (!isReversed) {
202
  newWidth = width * cosArc + height * sinArc;
203
  newHeight = width * sinArc + height * cosArc;
204
  } else {
213
  }
214
 
215
  function getSourceCanvas(image, data) {
216
+ var canvas = $('<canvas>')[0];
217
+ var context = canvas.getContext('2d');
218
+ var x = 0;
219
+ var y = 0;
220
+ var width = data.naturalWidth;
221
+ var height = data.naturalHeight;
222
+ var rotate = data.rotate;
223
+ var scaleX = data.scaleX;
224
+ var scaleY = data.scaleY;
225
+ var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1);
226
+ var rotatable = isNumber(rotate) && rotate !== 0;
227
+ var advanced = rotatable || scalable;
228
+ var canvasWidth = width;
229
+ var canvasHeight = height;
230
+ var translateX;
231
+ var translateY;
232
+ var rotated;
233
+
234
+ if (scalable) {
235
+ translateX = width / 2;
236
+ translateY = height / 2;
237
+ }
238
+
239
+ if (rotatable) {
240
+ rotated = getRotatedSizes({
241
+ width: width,
242
+ height: height,
243
+ degree: rotate
244
+ });
245
+
246
+ canvasWidth = rotated.width;
247
+ canvasHeight = rotated.height;
248
+ translateX = rotated.width / 2;
249
+ translateY = rotated.height / 2;
250
+ }
251
+
252
+ canvas.width = canvasWidth;
253
+ canvas.height = canvasHeight;
254
+
255
+ if (advanced) {
256
+ x = -width / 2;
257
+ y = -height / 2;
258
 
 
 
 
259
  context.save();
260
+ context.translate(translateX, translateY);
261
+ }
262
+
263
+ if (rotatable) {
264
  context.rotate(rotate * Math.PI / 180);
265
+ }
266
+
267
+ // Should call `scale` after rotated
268
+ if (scalable) {
269
+ context.scale(scaleX, scaleY);
270
+ }
271
+
272
+ context.drawImage(image, floor(x), floor(y), floor(width), floor(height));
273
+
274
+ if (advanced) {
275
  context.restore();
 
 
 
 
276
  }
277
 
278
  return canvas;
279
  }
280
 
281
+ function getTouchesCenter(touches) {
282
+ var length = touches.length;
283
+ var pageX = 0;
284
+ var pageY = 0;
285
+
286
+ if (length) {
287
+ $.each(touches, function (i, touch) {
288
+ pageX += touch.pageX;
289
+ pageY += touch.pageY;
290
+ });
291
+
292
+ pageX /= length;
293
+ pageY /= length;
294
+ }
295
+
296
+ return {
297
+ pageX: pageX,
298
+ pageY: pageY
299
+ };
300
+ }
301
+
302
+ function getStringFromCharCode(dataView, start, length) {
303
+ var str = '';
304
+ var i;
305
+
306
+ for (i = start, length += start; i < length; i++) {
307
+ str += fromCharCode(dataView.getUint8(i));
308
+ }
309
+
310
+ return str;
311
+ }
312
+
313
+ function getOrientation(arrayBuffer) {
314
+ var dataView = new DataView(arrayBuffer);
315
+ var length = dataView.byteLength;
316
+ var orientation;
317
+ var exifIDCode;
318
+ var tiffOffset;
319
+ var firstIFDOffset;
320
+ var littleEndian;
321
+ var endianness;
322
+ var app1Start;
323
+ var ifdStart;
324
+ var offset;
325
+ var i;
326
+
327
+ // Only handle JPEG image (start by 0xFFD8)
328
+ if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
329
+ offset = 2;
330
+
331
+ while (offset < length) {
332
+ if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
333
+ app1Start = offset;
334
+ break;
335
+ }
336
+
337
+ offset++;
338
+ }
339
+ }
340
+
341
+ if (app1Start) {
342
+ exifIDCode = app1Start + 4;
343
+ tiffOffset = app1Start + 10;
344
+
345
+ if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
346
+ endianness = dataView.getUint16(tiffOffset);
347
+ littleEndian = endianness === 0x4949;
348
+
349
+ if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
350
+ if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
351
+ firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
352
+
353
+ if (firstIFDOffset >= 0x00000008) {
354
+ ifdStart = tiffOffset + firstIFDOffset;
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
360
+
361
+ if (ifdStart) {
362
+ length = dataView.getUint16(ifdStart, littleEndian);
363
+
364
+ for (i = 0; i < length; i++) {
365
+ offset = ifdStart + i * 12 + 2;
366
+
367
+ if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {
368
+
369
+ // 8 is the offset of the current tag's value
370
+ offset += 8;
371
+
372
+ // Get the original orientation value
373
+ orientation = dataView.getUint16(offset, littleEndian);
374
+
375
+ // Override the orientation with the default value: 1
376
+ dataView.setUint16(offset, 1, littleEndian);
377
+ break;
378
+ }
379
+ }
380
+ }
381
+
382
+ return orientation;
383
+ }
384
+
385
+ function dataURLToArrayBuffer(dataURL) {
386
+ var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');
387
+ var binary = atob(base64);
388
+ var length = binary.length;
389
+ var arrayBuffer = new ArrayBuffer(length);
390
+ var dataView = new Uint8Array(arrayBuffer);
391
+ var i;
392
+
393
+ for (i = 0; i < length; i++) {
394
+ dataView[i] = binary.charCodeAt(i);
395
+ }
396
+
397
+ return arrayBuffer;
398
+ }
399
+
400
+ // Only available for JPEG image
401
+ function arrayBufferToDataURL(arrayBuffer) {
402
+ var dataView = new Uint8Array(arrayBuffer);
403
+ var length = dataView.length;
404
+ var base64 = '';
405
+ var i;
406
+
407
+ for (i = 0; i < length; i++) {
408
+ base64 += fromCharCode(dataView[i]);
409
+ }
410
+
411
+ return 'data:image/jpeg;base64,' + btoa(base64);
412
+ }
413
+
414
  function Cropper(element, options) {
415
  this.$element = $(element);
416
  this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
417
+ this.isLoaded = false;
418
+ this.isBuilt = false;
419
+ this.isCompleted = false;
420
+ this.isRotated = false;
421
+ this.isCropped = false;
422
+ this.isDisabled = false;
423
+ this.isReplaced = false;
424
+ this.isLimited = false;
425
+ this.wheeling = false;
426
+ this.isImg = false;
427
+ this.originalUrl = '';
428
  this.canvas = null;
429
  this.cropBox = null;
430
+ this.init();
 
431
  }
432
 
433
+ Cropper.prototype = {
434
+ constructor: Cropper,
435
+
436
+ init: function () {
437
+ var $this = this.$element;
438
+ var url;
 
439
 
 
440
  if ($this.is('img')) {
441
+ this.isImg = true;
442
+
443
+ // Should use `$.fn.attr` here. e.g.: "img/picture.jpg"
444
+ this.originalUrl = url = $this.attr('src');
445
+
446
+ // Stop when it's a blank image
447
+ if (!url) {
448
  return;
449
  }
450
 
451
+ // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg"
452
  url = $this.prop('src');
453
  } else if ($this.is('canvas') && SUPPORT_CANVAS) {
454
  url = $this[0].toDataURL();
455
  }
 
456
 
457
+ this.load(url);
458
+ },
 
459
 
460
+ // A shortcut for triggering custom events
461
+ trigger: function (type, data) {
462
+ var e = $.Event(type, data);
463
 
464
+ this.$element.trigger(e);
465
+
466
+ return e;
467
+ },
468
 
469
+ load: function (url) {
470
+ var options = this.options;
471
+ var $this = this.$element;
472
+ var read;
473
+ var xhr;
474
 
475
+ if (!url) {
476
+ return;
477
  }
 
478
 
479
+ // Trigger build event first
480
+ $this.one(EVENT_BUILD, options.build);
481
 
482
+ if (this.trigger(EVENT_BUILD).isDefaultPrevented()) {
483
+ return;
484
+ }
 
485
 
486
+ this.url = url;
487
+ this.image = {};
488
+
489
+ if (!options.checkOrientation || !ArrayBuffer) {
490
+ return this.clone();
491
+ }
492
+
493
+ read = $.proxy(this.read, this);
494
+
495
+ // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari
496
+ if (REGEXP_DATA_URL.test(url)) {
497
+ return REGEXP_DATA_URL_JPEG.test(url) ?
498
+ read(dataURLToArrayBuffer(url)) :
499
+ this.clone();
500
+ }
501
+
502
+ xhr = new XMLHttpRequest();
503
+
504
+ xhr.onerror = xhr.onabort = $.proxy(function () {
505
+ this.clone();
506
+ }, this);
507
+
508
+ xhr.onload = function () {
509
+ read(this.response);
510
  };
511
 
512
+ xhr.open('get', url);
513
+ xhr.responseType = 'arraybuffer';
514
+ xhr.send();
515
+ },
 
 
516
 
517
+ read: function (arrayBuffer) {
518
+ var options = this.options;
519
+ var orientation = getOrientation(arrayBuffer);
520
+ var image = this.image;
521
+ var rotate;
522
+ var scaleX;
523
+ var scaleY;
524
 
525
+ if (orientation > 1) {
526
+ this.url = arrayBufferToDataURL(arrayBuffer);
 
 
 
 
 
527
 
528
+ switch (orientation) {
 
 
529
 
530
+ // flip horizontal
531
+ case 2:
532
+ scaleX = -1;
533
+ break;
534
+
535
+ // rotate left 180°
536
+ case 3:
537
+ rotate = -180;
538
+ break;
539
+
540
+ // flip vertical
541
+ case 4:
542
+ scaleY = -1;
543
+ break;
544
+
545
+ // flip vertical + rotate right 90°
546
+ case 5:
547
+ rotate = 90;
548
+ scaleY = -1;
549
+ break;
550
 
551
+ // rotate right 90°
552
+ case 6:
553
+ rotate = 90;
554
+ break;
555
+
556
+ // flip horizontal + rotate right 90°
557
+ case 7:
558
+ rotate = 90;
559
+ scaleX = -1;
560
+ break;
561
+
562
+ // rotate left 90°
563
+ case 8:
564
+ rotate = -90;
565
+ break;
566
+ }
567
+ }
568
 
569
+ if (options.rotatable) {
570
+ image.rotate = rotate;
571
+ }
572
 
573
+ if (options.scalable) {
574
+ image.scaleX = scaleX;
575
+ image.scaleY = scaleY;
576
+ }
577
 
578
+ this.clone();
579
+ },
 
 
 
 
580
 
581
+ clone: function () {
582
+ var options = this.options;
583
+ var $this = this.$element;
584
+ var url = this.url;
585
+ var crossOrigin = '';
586
+ var crossOriginUrl;
587
+ var $clone;
588
 
589
+ if (options.checkCrossOrigin && isCrossOriginURL(url)) {
590
+ crossOrigin = $this.prop('crossOrigin');
591
 
592
+ if (crossOrigin) {
593
+ crossOriginUrl = url;
594
+ } else {
595
+ crossOrigin = 'anonymous';
596
 
597
+ // Bust cache (#148) when there is not a "crossOrigin" property
598
+ crossOriginUrl = addTimestamp(url);
599
+ }
600
  }
 
 
 
601
 
602
+ this.crossOrigin = crossOrigin;
603
+ this.crossOriginUrl = crossOriginUrl;
604
+ this.$clone = $clone = $('<img' + getCrossOrigin(crossOrigin) + ' src="' + (crossOriginUrl || url) + '">');
605
 
606
+ if (this.isImg) {
607
+ if ($this[0].complete) {
608
+ this.start();
609
+ } else {
610
+ $this.one(EVENT_LOAD, $.proxy(this.start, this));
611
+ }
612
+ } else {
613
+ $clone.
614
+ one(EVENT_LOAD, $.proxy(this.start, this)).
615
+ one(EVENT_ERROR, $.proxy(this.stop, this)).
616
+ addClass(CLASS_HIDE).
617
+ insertAfter($this);
618
+ }
619
+ },
620
 
621
+ start: function () {
622
+ var $image = this.$element;
623
+ var $clone = this.$clone;
624
 
625
+ if (!this.isImg) {
626
+ $clone.off(EVENT_ERROR, this.stop);
627
+ $image = $clone;
628
+ }
629
 
630
+ getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) {
631
+ $.extend(this.image, {
632
+ naturalWidth: naturalWidth,
633
+ naturalHeight: naturalHeight,
634
+ aspectRatio: naturalWidth / naturalHeight
635
+ });
636
 
637
+ this.isLoaded = true;
638
+ this.build();
639
+ }, this));
640
+ },
641
 
642
+ stop: function () {
643
+ this.$clone.remove();
644
+ this.$clone = null;
645
+ },
 
646
 
647
+ build: function () {
648
+ var options = this.options;
649
+ var $this = this.$element;
650
+ var $clone = this.$clone;
651
+ var $cropper;
652
+ var $cropBox;
653
+ var $face;
654
 
655
+ if (!this.isLoaded) {
656
+ return;
657
+ }
658
+
659
+ // Unbuild first when replace
660
+ if (this.isBuilt) {
661
+ this.unbuild();
662
+ }
663
 
664
+ // Create cropper elements
665
+ this.$container = $this.parent();
666
+ this.$cropper = $cropper = $(Cropper.TEMPLATE);
667
+ this.$canvas = $cropper.find('.cropper-canvas').append($clone);
668
+ this.$dragBox = $cropper.find('.cropper-drag-box');
669
+ this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
670
+ this.$viewBox = $cropper.find('.cropper-view-box');
671
+ this.$face = $face = $cropBox.find('.cropper-face');
672
+
673
+ // Hide the original image
674
+ $this.addClass(CLASS_HIDDEN).after($cropper);
675
+
676
+ // Show the clone image if is hidden
677
+ if (!this.isImg) {
678
+ $clone.removeClass(CLASS_HIDE);
679
+ }
680
 
681
+ this.initPreview();
682
+ this.bind();
 
 
 
683
 
684
+ options.aspectRatio = max(0, options.aspectRatio) || NaN;
685
+ options.viewMode = max(0, min(3, round(options.viewMode))) || 0;
686
+
687
+ if (options.autoCrop) {
688
+ this.isCropped = true;
689
+
690
+ if (options.modal) {
691
+ this.$dragBox.addClass(CLASS_MODAL);
692
+ }
693
+ } else {
694
+ $cropBox.addClass(CLASS_HIDDEN);
695
+ }
696
+
697
+ if (!options.guides) {
698
+ $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
699
+ }
700
+
701
+ if (!options.center) {
702
+ $cropBox.find('.cropper-center').addClass(CLASS_HIDDEN);
703
+ }
704
+
705
+ if (options.cropBoxMovable) {
706
+ $face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL);
707
+ }
708
+
709
+ if (!options.highlight) {
710
+ $face.addClass(CLASS_INVISIBLE);
711
+ }
712
+
713
+ if (options.background) {
714
+ $cropper.addClass(CLASS_BG);
715
+ }
716
+
717
+ if (!options.cropBoxResizable) {
718
+ $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
719
+ }
720
+
721
+ this.setDragMode(options.dragMode);
722
+ this.render();
723
+ this.isBuilt = true;
724
+ this.setData(options.data);
725
+ $this.one(EVENT_BUILT, options.built);
726
+
727
+ // Trigger the built event asynchronously to keep `data('cropper')` is defined
728
+ setTimeout($.proxy(function () {
729
+ this.trigger(EVENT_BUILT);
730
+ this.isCompleted = true;
731
+ }, this), 0);
732
+ },
733
+
734
+ unbuild: function () {
735
+ if (!this.isBuilt) {
736
+ return;
737
+ }
738
+
739
+ this.isBuilt = false;
740
+ this.isCompleted = false;
741
+ this.initialImage = null;
742
+
743
+ // Clear `initialCanvas` is necessary when replace
744
+ this.initialCanvas = null;
745
+ this.initialCropBox = null;
746
+ this.container = null;
747
+ this.canvas = null;
748
+
749
+ // Clear `cropBox` is necessary when replace
750
+ this.cropBox = null;
751
+ this.unbind();
752
+
753
+ this.resetPreview();
754
+ this.$preview = null;
755
+
756
+ this.$viewBox = null;
757
+ this.$cropBox = null;
758
+ this.$dragBox = null;
759
+ this.$canvas = null;
760
+ this.$container = null;
761
+
762
+ this.$cropper.remove();
763
+ this.$cropper = null;
764
+ },
765
 
 
766
  render: function () {
767
  this.initContainer();
768
  this.initCanvas();
770
 
771
  this.renderCanvas();
772
 
773
+ if (this.isCropped) {
774
  this.renderCropBox();
775
  }
776
  },
777
 
778
  initContainer: function () {
779
+ var options = this.options;
780
+ var $this = this.$element;
781
+ var $container = this.$container;
782
+ var $cropper = this.$cropper;
783
 
784
  $cropper.addClass(CLASS_HIDDEN);
785
  $this.removeClass(CLASS_HIDDEN);
793
  $cropper.removeClass(CLASS_HIDDEN);
794
  },
795
 
796
+ // Canvas (image wrapper)
797
  initCanvas: function () {
798
+ var viewMode = this.options.viewMode;
799
+ var container = this.container;
800
+ var containerWidth = container.width;
801
+ var containerHeight = container.height;
802
+ var image = this.image;
803
+ var imageNaturalWidth = image.naturalWidth;
804
+ var imageNaturalHeight = image.naturalHeight;
805
+ var is90Degree = abs(image.rotate) === 90;
806
+ var naturalWidth = is90Degree ? imageNaturalHeight : imageNaturalWidth;
807
+ var naturalHeight = is90Degree ? imageNaturalWidth : imageNaturalHeight;
808
+ var aspectRatio = naturalWidth / naturalHeight;
809
+ var canvasWidth = containerWidth;
810
+ var canvasHeight = containerHeight;
811
+ var canvas;
812
 
813
  if (containerHeight * aspectRatio > containerWidth) {
814
+ if (viewMode === 3) {
815
+ canvasWidth = containerHeight * aspectRatio;
816
+ } else {
817
+ canvasHeight = containerWidth / aspectRatio;
818
+ }
819
  } else {
820
+ if (viewMode === 3) {
821
+ canvasHeight = containerWidth / aspectRatio;
822
+ } else {
823
+ canvasWidth = containerHeight * aspectRatio;
824
+ }
825
  }
826
 
827
+ canvas = {
828
+ naturalWidth: naturalWidth,
829
+ naturalHeight: naturalHeight,
830
+ aspectRatio: aspectRatio,
831
+ width: canvasWidth,
832
+ height: canvasHeight
833
+ };
834
+
835
+ canvas.oldLeft = canvas.left = (containerWidth - canvasWidth) / 2;
836
+ canvas.oldTop = canvas.top = (containerHeight - canvasHeight) / 2;
837
 
838
  this.canvas = canvas;
839
+ this.isLimited = (viewMode === 1 || viewMode === 2);
840
  this.limitCanvas(true, true);
841
  this.initialImage = $.extend({}, image);
842
  this.initialCanvas = $.extend({}, canvas);
843
  },
844
 
845
+ limitCanvas: function (isSizeLimited, isPositionLimited) {
846
+ var options = this.options;
847
+ var viewMode = options.viewMode;
848
+ var container = this.container;
849
+ var containerWidth = container.width;
850
+ var containerHeight = container.height;
851
+ var canvas = this.canvas;
852
+ var aspectRatio = canvas.aspectRatio;
853
+ var cropBox = this.cropBox;
854
+ var isCropped = this.isCropped && cropBox;
855
+ var minCanvasWidth;
856
+ var minCanvasHeight;
857
+ var newCanvasLeft;
858
+ var newCanvasTop;
859
+
860
+ if (isSizeLimited) {
 
861
  minCanvasWidth = num(options.minCanvasWidth) || 0;
862
  minCanvasHeight = num(options.minCanvasHeight) || 0;
863
 
864
+ if (viewMode) {
865
+ if (viewMode > 1) {
866
+ minCanvasWidth = max(minCanvasWidth, containerWidth);
867
+ minCanvasHeight = max(minCanvasHeight, containerHeight);
868
+
869
+ if (viewMode === 3) {
870
+ if (minCanvasHeight * aspectRatio > minCanvasWidth) {
871
+ minCanvasWidth = minCanvasHeight * aspectRatio;
872
+ } else {
873
+ minCanvasHeight = minCanvasWidth / aspectRatio;
874
+ }
875
+ }
876
+ } else {
877
+ if (minCanvasWidth) {
878
+ minCanvasWidth = max(minCanvasWidth, isCropped ? cropBox.width : 0);
879
+ } else if (minCanvasHeight) {
880
+ minCanvasHeight = max(minCanvasHeight, isCropped ? cropBox.height : 0);
881
+ } else if (isCropped) {
882
+ minCanvasWidth = cropBox.width;
883
+ minCanvasHeight = cropBox.height;
884
+
885
+ if (minCanvasHeight * aspectRatio > minCanvasWidth) {
886
+ minCanvasWidth = minCanvasHeight * aspectRatio;
887
+ } else {
888
+ minCanvasHeight = minCanvasWidth / aspectRatio;
889
+ }
890
+ }
891
  }
892
+ }
893
 
894
+ if (minCanvasWidth && minCanvasHeight) {
895
+ if (minCanvasHeight * aspectRatio > minCanvasWidth) {
896
+ minCanvasHeight = minCanvasWidth / aspectRatio;
897
+ } else {
898
+ minCanvasWidth = minCanvasHeight * aspectRatio;
899
+ }
900
+ } else if (minCanvasWidth) {
901
  minCanvasHeight = minCanvasWidth / aspectRatio;
902
  } else if (minCanvasHeight) {
 
 
 
 
903
  minCanvasWidth = minCanvasHeight * aspectRatio;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
904
  }
905
 
906
+ canvas.minWidth = minCanvasWidth;
907
+ canvas.minHeight = minCanvasHeight;
908
+ canvas.maxWidth = Infinity;
909
+ canvas.maxHeight = Infinity;
 
 
910
  }
911
 
912
+ if (isPositionLimited) {
913
+ if (viewMode) {
914
+ newCanvasLeft = containerWidth - canvas.width;
915
+ newCanvasTop = containerHeight - canvas.height;
916
+
917
+ canvas.minLeft = min(0, newCanvasLeft);
918
+ canvas.minTop = min(0, newCanvasTop);
919
+ canvas.maxLeft = max(0, newCanvasLeft);
920
+ canvas.maxTop = max(0, newCanvasTop);
921
+
922
+ if (isCropped && this.isLimited) {
923
+ canvas.minLeft = min(
924
+ cropBox.left,
925
+ cropBox.left + cropBox.width - canvas.width
926
+ );
927
+ canvas.minTop = min(
928
+ cropBox.top,
929
+ cropBox.top + cropBox.height - canvas.height
930
+ );
931
  canvas.maxLeft = cropBox.left;
932
  canvas.maxTop = cropBox.top;
933
+
934
+ if (viewMode === 2) {
935
+ if (canvas.width >= containerWidth) {
936
+ canvas.minLeft = min(0, newCanvasLeft);
937
+ canvas.maxLeft = max(0, newCanvasLeft);
938
+ }
939
+
940
+ if (canvas.height >= containerHeight) {
941
+ canvas.minTop = min(0, newCanvasTop);
942
+ canvas.maxTop = max(0, newCanvasTop);
943
+ }
944
+ }
945
  }
946
  } else {
947
  canvas.minLeft = -canvas.width;
952
  }
953
  },
954
 
955
+ renderCanvas: function (isChanged) {
956
+ var canvas = this.canvas;
957
+ var image = this.image;
958
+ var rotate = image.rotate;
959
+ var naturalWidth = image.naturalWidth;
960
+ var naturalHeight = image.naturalHeight;
961
+ var aspectRatio;
962
+ var rotated;
963
 
964
+ if (this.isRotated) {
965
+ this.isRotated = false;
966
 
967
+ // Computes rotated sizes with image sizes
968
  rotated = getRotatedSizes({
969
  width: image.width,
970
  height: image.height,
971
+ degree: rotate
972
  });
973
 
974
  aspectRatio = rotated.width / rotated.height;
979
  canvas.width = rotated.width;
980
  canvas.height = rotated.height;
981
  canvas.aspectRatio = aspectRatio;
982
+ canvas.naturalWidth = naturalWidth;
983
+ canvas.naturalHeight = naturalHeight;
984
+
985
+ // Computes rotated sizes with natural image sizes
986
+ if (rotate % 180) {
987
+ rotated = getRotatedSizes({
988
+ width: naturalWidth,
989
+ height: naturalHeight,
990
+ degree: rotate
991
+ });
992
+
993
+ canvas.naturalWidth = rotated.width;
994
+ canvas.naturalHeight = rotated.height;
995
+ }
996
+
997
  this.limitCanvas(true, false);
998
  }
999
  }
1023
 
1024
  this.renderImage();
1025
 
1026
+ if (this.isCropped && this.isLimited) {
1027
  this.limitCropBox(true, true);
1028
  }
1029
 
1030
+ if (isChanged) {
1031
  this.output();
1032
  }
1033
  },
1034
 
1035
+ renderImage: function (isChanged) {
1036
+ var canvas = this.canvas;
1037
+ var image = this.image;
1038
+ var reversed;
1039
 
1040
  if (image.rotate) {
1041
  reversed = getRotatedSizes({
1063
  height: image.height,
1064
  marginLeft: image.left,
1065
  marginTop: image.top,
1066
+ transform: getTransform(image)
1067
  });
1068
+
1069
+ if (isChanged) {
1070
+ this.output();
1071
+ }
1072
  },
1073
 
1074
  initCropBox: function () {
1075
+ var options = this.options;
1076
+ var canvas = this.canvas;
1077
+ var aspectRatio = options.aspectRatio;
1078
+ var autoCropArea = num(options.autoCropArea) || 0.8;
1079
+ var cropBox = {
1080
  width: canvas.width,
1081
  height: canvas.height
1082
  };
1105
  this.initialCropBox = $.extend({}, cropBox);
1106
  },
1107
 
1108
+ limitCropBox: function (isSizeLimited, isPositionLimited) {
1109
+ var options = this.options;
1110
+ var aspectRatio = options.aspectRatio;
1111
+ var container = this.container;
1112
+ var containerWidth = container.width;
1113
+ var containerHeight = container.height;
1114
+ var canvas = this.canvas;
1115
+ var cropBox = this.cropBox;
1116
+ var isLimited = this.isLimited;
1117
+ var minCropBoxWidth;
1118
+ var minCropBoxHeight;
1119
+ var maxCropBoxWidth;
1120
+ var maxCropBoxHeight;
1121
+
1122
+ if (isSizeLimited) {
1123
  minCropBoxWidth = num(options.minCropBoxWidth) || 0;
1124
  minCropBoxHeight = num(options.minCropBoxHeight) || 0;
1125
 
1126
+ // The min/maxCropBoxWidth/Height must be less than containerWidth/Height
1127
+ minCropBoxWidth = min(minCropBoxWidth, containerWidth);
1128
+ minCropBoxHeight = min(minCropBoxHeight, containerHeight);
1129
+ maxCropBoxWidth = min(containerWidth, isLimited ? canvas.width : containerWidth);
1130
+ maxCropBoxHeight = min(containerHeight, isLimited ? canvas.height : containerHeight);
1131
 
1132
  if (aspectRatio) {
1133
+ if (minCropBoxWidth && minCropBoxHeight) {
1134
+ if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {
1135
+ minCropBoxHeight = minCropBoxWidth / aspectRatio;
1136
+ } else {
1137
+ minCropBoxWidth = minCropBoxHeight * aspectRatio;
1138
+ }
1139
+ } else if (minCropBoxWidth) {
1140
+ minCropBoxHeight = minCropBoxWidth / aspectRatio;
1141
+ } else if (minCropBoxHeight) {
1142
+ minCropBoxWidth = minCropBoxHeight * aspectRatio;
1143
+ }
1144
+
1145
+ if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {
1146
+ maxCropBoxHeight = maxCropBoxWidth / aspectRatio;
1147
  } else {
1148
+ maxCropBoxWidth = maxCropBoxHeight * aspectRatio;
 
1149
  }
1150
  }
1151
 
1152
+ // The minWidth/Height must be less than maxWidth/Height
1153
+ cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth);
1154
+ cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight);
1155
+ cropBox.maxWidth = maxCropBoxWidth;
1156
+ cropBox.maxHeight = maxCropBoxHeight;
1157
  }
1158
 
1159
+ if (isPositionLimited) {
1160
+ if (isLimited) {
1161
  cropBox.minLeft = max(0, canvas.left);
1162
  cropBox.minTop = max(0, canvas.top);
1163
  cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
1172
  },
1173
 
1174
  renderCropBox: function () {
1175
+ var options = this.options;
1176
+ var container = this.container;
1177
+ var containerWidth = container.width;
1178
+ var containerHeight = container.height;
1179
+ var cropBox = this.cropBox;
1180
 
1181
  if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
1182
  cropBox.left = cropBox.oldLeft;
1195
  cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);
1196
 
1197
  if (options.movable && options.cropBoxMovable) {
1198
+
1199
  // Turn to move the canvas when the crop box is equal to the container
1200
+ this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL);
1201
  }
1202
 
1203
  this.$cropBox.css({
1207
  top: cropBox.top
1208
  });
1209
 
1210
+ if (this.isCropped && this.isLimited) {
1211
  this.limitCanvas(true, true);
1212
  }
1213
 
1214
+ if (!this.isDisabled) {
1215
  this.output();
1216
  }
1217
  },
1218
 
1219
  output: function () {
 
 
 
1220
  this.preview();
1221
 
1222
+ if (this.isCompleted) {
1223
+ this.trigger(EVENT_CROP, this.getData());
1224
+ } else if (!this.isBuilt) {
1225
+
1226
+ // Only trigger one crop event before complete
1227
+ this.$element.one(EVENT_BUILT, $.proxy(function () {
1228
+ this.trigger(EVENT_CROP, this.getData());
1229
+ }, this));
1230
  }
1231
+ },
1232
 
1233
+ initPreview: function () {
1234
+ var crossOrigin = getCrossOrigin(this.crossOrigin);
1235
+ var url = crossOrigin ? this.crossOriginUrl : this.url;
1236
 
1237
+ this.$preview = $(this.options.preview);
1238
+ this.$viewBox.html('<img' + crossOrigin + ' src="' + url + '">');
1239
+ this.$preview.each(function () {
1240
+ var $this = $(this);
1241
 
1242
+ // Save the original size for recover
1243
+ $this.data(DATA_PREVIEW, {
1244
+ width: $this.width(),
1245
+ height: $this.height(),
1246
+ html: $this.html()
1247
+ });
 
 
 
 
 
 
 
 
 
1248
 
1249
+ /**
1250
+ * Override img element styles
1251
+ * Add `display:block` to avoid margin top issue
1252
+ * (Occur only when margin-top <= -height)
1253
+ */
1254
+ $this.html(
1255
+ '<img' + crossOrigin + ' src="' + url + '" style="' +
1256
+ 'display:block;width:100%;height:auto;' +
1257
+ 'min-width:0!important;min-height:0!important;' +
1258
+ 'max-width:none!important;max-height:none!important;' +
1259
+ 'image-orientation:0deg!important;">'
1260
+ );
1261
+ });
1262
+ },
1263
 
1264
+ resetPreview: function () {
1265
+ this.$preview.each(function () {
1266
+ var $this = $(this);
1267
+ var data = $this.data(DATA_PREVIEW);
1268
 
1269
+ $this.css({
1270
+ width: data.width,
1271
+ height: data.height
1272
+ }).html(data.html).removeData(DATA_PREVIEW);
1273
+ });
1274
+ },
 
 
 
 
 
 
 
1275
 
1276
+ preview: function () {
1277
+ var image = this.image;
1278
+ var canvas = this.canvas;
1279
+ var cropBox = this.cropBox;
1280
+ var cropBoxWidth = cropBox.width;
1281
+ var cropBoxHeight = cropBox.height;
1282
+ var width = image.width;
1283
+ var height = image.height;
1284
+ var left = cropBox.left - canvas.left - image.left;
1285
+ var top = cropBox.top - canvas.top - image.top;
1286
+
1287
+ if (!this.isCropped || this.isDisabled) {
1288
+ return;
1289
+ }
1290
 
1291
+ this.$viewBox.find('img').css({
1292
+ width: width,
1293
+ height: height,
1294
+ marginLeft: -left,
1295
+ marginTop: -top,
1296
+ transform: getTransform(image)
 
 
 
 
 
 
 
 
 
 
 
 
 
1297
  });
 
 
1298
 
1299
+ this.$preview.each(function () {
1300
+ var $this = $(this);
1301
+ var data = $this.data(DATA_PREVIEW);
1302
+ var originalWidth = data.width;
1303
+ var originalHeight = data.height;
1304
+ var newWidth = originalWidth;
1305
+ var newHeight = originalHeight;
1306
+ var ratio = 1;
1307
+
1308
+ if (cropBoxWidth) {
1309
+ ratio = originalWidth / cropBoxWidth;
1310
+ newHeight = cropBoxHeight * ratio;
1311
+ }
1312
 
1313
+ if (cropBoxHeight && newHeight > originalHeight) {
1314
+ ratio = originalHeight / cropBoxHeight;
1315
+ newWidth = cropBoxWidth * ratio;
1316
+ newHeight = originalHeight;
1317
+ }
1318
 
1319
+ $this.css({
1320
+ width: newWidth,
1321
+ height: newHeight
1322
+ }).find('img').css({
1323
+ width: width * ratio,
1324
+ height: height * ratio,
1325
+ marginLeft: -left * ratio,
1326
+ marginTop: -top * ratio,
1327
+ transform: getTransform(image)
1328
+ });
1329
+ });
1330
+ },
1331
 
1332
+ bind: function () {
1333
+ var options = this.options;
1334
+ var $this = this.$element;
1335
+ var $cropper = this.$cropper;
1336
 
1337
+ if ($.isFunction(options.cropstart)) {
1338
+ $this.on(EVENT_CROP_START, options.cropstart);
1339
+ }
1340
 
1341
+ if ($.isFunction(options.cropmove)) {
1342
+ $this.on(EVENT_CROP_MOVE, options.cropmove);
1343
+ }
1344
 
1345
+ if ($.isFunction(options.cropend)) {
1346
+ $this.on(EVENT_CROP_END, options.cropend);
1347
+ }
1348
 
1349
+ if ($.isFunction(options.crop)) {
1350
+ $this.on(EVENT_CROP, options.crop);
1351
+ }
1352
 
1353
+ if ($.isFunction(options.zoom)) {
1354
+ $this.on(EVENT_ZOOM, options.zoom);
1355
+ }
1356
 
1357
+ $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this));
 
 
1358
 
1359
+ if (options.zoomable && options.zoomOnWheel) {
1360
+ $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
1361
+ }
1362
 
1363
+ if (options.toggleDragModeOnDblclick) {
1364
+ $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
1365
+ }
 
1366
 
1367
+ $document.
1368
+ on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))).
1369
+ on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this)));
 
1370
 
1371
+ if (options.responsive) {
1372
+ $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
1373
+ }
1374
+ },
1375
 
1376
+ unbind: function () {
1377
+ var options = this.options;
1378
+ var $this = this.$element;
1379
+ var $cropper = this.$cropper;
1380
 
1381
+ if ($.isFunction(options.cropstart)) {
1382
+ $this.off(EVENT_CROP_START, options.cropstart);
1383
+ }
1384
 
1385
+ if ($.isFunction(options.cropmove)) {
1386
+ $this.off(EVENT_CROP_MOVE, options.cropmove);
1387
+ }
1388
 
1389
+ if ($.isFunction(options.cropend)) {
1390
+ $this.off(EVENT_CROP_END, options.cropend);
1391
+ }
1392
 
1393
+ if ($.isFunction(options.crop)) {
1394
+ $this.off(EVENT_CROP, options.crop);
1395
+ }
1396
 
1397
+ if ($.isFunction(options.zoom)) {
1398
+ $this.off(EVENT_ZOOM, options.zoom);
1399
+ }
1400
 
1401
+ $cropper.off(EVENT_MOUSE_DOWN, this.cropStart);
 
 
1402
 
1403
+ if (options.zoomable && options.zoomOnWheel) {
1404
+ $cropper.off(EVENT_WHEEL, this.wheel);
1405
+ }
1406
 
1407
+ if (options.toggleDragModeOnDblclick) {
1408
+ $cropper.off(EVENT_DBLCLICK, this.dblclick);
1409
+ }
1410
 
1411
+ $document.
1412
+ off(EVENT_MOUSE_MOVE, this._cropMove).
1413
+ off(EVENT_MOUSE_UP, this._cropEnd);
 
1414
 
1415
+ if (options.responsive) {
1416
+ $window.off(EVENT_RESIZE, this._resize);
1417
+ }
1418
+ },
 
 
 
1419
 
1420
+ resize: function () {
1421
+ var restore = this.options.restore;
1422
+ var $container = this.$container;
1423
+ var container = this.container;
1424
+ var canvasData;
1425
+ var cropBoxData;
1426
+ var ratio;
1427
+
1428
+ // Check `container` is necessary for IE8
1429
+ if (this.isDisabled || !container) {
1430
  return;
1431
  }
1432
 
1433
  ratio = $container.width() / container.width;
1434
 
1435
+ // Resize when width changed or height changed
1436
  if (ratio !== 1 || $container.height() !== container.height) {
1437
+ if (restore) {
1438
+ canvasData = this.getCanvasData();
1439
+ cropBoxData = this.getCropBoxData();
1440
+ }
1441
 
1442
  this.render();
1443
+
1444
+ if (restore) {
1445
+ this.setCanvasData($.each(canvasData, function (i, n) {
1446
+ canvasData[i] = n * ratio;
1447
+ }));
1448
+ this.setCropBoxData($.each(cropBoxData, function (i, n) {
1449
+ cropBoxData[i] = n * ratio;
1450
+ }));
1451
+ }
1452
  }
1453
  },
1454
 
1455
  dblclick: function () {
1456
+ if (this.isDisabled) {
1457
  return;
1458
  }
1459
 
1460
  if (this.$dragBox.hasClass(CLASS_CROP)) {
1461
+ this.setDragMode(ACTION_MOVE);
1462
  } else {
1463
+ this.setDragMode(ACTION_CROP);
1464
  }
1465
  },
1466
 
1467
  wheel: function (event) {
1468
+ var e = event.originalEvent || event;
1469
+ var ratio = num(this.options.wheelZoomRatio) || 0.1;
1470
+ var delta = 1;
1471
 
1472
+ if (this.isDisabled) {
1473
  return;
1474
  }
1475
 
1476
  event.preventDefault();
1477
 
1478
+ // Limit wheel speed to prevent zoom too fast
1479
+ if (this.wheeling) {
1480
+ return;
1481
+ }
1482
+
1483
+ this.wheeling = true;
1484
+
1485
+ setTimeout($.proxy(function () {
1486
+ this.wheeling = false;
1487
+ }, this), 50);
1488
+
1489
  if (e.deltaY) {
1490
  delta = e.deltaY > 0 ? 1 : -1;
1491
  } else if (e.wheelDelta) {
1494
  delta = e.detail > 0 ? 1 : -1;
1495
  }
1496
 
1497
+ this.zoom(-delta * ratio, event);
1498
  },
1499
 
1500
+ cropStart: function (event) {
1501
+ var options = this.options;
1502
+ var originalEvent = event.originalEvent;
1503
+ var touches = originalEvent && originalEvent.touches;
1504
+ var e = event;
1505
+ var touchesLength;
1506
+ var action;
 
1507
 
1508
+ if (this.isDisabled) {
1509
  return;
1510
  }
1511
 
1513
  touchesLength = touches.length;
1514
 
1515
  if (touchesLength > 1) {
1516
+ if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
1517
  e = touches[1];
1518
  this.startX2 = e.pageX;
1519
  this.startY2 = e.pageY;
1520
+ action = ACTION_ZOOM;
1521
  } else {
1522
  return;
1523
  }
1526
  e = touches[0];
1527
  }
1528
 
1529
+ action = action || $(e.target).data(DATA_ACTION);
 
 
 
1530
 
1531
+ if (REGEXP_ACTIONS.test(action)) {
1532
+ if (this.trigger(EVENT_CROP_START, {
1533
  originalEvent: originalEvent,
1534
+ action: action
1535
+ }).isDefaultPrevented()) {
 
 
 
 
1536
  return;
1537
  }
1538
 
1539
+ event.preventDefault();
1540
+
1541
+ this.action = action;
1542
  this.cropping = false;
 
 
1543
 
1544
+ // IE8 has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
1545
+ // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
1546
+ this.startX = e.pageX || originalEvent && originalEvent.pageX;
1547
+ this.startY = e.pageY || originalEvent && originalEvent.pageY;
1548
+
1549
+ if (action === ACTION_CROP) {
1550
  this.cropping = true;
1551
  this.$dragBox.addClass(CLASS_MODAL);
1552
  }
1553
  }
1554
  },
1555
 
1556
+ cropMove: function (event) {
1557
+ var options = this.options;
1558
+ var originalEvent = event.originalEvent;
1559
+ var touches = originalEvent && originalEvent.touches;
1560
+ var e = event;
1561
+ var action = this.action;
1562
+ var touchesLength;
 
1563
 
1564
+ if (this.isDisabled) {
1565
  return;
1566
  }
1567
 
1569
  touchesLength = touches.length;
1570
 
1571
  if (touchesLength > 1) {
1572
+ if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
1573
  e = touches[1];
1574
  this.endX2 = e.pageX;
1575
  this.endY2 = e.pageY;
1581
  e = touches[0];
1582
  }
1583
 
1584
+ if (action) {
1585
+ if (this.trigger(EVENT_CROP_MOVE, {
 
 
1586
  originalEvent: originalEvent,
1587
+ action: action
1588
+ }).isDefaultPrevented()) {
 
 
 
 
1589
  return;
1590
  }
1591
 
1592
+ event.preventDefault();
 
1593
 
1594
+ this.endX = e.pageX || originalEvent && originalEvent.pageX;
1595
+ this.endY = e.pageY || originalEvent && originalEvent.pageY;
1596
+
1597
+ this.change(e.shiftKey, action === ACTION_ZOOM ? event : null);
1598
  }
1599
  },
1600
 
1601
+ cropEnd: function (event) {
1602
+ var originalEvent = event.originalEvent;
1603
+ var action = this.action;
1604
 
1605
+ if (this.isDisabled) {
1606
  return;
1607
  }
1608
 
1609
+ if (action) {
1610
  event.preventDefault();
1611
 
1612
+ if (this.cropping) {
1613
+ this.cropping = false;
1614
+ this.$dragBox.toggleClass(CLASS_MODAL, this.isCropped && this.options.modal);
1615
+ }
1616
+
1617
+ this.action = '';
1618
+
1619
+ this.trigger(EVENT_CROP_END, {
1620
+ originalEvent: originalEvent,
1621
+ action: action
1622
  });
1623
+ }
1624
+ },
1625
 
1626
+ change: function (shiftKey, event) {
1627
+ var options = this.options;
1628
+ var aspectRatio = options.aspectRatio;
1629
+ var action = this.action;
1630
+ var container = this.container;
1631
+ var canvas = this.canvas;
1632
+ var cropBox = this.cropBox;
1633
+ var width = cropBox.width;
1634
+ var height = cropBox.height;
1635
+ var left = cropBox.left;
1636
+ var top = cropBox.top;
1637
+ var right = left + width;
1638
+ var bottom = top + height;
1639
+ var minLeft = 0;
1640
+ var minTop = 0;
1641
+ var maxWidth = container.width;
1642
+ var maxHeight = container.height;
1643
+ var renderable = true;
1644
+ var offset;
1645
+ var range;
1646
+
1647
+ // Locking aspect ratio in "free mode" by holding shift key (#259)
1648
+ if (!aspectRatio && shiftKey) {
1649
+ aspectRatio = width && height ? width / height : 1;
1650
+ }
1651
 
1652
+ if (this.limited) {
1653
+ minLeft = cropBox.minLeft;
1654
+ minTop = cropBox.minTop;
1655
+ maxWidth = minLeft + min(container.width, canvas.width);
1656
+ maxHeight = minTop + min(container.height, canvas.height);
1657
+ }
1658
 
1659
+ range = {
1660
+ x: this.endX - this.startX,
1661
+ y: this.endY - this.startY
1662
+ };
1663
 
1664
+ if (aspectRatio) {
1665
+ range.X = range.y * aspectRatio;
1666
+ range.Y = range.x / aspectRatio;
1667
  }
 
 
1668
 
1669
+ switch (action) {
1670
+ // Move crop box
1671
+ case ACTION_ALL:
1672
+ left += range.x;
1673
+ top += range.y;
1674
+ break;
1675
+
1676
+ // Resize crop box
1677
+ case ACTION_EAST:
1678
+ if (range.x >= 0 && (right >= maxWidth || aspectRatio &&
1679
+ (top <= minTop || bottom >= maxHeight))) {
1680
+
1681
+ renderable = false;
1682
+ break;
1683
+ }
1684
+
1685
+ width += range.x;
1686
+
1687
+ if (aspectRatio) {
1688
+ height = width / aspectRatio;
1689
+ top -= range.Y / 2;
1690
+ }
1691
+
1692
+ if (width < 0) {
1693
+ action = ACTION_WEST;
1694
+ width = 0;
1695
+ }
1696
+
1697
+ break;
1698
+
1699
+ case ACTION_NORTH:
1700
+ if (range.y <= 0 && (top <= minTop || aspectRatio &&
1701
+ (left <= minLeft || right >= maxWidth))) {
1702
+
1703
+ renderable = false;
1704
+ break;
1705
+ }
1706
+
1707
+ height -= range.y;
1708
+ top += range.y;
1709
+
1710
+ if (aspectRatio) {
1711
+ width = height * aspectRatio;
1712
+ left += range.X / 2;
1713
+ }
1714
+
1715
+ if (height < 0) {
1716
+ action = ACTION_SOUTH;
1717
+ height = 0;
1718
+ }
1719
+
1720
+ break;
1721
+
1722
+ case ACTION_WEST:
1723
+ if (range.x <= 0 && (left <= minLeft || aspectRatio &&
1724
+ (top <= minTop || bottom >= maxHeight))) {
1725
+
1726
+ renderable = false;
1727
+ break;
1728
+ }
1729
+
1730
+ width -= range.x;
1731
+ left += range.x;
1732
+
1733
+ if (aspectRatio) {
1734
+ height = width / aspectRatio;
1735
+ top += range.Y / 2;
1736
+ }
1737
+
1738
+ if (width < 0) {
1739
+ action = ACTION_EAST;
1740
+ width = 0;
1741
+ }
1742
+
1743
+ break;
1744
+
1745
+ case ACTION_SOUTH:
1746
+ if (range.y >= 0 && (bottom >= maxHeight || aspectRatio &&
1747
+ (left <= minLeft || right >= maxWidth))) {
1748
+
1749
+ renderable = false;
1750
+ break;
1751
+ }
1752
+
1753
+ height += range.y;
1754
+
1755
+ if (aspectRatio) {
1756
+ width = height * aspectRatio;
1757
+ left -= range.X / 2;
1758
+ }
1759
+
1760
+ if (height < 0) {
1761
+ action = ACTION_NORTH;
1762
+ height = 0;
1763
+ }
1764
+
1765
+ break;
1766
+
1767
+ case ACTION_NORTH_EAST:
1768
+ if (aspectRatio) {
1769
+ if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
1770
+ renderable = false;
1771
+ break;
1772
+ }
1773
+
1774
+ height -= range.y;
1775
+ top += range.y;
1776
+ width = height * aspectRatio;
1777
+ } else {
1778
+ if (range.x >= 0) {
1779
+ if (right < maxWidth) {
1780
+ width += range.x;
1781
+ } else if (range.y <= 0 && top <= minTop) {
1782
+ renderable = false;
1783
+ }
1784
+ } else {
1785
+ width += range.x;
1786
+ }
1787
+
1788
+ if (range.y <= 0) {
1789
+ if (top > minTop) {
1790
+ height -= range.y;
1791
+ top += range.y;
1792
+ }
1793
+ } else {
1794
+ height -= range.y;
1795
+ top += range.y;
1796
+ }
1797
+ }
1798
+
1799
+ if (width < 0 && height < 0) {
1800
+ action = ACTION_SOUTH_WEST;
1801
+ height = 0;
1802
+ width = 0;
1803
+ } else if (width < 0) {
1804
+ action = ACTION_NORTH_WEST;
1805
+ width = 0;
1806
+ } else if (height < 0) {
1807
+ action = ACTION_SOUTH_EAST;
1808
+ height = 0;
1809
+ }
1810
+
1811
+ break;
1812
+
1813
+ case ACTION_NORTH_WEST:
1814
+ if (aspectRatio) {
1815
+ if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
1816
+ renderable = false;
1817
+ break;
1818
+ }
1819
+
1820
+ height -= range.y;
1821
+ top += range.y;
1822
+ width = height * aspectRatio;
1823
+ left += range.X;
1824
+ } else {
1825
+ if (range.x <= 0) {
1826
+ if (left > minLeft) {
1827
+ width -= range.x;
1828
+ left += range.x;
1829
+ } else if (range.y <= 0 && top <= minTop) {
1830
+ renderable = false;
1831
+ }
1832
+ } else {
1833
+ width -= range.x;
1834
+ left += range.x;
1835
+ }
1836
+
1837
+ if (range.y <= 0) {
1838
+ if (top > minTop) {
1839
+ height -= range.y;
1840
+ top += range.y;
1841
+ }
1842
+ } else {
1843
+ height -= range.y;
1844
+ top += range.y;
1845
+ }
1846
+ }
1847
+
1848
+ if (width < 0 && height < 0) {
1849
+ action = ACTION_SOUTH_EAST;
1850
+ height = 0;
1851
+ width = 0;
1852
+ } else if (width < 0) {
1853
+ action = ACTION_NORTH_EAST;
1854
+ width = 0;
1855
+ } else if (height < 0) {
1856
+ action = ACTION_SOUTH_WEST;
1857
+ height = 0;
1858
+ }
1859
+
1860
+ break;
1861
+
1862
+ case ACTION_SOUTH_WEST:
1863
+ if (aspectRatio) {
1864
+ if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
1865
+ renderable = false;
1866
+ break;
1867
+ }
1868
+
1869
+ width -= range.x;
1870
+ left += range.x;
1871
+ height = width / aspectRatio;
1872
+ } else {
1873
+ if (range.x <= 0) {
1874
+ if (left > minLeft) {
1875
+ width -= range.x;
1876
+ left += range.x;
1877
+ } else if (range.y >= 0 && bottom >= maxHeight) {
1878
+ renderable = false;
1879
+ }
1880
+ } else {
1881
+ width -= range.x;
1882
+ left += range.x;
1883
+ }
1884
+
1885
+ if (range.y >= 0) {
1886
+ if (bottom < maxHeight) {
1887
+ height += range.y;
1888
+ }
1889
+ } else {
1890
+ height += range.y;
1891
+ }
1892
+ }
1893
+
1894
+ if (width < 0 && height < 0) {
1895
+ action = ACTION_NORTH_EAST;
1896
+ height = 0;
1897
+ width = 0;
1898
+ } else if (width < 0) {
1899
+ action = ACTION_SOUTH_EAST;
1900
+ width = 0;
1901
+ } else if (height < 0) {
1902
+ action = ACTION_NORTH_WEST;
1903
+ height = 0;
1904
+ }
1905
+
1906
+ break;
1907
+
1908
+ case ACTION_SOUTH_EAST:
1909
+ if (aspectRatio) {
1910
+ if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
1911
+ renderable = false;
1912
+ break;
1913
+ }
1914
+
1915
+ width += range.x;
1916
+ height = width / aspectRatio;
1917
+ } else {
1918
+ if (range.x >= 0) {
1919
+ if (right < maxWidth) {
1920
+ width += range.x;
1921
+ } else if (range.y >= 0 && bottom >= maxHeight) {
1922
+ renderable = false;
1923
+ }
1924
+ } else {
1925
+ width += range.x;
1926
+ }
1927
+
1928
+ if (range.y >= 0) {
1929
+ if (bottom < maxHeight) {
1930
+ height += range.y;
1931
+ }
1932
+ } else {
1933
+ height += range.y;
1934
+ }
1935
+ }
1936
+
1937
+ if (width < 0 && height < 0) {
1938
+ action = ACTION_NORTH_WEST;
1939
+ height = 0;
1940
+ width = 0;
1941
+ } else if (width < 0) {
1942
+ action = ACTION_SOUTH_WEST;
1943
+ width = 0;
1944
+ } else if (height < 0) {
1945
+ action = ACTION_NORTH_EAST;
1946
+ height = 0;
1947
+ }
1948
+
1949
+ break;
1950
+
1951
+ // Move canvas
1952
+ case ACTION_MOVE:
1953
+ this.move(range.x, range.y);
1954
+ renderable = false;
1955
+ break;
1956
+
1957
+ // Zoom canvas
1958
+ case ACTION_ZOOM:
1959
+ this.zoom((function (x1, y1, x2, y2) {
1960
+ var z1 = sqrt(x1 * x1 + y1 * y1);
1961
+ var z2 = sqrt(x2 * x2 + y2 * y2);
1962
+
1963
+ return (z2 - z1) / z1;
1964
+ })(
1965
+ abs(this.startX - this.startX2),
1966
+ abs(this.startY - this.startY2),
1967
+ abs(this.endX - this.endX2),
1968
+ abs(this.endY - this.endY2)
1969
+ ), event);
1970
+ this.startX2 = this.endX2;
1971
+ this.startY2 = this.endY2;
1972
+ renderable = false;
1973
+ break;
1974
+
1975
+ // Create crop box
1976
+ case ACTION_CROP:
1977
+ if (!range.x || !range.y) {
1978
+ renderable = false;
1979
+ break;
1980
+ }
1981
+
1982
+ offset = this.$cropper.offset();
1983
+ left = this.startX - offset.left;
1984
+ top = this.startY - offset.top;
1985
+ width = cropBox.minWidth;
1986
+ height = cropBox.minHeight;
1987
+
1988
+ if (range.x > 0) {
1989
+ action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;
1990
+ } else if (range.x < 0) {
1991
+ left -= width;
1992
+ action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;
1993
+ }
1994
+
1995
+ if (range.y < 0) {
1996
+ top -= height;
1997
+ }
1998
+
1999
+ // Show the crop box if is hidden
2000
+ if (!this.isCropped) {
2001
+ this.$cropBox.removeClass(CLASS_HIDDEN);
2002
+ this.isCropped = true;
2003
+
2004
+ if (this.limited) {
2005
+ this.limitCropBox(true, true);
2006
+ }
2007
+ }
2008
+
2009
+ break;
2010
+
2011
+ // No default
2012
+ }
2013
+
2014
+ if (renderable) {
2015
+ cropBox.width = width;
2016
+ cropBox.height = height;
2017
+ cropBox.left = left;
2018
+ cropBox.top = top;
2019
+ this.action = action;
2020
+
2021
+ this.renderCropBox();
2022
+ }
2023
+
2024
+ // Override
2025
+ this.startX = this.endX;
2026
+ this.startY = this.endY;
2027
+ },
2028
+
2029
+ // Show the crop box manually
2030
  crop: function () {
2031
+ if (!this.isBuilt || this.isDisabled) {
2032
  return;
2033
  }
2034
 
2035
+ if (!this.isCropped) {
2036
+ this.isCropped = true;
2037
  this.limitCropBox(true, true);
2038
 
2039
  if (this.options.modal) {
2046
  this.setCropBoxData(this.initialCropBox);
2047
  },
2048
 
2049
+ // Reset the image and crop box to their initial states
2050
  reset: function () {
2051
+ if (!this.isBuilt || this.isDisabled) {
2052
  return;
2053
  }
2054
 
2055
  this.image = $.extend({}, this.initialImage);
2056
  this.canvas = $.extend({}, this.initialCanvas);
2057
+ this.cropBox = $.extend({}, this.initialCropBox);
2058
 
2059
  this.renderCanvas();
2060
 
2061
+ if (this.isCropped) {
2062
  this.renderCropBox();
2063
  }
2064
  },
2065
 
2066
+ // Clear the crop box
2067
  clear: function () {
2068
+ if (!this.isCropped || this.isDisabled) {
2069
  return;
2070
  }
2071
 
2076
  height: 0
2077
  });
2078
 
2079
+ this.isCropped = false;
2080
  this.renderCropBox();
2081
 
2082
+ this.limitCanvas(true, true);
2083
+
2084
+ // Render canvas after crop box rendered
2085
+ this.renderCanvas();
2086
 
2087
  this.$dragBox.removeClass(CLASS_MODAL);
2088
  this.$cropBox.addClass(CLASS_HIDDEN);
2089
  },
2090
 
2091
+ /**
2092
+ * Replace the image's src and rebuild the cropper
2093
+ *
2094
+ * @param {String} url
2095
+ */
2096
+ replace: function (url) {
2097
+ if (!this.isDisabled && url) {
2098
+ if (this.isImg) {
2099
+ this.isReplaced = true;
2100
+ this.$element.attr('src', url);
2101
+ }
2102
+
2103
+ // Clear previous data
2104
+ this.options.data = null;
2105
+ this.load(url);
2106
+ }
2107
+ },
2108
+
2109
+ // Enable (unfreeze) the cropper
2110
+ enable: function () {
2111
+ if (this.isBuilt) {
2112
+ this.isDisabled = false;
2113
+ this.$cropper.removeClass(CLASS_DISABLED);
2114
+ }
2115
+ },
2116
+
2117
+ // Disable (freeze) the cropper
2118
+ disable: function () {
2119
+ if (this.isBuilt) {
2120
+ this.isDisabled = true;
2121
+ this.$cropper.addClass(CLASS_DISABLED);
2122
+ }
2123
+ },
2124
+
2125
+ // Destroy the cropper and remove the instance from the image
2126
+ destroy: function () {
2127
+ var $this = this.$element;
2128
+
2129
+ if (this.isLoaded) {
2130
+ if (this.isImg && this.isReplaced) {
2131
+ $this.attr('src', this.originalUrl);
2132
+ }
2133
+
2134
+ this.unbuild();
2135
+ $this.removeClass(CLASS_HIDDEN);
2136
+ } else {
2137
+ if (this.isImg) {
2138
+ $this.off(EVENT_LOAD, this.start);
2139
+ } else if (this.$clone) {
2140
+ this.$clone.remove();
2141
+ }
2142
+ }
2143
+
2144
+ $this.removeData(NAMESPACE);
2145
+ },
2146
+
2147
+ /**
2148
+ * Move the canvas with relative offsets
2149
+ *
2150
+ * @param {Number} offsetX
2151
+ * @param {Number} offsetY (optional)
2152
+ */
2153
+ move: function (offsetX, offsetY) {
2154
+ var canvas = this.canvas;
2155
+
2156
+ this.moveTo(
2157
+ isUndefined(offsetX) ? offsetX : canvas.left + num(offsetX),
2158
+ isUndefined(offsetY) ? offsetY : canvas.top + num(offsetY)
2159
+ );
2160
+ },
2161
+
2162
+ /**
2163
+ * Move the canvas to an absolute point
2164
+ *
2165
+ * @param {Number} x
2166
+ * @param {Number} y (optional)
2167
+ */
2168
+ moveTo: function (x, y) {
2169
+ var canvas = this.canvas;
2170
+ var isChanged = false;
2171
+
2172
+ // If "y" is not present, its default value is "x"
2173
+ if (isUndefined(y)) {
2174
+ y = x;
2175
+ }
2176
+
2177
+ x = num(x);
2178
+ y = num(y);
2179
+
2180
+ if (this.isBuilt && !this.isDisabled && this.options.movable) {
2181
+ if (isNumber(x)) {
2182
+ canvas.left = x;
2183
+ isChanged = true;
2184
+ }
2185
+
2186
+ if (isNumber(y)) {
2187
+ canvas.top = y;
2188
+ isChanged = true;
2189
+ }
2190
+
2191
+ if (isChanged) {
2192
+ this.renderCanvas(true);
2193
+ }
2194
+ }
2195
+ },
2196
+
2197
+ /**
2198
+ * Zoom the canvas with a relative ratio
2199
+ *
2200
+ * @param {Number} ratio
2201
+ * @param {jQuery Event} _event (private)
2202
+ */
2203
+ zoom: function (ratio, _event) {
2204
+ var canvas = this.canvas;
2205
+
2206
+ ratio = num(ratio);
2207
+
2208
+ if (ratio < 0) {
2209
+ ratio = 1 / (1 - ratio);
2210
+ } else {
2211
+ ratio = 1 + ratio;
2212
+ }
2213
+
2214
+ this.zoomTo(canvas.width * ratio / canvas.naturalWidth, _event);
2215
+ },
2216
+
2217
+ /**
2218
+ * Zoom the canvas to an absolute ratio
2219
+ *
2220
+ * @param {Number} ratio
2221
+ * @param {jQuery Event} _event (private)
2222
+ */
2223
+ zoomTo: function (ratio, _event) {
2224
+ var options = this.options;
2225
+ var canvas = this.canvas;
2226
+ var width = canvas.width;
2227
+ var height = canvas.height;
2228
+ var naturalWidth = canvas.naturalWidth;
2229
+ var naturalHeight = canvas.naturalHeight;
2230
+ var originalEvent;
2231
+ var newWidth;
2232
+ var newHeight;
2233
+ var offset;
2234
+ var center;
2235
+
2236
+ ratio = num(ratio);
2237
+
2238
+ if (ratio >= 0 && this.isBuilt && !this.isDisabled && options.zoomable) {
2239
+ newWidth = naturalWidth * ratio;
2240
+ newHeight = naturalHeight * ratio;
2241
+
2242
+ if (_event) {
2243
+ originalEvent = _event.originalEvent;
2244
+ }
2245
+
2246
+ if (this.trigger(EVENT_ZOOM, {
2247
+ originalEvent: originalEvent,
2248
+ oldRatio: width / naturalWidth,
2249
+ ratio: newWidth / naturalWidth
2250
+ }).isDefaultPrevented()) {
2251
+ return;
2252
+ }
2253
 
2254
+ if (originalEvent) {
2255
+ offset = this.$cropper.offset();
2256
+ center = originalEvent.touches ? getTouchesCenter(originalEvent.touches) : {
2257
+ pageX: _event.pageX || originalEvent.pageX || 0,
2258
+ pageY: _event.pageY || originalEvent.pageY || 0
2259
+ };
2260
 
2261
+ // Zoom from the triggering point of the event
2262
+ canvas.left -= (newWidth - width) * (
2263
+ ((center.pageX - offset.left) - canvas.left) / width
2264
+ );
2265
+ canvas.top -= (newHeight - height) * (
2266
+ ((center.pageY - offset.top) - canvas.top) / height
2267
+ );
2268
+ } else {
2269
 
2270
+ // Zoom from the center of the canvas
2271
+ canvas.left -= (newWidth - width) / 2;
2272
+ canvas.top -= (newHeight - height) / 2;
2273
+ }
 
 
2274
 
2275
+ canvas.width = newWidth;
2276
+ canvas.height = newHeight;
2277
+ this.renderCanvas(true);
 
2278
  }
2279
  },
2280
 
2281
+ /**
2282
+ * Rotate the canvas with a relative degree
2283
+ *
2284
+ * @param {Number} degree
2285
+ */
2286
+ rotate: function (degree) {
2287
+ this.rotateTo((this.image.rotate || 0) + num(degree));
2288
  },
2289
 
2290
+ /**
2291
+ * Rotate the canvas to an absolute degree
2292
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate()
2293
+ *
2294
+ * @param {Number} degree
2295
+ */
2296
+ rotateTo: function (degree) {
2297
+ degree = num(degree);
2298
 
2299
+ if (isNumber(degree) && this.isBuilt && !this.isDisabled && this.options.rotatable) {
2300
+ this.image.rotate = degree % 360;
2301
+ this.isRotated = true;
2302
  this.renderCanvas(true);
2303
  }
2304
  },
2305
 
2306
+ /**
2307
+ * Scale the image
2308
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale()
2309
+ *
2310
+ * @param {Number} scaleX
2311
+ * @param {Number} scaleY (optional)
2312
+ */
2313
+ scale: function (scaleX, scaleY) {
2314
+ var image = this.image;
2315
+ var isChanged = false;
2316
 
2317
+ // If "scaleY" is not present, its default value is "scaleX"
2318
+ if (isUndefined(scaleY)) {
2319
+ scaleY = scaleX;
2320
+ }
2321
 
2322
+ scaleX = num(scaleX);
2323
+ scaleY = num(scaleY);
 
2324
 
2325
+ if (this.isBuilt && !this.isDisabled && this.options.scalable) {
2326
+ if (isNumber(scaleX)) {
2327
+ image.scaleX = scaleX;
2328
+ isChanged = true;
2329
  }
2330
 
2331
+ if (isNumber(scaleY)) {
2332
+ image.scaleY = scaleY;
2333
+ isChanged = true;
2334
+ }
2335
+
2336
+ if (isChanged) {
2337
+ this.renderImage(true);
2338
+ }
 
2339
  }
2340
  },
2341
 
2342
+ /**
2343
+ * Scale the abscissa of the image
2344
+ *
2345
+ * @param {Number} scaleX
2346
+ */
2347
+ scaleX: function (scaleX) {
2348
+ var scaleY = this.image.scaleY;
2349
 
2350
+ this.scale(scaleX, isNumber(scaleY) ? scaleY : 1);
2351
+ },
2352
 
2353
+ /**
2354
+ * Scale the ordinate of the image
2355
+ *
2356
+ * @param {Number} scaleY
2357
+ */
2358
+ scaleY: function (scaleY) {
2359
+ var scaleX = this.image.scaleX;
2360
+
2361
+ this.scale(isNumber(scaleX) ? scaleX : 1, scaleY);
2362
  },
2363
 
2364
+ /**
2365
+ * Get the cropped area position and size data (base on the original image)
2366
+ *
2367
+ * @param {Boolean} isRounded (optional)
2368
+ * @return {Object} data
2369
+ */
2370
+ getData: function (isRounded) {
2371
+ var options = this.options;
2372
+ var image = this.image;
2373
+ var canvas = this.canvas;
2374
+ var cropBox = this.cropBox;
2375
+ var ratio;
2376
+ var data;
2377
 
2378
+ if (this.isBuilt && this.isCropped) {
2379
  data = {
2380
  x: cropBox.left - canvas.left,
2381
  y: cropBox.top - canvas.top,
2387
 
2388
  $.each(data, function (i, n) {
2389
  n = n / ratio;
2390
+ data[i] = isRounded ? round(n) : n;
2391
  });
2392
 
2393
  } else {
2399
  };
2400
  }
2401
 
2402
+ if (options.rotatable) {
2403
+ data.rotate = image.rotate || 0;
2404
+ }
2405
+
2406
+ if (options.scalable) {
2407
+ data.scaleX = image.scaleX || 1;
2408
+ data.scaleY = image.scaleY || 1;
2409
+ }
2410
 
2411
  return data;
2412
  },
2413
 
2414
+ /**
2415
+ * Set the cropped area position and size with new data
2416
+ *
2417
+ * @param {Object} data
2418
+ */
2419
  setData: function (data) {
2420
+ var options = this.options;
2421
+ var image = this.image;
2422
+ var canvas = this.canvas;
2423
+ var cropBoxData = {};
2424
+ var isRotated;
2425
+ var isScaled;
2426
+ var ratio;
2427
+
2428
+ if ($.isFunction(data)) {
2429
+ data = data.call(this.element);
2430
+ }
2431
+
2432
+ if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
2433
+ if (options.rotatable) {
2434
+ if (isNumber(data.rotate) && data.rotate !== image.rotate) {
2435
+ image.rotate = data.rotate;
2436
+ this.isRotated = isRotated = true;
2437
+ }
2438
+ }
2439
+
2440
+ if (options.scalable) {
2441
+ if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) {
2442
+ image.scaleX = data.scaleX;
2443
+ isScaled = true;
2444
+ }
2445
+
2446
+ if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) {
2447
+ image.scaleY = data.scaleY;
2448
+ isScaled = true;
2449
+ }
2450
+ }
2451
+
2452
+ if (isRotated) {
2453
+ this.renderCanvas();
2454
+ } else if (isScaled) {
2455
+ this.renderImage();
2456
  }
2457
 
2458
  ratio = image.width / image.naturalWidth;
2477
  }
2478
  },
2479
 
2480
+ /**
2481
+ * Get the container size data
2482
+ *
2483
+ * @return {Object} data
2484
+ */
2485
  getContainerData: function () {
2486
+ return this.isBuilt ? this.container : {};
2487
  },
2488
 
2489
+ /**
2490
+ * Get the image position and size data
2491
+ *
2492
+ * @return {Object} data
2493
+ */
2494
  getImageData: function () {
2495
+ return this.isLoaded ? this.image : {};
2496
  },
2497
 
2498
+ /**
2499
+ * Get the canvas position and size data
2500
+ *
2501
+ * @return {Object} data
2502
+ */
2503
  getCanvasData: function () {
2504
+ var canvas = this.canvas;
2505
+ var data = {};
2506
+
2507
+ if (this.isBuilt) {
2508
+ $.each([
2509
+ 'left',
2510
+ 'top',
2511
+ 'width',
2512
+ 'height',
2513
+ 'naturalWidth',
2514
+ 'naturalHeight'
2515
+ ], function (i, n) {
2516
+ data[n] = canvas[n];
2517
+ });
2518
  }
2519
 
2520
+ return data;
2521
  },
2522
 
2523
+ /**
2524
+ * Set the canvas position and size with new data
2525
+ *
2526
+ * @param {Object} data
2527
+ */
2528
  setCanvasData: function (data) {
2529
+ var canvas = this.canvas;
2530
+ var aspectRatio = canvas.aspectRatio;
2531
+
2532
+ if ($.isFunction(data)) {
2533
+ data = data.call(this.$element);
2534
+ }
2535
 
2536
+ if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
2537
  if (isNumber(data.left)) {
2538
  canvas.left = data.left;
2539
  }
2554
  }
2555
  },
2556
 
2557
+ /**
2558
+ * Get the crop box position and size data
2559
+ *
2560
+ * @return {Object} data
2561
+ */
2562
  getCropBoxData: function () {
2563
+ var cropBox = this.cropBox;
2564
+ var data;
2565
 
2566
+ if (this.isBuilt && this.isCropped) {
2567
  data = {
2568
  left: cropBox.left,
2569
  top: cropBox.top,
2575
  return data || {};
2576
  },
2577
 
2578
+ /**
2579
+ * Set the crop box position and size with new data
2580
+ *
2581
+ * @param {Object} data
2582
+ */
2583
  setCropBoxData: function (data) {
2584
+ var cropBox = this.cropBox;
2585
+ var aspectRatio = this.options.aspectRatio;
2586
+ var isWidthChanged;
2587
+ var isHeightChanged;
2588
+
2589
+ if ($.isFunction(data)) {
2590
+ data = data.call(this.$element);
2591
+ }
2592
 
2593
+ if (this.isBuilt && this.isCropped && !this.isDisabled && $.isPlainObject(data)) {
2594
 
2595
  if (isNumber(data.left)) {
2596
  cropBox.left = data.left;
2601
  }
2602
 
2603
  if (isNumber(data.width)) {
2604
+ isWidthChanged = true;
2605
  cropBox.width = data.width;
2606
  }
2607
 
2608
  if (isNumber(data.height)) {
2609
+ isHeightChanged = true;
2610
  cropBox.height = data.height;
2611
  }
2612
 
2613
  if (aspectRatio) {
2614
+ if (isWidthChanged) {
2615
  cropBox.height = cropBox.width / aspectRatio;
2616
+ } else if (isHeightChanged) {
2617
  cropBox.width = cropBox.height * aspectRatio;
2618
  }
2619
  }
2622
  }
2623
  },
2624
 
2625
+ /**
2626
+ * Get a canvas drawn the cropped image
2627
+ *
2628
+ * @param {Object} options (optional)
2629
+ * @return {HTMLCanvasElement} canvas
2630
+ */
2631
  getCroppedCanvas: function (options) {
2632
+ var originalWidth;
2633
+ var originalHeight;
2634
+ var canvasWidth;
2635
+ var canvasHeight;
2636
+ var scaledWidth;
2637
+ var scaledHeight;
2638
+ var scaledRatio;
2639
+ var aspectRatio;
2640
+ var canvas;
2641
+ var context;
2642
+ var data;
2643
+
2644
+ if (!this.isBuilt || !this.isCropped || !SUPPORT_CANVAS) {
2645
  return;
2646
  }
2647
 
2667
  }
2668
  }
2669
 
2670
+ // The canvas element will use `Math.floor` on a float number, so floor first
2671
+ canvasWidth = floor(scaledWidth || originalWidth);
2672
+ canvasHeight = floor(scaledHeight || originalHeight);
2673
 
2674
  canvas = $('<canvas>')[0];
2675
  canvas.width = canvasWidth;
2683
 
2684
  // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
2685
  context.drawImage.apply(context, (function () {
2686
+ var source = getSourceCanvas(this.$clone[0], this.image);
2687
+ var sourceWidth = source.width;
2688
+ var sourceHeight = source.height;
2689
+ var args = [source];
2690
+
2691
+ // Source canvas
2692
+ var srcX = data.x;
2693
+ var srcY = data.y;
2694
+ var srcWidth;
2695
+ var srcHeight;
2696
+
2697
+ // Destination canvas
2698
+ var dstX;
2699
+ var dstY;
2700
+ var dstWidth;
2701
+ var dstHeight;
2702
 
2703
  if (srcX <= -originalWidth || srcX > sourceWidth) {
2704
  srcX = srcWidth = dstX = dstWidth = 0;
2722
  srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
2723
  }
2724
 
2725
+ // All the numerical parameters should be integer for `drawImage` (#476)
2726
+ args.push(floor(srcX), floor(srcY), floor(srcWidth), floor(srcHeight));
2727
 
2728
  // Scale destination sizes
2729
  if (scaledRatio) {
2735
 
2736
  // Avoid "IndexSizeError" in IE and Firefox
2737
  if (dstWidth > 0 && dstHeight > 0) {
2738
+ args.push(floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));
2739
  }
2740
 
2741
  return args;
2744
  return canvas;
2745
  },
2746
 
2747
+ /**
2748
+ * Change the aspect ratio of the crop box
2749
+ *
2750
+ * @param {Number} aspectRatio
2751
+ */
2752
  setAspectRatio: function (aspectRatio) {
2753
  var options = this.options;
2754
 
2755
+ if (!this.isDisabled && !isUndefined(aspectRatio)) {
2756
+
2757
+ // 0 -> NaN
2758
+ options.aspectRatio = max(0, aspectRatio) || NaN;
2759
 
2760
+ if (this.isBuilt) {
2761
  this.initCropBox();
2762
 
2763
+ if (this.isCropped) {
2764
  this.renderCropBox();
2765
  }
2766
  }
2767
  }
2768
  },
2769
 
2770
+ /**
2771
+ * Change the drag mode
2772
+ *
2773
+ * @param {String} mode (optional)
2774
+ */
2775
  setDragMode: function (mode) {
2776
+ var options = this.options;
2777
+ var croppable;
2778
+ var movable;
2779
 
2780
+ if (this.isLoaded && !this.isDisabled) {
2781
+ croppable = mode === ACTION_CROP;
2782
+ movable = options.movable && mode === ACTION_MOVE;
2783
+ mode = (croppable || movable) ? mode : ACTION_NONE;
2784
 
2785
+ this.$dragBox.
2786
+ data(DATA_ACTION, mode).
2787
+ toggleClass(CLASS_CROP, croppable).
2788
+ toggleClass(CLASS_MOVE, movable);
2789
 
2790
  if (!options.cropBoxMovable) {
2791
+
2792
  // Sync drag mode to crop box when it is not movable(#300)
2793
+ this.$face.
2794
+ data(DATA_ACTION, mode).
2795
+ toggleClass(CLASS_CROP, croppable).
2796
+ toggleClass(CLASS_MOVE, movable);
2797
  }
2798
  }
2799
  }
2800
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2801
 
2802
+ Cropper.DEFAULTS = {
 
 
 
 
 
 
 
 
 
2803
 
2804
+ // Define the view mode of the cropper
2805
+ viewMode: 0, // 0, 1, 2, 3
 
 
 
 
 
 
 
 
 
2806
 
2807
+ // Define the dragging mode of the cropper
2808
+ dragMode: 'crop', // 'crop', 'move' or 'none'
2809
 
2810
+ // Define the aspect ratio of the crop box
2811
+ aspectRatio: NaN,
 
 
 
 
2812
 
2813
+ // An object with the previous cropping result data
2814
+ data: null,
 
 
 
 
 
 
 
 
 
 
 
 
 
2815
 
2816
+ // A jQuery selector for adding extra containers to preview
2817
+ preview: '',
 
 
 
 
 
 
2818
 
2819
+ // Re-render the cropper when resize the window
2820
+ responsive: true,
 
 
 
 
 
 
 
 
 
2821
 
2822
+ // Restore the cropped area after resize the window
2823
+ restore: true,
2824
 
2825
+ // Check if the current image is a cross-origin image
2826
+ checkCrossOrigin: true,
 
 
 
 
2827
 
2828
+ // Check the current image's Exif Orientation information
2829
+ checkOrientation: true,
 
 
 
 
 
 
 
 
 
 
2830
 
2831
+ // Show the black modal
2832
+ modal: true,
 
 
 
 
 
 
2833
 
2834
+ // Show the dashed lines for guiding
2835
+ guides: true,
 
 
 
 
 
 
 
 
 
2836
 
2837
+ // Show the center indicator for guiding
2838
+ center: true,
2839
 
2840
+ // Show the white modal to highlight the crop box
2841
+ highlight: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2842
 
2843
+ // Show the grid background
2844
+ background: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2845
 
2846
+ // Enable to crop the image automatically when initialize
2847
+ autoCrop: true,
 
 
 
 
2848
 
2849
+ // Define the percentage of automatic cropping area when initializes
2850
+ autoCropArea: 0.8,
2851
 
2852
+ // Enable to move the image
2853
+ movable: true,
2854
 
2855
+ // Enable to rotate the image
2856
+ rotatable: true,
 
 
 
 
2857
 
2858
+ // Enable to scale the image
2859
+ scalable: true,
2860
 
2861
+ // Enable to zoom the image
2862
+ zoomable: true,
 
 
2863
 
2864
+ // Enable to zoom the image by dragging touch
2865
+ zoomOnTouch: true,
2866
 
2867
+ // Enable to zoom the image by wheeling mouse
2868
+ zoomOnWheel: true,
 
 
2869
 
2870
+ // Define zoom ratio when zoom the image by wheeling mouse
2871
+ wheelZoomRatio: 0.1,
 
2872
 
2873
+ // Enable to move the crop box
2874
+ cropBoxMovable: true,
 
2875
 
2876
+ // Enable to resize the crop box
2877
+ cropBoxResizable: true,
 
2878
 
2879
+ // Toggle drag mode between "crop" and "move" when click twice on the cropper
2880
+ toggleDragModeOnDblclick: true,
 
2881
 
2882
+ // Size limitation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2883
  minCanvasWidth: 0,
2884
  minCanvasHeight: 0,
2885
  minCropBoxWidth: 0,
2887
  minContainerWidth: 200,
2888
  minContainerHeight: 100,
2889
 
2890
+ // Shortcuts of events
2891
+ build: null,
2892
+ built: null,
2893
+ cropstart: null,
2894
+ cropmove: null,
2895
+ cropend: null,
2896
+ crop: null,
2897
+ zoom: null
 
2898
  };
2899
 
2900
  Cropper.setDefaults = function (options) {
2901
  $.extend(Cropper.DEFAULTS, options);
2902
  };
2903
 
2904
+ Cropper.TEMPLATE = (
2905
+ '<div class="cropper-container">' +
2906
+ '<div class="cropper-wrap-box">' +
2907
+ '<div class="cropper-canvas"></div>' +
2908
+ '</div>' +
2909
+ '<div class="cropper-drag-box"></div>' +
2910
+ '<div class="cropper-crop-box">' +
2911
+ '<span class="cropper-view-box"></span>' +
2912
+ '<span class="cropper-dashed dashed-h"></span>' +
2913
+ '<span class="cropper-dashed dashed-v"></span>' +
2914
+ '<span class="cropper-center"></span>' +
2915
+ '<span class="cropper-face"></span>' +
2916
+ '<span class="cropper-line line-e" data-action="e"></span>' +
2917
+ '<span class="cropper-line line-n" data-action="n"></span>' +
2918
+ '<span class="cropper-line line-w" data-action="w"></span>' +
2919
+ '<span class="cropper-line line-s" data-action="s"></span>' +
2920
+ '<span class="cropper-point point-e" data-action="e"></span>' +
2921
+ '<span class="cropper-point point-n" data-action="n"></span>' +
2922
+ '<span class="cropper-point point-w" data-action="w"></span>' +
2923
+ '<span class="cropper-point point-s" data-action="s"></span>' +
2924
+ '<span class="cropper-point point-ne" data-action="ne"></span>' +
2925
+ '<span class="cropper-point point-nw" data-action="nw"></span>' +
2926
+ '<span class="cropper-point point-sw" data-action="sw"></span>' +
2927
+ '<span class="cropper-point point-se" data-action="se"></span>' +
2928
+ '</div>' +
2929
+ '</div>'
2930
+ );
 
 
 
 
 
2931
 
2932
  // Save the other cropper
2933
  Cropper.other = $.fn.cropper;
2934
 
2935
  // Register as jQuery plugin
2936
+ $.fn.cropper = function (option) {
2937
+ var args = toArray(arguments, 1);
2938
+ var result;
2939
 
2940
  this.each(function () {
2941
+ var $this = $(this);
2942
+ var data = $this.data(NAMESPACE);
2943
+ var options;
2944
+ var fn;
2945
 
2946
  if (!data) {
2947
+ if (/destroy/.test(option)) {
2948
+ return;
2949
+ }
2950
+
2951
+ options = $.extend({}, $this.data(), $.isPlainObject(option) && option);
2952
+ $this.data(NAMESPACE, (data = new Cropper(this, options)));
2953
  }
2954
 
2955
+ if (typeof option === 'string' && $.isFunction(fn = data[option])) {
2956
  result = fn.apply(data, args);
2957
  }
2958
  });
admin/js/cropper/cropper.min.css CHANGED
@@ -1,9 +1,9 @@
1
  /*!
2
- * Cropper v0.10.0
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
- * Copyright (c) 2014-2015 Fengyuan Chen and other contributors
6
  * Released under the MIT license
7
  *
8
- * Date: 2015-06-08T14:57:26.353Z
9
- */.cropper-container{position:relative;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.cropper-container img{display:block;width:100%;min-width:0!important;max-width:none!important;height:100%;min-height:0!important;max-height:none!important;image-orientation:0deg!important}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-drag-box{background-color:#fff;filter:alpha(opacity=0);opacity:0}.cropper-modal{background-color:#000;filter:alpha(opacity=50);opacity:.5}.cropper-view-box{display:block;width:100%;height:100%;overflow:hidden;outline:1px solid #69f;outline-color:rgba(102,153,255,.75)}.cropper-dashed{position:absolute;display:block;filter:alpha(opacity=50);border:0 dashed #fff;opacity:.5}.cropper-dashed.dashed-h{top:33.33333333%;left:0;width:100%;height:33.33333333%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.33333333%;width:33.33333333%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;filter:alpha(opacity=10);opacity:.1}.cropper-face{top:0;left:0;background-color:#fff}.cropper-line{background-color:#69f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;background-color:#69f;filter:alpha(opacity=75);opacity:.75}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;filter:alpha(opacity=100);opacity:1}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:" ";background-color:#69f;filter:alpha(opacity=0);opacity:0}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;filter:alpha(opacity=75);opacity:.75}}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-invisible{filter:alpha(opacity=0);opacity:0}.cropper-hide{position:fixed;top:0;left:0;z-index:-1;width:auto!important;min-width:0!important;max-width:none!important;height:auto!important;min-height:0!important;max-height:none!important;filter:alpha(opacity=0);opacity:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
1
  /*!
2
+ * Cropper v2.2.5
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
+ * Copyright (c) 2014-2016 Fengyuan Chen and contributors
6
  * Released under the MIT license
7
  *
8
+ * Date: 2016-01-18T05:42:29.639Z
9
+ */.cropper-container{font-size:0;line-height:0;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;direction:ltr!important;-ms-touch-action:none;touch-action:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.cropper-container img{display:block;width:100%;min-width:0!important;max-width:none!important;height:100%;min-height:0!important;max-height:none!important;image-orientation:0deg!important}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-wrap-box{overflow:hidden}.cropper-drag-box{opacity:0;background-color:#fff;filter:alpha(opacity=0)}.cropper-dashed,.cropper-modal{opacity:.5;filter:alpha(opacity=50)}.cropper-modal{background-color:#000}.cropper-view-box{display:block;overflow:hidden;width:100%;height:100%;outline:#39f solid 1px;outline-color:rgba(51,153,255,.75)}.cropper-dashed{position:absolute;display:block;border:0 dashed #eee}.cropper-dashed.dashed-h{top:33.33333%;left:0;width:100%;height:33.33333%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.33333%;width:33.33333%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-center{position:absolute;top:50%;left:50%;display:block;width:0;height:0;opacity:.75;filter:alpha(opacity=75)}.cropper-center:after,.cropper-center:before{position:absolute;display:block;content:' ';background-color:#eee}.cropper-center:before{top:0;left:-3px;width:7px;height:1px}.cropper-center:after{top:-3px;left:0;width:1px;height:7px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;opacity:.1;filter:alpha(opacity=10)}.cropper-face{top:0;left:0;background-color:#fff}.cropper-line,.cropper-point{background-color:#39f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;opacity:.75;filter:alpha(opacity=75)}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;opacity:1;filter:alpha(opacity=100)}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:' ';opacity:0;background-color:#39f;filter:alpha(opacity=0)}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;opacity:.75;filter:alpha(opacity=75)}}.cropper-invisible{opacity:0;filter:alpha(opacity=0)}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-hide{position:absolute;display:block;width:0;height:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
admin/js/cropper/cropper.min.js CHANGED
@@ -1,10 +1,10 @@
1
  /*!
2
- * Cropper v0.10.0
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
- * Copyright (c) 2014-2015 Fengyuan Chen and other contributors
6
  * Released under the MIT license
7
  *
8
- * Date: 2015-06-08T14:57:26.353Z
9
  */
10
- !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){"use strict";function b(a){return"number"==typeof a&&!isNaN(a)}function c(a){return"undefined"==typeof a}function d(a,c){var d=[];return b(c)&&d.push(c),d.slice.apply(a,d)}function e(a,b){var c=d(arguments,2);return function(){return a.apply(b,c.concat(d(arguments)))}}function f(a){var b=a.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return b&&(b[1]!==n.protocol||b[2]!==n.hostname||b[3]!==n.port)}function g(a){var b="timestamp="+(new Date).getTime();return a+(-1===a.indexOf("?")?"?":"&")+b}function h(a){return a?"rotate("+a+"deg)":"none"}function i(a,b){var c,d,e=R(a.degree)%180,f=(e>90?180-e:e)*Math.PI/180,g=S(f),h=T(f),i=a.width,j=a.height,k=a.aspectRatio;return b?(c=i/(h+g/k),d=c/k):(c=i*h+j*g,d=i*g+j*h),{width:c,height:d}}function j(b,c){var d=a("<canvas>")[0],e=d.getContext("2d"),f=c.naturalWidth,g=c.naturalHeight,h=c.rotate,j=i({width:f,height:g,degree:h});return h?(d.width=j.width,d.height=j.height,e.save(),e.translate(j.width/2,j.height/2),e.rotate(h*Math.PI/180),e.drawImage(b,-f/2,-g/2,f,g),e.restore()):(d.width=f,d.height=g,e.drawImage(b,0,0,f,g)),d}function k(b,c){this.$element=a(b),this.options=a.extend({},k.DEFAULTS,a.isPlainObject(c)&&c),this.ready=!1,this.built=!1,this.rotated=!1,this.cropped=!1,this.disabled=!1,this.canvas=null,this.cropBox=null,this.load()}var l=a(window),m=a(document),n=window.location,o=".cropper",p="preview"+o,q=/^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,r="cropper-modal",s="cropper-hide",t="cropper-hidden",u="cropper-invisible",v="cropper-move",w="cropper-crop",x="cropper-disabled",y="cropper-bg",z="mousedown touchstart",A="mousemove touchmove",B="mouseup mouseleave touchend touchleave touchcancel",C="wheel mousewheel DOMMouseScroll",D="dblclick",E="resize"+o,F="build"+o,G="built"+o,H="dragstart"+o,I="dragmove"+o,J="dragend"+o,K="zoomin"+o,L="zoomout"+o,M="change"+o,N=a.isFunction(a("<canvas>")[0].getContext),O=Math.sqrt,P=Math.min,Q=Math.max,R=Math.abs,S=Math.sin,T=Math.cos,U=parseFloat,V={};V.load=function(b){var c,d,e,h,i=this.options,j=this.$element;if(!b)if(j.is("img")){if(!j.attr("src"))return;b=j.prop("src")}else j.is("canvas")&&N&&(b=j[0].toDataURL());b&&(e=a.Event(F),j.one(F,i.build).trigger(e),e.isDefaultPrevented()||(i.checkImageOrigin&&f(b)&&(c=' crossOrigin="anonymous"',j.prop("crossOrigin")||(d=g(b))),this.$clone=h=a("<img"+(c||"")+' src="'+(d||b)+'">'),h.one("load",a.proxy(function(){var a=h[0],c=a.naturalWidth||a.width,d=a.naturalHeight||a.height;this.image={naturalWidth:c,naturalHeight:d,aspectRatio:c/d,rotate:0},this.url=b,this.ready=!0,this.build()},this)).one("error",function(){h.remove()}),h.addClass(s).insertAfter(j)))},V.build=function(){var b,c,d,e=this.$element,f=this.$clone,g=this.options;this.ready&&(this.built&&this.unbuild(),this.$cropper=b=a(k.TEMPLATE),e.addClass(t),f.removeClass(s),this.$container=e.parent().append(b),this.$canvas=b.find(".cropper-canvas").append(f),this.$dragBox=b.find(".cropper-drag-box"),this.$cropBox=c=b.find(".cropper-crop-box"),this.$viewBox=b.find(".cropper-view-box"),this.$face=d=c.find(".cropper-face"),this.addListeners(),this.initPreview(),g.aspectRatio=U(g.aspectRatio)||NaN,g.autoCrop?(this.cropped=!0,g.modal&&this.$dragBox.addClass(r)):c.addClass(t),g.background&&b.addClass(y),g.highlight||d.addClass(u),g.guides||c.find(".cropper-dashed").addClass(t),g.cropBoxMovable&&d.addClass(v).data("drag","all"),g.cropBoxResizable||c.find(".cropper-line, .cropper-point").addClass(t),this.setDragMode(g.dragCrop?"crop":g.movable?"move":"none"),this.built=!0,this.render(),this.setData(g.data),e.one(G,g.built).trigger(G))},V.unbuild=function(){this.built&&(this.built=!1,this.initialImage=null,this.initialCanvas=null,this.initialCropBox=null,this.container=null,this.canvas=null,this.cropBox=null,this.removeListeners(),this.resetPreview(),this.$preview=null,this.$viewBox=null,this.$cropBox=null,this.$dragBox=null,this.$canvas=null,this.$container=null,this.$cropper.remove(),this.$cropper=null)},a.extend(V,{render:function(){this.initContainer(),this.initCanvas(),this.initCropBox(),this.renderCanvas(),this.cropped&&this.renderCropBox()},initContainer:function(){var a=this.$element,b=this.$container,c=this.$cropper,d=this.options;c.addClass(t),a.removeClass(t),c.css(this.container={width:Q(b.width(),U(d.minContainerWidth)||200),height:Q(b.height(),U(d.minContainerHeight)||100)}),a.addClass(t),c.removeClass(t)},initCanvas:function(){var b=this.container,c=b.width,d=b.height,e=this.image,f=e.aspectRatio,g={aspectRatio:f,width:c,height:d};d*f>c?g.height=c/f:g.width=d*f,g.oldLeft=g.left=(c-g.width)/2,g.oldTop=g.top=(d-g.height)/2,this.canvas=g,this.limitCanvas(!0,!0),this.initialImage=a.extend({},e),this.initialCanvas=a.extend({},g)},limitCanvas:function(b,c){var d,e,f=this.options,g=f.strict,h=this.container,i=h.width,j=h.height,k=this.canvas,l=k.aspectRatio,m=this.cropBox,n=this.cropped&&m,o=this.initialCanvas||k,p=o.width,q=o.height;b&&(d=U(f.minCanvasWidth)||0,e=U(f.minCanvasHeight)||0,d?(g&&(d=Q(n?m.width:p,d)),e=d/l):e?(g&&(e=Q(n?m.height:q,e)),d=e*l):g&&(n?(d=m.width,e=m.height,e*l>d?d=e*l:e=d/l):(d=p,e=q)),a.extend(k,{minWidth:d,minHeight:e,maxWidth:1/0,maxHeight:1/0})),c&&(g?n?(k.minLeft=P(m.left,m.left+m.width-k.width),k.minTop=P(m.top,m.top+m.height-k.height),k.maxLeft=m.left,k.maxTop=m.top):(k.minLeft=P(0,i-k.width),k.minTop=P(0,j-k.height),k.maxLeft=Q(0,i-k.width),k.maxTop=Q(0,j-k.height)):(k.minLeft=-k.width,k.minTop=-k.height,k.maxLeft=i,k.maxTop=j))},renderCanvas:function(a){var b,c,d=this.options,e=this.canvas,f=this.image;this.rotated&&(this.rotated=!1,c=i({width:f.width,height:f.height,degree:f.rotate}),b=c.width/c.height,b!==e.aspectRatio&&(e.left-=(c.width-e.width)/2,e.top-=(c.height-e.height)/2,e.width=c.width,e.height=c.height,e.aspectRatio=b,this.limitCanvas(!0,!1))),(e.width>e.maxWidth||e.width<e.minWidth)&&(e.left=e.oldLeft),(e.height>e.maxHeight||e.height<e.minHeight)&&(e.top=e.oldTop),e.width=P(Q(e.width,e.minWidth),e.maxWidth),e.height=P(Q(e.height,e.minHeight),e.maxHeight),this.limitCanvas(!1,!0),e.oldLeft=e.left=P(Q(e.left,e.minLeft),e.maxLeft),e.oldTop=e.top=P(Q(e.top,e.minTop),e.maxTop),this.$canvas.css({width:e.width,height:e.height,left:e.left,top:e.top}),this.renderImage(),this.cropped&&d.strict&&this.limitCropBox(!0,!0),a&&this.output()},renderImage:function(){var b,c=this.canvas,d=this.image;d.rotate&&(b=i({width:c.width,height:c.height,degree:d.rotate,aspectRatio:d.aspectRatio},!0)),a.extend(d,b?{width:b.width,height:b.height,left:(c.width-b.width)/2,top:(c.height-b.height)/2}:{width:c.width,height:c.height,left:0,top:0}),this.$clone.css({width:d.width,height:d.height,marginLeft:d.left,marginTop:d.top,transform:h(d.rotate)})},initCropBox:function(){var b=this.options,c=this.canvas,d=b.aspectRatio,e=U(b.autoCropArea)||.8,f={width:c.width,height:c.height};d&&(c.height*d>c.width?f.height=f.width/d:f.width=f.height*d),this.cropBox=f,this.limitCropBox(!0,!0),f.width=P(Q(f.width,f.minWidth),f.maxWidth),f.height=P(Q(f.height,f.minHeight),f.maxHeight),f.width=Q(f.minWidth,f.width*e),f.height=Q(f.minHeight,f.height*e),f.oldLeft=f.left=c.left+(c.width-f.width)/2,f.oldTop=f.top=c.top+(c.height-f.height)/2,this.initialCropBox=a.extend({},f)},limitCropBox:function(a,b){var c,d,e=this.options,f=e.strict,g=this.container,h=g.width,i=g.height,j=this.canvas,k=this.cropBox,l=e.aspectRatio;a&&(c=U(e.minCropBoxWidth)||0,d=U(e.minCropBoxHeight)||0,k.minWidth=P(h,c),k.minHeight=P(i,d),k.maxWidth=P(h,f?j.width:h),k.maxHeight=P(i,f?j.height:i),l&&(k.maxHeight*l>k.maxWidth?(k.minHeight=k.minWidth/l,k.maxHeight=k.maxWidth/l):(k.minWidth=k.minHeight*l,k.maxWidth=k.maxHeight*l)),k.minWidth=P(k.maxWidth,k.minWidth),k.minHeight=P(k.maxHeight,k.minHeight)),b&&(f?(k.minLeft=Q(0,j.left),k.minTop=Q(0,j.top),k.maxLeft=P(h,j.left+j.width)-k.width,k.maxTop=P(i,j.top+j.height)-k.height):(k.minLeft=0,k.minTop=0,k.maxLeft=h-k.width,k.maxTop=i-k.height))},renderCropBox:function(){var a=this.options,b=this.container,c=b.width,d=b.height,e=this.cropBox;(e.width>e.maxWidth||e.width<e.minWidth)&&(e.left=e.oldLeft),(e.height>e.maxHeight||e.height<e.minHeight)&&(e.top=e.oldTop),e.width=P(Q(e.width,e.minWidth),e.maxWidth),e.height=P(Q(e.height,e.minHeight),e.maxHeight),this.limitCropBox(!1,!0),e.oldLeft=e.left=P(Q(e.left,e.minLeft),e.maxLeft),e.oldTop=e.top=P(Q(e.top,e.minTop),e.maxTop),a.movable&&a.cropBoxMovable&&this.$face.data("drag",e.width===c&&e.height===d?"move":"all"),this.$cropBox.css({width:e.width,height:e.height,left:e.left,top:e.top}),this.cropped&&a.strict&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){var a=this.options,b=this.$element;this.preview(),a.crop&&a.crop.call(b,this.getData()),b.trigger(M)}}),V.initPreview=function(){var b=this.url;this.$preview=a(this.options.preview),this.$viewBox.html('<img src="'+b+'">'),this.$preview.each(function(){var c=a(this);c.data(p,{width:c.width(),height:c.height(),original:c.html()}).html('<img src="'+b+'" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation: 0deg!important">')})},V.resetPreview=function(){this.$preview.each(function(){var b=a(this);b.html(b.data(p).original).removeData(p)})},V.preview=function(){var b=this.image,c=this.canvas,d=this.cropBox,e=b.width,f=b.height,g=d.left-c.left-b.left,i=d.top-c.top-b.top,j=b.rotate;this.cropped&&!this.disabled&&(this.$viewBox.find("img").css({width:e,height:f,marginLeft:-g,marginTop:-i,transform:h(j)}),this.$preview.each(function(){var b=a(this),c=b.data(p),k=c.width/d.width,l=c.width,m=d.height*k;m>c.height&&(k=c.height/d.height,l=d.width*k,m=c.height),b.width(l).height(m).find("img").css({width:e*k,height:f*k,marginLeft:-g*k,marginTop:-i*k,transform:h(j)})}))},V.addListeners=function(){var b=this.options,c=this.$element,d=this.$cropper;a.isFunction(b.dragstart)&&c.on(H,b.dragstart),a.isFunction(b.dragmove)&&c.on(I,b.dragmove),a.isFunction(b.dragend)&&c.on(J,b.dragend),a.isFunction(b.zoomin)&&c.on(K,b.zoomin),a.isFunction(b.zoomout)&&c.on(L,b.zoomout),a.isFunction(b.change)&&c.on(M,b.change),d.on(z,a.proxy(this.dragstart,this)),b.zoomable&&b.mouseWheelZoom&&d.on(C,a.proxy(this.wheel,this)),b.doubleClickToggle&&d.on(D,a.proxy(this.dblclick,this)),m.on(A,this._dragmove=e(this.dragmove,this)).on(B,this._dragend=e(this.dragend,this)),b.responsive&&l.on(E,this._resize=e(this.resize,this))},V.removeListeners=function(){var b=this.options,c=this.$element,d=this.$cropper;a.isFunction(b.dragstart)&&c.off(H,b.dragstart),a.isFunction(b.dragmove)&&c.off(I,b.dragmove),a.isFunction(b.dragend)&&c.off(J,b.dragend),a.isFunction(b.zoomin)&&c.off(K,b.zoomin),a.isFunction(b.zoomout)&&c.off(L,b.zoomout),a.isFunction(b.change)&&c.off(M,b.change),d.off(z,this.dragstart),b.zoomable&&b.mouseWheelZoom&&d.off(C,this.wheel),b.doubleClickToggle&&d.off(D,this.dblclick),m.off(A,this._dragmove).off(B,this._dragend),b.responsive&&l.off(E,this._resize)},a.extend(V,{resize:function(){var b,c,d,e=this.$container,f=this.container;!this.disabled&&f&&(d=e.width()/f.width,(1!==d||e.height()!==f.height)&&(b=this.getCanvasData(),c=this.getCropBoxData(),this.render(),this.setCanvasData(a.each(b,function(a,c){b[a]=c*d})),this.setCropBoxData(a.each(c,function(a,b){c[a]=b*d}))))},dblclick:function(){this.disabled||this.setDragMode(this.$dragBox.hasClass(w)?"move":"crop")},wheel:function(a){var b=a.originalEvent,c=1;this.disabled||(a.preventDefault(),b.deltaY?c=b.deltaY>0?1:-1:b.wheelDelta?c=-b.wheelDelta/120:b.detail&&(c=b.detail>0?1:-1),this.zoom(.1*-c))},dragstart:function(b){var c,d,e,f=this.options,g=b.originalEvent,h=g&&g.touches,i=b;if(!this.disabled){if(h){if(e=h.length,e>1){if(!f.zoomable||!f.touchDragZoom||2!==e)return;i=h[1],this.startX2=i.pageX,this.startY2=i.pageY,c="zoom"}i=h[0]}if(c=c||a(i.target).data("drag"),q.test(c)){if(b.preventDefault(),d=a.Event(H,{originalEvent:g,dragType:c}),this.$element.trigger(d),d.isDefaultPrevented())return;this.dragType=c,this.cropping=!1,this.startX=i.pageX,this.startY=i.pageY,"crop"===c&&(this.cropping=!0,this.$dragBox.addClass(r))}}},dragmove:function(b){var c,d,e=this.options,f=b.originalEvent,g=f&&f.touches,h=b,i=this.dragType;if(!this.disabled){if(g){if(d=g.length,d>1){if(!e.zoomable||!e.touchDragZoom||2!==d)return;h=g[1],this.endX2=h.pageX,this.endY2=h.pageY}h=g[0]}if(i){if(b.preventDefault(),c=a.Event(I,{originalEvent:f,dragType:i}),this.$element.trigger(c),c.isDefaultPrevented())return;this.endX=h.pageX,this.endY=h.pageY,this.change(h.shiftKey)}}},dragend:function(b){var c,d=this.dragType;if(!this.disabled&&d){if(b.preventDefault(),c=a.Event(J,{originalEvent:b.originalEvent,dragType:d}),this.$element.trigger(c),c.isDefaultPrevented())return;this.cropping&&(this.cropping=!1,this.$dragBox.toggleClass(r,this.cropped&&this.options.modal)),this.dragType=""}}}),a.extend(V,{crop:function(){this.built&&!this.disabled&&(this.cropped||(this.cropped=!0,this.limitCropBox(!0,!0),this.options.modal&&this.$dragBox.addClass(r),this.$cropBox.removeClass(t)),this.setCropBoxData(this.initialCropBox))},reset:function(){this.built&&!this.disabled&&(this.image=a.extend({},this.initialImage),this.canvas=a.extend({},this.initialCanvas),this.cropBox=a.extend({},this.initialCropBox),this.renderCanvas(),this.cropped&&this.renderCropBox())},clear:function(){this.cropped&&!this.disabled&&(a.extend(this.cropBox,{left:0,top:0,width:0,height:0}),this.cropped=!1,this.renderCropBox(),this.limitCanvas(),this.renderCanvas(),this.$dragBox.removeClass(r),this.$cropBox.addClass(t))},destroy:function(){var a=this.$element;this.ready?(this.unbuild(),a.removeClass(t)):this.$clone&&this.$clone.remove(),a.removeData("cropper")},replace:function(a){!this.disabled&&a&&(this.options.data=null,this.load(a))},enable:function(){this.built&&(this.disabled=!1,this.$cropper.removeClass(x))},disable:function(){this.built&&(this.disabled=!0,this.$cropper.addClass(x))},move:function(a,c){var d=this.canvas;this.built&&!this.disabled&&this.options.movable&&b(a)&&b(c)&&(d.left+=a,d.top+=c,this.renderCanvas(!0))},zoom:function(b){var c,d,e,f=this.canvas;if(b=U(b),b&&this.built&&!this.disabled&&this.options.zoomable){if(c=a.Event(b>0?K:L),this.$element.trigger(c),c.isDefaultPrevented())return;b=-1>=b?1/(1-b):1>=b?1+b:b,d=f.width*b,e=f.height*b,f.left-=(d-f.width)/2,f.top-=(e-f.height)/2,f.width=d,f.height=e,this.renderCanvas(!0),this.setDragMode("move")}},rotate:function(a){var b=this.image;a=U(a),a&&this.built&&!this.disabled&&this.options.rotatable&&(b.rotate=(b.rotate+a)%360,this.rotated=!0,this.renderCanvas(!0))},getData:function(b){var c,d,e=this.cropBox,f=this.canvas,g=this.image;return this.built&&this.cropped?(d={x:e.left-f.left,y:e.top-f.top,width:e.width,height:e.height},c=g.width/g.naturalWidth,a.each(d,function(a,e){e/=c,d[a]=b?Math.round(e):e})):d={x:0,y:0,width:0,height:0},d.rotate=this.ready?g.rotate:0,d},setData:function(c){var d,e=this.image,f=this.canvas,g={};this.built&&!this.disabled&&a.isPlainObject(c)&&(b(c.rotate)&&c.rotate!==e.rotate&&this.options.rotatable&&(e.rotate=c.rotate,this.rotated=!0,this.renderCanvas(!0)),d=e.width/e.naturalWidth,b(c.x)&&(g.left=c.x*d+f.left),b(c.y)&&(g.top=c.y*d+f.top),b(c.width)&&(g.width=c.width*d),b(c.height)&&(g.height=c.height*d),this.setCropBoxData(g))},getContainerData:function(){return this.built?this.container:{}},getImageData:function(){return this.ready?this.image:{}},getCanvasData:function(){var a,b=this.canvas;return this.built&&(a={left:b.left,top:b.top,width:b.width,height:b.height}),a||{}},setCanvasData:function(c){var d=this.canvas,e=d.aspectRatio;this.built&&!this.disabled&&a.isPlainObject(c)&&(b(c.left)&&(d.left=c.left),b(c.top)&&(d.top=c.top),b(c.width)?(d.width=c.width,d.height=c.width/e):b(c.height)&&(d.height=c.height,d.width=c.height*e),this.renderCanvas(!0))},getCropBoxData:function(){var a,b=this.cropBox;return this.built&&this.cropped&&(a={left:b.left,top:b.top,width:b.width,height:b.height}),a||{}},setCropBoxData:function(c){var d=this.cropBox,e=this.options.aspectRatio;this.built&&this.cropped&&!this.disabled&&a.isPlainObject(c)&&(b(c.left)&&(d.left=c.left),b(c.top)&&(d.top=c.top),b(c.width)&&(d.width=c.width),b(c.height)&&(d.height=c.height),e&&(b(c.width)?d.height=d.width/e:b(c.height)&&(d.width=d.height*e)),this.renderCropBox())},getCroppedCanvas:function(b){var c,d,e,f,g,h,i,k,l,m,n;if(this.built&&this.cropped&&N)return a.isPlainObject(b)||(b={}),n=this.getData(),c=n.width,d=n.height,k=c/d,a.isPlainObject(b)&&(g=b.width,h=b.height,g?(h=g/k,i=g/c):h&&(g=h*k,i=h/d)),e=g||c,f=h||d,l=a("<canvas>")[0],l.width=e,l.height=f,m=l.getContext("2d"),b.fillColor&&(m.fillStyle=b.fillColor,m.fillRect(0,0,e,f)),m.drawImage.apply(m,function(){var a,b,e,f,g,h,k=j(this.$clone[0],this.image),l=k.width,m=k.height,o=[k],p=n.x,q=n.y;return-c>=p||p>l?p=a=e=g=0:0>=p?(e=-p,p=0,a=g=P(l,c+p)):l>=p&&(e=0,a=g=P(c,l-p)),0>=a||-d>=q||q>m?q=b=f=h=0:0>=q?(f=-q,q=0,b=h=P(m,d+q)):m>=q&&(f=0,b=h=P(d,m-q)),o.push(p,q,a,b),i&&(e*=i,f*=i,g*=i,h*=i),g>0&&h>0&&o.push(e,f,g,h),o}.call(this)),l},setAspectRatio:function(a){var b=this.options;this.disabled||c(a)||(b.aspectRatio=U(a)||NaN,this.built&&(this.initCropBox(),this.cropped&&this.renderCropBox()))},setDragMode:function(a){var b,c,d=this.options;this.ready&&!this.disabled&&(b=d.dragCrop&&"crop"===a,c=d.movable&&"move"===a,a=b||c?a:"none",this.$dragBox.data("drag",a).toggleClass(w,b).toggleClass(v,c),d.cropBoxMovable||this.$face.data("drag",a).toggleClass(w,b).toggleClass(v,c))}}),V.change=function(a){var b,c=this.dragType,d=this.options,e=this.canvas,f=this.container,g=this.cropBox,h=g.width,i=g.height,j=g.left,k=g.top,l=j+h,m=k+i,n=0,o=0,p=f.width,q=f.height,r=!0,s=d.aspectRatio,u={x:this.endX-this.startX,y:this.endY-this.startY};switch(!s&&a&&(s=h&&i?h/i:1),d.strict&&(n=g.minLeft,o=g.minTop,p=n+P(f.width,e.width),q=o+P(f.height,e.height)),s&&(u.X=u.y*s,u.Y=u.x/s),c){case"all":j+=u.x,k+=u.y;break;case"e":if(u.x>=0&&(l>=p||s&&(o>=k||m>=q))){r=!1;break}h+=u.x,s&&(i=h/s,k-=u.Y/2),0>h&&(c="w",h=0);break;case"n":if(u.y<=0&&(o>=k||s&&(n>=j||l>=p))){r=!1;break}i-=u.y,k+=u.y,s&&(h=i*s,j+=u.X/2),0>i&&(c="s",i=0);break;case"w":if(u.x<=0&&(n>=j||s&&(o>=k||m>=q))){r=!1;break}h-=u.x,j+=u.x,s&&(i=h/s,k+=u.Y/2),0>h&&(c="e",h=0);break;case"s":if(u.y>=0&&(m>=q||s&&(n>=j||l>=p))){r=!1;break}i+=u.y,s&&(h=i*s,j-=u.X/2),0>i&&(c="n",i=0);break;case"ne":if(s){if(u.y<=0&&(o>=k||l>=p)){r=!1;break}i-=u.y,k+=u.y,h=i*s}else u.x>=0?p>l?h+=u.x:u.y<=0&&o>=k&&(r=!1):h+=u.x,u.y<=0?k>o&&(i-=u.y,k+=u.y):(i-=u.y,k+=u.y);0>h&&0>i?(c="sw",i=0,h=0):0>h?(c="nw",h=0):0>i&&(c="se",i=0);break;case"nw":if(s){if(u.y<=0&&(o>=k||n>=j)){r=!1;break}i-=u.y,k+=u.y,h=i*s,j+=u.X}else u.x<=0?j>n?(h-=u.x,j+=u.x):u.y<=0&&o>=k&&(r=!1):(h-=u.x,j+=u.x),u.y<=0?k>o&&(i-=u.y,k+=u.y):(i-=u.y,k+=u.y);0>h&&0>i?(c="se",i=0,h=0):0>h?(c="ne",h=0):0>i&&(c="sw",i=0);break;case"sw":if(s){if(u.x<=0&&(n>=j||m>=q)){r=!1;break}h-=u.x,j+=u.x,i=h/s}else u.x<=0?j>n?(h-=u.x,j+=u.x):u.y>=0&&m>=q&&(r=!1):(h-=u.x,j+=u.x),u.y>=0?q>m&&(i+=u.y):i+=u.y;0>h&&0>i?(c="ne",i=0,h=0):0>h?(c="se",h=0):0>i&&(c="nw",i=0);break;case"se":if(s){if(u.x>=0&&(l>=p||m>=q)){r=!1;break}h+=u.x,i=h/s}else u.x>=0?p>l?h+=u.x:u.y>=0&&m>=q&&(r=!1):h+=u.x,u.y>=0?q>m&&(i+=u.y):i+=u.y;0>h&&0>i?(c="nw",i=0,h=0):0>h?(c="sw",h=0):0>i&&(c="ne",i=0);break;case"move":e.left+=u.x,e.top+=u.y,this.renderCanvas(!0),r=!1;break;case"zoom":this.zoom(function(a,b,c,d){var e=O(a*a+b*b),f=O(c*c+d*d);return(f-e)/e}(R(this.startX-this.startX2),R(this.startY-this.startY2),R(this.endX-this.endX2),R(this.endY-this.endY2))),this.startX2=this.endX2,this.startY2=this.endY2,r=!1;break;case"crop":u.x&&u.y&&(b=this.$cropper.offset(),j=this.startX-b.left,k=this.startY-b.top,h=g.minWidth,i=g.minHeight,u.x>0?u.y>0?c="se":(c="ne",k-=i):u.y>0?(c="sw",j-=h):(c="nw",j-=h,k-=i),this.cropped||(this.cropped=!0,this.$cropBox.removeClass(t)))}r&&(g.width=h,g.height=i,g.left=j,g.top=k,this.dragType=c,this.renderCropBox()),this.startX=this.endX,this.startY=this.endY},a.extend(k.prototype,V),k.DEFAULTS={aspectRatio:NaN,autoCropArea:.8,crop:null,data:null,preview:"",strict:!0,responsive:!0,checkImageOrigin:!0,modal:!0,guides:!0,highlight:!0,background:!0,autoCrop:!0,dragCrop:!0,movable:!0,rotatable:!0,zoomable:!0,touchDragZoom:!0,mouseWheelZoom:!0,cropBoxMovable:!0,cropBoxResizable:!0,doubleClickToggle:!0,minCanvasWidth:0,minCanvasHeight:0,minCropBoxWidth:0,minCropBoxHeight:0,minContainerWidth:200,minContainerHeight:100,build:null,built:null,dragstart:null,dragmove:null,dragend:null,zoomin:null,zoomout:null,change:null},k.setDefaults=function(b){a.extend(k.DEFAULTS,b)},k.TEMPLATE=function(a,b){return b=b.split(","),a.replace(/\d+/g,function(a){return b[a]})}('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-2-9"></0><0 6="5-crop-9"><1 6="5-view-9"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>',"div,span,drag,data,point,cropper,class,line,dashed,box"),k.other=a.fn.cropper,a.fn.cropper=function(b){var e,f=d(arguments,1);return this.each(function(){var c,d=a(this),g=d.data("cropper");g||d.data("cropper",g=new k(this,b)),"string"==typeof b&&a.isFunction(c=g[b])&&(e=c.apply(g,f))}),c(e)?this:e},a.fn.cropper.Constructor=k,a.fn.cropper.setDefaults=k.setDefaults,a.fn.cropper.noConflict=function(){return a.fn.cropper=k.other,this}});
1
  /*!
2
+ * Cropper v2.2.5
3
  * https://github.com/fengyuanchen/cropper
4
  *
5
+ * Copyright (c) 2014-2016 Fengyuan Chen and contributors
6
  * Released under the MIT license
7
  *
8
+ * Date: 2016-01-18T05:42:50.800Z
9
  */
10
+ !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){"use strict";function i(t){return"number"==typeof t&&!isNaN(t)}function e(t){return"undefined"==typeof t}function s(t,e){var s=[];return i(e)&&s.push(e),s.slice.apply(t,s)}function a(t,i){var e=s(arguments,2);return function(){return t.apply(i,e.concat(s(arguments)))}}function o(t){var i=t.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return i&&(i[1]!==C.protocol||i[2]!==C.hostname||i[3]!==C.port)}function h(t){var i="timestamp="+(new Date).getTime();return t+(-1===t.indexOf("?")?"?":"&")+i}function n(t){return t?' crossOrigin="'+t+'"':""}function r(t,i){var e;return t.naturalWidth?i(t.naturalWidth,t.naturalHeight):(e=document.createElement("img"),e.onload=function(){i(this.width,this.height)},void(e.src=t.src))}function p(t){var e=[],s=t.rotate,a=t.scaleX,o=t.scaleY;return i(s)&&e.push("rotate("+s+"deg)"),i(a)&&i(o)&&e.push("scale("+a+","+o+")"),e.length?e.join(" "):"none"}function l(t,i){var e,s,a=wt(t.degree)%180,o=(a>90?180-a:a)*Math.PI/180,h=xt(o),n=Ct(o),r=t.width,p=t.height,l=t.aspectRatio;return i?(e=r/(n+h/l),s=e/l):(e=r*n+p*h,s=r*h+p*n),{width:e,height:s}}function c(e,s){var a,o,h,n=t("<canvas>")[0],r=n.getContext("2d"),p=0,c=0,d=s.naturalWidth,g=s.naturalHeight,u=s.rotate,f=s.scaleX,m=s.scaleY,v=i(f)&&i(m)&&(1!==f||1!==m),w=i(u)&&0!==u,x=w||v,C=d,b=g;return v&&(a=d/2,o=g/2),w&&(h=l({width:d,height:g,degree:u}),C=h.width,b=h.height,a=h.width/2,o=h.height/2),n.width=C,n.height=b,x&&(p=-d/2,c=-g/2,r.save(),r.translate(a,o)),w&&r.rotate(u*Math.PI/180),v&&r.scale(f,m),r.drawImage(e,yt(p),yt(c),yt(d),yt(g)),x&&r.restore(),n}function d(i){var e=i.length,s=0,a=0;return e&&(t.each(i,function(t,i){s+=i.pageX,a+=i.pageY}),s/=e,a/=e),{pageX:s,pageY:a}}function g(t,i,e){var s,a="";for(s=i,e+=i;e>s;s++)a+=Dt(t.getUint8(s));return a}function u(t){var i,e,s,a,o,h,n,r,p,l,c=new y(t),d=c.byteLength;if(255===c.getUint8(0)&&216===c.getUint8(1))for(p=2;d>p;){if(255===c.getUint8(p)&&225===c.getUint8(p+1)){n=p;break}p++}if(n&&(e=n+4,s=n+10,"Exif"===g(c,e,4)&&(h=c.getUint16(s),o=18761===h,(o||19789===h)&&42===c.getUint16(s+2,o)&&(a=c.getUint32(s+4,o),a>=8&&(r=s+a)))),r)for(d=c.getUint16(r,o),l=0;d>l;l++)if(p=r+12*l+2,274===c.getUint16(p,o)){p+=8,i=c.getUint16(p,o),c.setUint16(p,1,o);break}return i}function f(t){var i,e=t.replace(V,""),s=atob(e),a=s.length,o=new b(a),h=new B(o);for(i=0;a>i;i++)h[i]=s.charCodeAt(i);return o}function m(t){var i,e=new B(t),s=e.length,a="";for(i=0;s>i;i++)a+=Dt(e[i]);return"data:image/jpeg;base64,"+D(a)}function v(i,e){this.$element=t(i),this.options=t.extend({},v.DEFAULTS,t.isPlainObject(e)&&e),this.isLoaded=!1,this.isBuilt=!1,this.isCompleted=!1,this.isRotated=!1,this.isCropped=!1,this.isDisabled=!1,this.isReplaced=!1,this.isLimited=!1,this.wheeling=!1,this.isImg=!1,this.originalUrl="",this.canvas=null,this.cropBox=null,this.init()}var w=t(window),x=t(document),C=window.location,b=window.ArrayBuffer,B=window.Uint8Array,y=window.DataView,D=window.btoa,$="cropper",L="cropper-modal",T="cropper-hide",X="cropper-hidden",Y="cropper-invisible",k="cropper-move",M="cropper-crop",W="cropper-disabled",R="cropper-bg",H="mousedown touchstart pointerdown MSPointerDown",z="mousemove touchmove pointermove MSPointerMove",O="mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel",E="wheel mousewheel DOMMouseScroll",P="dblclick",U="load."+$,I="error."+$,F="resize."+$,j="build."+$,S="built."+$,A="cropstart."+$,N="cropmove."+$,_="cropend."+$,q="crop."+$,Z="zoom."+$,K=/e|w|s|n|se|sw|ne|nw|all|crop|move|zoom/,Q=/^data\:/,V=/^data\:([^\;]+)\;base64,/,G=/^data\:image\/jpeg.*;base64,/,J="preview",tt="action",it="e",et="w",st="s",at="n",ot="se",ht="sw",nt="ne",rt="nw",pt="all",lt="crop",ct="move",dt="zoom",gt="none",ut=t.isFunction(t("<canvas>")[0].getContext),ft=Number,mt=Math.min,vt=Math.max,wt=Math.abs,xt=Math.sin,Ct=Math.cos,bt=Math.sqrt,Bt=Math.round,yt=Math.floor,Dt=String.fromCharCode;v.prototype={constructor:v,init:function(){var t,i=this.$element;if(i.is("img")){if(this.isImg=!0,this.originalUrl=t=i.attr("src"),!t)return;t=i.prop("src")}else i.is("canvas")&&ut&&(t=i[0].toDataURL());this.load(t)},trigger:function(i,e){var s=t.Event(i,e);return this.$element.trigger(s),s},load:function(i){var e,s,a=this.options,o=this.$element;if(i&&(o.one(j,a.build),!this.trigger(j).isDefaultPrevented())){if(this.url=i,this.image={},!a.checkOrientation||!b)return this.clone();if(e=t.proxy(this.read,this),Q.test(i))return G.test(i)?e(f(i)):this.clone();s=new XMLHttpRequest,s.onerror=s.onabort=t.proxy(function(){this.clone()},this),s.onload=function(){e(this.response)},s.open("get",i),s.responseType="arraybuffer",s.send()}},read:function(t){var i,e,s,a=this.options,o=u(t),h=this.image;if(o>1)switch(this.url=m(t),o){case 2:e=-1;break;case 3:i=-180;break;case 4:s=-1;break;case 5:i=90,s=-1;break;case 6:i=90;break;case 7:i=90,e=-1;break;case 8:i=-90}a.rotatable&&(h.rotate=i),a.scalable&&(h.scaleX=e,h.scaleY=s),this.clone()},clone:function(){var i,e,s=this.options,a=this.$element,r=this.url,p="";s.checkCrossOrigin&&o(r)&&(p=a.prop("crossOrigin"),p?i=r:(p="anonymous",i=h(r))),this.crossOrigin=p,this.crossOriginUrl=i,this.$clone=e=t("<img"+n(p)+' src="'+(i||r)+'">'),this.isImg?a[0].complete?this.start():a.one(U,t.proxy(this.start,this)):e.one(U,t.proxy(this.start,this)).one(I,t.proxy(this.stop,this)).addClass(T).insertAfter(a)},start:function(){var i=this.$element,e=this.$clone;this.isImg||(e.off(I,this.stop),i=e),r(i[0],t.proxy(function(i,e){t.extend(this.image,{naturalWidth:i,naturalHeight:e,aspectRatio:i/e}),this.isLoaded=!0,this.build()},this))},stop:function(){this.$clone.remove(),this.$clone=null},build:function(){var i,e,s,a=this.options,o=this.$element,h=this.$clone;this.isLoaded&&(this.isBuilt&&this.unbuild(),this.$container=o.parent(),this.$cropper=i=t(v.TEMPLATE),this.$canvas=i.find(".cropper-canvas").append(h),this.$dragBox=i.find(".cropper-drag-box"),this.$cropBox=e=i.find(".cropper-crop-box"),this.$viewBox=i.find(".cropper-view-box"),this.$face=s=e.find(".cropper-face"),o.addClass(X).after(i),this.isImg||h.removeClass(T),this.initPreview(),this.bind(),a.aspectRatio=vt(0,a.aspectRatio)||NaN,a.viewMode=vt(0,mt(3,Bt(a.viewMode)))||0,a.autoCrop?(this.isCropped=!0,a.modal&&this.$dragBox.addClass(L)):e.addClass(X),a.guides||e.find(".cropper-dashed").addClass(X),a.center||e.find(".cropper-center").addClass(X),a.cropBoxMovable&&s.addClass(k).data(tt,pt),a.highlight||s.addClass(Y),a.background&&i.addClass(R),a.cropBoxResizable||e.find(".cropper-line, .cropper-point").addClass(X),this.setDragMode(a.dragMode),this.render(),this.isBuilt=!0,this.setData(a.data),o.one(S,a.built),setTimeout(t.proxy(function(){this.trigger(S),this.isCompleted=!0},this),0))},unbuild:function(){this.isBuilt&&(this.isBuilt=!1,this.isCompleted=!1,this.initialImage=null,this.initialCanvas=null,this.initialCropBox=null,this.container=null,this.canvas=null,this.cropBox=null,this.unbind(),this.resetPreview(),this.$preview=null,this.$viewBox=null,this.$cropBox=null,this.$dragBox=null,this.$canvas=null,this.$container=null,this.$cropper.remove(),this.$cropper=null)},render:function(){this.initContainer(),this.initCanvas(),this.initCropBox(),this.renderCanvas(),this.isCropped&&this.renderCropBox()},initContainer:function(){var t=this.options,i=this.$element,e=this.$container,s=this.$cropper;s.addClass(X),i.removeClass(X),s.css(this.container={width:vt(e.width(),ft(t.minContainerWidth)||200),height:vt(e.height(),ft(t.minContainerHeight)||100)}),i.addClass(X),s.removeClass(X)},initCanvas:function(){var i,e=this.options.viewMode,s=this.container,a=s.width,o=s.height,h=this.image,n=h.naturalWidth,r=h.naturalHeight,p=90===wt(h.rotate),l=p?r:n,c=p?n:r,d=l/c,g=a,u=o;o*d>a?3===e?g=o*d:u=a/d:3===e?u=a/d:g=o*d,i={naturalWidth:l,naturalHeight:c,aspectRatio:d,width:g,height:u},i.oldLeft=i.left=(a-g)/2,i.oldTop=i.top=(o-u)/2,this.canvas=i,this.isLimited=1===e||2===e,this.limitCanvas(!0,!0),this.initialImage=t.extend({},h),this.initialCanvas=t.extend({},i)},limitCanvas:function(t,i){var e,s,a,o,h=this.options,n=h.viewMode,r=this.container,p=r.width,l=r.height,c=this.canvas,d=c.aspectRatio,g=this.cropBox,u=this.isCropped&&g;t&&(e=ft(h.minCanvasWidth)||0,s=ft(h.minCanvasHeight)||0,n&&(n>1?(e=vt(e,p),s=vt(s,l),3===n&&(s*d>e?e=s*d:s=e/d)):e?e=vt(e,u?g.width:0):s?s=vt(s,u?g.height:0):u&&(e=g.width,s=g.height,s*d>e?e=s*d:s=e/d)),e&&s?s*d>e?s=e/d:e=s*d:e?s=e/d:s&&(e=s*d),c.minWidth=e,c.minHeight=s,c.maxWidth=1/0,c.maxHeight=1/0),i&&(n?(a=p-c.width,o=l-c.height,c.minLeft=mt(0,a),c.minTop=mt(0,o),c.maxLeft=vt(0,a),c.maxTop=vt(0,o),u&&this.isLimited&&(c.minLeft=mt(g.left,g.left+g.width-c.width),c.minTop=mt(g.top,g.top+g.height-c.height),c.maxLeft=g.left,c.maxTop=g.top,2===n&&(c.width>=p&&(c.minLeft=mt(0,a),c.maxLeft=vt(0,a)),c.height>=l&&(c.minTop=mt(0,o),c.maxTop=vt(0,o))))):(c.minLeft=-c.width,c.minTop=-c.height,c.maxLeft=p,c.maxTop=l))},renderCanvas:function(t){var i,e,s=this.canvas,a=this.image,o=a.rotate,h=a.naturalWidth,n=a.naturalHeight;this.isRotated&&(this.isRotated=!1,e=l({width:a.width,height:a.height,degree:o}),i=e.width/e.height,i!==s.aspectRatio&&(s.left-=(e.width-s.width)/2,s.top-=(e.height-s.height)/2,s.width=e.width,s.height=e.height,s.aspectRatio=i,s.naturalWidth=h,s.naturalHeight=n,o%180&&(e=l({width:h,height:n,degree:o}),s.naturalWidth=e.width,s.naturalHeight=e.height),this.limitCanvas(!0,!1))),(s.width>s.maxWidth||s.width<s.minWidth)&&(s.left=s.oldLeft),(s.height>s.maxHeight||s.height<s.minHeight)&&(s.top=s.oldTop),s.width=mt(vt(s.width,s.minWidth),s.maxWidth),s.height=mt(vt(s.height,s.minHeight),s.maxHeight),this.limitCanvas(!1,!0),s.oldLeft=s.left=mt(vt(s.left,s.minLeft),s.maxLeft),s.oldTop=s.top=mt(vt(s.top,s.minTop),s.maxTop),this.$canvas.css({width:s.width,height:s.height,left:s.left,top:s.top}),this.renderImage(),this.isCropped&&this.isLimited&&this.limitCropBox(!0,!0),t&&this.output()},renderImage:function(i){var e,s=this.canvas,a=this.image;a.rotate&&(e=l({width:s.width,height:s.height,degree:a.rotate,aspectRatio:a.aspectRatio},!0)),t.extend(a,e?{width:e.width,height:e.height,left:(s.width-e.width)/2,top:(s.height-e.height)/2}:{width:s.width,height:s.height,left:0,top:0}),this.$clone.css({width:a.width,height:a.height,marginLeft:a.left,marginTop:a.top,transform:p(a)}),i&&this.output()},initCropBox:function(){var i=this.options,e=this.canvas,s=i.aspectRatio,a=ft(i.autoCropArea)||.8,o={width:e.width,height:e.height};s&&(e.height*s>e.width?o.height=o.width/s:o.width=o.height*s),this.cropBox=o,this.limitCropBox(!0,!0),o.width=mt(vt(o.width,o.minWidth),o.maxWidth),o.height=mt(vt(o.height,o.minHeight),o.maxHeight),o.width=vt(o.minWidth,o.width*a),o.height=vt(o.minHeight,o.height*a),o.oldLeft=o.left=e.left+(e.width-o.width)/2,o.oldTop=o.top=e.top+(e.height-o.height)/2,this.initialCropBox=t.extend({},o)},limitCropBox:function(t,i){var e,s,a,o,h=this.options,n=h.aspectRatio,r=this.container,p=r.width,l=r.height,c=this.canvas,d=this.cropBox,g=this.isLimited;t&&(e=ft(h.minCropBoxWidth)||0,s=ft(h.minCropBoxHeight)||0,e=mt(e,p),s=mt(s,l),a=mt(p,g?c.width:p),o=mt(l,g?c.height:l),n&&(e&&s?s*n>e?s=e/n:e=s*n:e?s=e/n:s&&(e=s*n),o*n>a?o=a/n:a=o*n),d.minWidth=mt(e,a),d.minHeight=mt(s,o),d.maxWidth=a,d.maxHeight=o),i&&(g?(d.minLeft=vt(0,c.left),d.minTop=vt(0,c.top),d.maxLeft=mt(p,c.left+c.width)-d.width,d.maxTop=mt(l,c.top+c.height)-d.height):(d.minLeft=0,d.minTop=0,d.maxLeft=p-d.width,d.maxTop=l-d.height))},renderCropBox:function(){var t=this.options,i=this.container,e=i.width,s=i.height,a=this.cropBox;(a.width>a.maxWidth||a.width<a.minWidth)&&(a.left=a.oldLeft),(a.height>a.maxHeight||a.height<a.minHeight)&&(a.top=a.oldTop),a.width=mt(vt(a.width,a.minWidth),a.maxWidth),a.height=mt(vt(a.height,a.minHeight),a.maxHeight),this.limitCropBox(!1,!0),a.oldLeft=a.left=mt(vt(a.left,a.minLeft),a.maxLeft),a.oldTop=a.top=mt(vt(a.top,a.minTop),a.maxTop),t.movable&&t.cropBoxMovable&&this.$face.data(tt,a.width===e&&a.height===s?ct:pt),this.$cropBox.css({width:a.width,height:a.height,left:a.left,top:a.top}),this.isCropped&&this.isLimited&&this.limitCanvas(!0,!0),this.isDisabled||this.output()},output:function(){this.preview(),this.isCompleted?this.trigger(q,this.getData()):this.isBuilt||this.$element.one(S,t.proxy(function(){this.trigger(q,this.getData())},this))},initPreview:function(){var i=n(this.crossOrigin),e=i?this.crossOriginUrl:this.url;this.$preview=t(this.options.preview),this.$viewBox.html("<img"+i+' src="'+e+'">'),this.$preview.each(function(){var s=t(this);s.data(J,{width:s.width(),height:s.height(),html:s.html()}),s.html("<img"+i+' src="'+e+'" style="display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;">')})},resetPreview:function(){this.$preview.each(function(){var i=t(this),e=i.data(J);i.css({width:e.width,height:e.height}).html(e.html).removeData(J)})},preview:function(){var i=this.image,e=this.canvas,s=this.cropBox,a=s.width,o=s.height,h=i.width,n=i.height,r=s.left-e.left-i.left,l=s.top-e.top-i.top;this.isCropped&&!this.isDisabled&&(this.$viewBox.find("img").css({width:h,height:n,marginLeft:-r,marginTop:-l,transform:p(i)}),this.$preview.each(function(){var e=t(this),s=e.data(J),c=s.width,d=s.height,g=c,u=d,f=1;a&&(f=c/a,u=o*f),o&&u>d&&(f=d/o,g=a*f,u=d),e.css({width:g,height:u}).find("img").css({width:h*f,height:n*f,marginLeft:-r*f,marginTop:-l*f,transform:p(i)})}))},bind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.on(A,i.cropstart),t.isFunction(i.cropmove)&&e.on(N,i.cropmove),t.isFunction(i.cropend)&&e.on(_,i.cropend),t.isFunction(i.crop)&&e.on(q,i.crop),t.isFunction(i.zoom)&&e.on(Z,i.zoom),s.on(H,t.proxy(this.cropStart,this)),i.zoomable&&i.zoomOnWheel&&s.on(E,t.proxy(this.wheel,this)),i.toggleDragModeOnDblclick&&s.on(P,t.proxy(this.dblclick,this)),x.on(z,this._cropMove=a(this.cropMove,this)).on(O,this._cropEnd=a(this.cropEnd,this)),i.responsive&&w.on(F,this._resize=a(this.resize,this))},unbind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.off(A,i.cropstart),t.isFunction(i.cropmove)&&e.off(N,i.cropmove),t.isFunction(i.cropend)&&e.off(_,i.cropend),t.isFunction(i.crop)&&e.off(q,i.crop),t.isFunction(i.zoom)&&e.off(Z,i.zoom),s.off(H,this.cropStart),i.zoomable&&i.zoomOnWheel&&s.off(E,this.wheel),i.toggleDragModeOnDblclick&&s.off(P,this.dblclick),x.off(z,this._cropMove).off(O,this._cropEnd),i.responsive&&w.off(F,this._resize)},resize:function(){var i,e,s,a=this.options.restore,o=this.$container,h=this.container;!this.isDisabled&&h&&(s=o.width()/h.width,(1!==s||o.height()!==h.height)&&(a&&(i=this.getCanvasData(),e=this.getCropBoxData()),this.render(),a&&(this.setCanvasData(t.each(i,function(t,e){i[t]=e*s})),this.setCropBoxData(t.each(e,function(t,i){e[t]=i*s})))))},dblclick:function(){this.isDisabled||(this.$dragBox.hasClass(M)?this.setDragMode(ct):this.setDragMode(lt))},wheel:function(i){var e=i.originalEvent||i,s=ft(this.options.wheelZoomRatio)||.1,a=1;this.isDisabled||(i.preventDefault(),this.wheeling||(this.wheeling=!0,setTimeout(t.proxy(function(){this.wheeling=!1},this),50),e.deltaY?a=e.deltaY>0?1:-1:e.wheelDelta?a=-e.wheelDelta/120:e.detail&&(a=e.detail>0?1:-1),this.zoom(-a*s,i)))},cropStart:function(i){var e,s,a=this.options,o=i.originalEvent,h=o&&o.touches,n=i;if(!this.isDisabled){if(h){if(e=h.length,e>1){if(!a.zoomable||!a.zoomOnTouch||2!==e)return;n=h[1],this.startX2=n.pageX,this.startY2=n.pageY,s=dt}n=h[0]}if(s=s||t(n.target).data(tt),K.test(s)){if(this.trigger(A,{originalEvent:o,action:s}).isDefaultPrevented())return;i.preventDefault(),this.action=s,this.cropping=!1,this.startX=n.pageX||o&&o.pageX,this.startY=n.pageY||o&&o.pageY,s===lt&&(this.cropping=!0,this.$dragBox.addClass(L))}}},cropMove:function(t){var i,e=this.options,s=t.originalEvent,a=s&&s.touches,o=t,h=this.action;if(!this.isDisabled){if(a){if(i=a.length,i>1){if(!e.zoomable||!e.zoomOnTouch||2!==i)return;o=a[1],this.endX2=o.pageX,this.endY2=o.pageY}o=a[0]}if(h){if(this.trigger(N,{originalEvent:s,action:h}).isDefaultPrevented())return;t.preventDefault(),this.endX=o.pageX||s&&s.pageX,this.endY=o.pageY||s&&s.pageY,this.change(o.shiftKey,h===dt?t:null)}}},cropEnd:function(t){var i=t.originalEvent,e=this.action;this.isDisabled||e&&(t.preventDefault(),this.cropping&&(this.cropping=!1,this.$dragBox.toggleClass(L,this.isCropped&&this.options.modal)),this.action="",this.trigger(_,{originalEvent:i,action:e}))},change:function(t,i){var e,s,a=this.options,o=a.aspectRatio,h=this.action,n=this.container,r=this.canvas,p=this.cropBox,l=p.width,c=p.height,d=p.left,g=p.top,u=d+l,f=g+c,m=0,v=0,w=n.width,x=n.height,C=!0;switch(!o&&t&&(o=l&&c?l/c:1),this.limited&&(m=p.minLeft,v=p.minTop,w=m+mt(n.width,r.width),x=v+mt(n.height,r.height)),s={x:this.endX-this.startX,y:this.endY-this.startY},o&&(s.X=s.y*o,s.Y=s.x/o),h){case pt:d+=s.x,g+=s.y;break;case it:if(s.x>=0&&(u>=w||o&&(v>=g||f>=x))){C=!1;break}l+=s.x,o&&(c=l/o,g-=s.Y/2),0>l&&(h=et,l=0);break;case at:if(s.y<=0&&(v>=g||o&&(m>=d||u>=w))){C=!1;break}c-=s.y,g+=s.y,o&&(l=c*o,d+=s.X/2),0>c&&(h=st,c=0);break;case et:if(s.x<=0&&(m>=d||o&&(v>=g||f>=x))){C=!1;break}l-=s.x,d+=s.x,o&&(c=l/o,g+=s.Y/2),0>l&&(h=it,l=0);break;case st:if(s.y>=0&&(f>=x||o&&(m>=d||u>=w))){C=!1;break}c+=s.y,o&&(l=c*o,d-=s.X/2),0>c&&(h=at,c=0);break;case nt:if(o){if(s.y<=0&&(v>=g||u>=w)){C=!1;break}c-=s.y,g+=s.y,l=c*o}else s.x>=0?w>u?l+=s.x:s.y<=0&&v>=g&&(C=!1):l+=s.x,s.y<=0?g>v&&(c-=s.y,g+=s.y):(c-=s.y,g+=s.y);0>l&&0>c?(h=ht,c=0,l=0):0>l?(h=rt,l=0):0>c&&(h=ot,c=0);break;case rt:if(o){if(s.y<=0&&(v>=g||m>=d)){C=!1;break}c-=s.y,g+=s.y,l=c*o,d+=s.X}else s.x<=0?d>m?(l-=s.x,d+=s.x):s.y<=0&&v>=g&&(C=!1):(l-=s.x,d+=s.x),s.y<=0?g>v&&(c-=s.y,g+=s.y):(c-=s.y,g+=s.y);0>l&&0>c?(h=ot,c=0,l=0):0>l?(h=nt,l=0):0>c&&(h=ht,c=0);break;case ht:if(o){if(s.x<=0&&(m>=d||f>=x)){C=!1;break}l-=s.x,d+=s.x,c=l/o}else s.x<=0?d>m?(l-=s.x,d+=s.x):s.y>=0&&f>=x&&(C=!1):(l-=s.x,d+=s.x),s.y>=0?x>f&&(c+=s.y):c+=s.y;0>l&&0>c?(h=nt,c=0,l=0):0>l?(h=ot,l=0):0>c&&(h=rt,c=0);break;case ot:if(o){if(s.x>=0&&(u>=w||f>=x)){C=!1;break}l+=s.x,c=l/o}else s.x>=0?w>u?l+=s.x:s.y>=0&&f>=x&&(C=!1):l+=s.x,s.y>=0?x>f&&(c+=s.y):c+=s.y;0>l&&0>c?(h=rt,c=0,l=0):0>l?(h=ht,l=0):0>c&&(h=nt,c=0);break;case ct:this.move(s.x,s.y),C=!1;break;case dt:this.zoom(function(t,i,e,s){var a=bt(t*t+i*i),o=bt(e*e+s*s);return(o-a)/a}(wt(this.startX-this.startX2),wt(this.startY-this.startY2),wt(this.endX-this.endX2),wt(this.endY-this.endY2)),i),this.startX2=this.endX2,this.startY2=this.endY2,C=!1;break;case lt:if(!s.x||!s.y){C=!1;break}e=this.$cropper.offset(),d=this.startX-e.left,g=this.startY-e.top,l=p.minWidth,c=p.minHeight,s.x>0?h=s.y>0?ot:nt:s.x<0&&(d-=l,h=s.y>0?ht:rt),s.y<0&&(g-=c),this.isCropped||(this.$cropBox.removeClass(X),this.isCropped=!0,this.limited&&this.limitCropBox(!0,!0))}C&&(p.width=l,p.height=c,p.left=d,p.top=g,this.action=h,this.renderCropBox()),this.startX=this.endX,this.startY=this.endY},crop:function(){this.isBuilt&&!this.isDisabled&&(this.isCropped||(this.isCropped=!0,this.limitCropBox(!0,!0),this.options.modal&&this.$dragBox.addClass(L),this.$cropBox.removeClass(X)),this.setCropBoxData(this.initialCropBox))},reset:function(){this.isBuilt&&!this.isDisabled&&(this.image=t.extend({},this.initialImage),this.canvas=t.extend({},this.initialCanvas),this.cropBox=t.extend({},this.initialCropBox),this.renderCanvas(),this.isCropped&&this.renderCropBox())},clear:function(){this.isCropped&&!this.isDisabled&&(t.extend(this.cropBox,{left:0,top:0,width:0,height:0}),this.isCropped=!1,this.renderCropBox(),this.limitCanvas(!0,!0),this.renderCanvas(),this.$dragBox.removeClass(L),this.$cropBox.addClass(X))},replace:function(t){!this.isDisabled&&t&&(this.isImg&&(this.isReplaced=!0,this.$element.attr("src",t)),this.options.data=null,this.load(t))},enable:function(){this.isBuilt&&(this.isDisabled=!1,this.$cropper.removeClass(W))},disable:function(){this.isBuilt&&(this.isDisabled=!0,this.$cropper.addClass(W))},destroy:function(){var t=this.$element;this.isLoaded?(this.isImg&&this.isReplaced&&t.attr("src",this.originalUrl),this.unbuild(),t.removeClass(X)):this.isImg?t.off(U,this.start):this.$clone&&this.$clone.remove(),t.removeData($)},move:function(t,i){var s=this.canvas;this.moveTo(e(t)?t:s.left+ft(t),e(i)?i:s.top+ft(i))},moveTo:function(t,s){var a=this.canvas,o=!1;e(s)&&(s=t),t=ft(t),s=ft(s),this.isBuilt&&!this.isDisabled&&this.options.movable&&(i(t)&&(a.left=t,o=!0),i(s)&&(a.top=s,o=!0),o&&this.renderCanvas(!0))},zoom:function(t,i){var e=this.canvas;t=ft(t),t=0>t?1/(1-t):1+t,this.zoomTo(e.width*t/e.naturalWidth,i)},zoomTo:function(t,i){var e,s,a,o,h,n=this.options,r=this.canvas,p=r.width,l=r.height,c=r.naturalWidth,g=r.naturalHeight;if(t=ft(t),t>=0&&this.isBuilt&&!this.isDisabled&&n.zoomable){if(s=c*t,a=g*t,i&&(e=i.originalEvent),this.trigger(Z,{originalEvent:e,oldRatio:p/c,ratio:s/c}).isDefaultPrevented())return;e?(o=this.$cropper.offset(),h=e.touches?d(e.touches):{pageX:i.pageX||e.pageX||0,pageY:i.pageY||e.pageY||0},r.left-=(s-p)*((h.pageX-o.left-r.left)/p),r.top-=(a-l)*((h.pageY-o.top-r.top)/l)):(r.left-=(s-p)/2,r.top-=(a-l)/2),r.width=s,r.height=a,this.renderCanvas(!0)}},rotate:function(t){this.rotateTo((this.image.rotate||0)+ft(t))},rotateTo:function(t){t=ft(t),i(t)&&this.isBuilt&&!this.isDisabled&&this.options.rotatable&&(this.image.rotate=t%360,this.isRotated=!0,this.renderCanvas(!0))},scale:function(t,s){var a=this.image,o=!1;e(s)&&(s=t),t=ft(t),s=ft(s),this.isBuilt&&!this.isDisabled&&this.options.scalable&&(i(t)&&(a.scaleX=t,o=!0),i(s)&&(a.scaleY=s,o=!0),o&&this.renderImage(!0))},scaleX:function(t){var e=this.image.scaleY;this.scale(t,i(e)?e:1)},scaleY:function(t){var e=this.image.scaleX;this.scale(i(e)?e:1,t)},getData:function(i){var e,s,a=this.options,o=this.image,h=this.canvas,n=this.cropBox;return this.isBuilt&&this.isCropped?(s={x:n.left-h.left,y:n.top-h.top,width:n.width,height:n.height},e=o.width/o.naturalWidth,t.each(s,function(t,a){a/=e,s[t]=i?Bt(a):a})):s={x:0,y:0,width:0,height:0},a.rotatable&&(s.rotate=o.rotate||0),a.scalable&&(s.scaleX=o.scaleX||1,s.scaleY=o.scaleY||1),s},setData:function(e){var s,a,o,h=this.options,n=this.image,r=this.canvas,p={};t.isFunction(e)&&(e=e.call(this.element)),this.isBuilt&&!this.isDisabled&&t.isPlainObject(e)&&(h.rotatable&&i(e.rotate)&&e.rotate!==n.rotate&&(n.rotate=e.rotate,this.isRotated=s=!0),h.scalable&&(i(e.scaleX)&&e.scaleX!==n.scaleX&&(n.scaleX=e.scaleX,a=!0),i(e.scaleY)&&e.scaleY!==n.scaleY&&(n.scaleY=e.scaleY,a=!0)),s?this.renderCanvas():a&&this.renderImage(),o=n.width/n.naturalWidth,i(e.x)&&(p.left=e.x*o+r.left),i(e.y)&&(p.top=e.y*o+r.top),i(e.width)&&(p.width=e.width*o),i(e.height)&&(p.height=e.height*o),this.setCropBoxData(p))},getContainerData:function(){return this.isBuilt?this.container:{}},getImageData:function(){return this.isLoaded?this.image:{}},getCanvasData:function(){var i=this.canvas,e={};return this.isBuilt&&t.each(["left","top","width","height","naturalWidth","naturalHeight"],function(t,s){e[s]=i[s]}),e},setCanvasData:function(e){var s=this.canvas,a=s.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.isBuilt&&!this.isDisabled&&t.isPlainObject(e)&&(i(e.left)&&(s.left=e.left),i(e.top)&&(s.top=e.top),i(e.width)?(s.width=e.width,s.height=e.width/a):i(e.height)&&(s.height=e.height,s.width=e.height*a),this.renderCanvas(!0))},getCropBoxData:function(){var t,i=this.cropBox;return this.isBuilt&&this.isCropped&&(t={left:i.left,top:i.top,width:i.width,height:i.height}),t||{}},setCropBoxData:function(e){var s,a,o=this.cropBox,h=this.options.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.isBuilt&&this.isCropped&&!this.isDisabled&&t.isPlainObject(e)&&(i(e.left)&&(o.left=e.left),i(e.top)&&(o.top=e.top),i(e.width)&&(s=!0,o.width=e.width),i(e.height)&&(a=!0,o.height=e.height),h&&(s?o.height=o.width/h:a&&(o.width=o.height*h)),this.renderCropBox())},getCroppedCanvas:function(i){var e,s,a,o,h,n,r,p,l,d,g;return this.isBuilt&&this.isCropped&&ut?(t.isPlainObject(i)||(i={}),g=this.getData(),e=g.width,s=g.height,p=e/s,t.isPlainObject(i)&&(h=i.width,n=i.height,h?(n=h/p,r=h/e):n&&(h=n*p,r=n/s)),a=yt(h||e),o=yt(n||s),l=t("<canvas>")[0],l.width=a,l.height=o,d=l.getContext("2d"),i.fillColor&&(d.fillStyle=i.fillColor,d.fillRect(0,0,a,o)),d.drawImage.apply(d,function(){var t,i,a,o,h,n,p=c(this.$clone[0],this.image),l=p.width,d=p.height,u=[p],f=g.x,m=g.y;return-e>=f||f>l?f=t=a=h=0:0>=f?(a=-f,f=0,t=h=mt(l,e+f)):l>=f&&(a=0,t=h=mt(e,l-f)),0>=t||-s>=m||m>d?m=i=o=n=0:0>=m?(o=-m,m=0,i=n=mt(d,s+m)):d>=m&&(o=0,i=n=mt(s,d-m)),u.push(yt(f),yt(m),yt(t),yt(i)),r&&(a*=r,o*=r,h*=r,n*=r),h>0&&n>0&&u.push(yt(a),yt(o),yt(h),yt(n)),u}.call(this)),l):void 0},setAspectRatio:function(t){var i=this.options;this.isDisabled||e(t)||(i.aspectRatio=vt(0,t)||NaN,this.isBuilt&&(this.initCropBox(),this.isCropped&&this.renderCropBox()))},setDragMode:function(t){var i,e,s=this.options;this.isLoaded&&!this.isDisabled&&(i=t===lt,e=s.movable&&t===ct,t=i||e?t:gt,this.$dragBox.data(tt,t).toggleClass(M,i).toggleClass(k,e),s.cropBoxMovable||this.$face.data(tt,t).toggleClass(M,i).toggleClass(k,e))}},v.DEFAULTS={viewMode:0,dragMode:"crop",aspectRatio:NaN,data:null,preview:"",responsive:!0,restore:!0,checkCrossOrigin:!0,checkOrientation:!0,modal:!0,guides:!0,center:!0,highlight:!0,background:!0,autoCrop:!0,autoCropArea:.8,movable:!0,rotatable:!0,scalable:!0,zoomable:!0,zoomOnTouch:!0,zoomOnWheel:!0,wheelZoomRatio:.1,cropBoxMovable:!0,cropBoxResizable:!0,toggleDragModeOnDblclick:!0,minCanvasWidth:0,minCanvasHeight:0,minCropBoxWidth:0,minCropBoxHeight:0,minContainerWidth:200,minContainerHeight:100,build:null,built:null,cropstart:null,cropmove:null,cropend:null,crop:null,zoom:null},v.setDefaults=function(i){t.extend(v.DEFAULTS,i)},v.TEMPLATE='<div class="cropper-container"><div class="cropper-wrap-box"><div class="cropper-canvas"></div></div><div class="cropper-drag-box"></div><div class="cropper-crop-box"><span class="cropper-view-box"></span><span class="cropper-dashed dashed-h"></span><span class="cropper-dashed dashed-v"></span><span class="cropper-center"></span><span class="cropper-face"></span><span class="cropper-line line-e" data-action="e"></span><span class="cropper-line line-n" data-action="n"></span><span class="cropper-line line-w" data-action="w"></span><span class="cropper-line line-s" data-action="s"></span><span class="cropper-point point-e" data-action="e"></span><span class="cropper-point point-n" data-action="n"></span><span class="cropper-point point-w" data-action="w"></span><span class="cropper-point point-s" data-action="s"></span><span class="cropper-point point-ne" data-action="ne"></span><span class="cropper-point point-nw" data-action="nw"></span><span class="cropper-point point-sw" data-action="sw"></span><span class="cropper-point point-se" data-action="se"></span></div></div>',v.other=t.fn.cropper,t.fn.cropper=function(i){var a,o=s(arguments,1);return this.each(function(){var e,s,h=t(this),n=h.data($);if(!n){if(/destroy/.test(i))return;e=t.extend({},h.data(),t.isPlainObject(i)&&i),h.data($,n=new v(this,e))}"string"==typeof i&&t.isFunction(s=n[i])&&(a=s.apply(n,o))}),e(a)?this:a},t.fn.cropper.Constructor=v,t.fn.cropper.setDefaults=v.setDefaults,t.fn.cropper.noConflict=function(){return t.fn.cropper=v.other,this}});
admin/manage/actions.php CHANGED
@@ -240,6 +240,13 @@ function ngg_edit_thumbnail( $id ) {
240
  $width = $picture->meta_data['width'];
241
  $height = $picture->meta_data['height'];
242
 
 
 
 
 
 
 
 
243
  ?>
244
  <table style="width: 100%">
245
  <tr>
@@ -270,7 +277,7 @@ function ngg_edit_thumbnail( $id ) {
270
  <span class="dashicons dashicons-align-center"></span>
271
  </button>
272
  </div>
273
- <img src="<?php echo esc_url( $picture->imageURL ); ?>" alt="" id="imageToEdit" style="max-width: 100%; max-height: 100%; width: auto; height: auto;"/>
274
  </td>
275
  <td>
276
  <div class="thumb-preview" style="max-width: 100%; width: 300px; height: 150px; overflow: hidden; margin-bottom: 10px; margin-left: auto; margin-right: auto; border: 1px solid black">
@@ -304,37 +311,36 @@ function ngg_edit_thumbnail( $id ) {
304
  <input id="dataY" type="number" placeholder="0"> <?php _e( 'px', 'nggallery' ) ?>
305
  </td>
306
  </tr>
307
- <tr>
308
- <td>
309
- <label for="dataWidth"><?php _e( 'Width', 'nggallery' ) ?></label>
310
- </td>
311
- <td style="text-align: right">
312
- <input id="dataWidth" type="number" placeholder="<?php echo $width ?>"> <?php _e( 'px',
313
- 'nggallery' ) ?>
314
- </td>
315
- </tr>
316
- <tr>
317
- <td>
318
- <label for="dataHeight"><?php _e( 'Height', 'nggallery' ) ?></label>
319
- </td>
320
- <td style="text-align: right">
321
- <input id="dataHeight" type="number" placeholder="<?php echo $height ?>"> <?php _e( 'px',
322
- 'nggallery' ) ?>
323
- </td>
324
- </tr>
325
- <tr>
326
- <td>
327
- <label for="dataRotate"><?php _e( 'Rotation', 'nggallery' ) ?></label>
328
- </td>
329
- <td style="text-align: right">
330
- <?php /* translators: stands for degrees, as in a rotation. Should be pretty short. */ ?>
331
- <input id="dataRotate" type="number" placeholder="0"> <?php _e( 'deg', 'nggallery' ) ?>
332
- </td>
333
- </tr>
334
  <tr>
335
  <td colspan="2" style="text-align: right">
336
- <button class="button button-secondary" type="button" id="apply-data" title="<?php _e( 'Apply the parameters',
337
- 'nggallery' ); ?>">
338
  <?php _e( 'Apply', 'nggallery' ); ?>
339
  </button>
340
  </td>
@@ -413,8 +419,13 @@ function ngg_edit_thumbnail( $id ) {
413
  */
414
  jQuery("#center-selection").click(function() {
415
 
 
416
  var width = parseInt($dataWidth.val());
417
  var height = parseInt($dataHeight.val());
 
 
 
 
418
  var img_width = <?php echo esc_js( $width ) ?>;
419
  var img_height = <?php echo esc_js( $height ) ?>;
420
 
@@ -438,7 +449,10 @@ function ngg_edit_thumbnail( $id ) {
438
  $dataHeight.val(Math.round(data.height));
439
  $dataWidth.val(Math.round(data.width));
440
  $dataRotate.val(Math.round(data.rotate));
441
- }
 
 
 
442
  });
443
  });
444
  </script>
240
  $width = $picture->meta_data['width'];
241
  $height = $picture->meta_data['height'];
242
 
243
+ $ngg_options = get_option('ngg_options');
244
+
245
+ $differentSizes = false;
246
+ if(isset($ngg_options['thumbDifferentSize'])) {
247
+ $differentSizes = (bool) $ngg_options['thumbDifferentSize'];
248
+ }
249
+
250
  ?>
251
  <table style="width: 100%">
252
  <tr>
277
  <span class="dashicons dashicons-align-center"></span>
278
  </button>
279
  </div>
280
+ <img src="<?php echo esc_url( $picture->imageURL ); ?>" alt="" id="imageToEdit" style="max-width: 60%; max-height: 60%; width: auto; height: auto;"/>
281
  </td>
282
  <td>
283
  <div class="thumb-preview" style="max-width: 100%; width: 300px; height: 150px; overflow: hidden; margin-bottom: 10px; margin-left: auto; margin-right: auto; border: 1px solid black">
311
  <input id="dataY" type="number" placeholder="0"> <?php _e( 'px', 'nggallery' ) ?>
312
  </td>
313
  </tr>
314
+ <?php if($differentSizes): ?>
315
+ <tr>
316
+ <td>
317
+ <label for="dataWidth"><?php _e( 'Width', 'nggallery' ) ?></label>
318
+ </td>
319
+ <td style="text-align: right">
320
+ <input id="dataWidth" type="number" placeholder="<?php echo $width ?>"> <?php _e( 'px', 'nggallery' ) ?>
321
+ </td>
322
+ </tr>
323
+ <tr>
324
+ <td>
325
+ <label for="dataHeight"><?php _e( 'Height', 'nggallery' ) ?></label>
326
+ </td>
327
+ <td style="text-align: right">
328
+ <input id="dataHeight" type="number" placeholder="<?php echo $height ?>"> <?php _e( 'px', 'nggallery' ) ?>
329
+ </td>
330
+ </tr>
331
+ <tr>
332
+ <td>
333
+ <label for="dataRotate"><?php _e( 'Rotation', 'nggallery' ) ?></label>
334
+ </td>
335
+ <td style="text-align: right">
336
+ <?php /* translators: stands for degrees, as in a rotation. Should be pretty short. */ ?>
337
+ <input id="dataRotate" type="number" placeholder="0"> <?php _e( 'deg', 'nggallery' ) ?>
338
+ </td>
339
+ </tr>
340
+ <?php endif; ?>
341
  <tr>
342
  <td colspan="2" style="text-align: right">
343
+ <button class="button button-secondary" type="button" id="apply-data" title="<?php _e( 'Apply the parameters', 'nggallery' ); ?>">
 
344
  <?php _e( 'Apply', 'nggallery' ); ?>
345
  </button>
346
  </td>
419
  */
420
  jQuery("#center-selection").click(function() {
421
 
422
+ <?php if($differentSizes): ?>
423
  var width = parseInt($dataWidth.val());
424
  var height = parseInt($dataHeight.val());
425
+ <?php else: ?>
426
+ var width = <?php echo esc_js( $ngg_options['thumbwidth'] ) ?>;
427
+ var height = <?php echo esc_js( $ngg_options['thumbheight'] ) ?>;
428
+ <?php endif; ?>
429
  var img_width = <?php echo esc_js( $width ) ?>;
430
  var img_height = <?php echo esc_js( $height ) ?>;
431
 
449
  $dataHeight.val(Math.round(data.height));
450
  $dataWidth.val(Math.round(data.width));
451
  $dataRotate.val(Math.round(data.rotate));
452
+ },
453
+ <?php if(!$differentSizes): ?>
454
+ aspectRatio: <?php echo esc_js( $ngg_options['thumbwidth'] ) ?> / <?php echo esc_js( $ngg_options['thumbheight'] ) ?>
455
+ <?php endif; ?>
456
  });
457
  });
458
  </script>
admin/manage/class-ngg-abstract-image-manager.php CHANGED
@@ -42,7 +42,7 @@ abstract class NGG_Abstract_Image_Manager extends NGG_Manager {
42
  var $this = jQuery(this);
43
  var action = $this.data("action");
44
  var id = $this.data("id");
45
- var base_url = "<?php echo esc_js(NGGALLERY_URLPATH) . "admin/manage/actions.php?cmd=" ?>";
46
 
47
  if (!$spinner.length) {
48
  jQuery("body").append('<div id="spinner"></div>');
42
  var $this = jQuery(this);
43
  var action = $this.data("action");
44
  var id = $this.data("id");
45
+ var base_url = "<?php echo plugins_url('actions.php?cmd=', __FILE__) ?>";
46
 
47
  if (!$spinner.length) {
48
  jQuery("body").append('<div id="spinner"></div>');
admin/manage/class-ngg-gallery-list-table.php CHANGED
@@ -171,7 +171,7 @@ class NGG_Gallery_List_Table extends WP_List_Table {
171
  */
172
  public function get_columns() {
173
 
174
- return $this::get_columns_static();
175
  }
176
 
177
  /**
171
  */
172
  public function get_columns() {
173
 
174
+ return self::get_columns_static();
175
  }
176
 
177
  /**
admin/manage/class-ngg-image-list-table.php CHANGED
@@ -211,10 +211,14 @@ class NGG_Image_List_Table extends WP_List_Table {
211
  return '<textarea placeholder="' . __( "Separated by commas",
212
  'nggallery' ) . '" name="tags[' . $item->pid . ']" style="width:95%;" rows="2">' . $item->tags . '</textarea>';
213
  case 'exclude':
214
- return '<input name="exclude[' . $item->pid . ']" type="checkbox" value="1" ' . checked( $item->exclude ) . '/>';
215
  default:
216
  ob_start();
217
- do_action( 'ngg_manage_image_custom_column', $column_name, $item );
 
 
 
 
218
 
219
  return ob_get_clean();
220
  }
@@ -247,7 +251,7 @@ class NGG_Image_List_Table extends WP_List_Table {
247
  */
248
  public function get_columns() {
249
 
250
- return $this::get_columns_static();
251
  }
252
 
253
  /**
211
  return '<textarea placeholder="' . __( "Separated by commas",
212
  'nggallery' ) . '" name="tags[' . $item->pid . ']" style="width:95%;" rows="2">' . $item->tags . '</textarea>';
213
  case 'exclude':
214
+ return '<input name="exclude[' . $item->pid . ']" type="checkbox" value="1" ' . checked( $item->exclude, true, false ) . '/>';
215
  default:
216
  ob_start();
217
+ //The old action needs a pid.
218
+ do_action( 'ngg_manage_image_custom_column', $column_name, $item->pid );
219
+
220
+ //We pass the whole object to new action.
221
+ do_action( 'ncg_manage_image_custom_column', $column_name, $item );
222
 
223
  return ob_get_clean();
224
  }
251
  */
252
  public function get_columns() {
253
 
254
+ return self::get_columns_static();
255
  }
256
 
257
  /**
admin/manage/class-ngg-image-manager.php CHANGED
@@ -23,7 +23,11 @@ class NGG_Image_Manager extends NGG_Abstract_Image_Manager {
23
  parent::display();
24
 
25
  if ( isset( $_POST['form'] ) && $_POST['form'] === "gallery" ) {
26
- $this->handle_update_gallery();
 
 
 
 
27
  }
28
 
29
  if ( isset( $_POST['scan_folder'] ) ) {
@@ -227,7 +231,7 @@ class NGG_Image_Manager extends NGG_Abstract_Image_Manager {
227
  parent_dropdown();
228
  } ?>
229
  </select>
230
- <input class="button-secondary action" type="submit" name="addnewpage" value="<?php _e( 'Add page',
231
  'nggallery' ); ?>" id="group"/>
232
  </td>
233
  <?php } ?>
@@ -356,6 +360,44 @@ class NGG_Image_Manager extends NGG_Abstract_Image_Manager {
356
 
357
  return;
358
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
 
360
  }
361
  }
23
  parent::display();
24
 
25
  if ( isset( $_POST['form'] ) && $_POST['form'] === "gallery" ) {
26
+ if (isset ($_POST['add-new-page'])) {
27
+ $this->create_page();
28
+ } else {
29
+ $this->handle_update_gallery();
30
+ }
31
  }
32
 
33
  if ( isset( $_POST['scan_folder'] ) ) {
231
  parent_dropdown();
232
  } ?>
233
  </select>
234
+ <input class="button-secondary action" type="submit" name="add-new-page" value="<?php _e( 'Add page',
235
  'nggallery' ); ?>" id="group"/>
236
  </td>
237
  <?php } ?>
360
 
361
  return;
362
  }
363
+ }
364
+
365
+ /**
366
+ * Create a page with the same title as the current gallery, and include a shortcode to this
367
+ * gallery.
368
+ */
369
+ private function create_page()
370
+ {
371
+ if ( wp_verify_nonce( $_POST['_ngg_nonce_gallery'], 'ngg-update-gallery' ) === false ) {
372
+ nggGallery::show_error( __( 'You waited too long, or you cheated.', 'nggallery' ) );
373
+
374
+ return;
375
+ }
376
+
377
+ global $wpdb;
378
+
379
+ $parent_id = esc_attr($_POST['parent_id']);
380
+ $gallery_title = esc_attr($_POST['title']);
381
+ $gallery_name = $wpdb->get_var("SELECT name FROM $wpdb->nggallery WHERE gid = '$this->gid' ");
382
+
383
+ // Create a WP page
384
+ global $user_ID;
385
+
386
+ $page['post_type'] = 'page';
387
+ $page['post_content'] = '[nggallery id=' . $this->gid . ']';
388
+ $page['post_parent'] = $parent_id;
389
+ $page['post_author'] = $user_ID;
390
+ $page['post_status'] = 'publish';
391
+ $page['post_title'] = $gallery_title == '' ? $gallery_name : $gallery_title;
392
+ $page = apply_filters('ngg_add_new_page', $page, $this->gid);
393
+
394
+ $gallery_pageid = wp_insert_post ($page);
395
+ if ($gallery_pageid != 0) {
396
+ $result = $wpdb->query("UPDATE $wpdb->nggallery SET title= '$gallery_title', pageid = '$gallery_pageid' WHERE gid = '$this->gid'");
397
+ wp_cache_delete($this->gid, 'ngg_gallery');
398
+ nggGallery::show_message( sprintf( __( 'New page <strong>%s</strong> (ID: %s) created.','nggallery'), $gallery_title, $gallery_pageid ));
399
+ }
400
 
401
+ do_action('ngg_gallery_addnewpage', $this->gid);
402
  }
403
  }
admin/manage/class-ngg-search-manager.php CHANGED
@@ -18,7 +18,7 @@ class NGG_Search_Manager extends NGG_Abstract_Image_Manager {
18
  $this->search = $_GET['s'];
19
 
20
  add_filter( 'ngg_manage_images_columns', array( $this, 'add_column' ) );
21
- add_action( 'ngg_manage_image_custom_column', array( $this, 'add_column_content' ), 10, 2 );
22
  }
23
 
24
  public function display() {
18
  $this->search = $_GET['s'];
19
 
20
  add_filter( 'ngg_manage_images_columns', array( $this, 'add_column' ) );
21
+ add_action( 'ncg_manage_image_custom_column', array( $this, 'add_column_content' ), 10, 2 );
22
  }
23
 
24
  public function display() {
nggallery.php CHANGED
@@ -5,7 +5,7 @@ Plugin URI: http://www.wpgetready.com/nextcellent-gallery
5
  Description: A Photo Gallery for WordPress providing NextGEN legacy compatibility from version 1.9.13
6
  Author: WPGReady, Niknetniko based on Alex Rabe & PhotoCrati work.
7
  Author URI: http://www.wpgetready.com
8
- Version: 1.9.30
9
 
10
  Copyright (c) 2007-2011 by Alex Rabe & NextGEN DEV-Team
11
  Copyright (c) 2012 Photocrati Media
@@ -53,7 +53,7 @@ if (!class_exists('nggLoader')) {
53
  */
54
  class nggLoader {
55
 
56
- var $version = '1.9.30';
57
  var $dbversion = '1.8.3';
58
  var $minimum_WP = '4.0';
59
  var $options = '';
5
  Description: A Photo Gallery for WordPress providing NextGEN legacy compatibility from version 1.9.13
6
  Author: WPGReady, Niknetniko based on Alex Rabe & PhotoCrati work.
7
  Author URI: http://www.wpgetready.com
8
+ Version: 1.9.31
9
 
10
  Copyright (c) 2007-2011 by Alex Rabe & NextGEN DEV-Team
11
  Copyright (c) 2012 Photocrati Media
53
  */
54
  class nggLoader {
55
 
56
+ var $version = '1.9.31';
57
  var $dbversion = '1.8.3';
58
  var $minimum_WP = '4.0';
59
  var $options = '';
readme.txt CHANGED
@@ -8,15 +8,21 @@ License: GPLv2
8
 
9
  == Description ==
10
 
11
- = 1.9.30 - 2016-02-05 =
12
 
13
  What's in it for you?
14
 
15
- * Completely admin rewrite (Credits to Niko Strijbol. See details on https://bitbucket.org/wpgetready/nextcellent/pull-requests/62/rewrite-admin-section)
16
- * Several fixes (Credits to Niko Strijbol)
17
- * Bios4 provided also German translation (Late credits (included in previous version))
18
- * Etard the Live Caster found a XSS vulnerability (Late credits (included in previous version))
19
- * Thomas Bloomberg Hansen: Dashicon in TinyMCE
 
 
 
 
 
 
20
 
21
  VERY IMPORTANT: Read ON!
22
  -----------------------
@@ -326,14 +332,29 @@ Yes, since we use Javascript rather than flash, NextCellent Gallery is compatibl
326
 
327
  == Changelog ==
328
 
329
- = 1.9.30 - 2015-11-01 =
 
 
 
 
 
 
 
 
 
 
 
 
330
 
 
331
  * Completely admin rewrite (Credits to Niko Strijbol. See details on https://bitbucket.org/wpgetready/nextcellent/pull-requests/62/rewrite-admin-section)
332
  * Several fixes (Credits to Niko Strijbol)
333
  * Bios4 provided also German translation (Late credits (included in previous version))
334
  * Etard the Live Caster found a XSS vulnerability (Late credits (included in previous version))
335
  * Thomas Bloomberg Hansen: Dashicon in TinyMCE
336
 
 
 
337
  = 1.9.27 - 2015-10-01 =
338
  * Fixes for multisite (credits to Niko Strijbol)
339
  * Fix for slideshow (credits to Niko Strijbol)
8
 
9
  == Description ==
10
 
11
+ = 1.9.31 - 2016-09-05 = Fixes for 1.9.30
12
 
13
  What's in it for you?
14
 
15
+ * Added more help documentation
16
+ * Fix Add new page button
17
+ * Style improvement
18
+ * Enable different size thumbnails only if the option is set
19
+ * Wrong url fixed
20
+ * Updated cropper library to the latest version
21
+ * Fixed few things now working with several PHP versions.
22
+ * Few css fixes
23
+ * Update setting(s) class(es)
24
+ * Several fixes
25
+ ** All credits for Niko Strijbol **
26
 
27
  VERY IMPORTANT: Read ON!
28
  -----------------------
332
 
333
  == Changelog ==
334
 
335
+ = 1.9.31 - 2016-09-05 = FIX
336
+
337
+ * Added more help documentation
338
+ * Fix Add new page button
339
+ * Style improvement
340
+ * Enable different size thumbnails only if the option is set
341
+ * Wrong url fixed
342
+ * Updated cropper library to the latest version
343
+ * Fixed few things now working with several PHP versions.
344
+ * Few css fixes
345
+ * Update setting(s) class(es)
346
+ * Several fixes
347
+ ** All credits for Niko Strijbol **
348
 
349
+ = 1.9.30 - 2015-11-01 =
350
  * Completely admin rewrite (Credits to Niko Strijbol. See details on https://bitbucket.org/wpgetready/nextcellent/pull-requests/62/rewrite-admin-section)
351
  * Several fixes (Credits to Niko Strijbol)
352
  * Bios4 provided also German translation (Late credits (included in previous version))
353
  * Etard the Live Caster found a XSS vulnerability (Late credits (included in previous version))
354
  * Thomas Bloomberg Hansen: Dashicon in TinyMCE
355
 
356
+ = Versions 1.9.28 & 1.9.29 - Skipped
357
+
358
  = 1.9.27 - 2015-10-01 =
359
  * Fixes for multisite (credits to Niko Strijbol)
360
  * Fix for slideshow (credits to Niko Strijbol)