├── .gitignore
├── CropImageUpload.php
├── CropImageUploadAsset.php
├── CropImageUploadBehavior.php
├── LICENSE
├── README.md
├── assets
├── css
│ ├── Jcrop.gif
│ ├── jquery.Jcrop.css
│ └── jquery.Jcrop.min.css
└── js
│ ├── cropImageUpload.js
│ ├── jquery.Jcrop.js
│ ├── jquery.Jcrop.min.js
│ └── jquery.color.js
└── composer.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Include your project-specific ignores in this file
2 | # Read about how to use .gitignore: https://help.github.com/articles/ignoring-files
3 | # Compiled source #
4 | ###################
5 | *.com
6 | #*.class
7 | *.dll
8 | *.exe
9 | *.o
10 | *.so
11 | # Packages #
12 | ############
13 | # it's better to unpack these files and commit the raw source
14 | # git has its own built in compression methods
15 | *.7z
16 | *.dmg
17 | *.gz
18 | *.iso
19 | *.jar
20 | *.rar
21 | *.tar
22 | *.zip
23 | # Logs and databases #
24 | ######################
25 | *.log
26 | *.sql
27 | *.sqlite
28 | # OS generated files #
29 | ######################
30 | .DS_Store
31 | .DS_Store?
32 | ._*
33 | .Spotlight-V100
34 | .Trashes
35 | ehthumbs.db
36 | Thumbs.db
37 | #Composer
38 | #########
39 | composer.phar
40 | vendor
41 | composer.lock
42 | #Compass
43 | #########
44 | .sass-cache
45 | # Node
46 | #########
47 | lib-cov
48 | lcov.info
49 | *.seed
50 | *.csv
51 | *.dat
52 | *.out
53 | *.pid
54 | pids
55 | logs
56 | results
57 | build
58 | .grunt
59 | node_modules
60 | bower_components
61 | # PHPSTORM
62 | #########
63 | .idea
--------------------------------------------------------------------------------
/CropImageUpload.php:
--------------------------------------------------------------------------------
1 | 450, 'boxHeight' => 400];
28 |
29 | /**
30 | * @var string crop ratio
31 | * format is width:height where width and height are both floats
32 | * if has model, will be got from CropImageBehavior
33 | */
34 | public $ratio;
35 |
36 | /**
37 | * @var string attribute name storing crop value or crop value itself if no model
38 | * if has model, will be got from CropImageBehavior
39 | * crop value has topLeftX-topLeftY-width-height format where all variables are float
40 | * all coordinates are in percents of corresponded image dimension
41 | */
42 | public $crop_field;
43 |
44 | /**
45 | * @var string crop value
46 | * if has model, will be got from $crop_field of model
47 | * crop value has topLeftX-topLeftY-width-height format where all variables are float
48 | * all coordinates are in percents of corresponded image dimension
49 | */
50 | public $crop_value;
51 |
52 | /**
53 | * @var string css class of container that stores image crop
54 | */
55 | public $crop_class = 'crop_medium';
56 |
57 |
58 |
59 | /**
60 | * @var string url where uploaded files are stored
61 | * if empty and has model, will be got from CropImageBehavior
62 | */
63 | public $url;
64 |
65 |
66 | /**
67 | * @inheritdoc
68 | */
69 | public function run()
70 | {
71 | $jsOptions = [
72 | 'clientOptions' => $this->clientOptions,
73 | 'crop_class' => $this->crop_class,
74 | ];
75 |
76 | if ($this->hasModel()) {
77 | echo Html::activeInput('file', $this->model, $this->attribute, $this->options);
78 |
79 | $crops = null;
80 | foreach ($this->model->getBehaviors() as $beh) {
81 | if (!empty($beh->attribute) && $beh->attribute == $this->attribute && $beh instanceof CropImageUploadBehavior) {
82 | $crops = $beh->getConfigurations();
83 | $this->url = $beh->url;
84 | break;
85 | }
86 | }
87 |
88 | if (!$crops)
89 | throw new InvalidConfigException("CropImageUploadBehavior is not found for {$this->attribute} attribute");
90 |
91 | $jsOptions['crops'] = [];
92 | $input_name = Html::getInputName($this->model, $this->attribute);
93 | $input_id = Html::getInputId($this->model, $this->attribute);
94 |
95 | echo Html::hiddenInput($input_name . '[file]', Html::getAttributeValue($this->model, $this->attribute), ['id' => $input_id . '_image']);
96 |
97 | foreach ($crops as $ind => $crop) {
98 | $crop_id = $input_id . '_crop' . $ind;
99 | echo Html::hiddenInput($input_name . '[' . $ind . ']', $crop['value'] === false ? '-' : $crop['value'], ['id' => $crop_id]);
100 |
101 | $jsOptions['crops'][] = [
102 | 'input_id' => $crop_id,
103 | 'ratio' => $crop['ratio'],
104 | 'image' => $crop['image'],
105 | ];
106 | }
107 |
108 | } else {
109 | echo Html::fileInput($this->name, $this->value, $this->options);
110 |
111 | $crop_id = (isset($this->options['id']) ? $this->options['id'] : ($this->name . '_id')) . '_' . $this->crop_field;;
112 | echo Html::hiddenInput($this->crop_field, $this->crop_value, ['id' => $crop_id]);
113 |
114 | $jsOptions['crops'][] = [
115 | 'input_id' => $crop_id,
116 | 'ratio' => $this->ratio,
117 | ];
118 | }
119 |
120 | if ($this->url)
121 | $this->url = \Yii::getAlias($this->url);
122 |
123 | $jsOptions['url'] = $this->url;
124 |
125 |
126 | $this->registerPlugin($jsOptions);
127 | }
128 |
129 | /**
130 | * Registers jCrop
131 | */
132 | protected function registerPlugin($options)
133 | {
134 | $view = $this->getView();
135 | CropImageUploadAsset::register($view);
136 |
137 | $id = $this->options['id'];
138 |
139 | $view->registerJs("jQuery('#{$id}').cropImageUpload(".json_encode($options).");");
140 | }
141 | }
--------------------------------------------------------------------------------
/CropImageUploadAsset.php:
--------------------------------------------------------------------------------
1 | css[] = YII_DEBUG ? 'css/jquery.Jcrop.css' : 'css/jquery.Jcrop.min.css';
25 | $this->js[] = YII_DEBUG ? 'js/jquery.Jcrop.js' : 'js/jquery.Jcrop.min.js';
26 | $this->js[] = 'js/cropImageUpload.js';
27 | }
28 | }
--------------------------------------------------------------------------------
/CropImageUploadBehavior.php:
--------------------------------------------------------------------------------
1 | crops_internal === null) {
67 | /** @var BaseActiveRecord $model */
68 | $model = $this->owner;
69 |
70 | if (!empty($this->crops)) {
71 | $this->crops_internal = $this->crops;
72 | } else {
73 | $o = [];
74 | foreach (['cropped_field', 'crop_field', 'crop_width', 'ratio'] as $f) {
75 | if ($this->$f) {
76 | $o[$f] = $this->$f;
77 | }
78 | }
79 | $this->crops_internal = [$o];
80 | }
81 |
82 | foreach ($this->crops_internal as &$crop) {
83 | if (empty($crop['cropped_field'])) {
84 | $crop['value'] = false;
85 | $crop['image'] = $model->getOldAttribute($this->attribute);
86 | } else if (empty($crop['crop_field'])) {
87 | $crop['value'] = false;
88 | $crop['image'] = $model->getAttribute($crop['cropped_field']);
89 | } else {
90 | $crop['value'] = $model->getAttribute($crop['crop_field']);
91 | $crop['image'] = $model->getOldAttribute($this->attribute);
92 | }
93 | }
94 | }
95 | return $this->crops_internal;
96 | }
97 |
98 | /**
99 | * @inheritdoc
100 | */
101 | public function beforeValidate()
102 | {
103 | /** @var BaseActiveRecord $model */
104 | $model = $this->owner;
105 |
106 | if (in_array($model->scenario, $this->scenarios) && ($crops = $model->getAttribute($this->attribute)) && is_array($crops)) {
107 |
108 | $image_changed = (!$model->getOldAttribute($this->attribute) && $crops['file']) || ($model->getOldAttribute($this->attribute) != $crops['file']);
109 |
110 | $this->getConfigurations();
111 | foreach ($this->crops_internal as $ind => &$crop) {
112 | $crop['value'] = $crops[$ind];
113 | if ($crops[$ind] == '-')
114 | $crops[$ind] = '';
115 | if (empty($crop['crop_field'])) {
116 | $crop['_changed'] = !empty($crops[$ind]);
117 | } else {
118 | $crop['_changed'] = $crops[$ind] != $model->getAttribute($crop['crop_field']);
119 | $model->setAttribute($crop['crop_field'], $crops[$ind]);
120 | }
121 | if ($image_changed)
122 | $crop['_changed'] = true;
123 | else if ($model->getOldAttribute($this->attribute) == null)
124 | $crop['_changed'] = false;
125 | }
126 |
127 | $model->setAttribute($this->attribute, $crops['file']);
128 | }
129 |
130 | parent::beforeValidate();
131 | }
132 |
133 | /**
134 | * @inheritdoc
135 | */
136 | public function beforeSave()
137 | {
138 | parent::beforeSave();
139 |
140 | /** @var BaseActiveRecord $model */
141 | $model = $this->owner;
142 |
143 | if (in_array($model->scenario, $this->scenarios)) {
144 |
145 | $original = $model->getAttribute($this->attribute);
146 | if (!$original)
147 | $original = $model->getOldAttribute($this->attribute);
148 |
149 | foreach ($this->getConfigurations() as $crop) {
150 | if (isset($crop['_changed']) && $crop['_changed'] && !empty($crop['cropped_field'])) {
151 | $this->delete($crop['cropped_field'], true);
152 | if (!empty($crop['cropped_field']))
153 | $model->setAttribute($crop['cropped_field'], $this->getCropFileName($original));
154 | }
155 | }
156 | }
157 | }
158 | /**
159 | * @inheritdoc
160 | */
161 | public function afterSave()
162 | {
163 | parent::afterSave();
164 |
165 | if (in_array($this->owner->scenario, $this->scenarios)) {
166 | $image = null;
167 |
168 | foreach ($this->getConfigurations() as $crop) {
169 | if (isset($crop['_changed']) && $crop['_changed']) {
170 | if (!$image) {
171 | $path = $this->getUploadPath($this->attribute);
172 | if (!$path)
173 | $path = $this->getUploadPath($this->attribute, true);
174 | $image = Image::getImagine()->open($path);
175 | }
176 | $this->createCrop($crop, $image->copy());
177 | }
178 | }
179 | }
180 | }
181 | /**
182 | * this method crops the image
183 | * @param Array $crop crop config
184 | * @param \Imagine\Gd\Image $image
185 | */
186 | protected function createCrop($crop, $image)
187 | {
188 | if (!empty($crop['cropped_field'])) {
189 | $save_path = $this->getUploadPath($crop['cropped_field']);
190 | } else {
191 | $save_path = $this->getUploadPath($this->attribute);
192 | }
193 |
194 | $sizes = explode('-', $crop['value']);
195 |
196 | $real_size = $image->getSize();
197 |
198 | foreach ($sizes as $ind => $cr) {
199 | $sizes[$ind] = round($sizes[$ind]*($ind%2 == 0 ? $real_size->getWidth() : $real_size->getHeight())/100);
200 | }
201 |
202 | $crop_image = $image->crop(new Point($sizes[0], $sizes[1]), new Box($sizes[2]-$sizes[0], $sizes[3]-$sizes[1]));
203 |
204 | if (!empty($crop['crop_width']))
205 | $crop_image = $crop_image->resize(new Box($crop['crop_width'], $crop['crop_width'] / $crop['ratio']));
206 |
207 | $crop_image->save($save_path, isset($crop['save_options']) ? $crop['save_options'] : $this->save_options);
208 | }
209 |
210 | /**
211 | * @param $filename
212 | * @return string
213 | */
214 | protected function getCropFileName($filename)
215 | {
216 | return uniqid(rand(0, 9999)).'_'. $filename;
217 | }
218 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, karpoff
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of yii2-crop-image-upload nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | cropped image upload extension for Yii2
2 | ======================
3 |
4 | [](https://packagist.org/packages/karpoff/yii2-crop-image-upload) [](https://packagist.org/packages/karpoff/yii2-crop-image-upload) [](https://packagist.org/packages/karpoff/yii2-crop-image-upload) [](https://packagist.org/packages/karpoff/yii2-crop-image-upload)
5 |
6 | This extension automatically uploads image and make crop.
7 |
8 | Installation
9 | ------------
10 |
11 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
12 |
13 | Either run
14 |
15 | ```
16 | php composer.phar require --prefer-dist karpoff/yii2-crop-image-upload "*"
17 | ```
18 |
19 | or add
20 |
21 | ```json
22 | "karpoff/yii2-crop-image-upload": "*"
23 | ```
24 |
25 | to the `require` section of your `composer.json` file.
26 |
27 | Usage
28 | -----
29 |
30 | ### Upload image and create crop
31 |
32 | Attach the behavior in your model:
33 |
34 | ```php
35 | use karpoff\icrop\CropImageUploadBehavior;
36 |
37 | class Document extends ActiveRecord
38 | {
39 | /**
40 | * @inheritdoc
41 | */
42 | public function rules()
43 | {
44 | return [
45 | ['photo', 'file', 'extensions' => 'jpeg, gif, png', 'on' => ['insert', 'update']],
46 | ];
47 | }
48 |
49 | /**
50 | * @inheritdoc
51 | */
52 | function behaviors()
53 | {
54 | return [
55 | [
56 | 'class' => CropImageUploadBehavior::className(),
57 | 'attribute' => 'photo',
58 | 'scenarios' => ['insert', 'update'],
59 | 'path' => '@webroot/upload/docs',
60 | 'url' => '@web/upload/docs',
61 | 'ratio' => 1,
62 | 'crop_field' => 'photo_crop',
63 | 'cropped_field' => 'photo_cropped',
64 | ],
65 | ];
66 | }
67 | }
68 | ```
69 |
70 | Example view file:
71 |
72 | ```php
73 |
74 |
75 | ['enctype' => 'multipart/form-data']]); ?>
76 | = $form->field($model, 'photo')->widget(CropImageUpload::className()) ?>
77 |
78 | = Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
79 |
80 |
81 | ```
82 |
--------------------------------------------------------------------------------
/assets/css/Jcrop.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/karpoff/yii2-crop-image-upload/fd32a9c75539450a5e654f01004342aa47857c3f/assets/css/Jcrop.gif
--------------------------------------------------------------------------------
/assets/css/jquery.Jcrop.css:
--------------------------------------------------------------------------------
1 | /* jquery.Jcrop.css v0.9.12 - MIT License */
2 | /*
3 | The outer-most container in a typical Jcrop instance
4 | If you are having difficulty with formatting related to styles
5 | on a parent element, place any fixes here or in a like selector
6 |
7 | You can also style this element if you want to add a border, etc
8 | A better method for styling can be seen below with .jcrop-light
9 | (Add a class to the holder and style elements for that extended class)
10 | */
11 | .jcrop-holder {
12 | direction: ltr;
13 | text-align: left;
14 | }
15 | /* Selection Border */
16 | .jcrop-vline,
17 | .jcrop-hline {
18 | background: #ffffff url("Jcrop.gif");
19 | font-size: 0;
20 | position: absolute;
21 | }
22 | .jcrop-vline {
23 | height: 100%;
24 | width: 1px !important;
25 | }
26 | .jcrop-vline.right {
27 | right: 0;
28 | }
29 | .jcrop-hline {
30 | height: 1px !important;
31 | width: 100%;
32 | }
33 | .jcrop-hline.bottom {
34 | bottom: 0;
35 | }
36 | /* Invisible click targets */
37 | .jcrop-tracker {
38 | height: 100%;
39 | width: 100%;
40 | /* "turn off" link highlight */
41 | -webkit-tap-highlight-color: transparent;
42 | /* disable callout, image save panel */
43 | -webkit-touch-callout: none;
44 | /* disable cut copy paste */
45 | -webkit-user-select: none;
46 | }
47 | /* Selection Handles */
48 | .jcrop-handle {
49 | background-color: #333333;
50 | border: 1px #eeeeee solid;
51 | width: 7px;
52 | height: 7px;
53 | font-size: 1px;
54 | }
55 | .jcrop-handle.ord-n {
56 | left: 50%;
57 | margin-left: -4px;
58 | margin-top: -4px;
59 | top: 0;
60 | }
61 | .jcrop-handle.ord-s {
62 | bottom: 0;
63 | left: 50%;
64 | margin-bottom: -4px;
65 | margin-left: -4px;
66 | }
67 | .jcrop-handle.ord-e {
68 | margin-right: -4px;
69 | margin-top: -4px;
70 | right: 0;
71 | top: 50%;
72 | }
73 | .jcrop-handle.ord-w {
74 | left: 0;
75 | margin-left: -4px;
76 | margin-top: -4px;
77 | top: 50%;
78 | }
79 | .jcrop-handle.ord-nw {
80 | left: 0;
81 | margin-left: -4px;
82 | margin-top: -4px;
83 | top: 0;
84 | }
85 | .jcrop-handle.ord-ne {
86 | margin-right: -4px;
87 | margin-top: -4px;
88 | right: 0;
89 | top: 0;
90 | }
91 | .jcrop-handle.ord-se {
92 | bottom: 0;
93 | margin-bottom: -4px;
94 | margin-right: -4px;
95 | right: 0;
96 | }
97 | .jcrop-handle.ord-sw {
98 | bottom: 0;
99 | left: 0;
100 | margin-bottom: -4px;
101 | margin-left: -4px;
102 | }
103 | /* Dragbars */
104 | .jcrop-dragbar.ord-n,
105 | .jcrop-dragbar.ord-s {
106 | height: 7px;
107 | width: 100%;
108 | }
109 | .jcrop-dragbar.ord-e,
110 | .jcrop-dragbar.ord-w {
111 | height: 100%;
112 | width: 7px;
113 | }
114 | .jcrop-dragbar.ord-n {
115 | margin-top: -4px;
116 | }
117 | .jcrop-dragbar.ord-s {
118 | bottom: 0;
119 | margin-bottom: -4px;
120 | }
121 | .jcrop-dragbar.ord-e {
122 | margin-right: -4px;
123 | right: 0;
124 | }
125 | .jcrop-dragbar.ord-w {
126 | margin-left: -4px;
127 | }
128 | /* The "jcrop-light" class/extension */
129 | .jcrop-light .jcrop-vline,
130 | .jcrop-light .jcrop-hline {
131 | background: #ffffff;
132 | filter: alpha(opacity=70) !important;
133 | opacity: .70!important;
134 | }
135 | .jcrop-light .jcrop-handle {
136 | -moz-border-radius: 3px;
137 | -webkit-border-radius: 3px;
138 | background-color: #000000;
139 | border-color: #ffffff;
140 | border-radius: 3px;
141 | }
142 | /* The "jcrop-dark" class/extension */
143 | .jcrop-dark .jcrop-vline,
144 | .jcrop-dark .jcrop-hline {
145 | background: #000000;
146 | filter: alpha(opacity=70) !important;
147 | opacity: 0.7 !important;
148 | }
149 | .jcrop-dark .jcrop-handle {
150 | -moz-border-radius: 3px;
151 | -webkit-border-radius: 3px;
152 | background-color: #ffffff;
153 | border-color: #000000;
154 | border-radius: 3px;
155 | }
156 | /* Simple macro to turn off the antlines */
157 | .solid-line .jcrop-vline,
158 | .solid-line .jcrop-hline {
159 | background: #ffffff;
160 | }
161 | /* Fix for twitter bootstrap et al. */
162 | .jcrop-holder img,
163 | img.jcrop-preview {
164 | max-width: none;
165 | }
166 |
--------------------------------------------------------------------------------
/assets/css/jquery.Jcrop.min.css:
--------------------------------------------------------------------------------
1 | /* jquery.Jcrop.min.css v0.9.12 (build:20130126) */
2 | .jcrop-holder{direction:ltr;text-align:left;}
3 | .jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif);font-size:0;position:absolute;}
4 | .jcrop-vline{height:100%;width:1px!important;}
5 | .jcrop-vline.right{right:0;}
6 | .jcrop-hline{height:1px!important;width:100%;}
7 | .jcrop-hline.bottom{bottom:0;}
8 | .jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;}
9 | .jcrop-handle{background-color:#333;border:1px #EEE solid;font-size:1px;height:7px;width:7px;}
10 | .jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
11 | .jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
12 | .jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
13 | .jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
14 | .jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
15 | .jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
16 | .jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
17 | .jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
18 | .jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
19 | .jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
20 | .jcrop-dragbar.ord-n{margin-top:-4px;}
21 | .jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
22 | .jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
23 | .jcrop-dragbar.ord-w{margin-left:-4px;}
24 | .jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:alpha(opacity=70)!important;opacity:.70!important;}
25 | .jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;}
26 | .jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:alpha(opacity=70)!important;opacity:.7!important;}
27 | .jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;}
28 | .solid-line .jcrop-vline,.solid-line .jcrop-hline{background:#FFF;}
29 | .jcrop-holder img,img.jcrop-preview{max-width:none;}
30 |
--------------------------------------------------------------------------------
/assets/js/cropImageUpload.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 |
3 | $.fn.cropImageUpload = function (config) {
4 | var _obj = $(this);
5 | _obj.on('change', function() {
6 | var file = this.files[0];
7 | var fr = new FileReader();
8 | fr.onload = function (readerEvt) {
9 | _image_store.html('');
10 | $('#' + _obj.attr('id') + '_image').val(Math.random().toString(36).replace(/[^a-z]+/g, '') + '.' + fr.result.split(';')[0].split('/')[1]);
11 | $.each(config.crops, function() {
12 | make_crops(this, fr.result);
13 | });
14 | };
15 | fr.readAsDataURL(file);
16 | return false;
17 | });
18 |
19 | var _image_store = $('', {'class': 'crop-image-upload-container'}).insertAfter(_obj);
20 |
21 | if (config.crop_class)
22 | _image_store.addClass(config.crop_class);
23 |
24 | var make_crops = function(crop, src) {
25 | if (crop.ratio && (crop.image || src)) {
26 | var cropImage = $('
![]()
', {
27 | 'src': src ? src : ((config.url ? config.url : '') + '/' + crop.image)
28 | }).hide();
29 | _image_store.append(cropImage);
30 |
31 | var cropStore = $('#' + crop.input_id);
32 | var cropValue = cropStore.val();
33 |
34 | var cropImageW;
35 | var cropImageH;
36 | var cropTimeout;
37 |
38 | if (cropValue == '-') {
39 | cropValue = '';
40 | cropStore.val(cropValue);
41 | if (!src) {
42 | cropImage.show();
43 | return;
44 | }
45 | }
46 |
47 | if (cropValue == '')
48 | cropValue = ('0-0-100-100');
49 |
50 | function percent (val, main) { return Number((val*100/main).toFixed(2)); }
51 |
52 | var storeCropParams = function(c) {
53 | cropStore.val(percent(c.x, cropImageW) + '-' + percent(c.y, cropImageH) + '-' + percent(c.x2, cropImageW) + '-' + percent(c.y2, cropImageH));
54 | };
55 |
56 | var cropParams = {};
57 | if (config.clientOptions)
58 | $.extend(cropParams, config.clientOptions);
59 | cropParams.onSelect = storeCropParams;
60 | cropParams.onChange = storeCropParams;
61 |
62 | if (crop.ratio) {
63 | cropParams.aspectRatio = crop.ratio;
64 | }
65 |
66 | cropImage.Jcrop(cropParams, function(){
67 | cropImageW = cropImage.width();
68 | cropImageH = cropImage.height();
69 |
70 | var pp = cropValue.split('-');
71 |
72 | pp[0] = pp[0]*cropImageW/100;
73 | pp[1] = pp[1]*cropImageH/100;
74 | pp[2] = pp[2]*cropImageW/100;
75 | pp[3] = pp[3]*cropImageH/100;
76 | this.setSelect(pp);
77 | _image_store.show();
78 | });
79 | }
80 | };
81 |
82 | $.each(config.crops, function() {
83 | make_crops(this);
84 | });
85 | };
86 |
87 |
88 | })(window.jQuery);
89 |
--------------------------------------------------------------------------------
/assets/js/jquery.Jcrop.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.Jcrop.js v0.9.12
3 | * jQuery Image Cropping Plugin - released under MIT License
4 | * Author: Kelly Hallman
5 | * http://github.com/tapmodo/Jcrop
6 | * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{
7 | *
8 | * Permission is hereby granted, free of charge, to any person
9 | * obtaining a copy of this software and associated documentation
10 | * files (the "Software"), to deal in the Software without
11 | * restriction, including without limitation the rights to use,
12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the
14 | * Software is furnished to do so, subject to the following
15 | * conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be
18 | * included in all copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 | * OTHER DEALINGS IN THE SOFTWARE.
28 | *
29 | * }}}
30 | */
31 |
32 | (function ($) {
33 |
34 | $.Jcrop = function (obj, opt) {
35 | var options = $.extend({}, $.Jcrop.defaults),
36 | docOffset,
37 | _ua = navigator.userAgent.toLowerCase(),
38 | is_msie = /msie/.test(_ua),
39 | ie6mode = /msie [1-6]\./.test(_ua);
40 |
41 | // Internal Methods {{{
42 | function px(n) {
43 | return Math.round(n) + 'px';
44 | }
45 | function cssClass(cl) {
46 | return options.baseClass + '-' + cl;
47 | }
48 | function supportsColorFade() {
49 | return $.fx.step.hasOwnProperty('backgroundColor');
50 | }
51 | function getPos(obj) //{{{
52 | {
53 | var pos = $(obj).offset();
54 | return [pos.left, pos.top];
55 | }
56 | //}}}
57 | function mouseAbs(e) //{{{
58 | {
59 | return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
60 | }
61 | //}}}
62 | function setOptions(opt) //{{{
63 | {
64 | if (typeof(opt) !== 'object') opt = {};
65 | options = $.extend(options, opt);
66 |
67 | $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) {
68 | if (typeof(options[e]) !== 'function') options[e] = function () {};
69 | });
70 | }
71 | //}}}
72 | function startDragMode(mode, pos, touch) //{{{
73 | {
74 | docOffset = getPos($img);
75 | Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');
76 |
77 | if (mode === 'move') {
78 | return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
79 | }
80 |
81 | var fc = Coords.getFixed();
82 | var opp = oppLockCorner(mode);
83 | var opc = Coords.getCorner(oppLockCorner(opp));
84 |
85 | Coords.setPressed(Coords.getCorner(opp));
86 | Coords.setCurrent(opc);
87 |
88 | Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
89 | }
90 | //}}}
91 | function dragmodeHandler(mode, f) //{{{
92 | {
93 | return function (pos) {
94 | if (!options.aspectRatio) {
95 | switch (mode) {
96 | case 'e':
97 | pos[1] = f.y2;
98 | break;
99 | case 'w':
100 | pos[1] = f.y2;
101 | break;
102 | case 'n':
103 | pos[0] = f.x2;
104 | break;
105 | case 's':
106 | pos[0] = f.x2;
107 | break;
108 | }
109 | } else {
110 | switch (mode) {
111 | case 'e':
112 | pos[1] = f.y + 1;
113 | break;
114 | case 'w':
115 | pos[1] = f.y + 1;
116 | break;
117 | case 'n':
118 | pos[0] = f.x + 1;
119 | break;
120 | case 's':
121 | pos[0] = f.x + 1;
122 | break;
123 | }
124 | }
125 | Coords.setCurrent(pos);
126 | Selection.update();
127 | };
128 | }
129 | //}}}
130 | function createMover(pos) //{{{
131 | {
132 | var lloc = pos;
133 | KeyManager.watchKeys();
134 |
135 | return function (pos) {
136 | Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
137 | lloc = pos;
138 |
139 | Selection.update();
140 | };
141 | }
142 | //}}}
143 | function oppLockCorner(ord) //{{{
144 | {
145 | switch (ord) {
146 | case 'n':
147 | return 'sw';
148 | case 's':
149 | return 'nw';
150 | case 'e':
151 | return 'nw';
152 | case 'w':
153 | return 'ne';
154 | case 'ne':
155 | return 'sw';
156 | case 'nw':
157 | return 'se';
158 | case 'se':
159 | return 'nw';
160 | case 'sw':
161 | return 'ne';
162 | }
163 | }
164 | //}}}
165 | function createDragger(ord) //{{{
166 | {
167 | return function (e) {
168 | if (options.disabled) {
169 | return false;
170 | }
171 | if ((ord === 'move') && !options.allowMove) {
172 | return false;
173 | }
174 |
175 | // Fix position of crop area when dragged the very first time.
176 | // Necessary when crop image is in a hidden element when page is loaded.
177 | docOffset = getPos($img);
178 |
179 | btndown = true;
180 | startDragMode(ord, mouseAbs(e));
181 | e.stopPropagation();
182 | e.preventDefault();
183 | return false;
184 | };
185 | }
186 | //}}}
187 | function presize($obj, w, h) //{{{
188 | {
189 | var nw = $obj.width(),
190 | nh = $obj.height();
191 | if ((nw > w) && w > 0) {
192 | nw = w;
193 | nh = (w / $obj.width()) * $obj.height();
194 | }
195 | if ((nh > h) && h > 0) {
196 | nh = h;
197 | nw = (h / $obj.height()) * $obj.width();
198 | }
199 | xscale = $obj.width() / nw;
200 | yscale = $obj.height() / nh;
201 | $obj.width(nw).height(nh);
202 | }
203 | //}}}
204 | function unscale(c) //{{{
205 | {
206 | return {
207 | x: c.x * xscale,
208 | y: c.y * yscale,
209 | x2: c.x2 * xscale,
210 | y2: c.y2 * yscale,
211 | w: c.w * xscale,
212 | h: c.h * yscale
213 | };
214 | }
215 | //}}}
216 | function doneSelect(pos) //{{{
217 | {
218 | var c = Coords.getFixed();
219 | if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
220 | Selection.enableHandles();
221 | Selection.done();
222 | } else {
223 | Selection.release();
224 | }
225 | Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
226 | }
227 | //}}}
228 | function newSelection(e) //{{{
229 | {
230 | if (options.disabled) {
231 | return false;
232 | }
233 | if (!options.allowSelect) {
234 | return false;
235 | }
236 | btndown = true;
237 | docOffset = getPos($img);
238 | Selection.disableHandles();
239 | Tracker.setCursor('crosshair');
240 | var pos = mouseAbs(e);
241 | Coords.setPressed(pos);
242 | Selection.update();
243 | Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0,5)==='touch');
244 | KeyManager.watchKeys();
245 |
246 | e.stopPropagation();
247 | e.preventDefault();
248 | return false;
249 | }
250 | //}}}
251 | function selectDrag(pos) //{{{
252 | {
253 | Coords.setCurrent(pos);
254 | Selection.update();
255 | }
256 | //}}}
257 | function newTracker() //{{{
258 | {
259 | var trk = $('').addClass(cssClass('tracker'));
260 | if (is_msie) {
261 | trk.css({
262 | opacity: 0,
263 | backgroundColor: 'white'
264 | });
265 | }
266 | return trk;
267 | }
268 | //}}}
269 |
270 | // }}}
271 | // Initialization {{{
272 | // Sanitize some options {{{
273 | if (typeof(obj) !== 'object') {
274 | obj = $(obj)[0];
275 | }
276 | if (typeof(opt) !== 'object') {
277 | opt = {};
278 | }
279 | // }}}
280 | setOptions(opt);
281 | // Initialize some jQuery objects {{{
282 | // The values are SET on the image(s) for the interface
283 | // If the original image has any of these set, they will be reset
284 | // However, if you destroy() the Jcrop instance the original image's
285 | // character in the DOM will be as you left it.
286 | var img_css = {
287 | border: 'none',
288 | visibility: 'visible',
289 | margin: 0,
290 | padding: 0,
291 | position: 'absolute',
292 | top: 0,
293 | left: 0
294 | };
295 |
296 | var $origimg = $(obj),
297 | img_mode = true;
298 |
299 | if (obj.tagName == 'IMG') {
300 | // Fix size of crop image.
301 | // Necessary when crop image is within a hidden element when page is loaded.
302 | if ($origimg[0].width != 0 && $origimg[0].height != 0) {
303 | // Obtain dimensions from contained img element.
304 | $origimg.width($origimg[0].width);
305 | $origimg.height($origimg[0].height);
306 | } else {
307 | // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0).
308 | var tempImage = new Image();
309 | tempImage.src = $origimg[0].src;
310 | $origimg.width(tempImage.width);
311 | $origimg.height(tempImage.height);
312 | }
313 |
314 | var $img = $origimg.clone().removeAttr('id').css(img_css).show();
315 |
316 | $img.width($origimg.width());
317 | $img.height($origimg.height());
318 | $origimg.after($img).hide();
319 |
320 | } else {
321 | $img = $origimg.css(img_css).show();
322 | img_mode = false;
323 | if (options.shade === null) { options.shade = true; }
324 | }
325 |
326 | presize($img, options.boxWidth, options.boxHeight);
327 |
328 | var boundx = $img.width(),
329 | boundy = $img.height(),
330 |
331 |
332 | $div = $('').width(boundx).height(boundy).addClass(cssClass('holder')).css({
333 | position: 'relative',
334 | backgroundColor: options.bgColor
335 | }).insertAfter($origimg).append($img);
336 |
337 | if (options.addClass) {
338 | $div.addClass(options.addClass);
339 | }
340 |
341 | var $img2 = $(''),
342 |
343 | $img_holder = $('')
344 | .width('100%').height('100%').css({
345 | zIndex: 310,
346 | position: 'absolute',
347 | overflow: 'hidden'
348 | }),
349 |
350 | $hdl_holder = $('')
351 | .width('100%').height('100%').css('zIndex', 320),
352 |
353 | $sel = $('')
354 | .css({
355 | position: 'absolute',
356 | zIndex: 600
357 | }).dblclick(function(){
358 | var c = Coords.getFixed();
359 | options.onDblClick.call(api,c);
360 | }).insertBefore($img).append($img_holder, $hdl_holder);
361 |
362 | if (img_mode) {
363 |
364 | $img2 = $('
')
365 | .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),
366 |
367 | $img_holder.append($img2);
368 |
369 | }
370 |
371 | if (ie6mode) {
372 | $sel.css({
373 | overflowY: 'hidden'
374 | });
375 | }
376 |
377 | var bound = options.boundary;
378 | var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
379 | position: 'absolute',
380 | top: px(-bound),
381 | left: px(-bound),
382 | zIndex: 290
383 | }).mousedown(newSelection);
384 |
385 | /* }}} */
386 | // Set more variables {{{
387 | var bgcolor = options.bgColor,
388 | bgopacity = options.bgOpacity,
389 | xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
390 | btndown, animating, shift_down;
391 |
392 | docOffset = getPos($img);
393 | // }}}
394 | // }}}
395 | // Internal Modules {{{
396 | // Touch Module {{{
397 | var Touch = (function () {
398 | // Touch support detection function adapted (under MIT License)
399 | // from code by Jeffrey Sambells - http://github.com/iamamused/
400 | function hasTouchSupport() {
401 | var support = {}, events = ['touchstart', 'touchmove', 'touchend'],
402 | el = document.createElement('div'), i;
403 |
404 | try {
405 | for(i=0; i x1 + ox) {
491 | ox -= ox + x1;
492 | }
493 | if (0 > y1 + oy) {
494 | oy -= oy + y1;
495 | }
496 |
497 | if (boundy < y2 + oy) {
498 | oy += boundy - (y2 + oy);
499 | }
500 | if (boundx < x2 + ox) {
501 | ox += boundx - (x2 + ox);
502 | }
503 |
504 | x1 += ox;
505 | x2 += ox;
506 | y1 += oy;
507 | y2 += oy;
508 | }
509 | //}}}
510 | function getCorner(ord) //{{{
511 | {
512 | var c = getFixed();
513 | switch (ord) {
514 | case 'ne':
515 | return [c.x2, c.y];
516 | case 'nw':
517 | return [c.x, c.y];
518 | case 'se':
519 | return [c.x2, c.y2];
520 | case 'sw':
521 | return [c.x, c.y2];
522 | }
523 | }
524 | //}}}
525 | function getFixed() //{{{
526 | {
527 | if (!options.aspectRatio) {
528 | return getRect();
529 | }
530 | // This function could use some optimization I think...
531 | var aspect = options.aspectRatio,
532 | min_x = options.minSize[0] / xscale,
533 |
534 |
535 | //min_y = options.minSize[1]/yscale,
536 | max_x = options.maxSize[0] / xscale,
537 | max_y = options.maxSize[1] / yscale,
538 | rw = x2 - x1,
539 | rh = y2 - y1,
540 | rwa = Math.abs(rw),
541 | rha = Math.abs(rh),
542 | real_ratio = rwa / rha,
543 | xx, yy, w, h;
544 |
545 | if (max_x === 0) {
546 | max_x = boundx * 10;
547 | }
548 | if (max_y === 0) {
549 | max_y = boundy * 10;
550 | }
551 | if (real_ratio < aspect) {
552 | yy = y2;
553 | w = rha * aspect;
554 | xx = rw < 0 ? x1 - w : w + x1;
555 |
556 | if (xx < 0) {
557 | xx = 0;
558 | h = Math.abs((xx - x1) / aspect);
559 | yy = rh < 0 ? y1 - h : h + y1;
560 | } else if (xx > boundx) {
561 | xx = boundx;
562 | h = Math.abs((xx - x1) / aspect);
563 | yy = rh < 0 ? y1 - h : h + y1;
564 | }
565 | } else {
566 | xx = x2;
567 | h = rwa / aspect;
568 | yy = rh < 0 ? y1 - h : y1 + h;
569 | if (yy < 0) {
570 | yy = 0;
571 | w = Math.abs((yy - y1) * aspect);
572 | xx = rw < 0 ? x1 - w : w + x1;
573 | } else if (yy > boundy) {
574 | yy = boundy;
575 | w = Math.abs(yy - y1) * aspect;
576 | xx = rw < 0 ? x1 - w : w + x1;
577 | }
578 | }
579 |
580 | // Magic %-)
581 | if (xx > x1) { // right side
582 | if (xx - x1 < min_x) {
583 | xx = x1 + min_x;
584 | } else if (xx - x1 > max_x) {
585 | xx = x1 + max_x;
586 | }
587 | if (yy > y1) {
588 | yy = y1 + (xx - x1) / aspect;
589 | } else {
590 | yy = y1 - (xx - x1) / aspect;
591 | }
592 | } else if (xx < x1) { // left side
593 | if (x1 - xx < min_x) {
594 | xx = x1 - min_x;
595 | } else if (x1 - xx > max_x) {
596 | xx = x1 - max_x;
597 | }
598 | if (yy > y1) {
599 | yy = y1 + (x1 - xx) / aspect;
600 | } else {
601 | yy = y1 - (x1 - xx) / aspect;
602 | }
603 | }
604 |
605 | if (xx < 0) {
606 | x1 -= xx;
607 | xx = 0;
608 | } else if (xx > boundx) {
609 | x1 -= xx - boundx;
610 | xx = boundx;
611 | }
612 |
613 | if (yy < 0) {
614 | y1 -= yy;
615 | yy = 0;
616 | } else if (yy > boundy) {
617 | y1 -= yy - boundy;
618 | yy = boundy;
619 | }
620 |
621 | return makeObj(flipCoords(x1, y1, xx, yy));
622 | }
623 | //}}}
624 | function rebound(p) //{{{
625 | {
626 | if (p[0] < 0) p[0] = 0;
627 | if (p[1] < 0) p[1] = 0;
628 |
629 | if (p[0] > boundx) p[0] = boundx;
630 | if (p[1] > boundy) p[1] = boundy;
631 |
632 | return [Math.round(p[0]), Math.round(p[1])];
633 | }
634 | //}}}
635 | function flipCoords(x1, y1, x2, y2) //{{{
636 | {
637 | var xa = x1,
638 | xb = x2,
639 | ya = y1,
640 | yb = y2;
641 | if (x2 < x1) {
642 | xa = x2;
643 | xb = x1;
644 | }
645 | if (y2 < y1) {
646 | ya = y2;
647 | yb = y1;
648 | }
649 | return [xa, ya, xb, yb];
650 | }
651 | //}}}
652 | function getRect() //{{{
653 | {
654 | var xsize = x2 - x1,
655 | ysize = y2 - y1,
656 | delta;
657 |
658 | if (xlimit && (Math.abs(xsize) > xlimit)) {
659 | x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
660 | }
661 | if (ylimit && (Math.abs(ysize) > ylimit)) {
662 | y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
663 | }
664 |
665 | if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
666 | y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
667 | }
668 | if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
669 | x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
670 | }
671 |
672 | if (x1 < 0) {
673 | x2 -= x1;
674 | x1 -= x1;
675 | }
676 | if (y1 < 0) {
677 | y2 -= y1;
678 | y1 -= y1;
679 | }
680 | if (x2 < 0) {
681 | x1 -= x2;
682 | x2 -= x2;
683 | }
684 | if (y2 < 0) {
685 | y1 -= y2;
686 | y2 -= y2;
687 | }
688 | if (x2 > boundx) {
689 | delta = x2 - boundx;
690 | x1 -= delta;
691 | x2 -= delta;
692 | }
693 | if (y2 > boundy) {
694 | delta = y2 - boundy;
695 | y1 -= delta;
696 | y2 -= delta;
697 | }
698 | if (x1 > boundx) {
699 | delta = x1 - boundy;
700 | y2 -= delta;
701 | y1 -= delta;
702 | }
703 | if (y1 > boundy) {
704 | delta = y1 - boundy;
705 | y2 -= delta;
706 | y1 -= delta;
707 | }
708 |
709 | return makeObj(flipCoords(x1, y1, x2, y2));
710 | }
711 | //}}}
712 | function makeObj(a) //{{{
713 | {
714 | return {
715 | x: a[0],
716 | y: a[1],
717 | x2: a[2],
718 | y2: a[3],
719 | w: a[2] - a[0],
720 | h: a[3] - a[1]
721 | };
722 | }
723 | //}}}
724 |
725 | return {
726 | flipCoords: flipCoords,
727 | setPressed: setPressed,
728 | setCurrent: setCurrent,
729 | getOffset: getOffset,
730 | moveOffset: moveOffset,
731 | getCorner: getCorner,
732 | getFixed: getFixed
733 | };
734 | }());
735 |
736 | //}}}
737 | // Shade Module {{{
738 | var Shade = (function() {
739 | var enabled = false,
740 | holder = $('').css({
741 | position: 'absolute',
742 | zIndex: 240,
743 | opacity: 0
744 | }),
745 | shades = {
746 | top: createShade(),
747 | left: createShade().height(boundy),
748 | right: createShade().height(boundy),
749 | bottom: createShade()
750 | };
751 |
752 | function resizeShades(w,h) {
753 | shades.left.css({ height: px(h) });
754 | shades.right.css({ height: px(h) });
755 | }
756 | function updateAuto()
757 | {
758 | return updateShade(Coords.getFixed());
759 | }
760 | function updateShade(c)
761 | {
762 | shades.top.css({
763 | left: px(c.x),
764 | width: px(c.w),
765 | height: px(c.y)
766 | });
767 | shades.bottom.css({
768 | top: px(c.y2),
769 | left: px(c.x),
770 | width: px(c.w),
771 | height: px(boundy-c.y2)
772 | });
773 | shades.right.css({
774 | left: px(c.x2),
775 | width: px(boundx-c.x2)
776 | });
777 | shades.left.css({
778 | width: px(c.x)
779 | });
780 | }
781 | function createShade() {
782 | return $('').css({
783 | position: 'absolute',
784 | backgroundColor: options.shadeColor||options.bgColor
785 | }).appendTo(holder);
786 | }
787 | function enableShade() {
788 | if (!enabled) {
789 | enabled = true;
790 | holder.insertBefore($img);
791 | updateAuto();
792 | Selection.setBgOpacity(1,0,1);
793 | $img2.hide();
794 |
795 | setBgColor(options.shadeColor||options.bgColor,1);
796 | if (Selection.isAwake())
797 | {
798 | setOpacity(options.bgOpacity,1);
799 | }
800 | else setOpacity(1,1);
801 | }
802 | }
803 | function setBgColor(color,now) {
804 | colorChangeMacro(getShades(),color,now);
805 | }
806 | function disableShade() {
807 | if (enabled) {
808 | holder.remove();
809 | $img2.show();
810 | enabled = false;
811 | if (Selection.isAwake()) {
812 | Selection.setBgOpacity(options.bgOpacity,1,1);
813 | } else {
814 | Selection.setBgOpacity(1,1,1);
815 | Selection.disableHandles();
816 | }
817 | colorChangeMacro($div,0,1);
818 | }
819 | }
820 | function setOpacity(opacity,now) {
821 | if (enabled) {
822 | if (options.bgFade && !now) {
823 | holder.animate({
824 | opacity: 1-opacity
825 | },{
826 | queue: false,
827 | duration: options.fadeTime
828 | });
829 | }
830 | else holder.css({opacity:1-opacity});
831 | }
832 | }
833 | function refreshAll() {
834 | options.shade ? enableShade() : disableShade();
835 | if (Selection.isAwake()) setOpacity(options.bgOpacity);
836 | }
837 | function getShades() {
838 | return holder.children();
839 | }
840 |
841 | return {
842 | update: updateAuto,
843 | updateRaw: updateShade,
844 | getShades: getShades,
845 | setBgColor: setBgColor,
846 | enable: enableShade,
847 | disable: disableShade,
848 | resize: resizeShades,
849 | refresh: refreshAll,
850 | opacity: setOpacity
851 | };
852 | }());
853 | // }}}
854 | // Selection Module {{{
855 | var Selection = (function () {
856 | var awake,
857 | hdep = 370,
858 | borders = {},
859 | handle = {},
860 | dragbar = {},
861 | seehandles = false;
862 |
863 | // Private Methods
864 | function insertBorder(type) //{{{
865 | {
866 | var jq = $('').css({
867 | position: 'absolute',
868 | opacity: options.borderOpacity
869 | }).addClass(cssClass(type));
870 | $img_holder.append(jq);
871 | return jq;
872 | }
873 | //}}}
874 | function dragDiv(ord, zi) //{{{
875 | {
876 | var jq = $('').mousedown(createDragger(ord)).css({
877 | cursor: ord + '-resize',
878 | position: 'absolute',
879 | zIndex: zi
880 | }).addClass('ord-'+ord);
881 |
882 | if (Touch.support) {
883 | jq.bind('touchstart.jcrop', Touch.createDragger(ord));
884 | }
885 |
886 | $hdl_holder.append(jq);
887 | return jq;
888 | }
889 | //}}}
890 | function insertHandle(ord) //{{{
891 | {
892 | var hs = options.handleSize,
893 |
894 | div = dragDiv(ord, hdep++).css({
895 | opacity: options.handleOpacity
896 | }).addClass(cssClass('handle'));
897 |
898 | if (hs) { div.width(hs).height(hs); }
899 |
900 | return div;
901 | }
902 | //}}}
903 | function insertDragbar(ord) //{{{
904 | {
905 | return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
906 | }
907 | //}}}
908 | function createDragbars(li) //{{{
909 | {
910 | var i;
911 | for (i = 0; i < li.length; i++) {
912 | dragbar[li[i]] = insertDragbar(li[i]);
913 | }
914 | }
915 | //}}}
916 | function createBorders(li) //{{{
917 | {
918 | var cl,i;
919 | for (i = 0; i < li.length; i++) {
920 | switch(li[i]){
921 | case'n': cl='hline'; break;
922 | case's': cl='hline bottom'; break;
923 | case'e': cl='vline right'; break;
924 | case'w': cl='vline'; break;
925 | }
926 | borders[li[i]] = insertBorder(cl);
927 | }
928 | }
929 | //}}}
930 | function createHandles(li) //{{{
931 | {
932 | var i;
933 | for (i = 0; i < li.length; i++) {
934 | handle[li[i]] = insertHandle(li[i]);
935 | }
936 | }
937 | //}}}
938 | function moveto(x, y) //{{{
939 | {
940 | if (!options.shade) {
941 | $img2.css({
942 | top: px(-y),
943 | left: px(-x)
944 | });
945 | }
946 | $sel.css({
947 | top: px(y),
948 | left: px(x)
949 | });
950 | }
951 | //}}}
952 | function resize(w, h) //{{{
953 | {
954 | $sel.width(Math.round(w)).height(Math.round(h));
955 | }
956 | //}}}
957 | function refresh() //{{{
958 | {
959 | var c = Coords.getFixed();
960 |
961 | Coords.setPressed([c.x, c.y]);
962 | Coords.setCurrent([c.x2, c.y2]);
963 |
964 | updateVisible();
965 | }
966 | //}}}
967 |
968 | // Internal Methods
969 | function updateVisible(select) //{{{
970 | {
971 | if (awake) {
972 | return update(select);
973 | }
974 | }
975 | //}}}
976 | function update(select) //{{{
977 | {
978 | var c = Coords.getFixed();
979 |
980 | resize(c.w, c.h);
981 | moveto(c.x, c.y);
982 | if (options.shade) Shade.updateRaw(c);
983 |
984 | awake || show();
985 |
986 | if (select) {
987 | options.onSelect.call(api, unscale(c));
988 | } else {
989 | options.onChange.call(api, unscale(c));
990 | }
991 | }
992 | //}}}
993 | function setBgOpacity(opacity,force,now) //{{{
994 | {
995 | if (!awake && !force) return;
996 | if (options.bgFade && !now) {
997 | $img.animate({
998 | opacity: opacity
999 | },{
1000 | queue: false,
1001 | duration: options.fadeTime
1002 | });
1003 | } else {
1004 | $img.css('opacity', opacity);
1005 | }
1006 | }
1007 | //}}}
1008 | function show() //{{{
1009 | {
1010 | $sel.show();
1011 |
1012 | if (options.shade) Shade.opacity(bgopacity);
1013 | else setBgOpacity(bgopacity,true);
1014 |
1015 | awake = true;
1016 | }
1017 | //}}}
1018 | function release() //{{{
1019 | {
1020 | disableHandles();
1021 | $sel.hide();
1022 |
1023 | if (options.shade) Shade.opacity(1);
1024 | else setBgOpacity(1);
1025 |
1026 | awake = false;
1027 | options.onRelease.call(api);
1028 | }
1029 | //}}}
1030 | function showHandles() //{{{
1031 | {
1032 | if (seehandles) {
1033 | $hdl_holder.show();
1034 | }
1035 | }
1036 | //}}}
1037 | function enableHandles() //{{{
1038 | {
1039 | seehandles = true;
1040 | if (options.allowResize) {
1041 | $hdl_holder.show();
1042 | return true;
1043 | }
1044 | }
1045 | //}}}
1046 | function disableHandles() //{{{
1047 | {
1048 | seehandles = false;
1049 | $hdl_holder.hide();
1050 | }
1051 | //}}}
1052 | function animMode(v) //{{{
1053 | {
1054 | if (v) {
1055 | animating = true;
1056 | disableHandles();
1057 | } else {
1058 | animating = false;
1059 | enableHandles();
1060 | }
1061 | }
1062 | //}}}
1063 | function done() //{{{
1064 | {
1065 | animMode(false);
1066 | refresh();
1067 | }
1068 | //}}}
1069 | // Insert draggable elements {{{
1070 | // Insert border divs for outline
1071 |
1072 | if (options.dragEdges && $.isArray(options.createDragbars))
1073 | createDragbars(options.createDragbars);
1074 |
1075 | if ($.isArray(options.createHandles))
1076 | createHandles(options.createHandles);
1077 |
1078 | if (options.drawBorders && $.isArray(options.createBorders))
1079 | createBorders(options.createBorders);
1080 |
1081 | //}}}
1082 |
1083 | // This is a hack for iOS5 to support drag/move touch functionality
1084 | $(document).bind('touchstart.jcrop-ios',function(e) {
1085 | if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation();
1086 | });
1087 |
1088 | var $track = newTracker().mousedown(createDragger('move')).css({
1089 | cursor: 'move',
1090 | position: 'absolute',
1091 | zIndex: 360
1092 | });
1093 |
1094 | if (Touch.support) {
1095 | $track.bind('touchstart.jcrop', Touch.createDragger('move'));
1096 | }
1097 |
1098 | $img_holder.append($track);
1099 | disableHandles();
1100 |
1101 | return {
1102 | updateVisible: updateVisible,
1103 | update: update,
1104 | release: release,
1105 | refresh: refresh,
1106 | isAwake: function () {
1107 | return awake;
1108 | },
1109 | setCursor: function (cursor) {
1110 | $track.css('cursor', cursor);
1111 | },
1112 | enableHandles: enableHandles,
1113 | enableOnly: function () {
1114 | seehandles = true;
1115 | },
1116 | showHandles: showHandles,
1117 | disableHandles: disableHandles,
1118 | animMode: animMode,
1119 | setBgOpacity: setBgOpacity,
1120 | done: done
1121 | };
1122 | }());
1123 |
1124 | //}}}
1125 | // Tracker Module {{{
1126 | var Tracker = (function () {
1127 | var onMove = function () {},
1128 | onDone = function () {},
1129 | trackDoc = options.trackDocument;
1130 |
1131 | function toFront(touch) //{{{
1132 | {
1133 | $trk.css({
1134 | zIndex: 450
1135 | });
1136 |
1137 | if (touch)
1138 | $(document)
1139 | .bind('touchmove.jcrop', trackTouchMove)
1140 | .bind('touchend.jcrop', trackTouchEnd);
1141 |
1142 | else if (trackDoc)
1143 | $(document)
1144 | .bind('mousemove.jcrop',trackMove)
1145 | .bind('mouseup.jcrop',trackUp);
1146 | }
1147 | //}}}
1148 | function toBack() //{{{
1149 | {
1150 | $trk.css({
1151 | zIndex: 290
1152 | });
1153 | $(document).unbind('.jcrop');
1154 | }
1155 | //}}}
1156 | function trackMove(e) //{{{
1157 | {
1158 | onMove(mouseAbs(e));
1159 | return false;
1160 | }
1161 | //}}}
1162 | function trackUp(e) //{{{
1163 | {
1164 | e.preventDefault();
1165 | e.stopPropagation();
1166 |
1167 | if (btndown) {
1168 | btndown = false;
1169 |
1170 | onDone(mouseAbs(e));
1171 |
1172 | if (Selection.isAwake()) {
1173 | options.onSelect.call(api, unscale(Coords.getFixed()));
1174 | }
1175 |
1176 | toBack();
1177 | onMove = function () {};
1178 | onDone = function () {};
1179 | }
1180 |
1181 | return false;
1182 | }
1183 | //}}}
1184 | function activateHandlers(move, done, touch) //{{{
1185 | {
1186 | btndown = true;
1187 | onMove = move;
1188 | onDone = done;
1189 | toFront(touch);
1190 | return false;
1191 | }
1192 | //}}}
1193 | function trackTouchMove(e) //{{{
1194 | {
1195 | onMove(mouseAbs(Touch.cfilter(e)));
1196 | return false;
1197 | }
1198 | //}}}
1199 | function trackTouchEnd(e) //{{{
1200 | {
1201 | return trackUp(Touch.cfilter(e));
1202 | }
1203 | //}}}
1204 | function setCursor(t) //{{{
1205 | {
1206 | $trk.css('cursor', t);
1207 | }
1208 | //}}}
1209 |
1210 | if (!trackDoc) {
1211 | $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
1212 | }
1213 |
1214 | $img.before($trk);
1215 | return {
1216 | activateHandlers: activateHandlers,
1217 | setCursor: setCursor
1218 | };
1219 | }());
1220 | //}}}
1221 | // KeyManager Module {{{
1222 | var KeyManager = (function () {
1223 | var $keymgr = $('').css({
1224 | position: 'fixed',
1225 | left: '-120px',
1226 | width: '12px'
1227 | }).addClass('jcrop-keymgr'),
1228 |
1229 | $keywrap = $('').css({
1230 | position: 'absolute',
1231 | overflow: 'hidden'
1232 | }).append($keymgr);
1233 |
1234 | function watchKeys() //{{{
1235 | {
1236 | if (options.keySupport) {
1237 | $keymgr.show();
1238 | $keymgr.focus();
1239 | }
1240 | }
1241 | //}}}
1242 | function onBlur(e) //{{{
1243 | {
1244 | $keymgr.hide();
1245 | }
1246 | //}}}
1247 | function doNudge(e, x, y) //{{{
1248 | {
1249 | if (options.allowMove) {
1250 | Coords.moveOffset([x, y]);
1251 | Selection.updateVisible(true);
1252 | }
1253 | e.preventDefault();
1254 | e.stopPropagation();
1255 | }
1256 | //}}}
1257 | function parseKey(e) //{{{
1258 | {
1259 | if (e.ctrlKey || e.metaKey) {
1260 | return true;
1261 | }
1262 | shift_down = e.shiftKey ? true : false;
1263 | var nudge = shift_down ? 10 : 1;
1264 |
1265 | switch (e.keyCode) {
1266 | case 37:
1267 | doNudge(e, -nudge, 0);
1268 | break;
1269 | case 39:
1270 | doNudge(e, nudge, 0);
1271 | break;
1272 | case 38:
1273 | doNudge(e, 0, -nudge);
1274 | break;
1275 | case 40:
1276 | doNudge(e, 0, nudge);
1277 | break;
1278 | case 27:
1279 | if (options.allowSelect) Selection.release();
1280 | break;
1281 | case 9:
1282 | return true;
1283 | }
1284 |
1285 | return false;
1286 | }
1287 | //}}}
1288 |
1289 | if (options.keySupport) {
1290 | $keymgr.keydown(parseKey).blur(onBlur);
1291 | if (ie6mode || !options.fixedSupport) {
1292 | $keymgr.css({
1293 | position: 'absolute',
1294 | left: '-20px'
1295 | });
1296 | $keywrap.append($keymgr).insertBefore($img);
1297 | } else {
1298 | $keymgr.insertBefore($img);
1299 | }
1300 | }
1301 |
1302 |
1303 | return {
1304 | watchKeys: watchKeys
1305 | };
1306 | }());
1307 | //}}}
1308 | // }}}
1309 | // API methods {{{
1310 | function setClass(cname) //{{{
1311 | {
1312 | $div.removeClass().addClass(cssClass('holder')).addClass(cname);
1313 | }
1314 | //}}}
1315 | function animateTo(a, callback) //{{{
1316 | {
1317 | var x1 = a[0] / xscale,
1318 | y1 = a[1] / yscale,
1319 | x2 = a[2] / xscale,
1320 | y2 = a[3] / yscale;
1321 |
1322 | if (animating) {
1323 | return;
1324 | }
1325 |
1326 | var animto = Coords.flipCoords(x1, y1, x2, y2),
1327 | c = Coords.getFixed(),
1328 | initcr = [c.x, c.y, c.x2, c.y2],
1329 | animat = initcr,
1330 | interv = options.animationDelay,
1331 | ix1 = animto[0] - initcr[0],
1332 | iy1 = animto[1] - initcr[1],
1333 | ix2 = animto[2] - initcr[2],
1334 | iy2 = animto[3] - initcr[3],
1335 | pcent = 0,
1336 | velocity = options.swingSpeed;
1337 |
1338 | x1 = animat[0];
1339 | y1 = animat[1];
1340 | x2 = animat[2];
1341 | y2 = animat[3];
1342 |
1343 | Selection.animMode(true);
1344 | var anim_timer;
1345 |
1346 | function queueAnimator() {
1347 | window.setTimeout(animator, interv);
1348 | }
1349 | var animator = (function () {
1350 | return function () {
1351 | pcent += (100 - pcent) / velocity;
1352 |
1353 | animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
1354 | animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
1355 | animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
1356 | animat[3] = Math.round(y2 + ((pcent / 100) * iy2));
1357 |
1358 | if (pcent >= 99.8) {
1359 | pcent = 100;
1360 | }
1361 | if (pcent < 100) {
1362 | setSelectRaw(animat);
1363 | queueAnimator();
1364 | } else {
1365 | Selection.done();
1366 | Selection.animMode(false);
1367 | if (typeof(callback) === 'function') {
1368 | callback.call(api);
1369 | }
1370 | }
1371 | };
1372 | }());
1373 | queueAnimator();
1374 | }
1375 | //}}}
1376 | function setSelect(rect) //{{{
1377 | {
1378 | setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
1379 | options.onSelect.call(api, unscale(Coords.getFixed()));
1380 | Selection.enableHandles();
1381 | }
1382 | //}}}
1383 | function setSelectRaw(l) //{{{
1384 | {
1385 | Coords.setPressed([l[0], l[1]]);
1386 | Coords.setCurrent([l[2], l[3]]);
1387 | Selection.update();
1388 | }
1389 | //}}}
1390 | function tellSelect() //{{{
1391 | {
1392 | return unscale(Coords.getFixed());
1393 | }
1394 | //}}}
1395 | function tellScaled() //{{{
1396 | {
1397 | return Coords.getFixed();
1398 | }
1399 | //}}}
1400 | function setOptionsNew(opt) //{{{
1401 | {
1402 | setOptions(opt);
1403 | interfaceUpdate();
1404 | }
1405 | //}}}
1406 | function disableCrop() //{{{
1407 | {
1408 | options.disabled = true;
1409 | Selection.disableHandles();
1410 | Selection.setCursor('default');
1411 | Tracker.setCursor('default');
1412 | }
1413 | //}}}
1414 | function enableCrop() //{{{
1415 | {
1416 | options.disabled = false;
1417 | interfaceUpdate();
1418 | }
1419 | //}}}
1420 | function cancelCrop() //{{{
1421 | {
1422 | Selection.done();
1423 | Tracker.activateHandlers(null, null);
1424 | }
1425 | //}}}
1426 | function destroy() //{{{
1427 | {
1428 | $div.remove();
1429 | $origimg.show();
1430 | $origimg.css('visibility','visible');
1431 | $(obj).removeData('Jcrop');
1432 | }
1433 | //}}}
1434 | function setImage(src, callback) //{{{
1435 | {
1436 | Selection.release();
1437 | disableCrop();
1438 | var img = new Image();
1439 | img.onload = function () {
1440 | var iw = img.width;
1441 | var ih = img.height;
1442 | var bw = options.boxWidth;
1443 | var bh = options.boxHeight;
1444 | $img.width(iw).height(ih);
1445 | $img.attr('src', src);
1446 | $img2.attr('src', src);
1447 | presize($img, bw, bh);
1448 | boundx = $img.width();
1449 | boundy = $img.height();
1450 | $img2.width(boundx).height(boundy);
1451 | $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
1452 | $div.width(boundx).height(boundy);
1453 | Shade.resize(boundx,boundy);
1454 | enableCrop();
1455 |
1456 | if (typeof(callback) === 'function') {
1457 | callback.call(api);
1458 | }
1459 | };
1460 | img.src = src;
1461 | }
1462 | //}}}
1463 | function colorChangeMacro($obj,color,now) {
1464 | var mycolor = color || options.bgColor;
1465 | if (options.bgFade && supportsColorFade() && options.fadeTime && !now) {
1466 | $obj.animate({
1467 | backgroundColor: mycolor
1468 | }, {
1469 | queue: false,
1470 | duration: options.fadeTime
1471 | });
1472 | } else {
1473 | $obj.css('backgroundColor', mycolor);
1474 | }
1475 | }
1476 | function interfaceUpdate(alt) //{{{
1477 | // This method tweaks the interface based on options object.
1478 | // Called when options are changed and at end of initialization.
1479 | {
1480 | if (options.allowResize) {
1481 | if (alt) {
1482 | Selection.enableOnly();
1483 | } else {
1484 | Selection.enableHandles();
1485 | }
1486 | } else {
1487 | Selection.disableHandles();
1488 | }
1489 |
1490 | Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
1491 | Selection.setCursor(options.allowMove ? 'move' : 'default');
1492 |
1493 | if (options.hasOwnProperty('trueSize')) {
1494 | xscale = options.trueSize[0] / boundx;
1495 | yscale = options.trueSize[1] / boundy;
1496 | }
1497 |
1498 | if (options.hasOwnProperty('setSelect')) {
1499 | setSelect(options.setSelect);
1500 | Selection.done();
1501 | delete(options.setSelect);
1502 | }
1503 |
1504 | Shade.refresh();
1505 |
1506 | if (options.bgColor != bgcolor) {
1507 | colorChangeMacro(
1508 | options.shade? Shade.getShades(): $div,
1509 | options.shade?
1510 | (options.shadeColor || options.bgColor):
1511 | options.bgColor
1512 | );
1513 | bgcolor = options.bgColor;
1514 | }
1515 |
1516 | if (bgopacity != options.bgOpacity) {
1517 | bgopacity = options.bgOpacity;
1518 | if (options.shade) Shade.refresh();
1519 | else Selection.setBgOpacity(bgopacity);
1520 | }
1521 |
1522 | xlimit = options.maxSize[0] || 0;
1523 | ylimit = options.maxSize[1] || 0;
1524 | xmin = options.minSize[0] || 0;
1525 | ymin = options.minSize[1] || 0;
1526 |
1527 | if (options.hasOwnProperty('outerImage')) {
1528 | $img.attr('src', options.outerImage);
1529 | delete(options.outerImage);
1530 | }
1531 |
1532 | Selection.refresh();
1533 | }
1534 | //}}}
1535 | //}}}
1536 |
1537 | if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
1538 |
1539 | $hdl_holder.hide();
1540 | interfaceUpdate(true);
1541 |
1542 | var api = {
1543 | setImage: setImage,
1544 | animateTo: animateTo,
1545 | setSelect: setSelect,
1546 | setOptions: setOptionsNew,
1547 | tellSelect: tellSelect,
1548 | tellScaled: tellScaled,
1549 | setClass: setClass,
1550 |
1551 | disable: disableCrop,
1552 | enable: enableCrop,
1553 | cancel: cancelCrop,
1554 | release: Selection.release,
1555 | destroy: destroy,
1556 |
1557 | focus: KeyManager.watchKeys,
1558 |
1559 | getBounds: function () {
1560 | return [boundx * xscale, boundy * yscale];
1561 | },
1562 | getWidgetSize: function () {
1563 | return [boundx, boundy];
1564 | },
1565 | getScaleFactor: function () {
1566 | return [xscale, yscale];
1567 | },
1568 | getOptions: function() {
1569 | // careful: internal values are returned
1570 | return options;
1571 | },
1572 |
1573 | ui: {
1574 | holder: $div,
1575 | selection: $sel
1576 | }
1577 | };
1578 |
1579 | if (is_msie) $div.bind('selectstart', function () { return false; });
1580 |
1581 | $origimg.data('Jcrop', api);
1582 | return api;
1583 | };
1584 | $.fn.Jcrop = function (options, callback) //{{{
1585 | {
1586 | var api;
1587 | // Iterate over each object, attach Jcrop
1588 | this.each(function () {
1589 | // If we've already attached to this object
1590 | if ($(this).data('Jcrop')) {
1591 | // The API can be requested this way (undocumented)
1592 | if (options === 'api') return $(this).data('Jcrop');
1593 | // Otherwise, we just reset the options...
1594 | else $(this).data('Jcrop').setOptions(options);
1595 | }
1596 | // If we haven't been attached, preload and attach
1597 | else {
1598 | if (this.tagName == 'IMG')
1599 | $.Jcrop.Loader(this,function(){
1600 | $(this).css({display:'block',visibility:'hidden'});
1601 | api = $.Jcrop(this, options);
1602 | if ($.isFunction(callback)) callback.call(api);
1603 | });
1604 | else {
1605 | $(this).css({display:'block',visibility:'hidden'});
1606 | api = $.Jcrop(this, options);
1607 | if ($.isFunction(callback)) callback.call(api);
1608 | }
1609 | }
1610 | });
1611 |
1612 | // Return "this" so the object is chainable (jQuery-style)
1613 | return this;
1614 | };
1615 | //}}}
1616 | // $.Jcrop.Loader - basic image loader {{{
1617 |
1618 | $.Jcrop.Loader = function(imgobj,success,error){
1619 | var $img = $(imgobj), img = $img[0];
1620 |
1621 | function completeCheck(){
1622 | if (img.complete) {
1623 | $img.unbind('.jcloader');
1624 | if ($.isFunction(success)) success.call(img);
1625 | }
1626 | else window.setTimeout(completeCheck,50);
1627 | }
1628 |
1629 | $img
1630 | .bind('load.jcloader',completeCheck)
1631 | .bind('error.jcloader',function(e){
1632 | $img.unbind('.jcloader');
1633 | if ($.isFunction(error)) error.call(img);
1634 | });
1635 |
1636 | if (img.complete && $.isFunction(success)){
1637 | $img.unbind('.jcloader');
1638 | success.call(img);
1639 | }
1640 | };
1641 |
1642 | //}}}
1643 | // Global Defaults {{{
1644 | $.Jcrop.defaults = {
1645 |
1646 | // Basic Settings
1647 | allowSelect: true,
1648 | allowMove: true,
1649 | allowResize: true,
1650 |
1651 | trackDocument: true,
1652 |
1653 | // Styling Options
1654 | baseClass: 'jcrop',
1655 | addClass: null,
1656 | bgColor: 'black',
1657 | bgOpacity: 0.6,
1658 | bgFade: false,
1659 | borderOpacity: 0.4,
1660 | handleOpacity: 0.5,
1661 | handleSize: null,
1662 |
1663 | aspectRatio: 0,
1664 | keySupport: true,
1665 | createHandles: ['n','s','e','w','nw','ne','se','sw'],
1666 | createDragbars: ['n','s','e','w'],
1667 | createBorders: ['n','s','e','w'],
1668 | drawBorders: true,
1669 | dragEdges: true,
1670 | fixedSupport: true,
1671 | touchSupport: null,
1672 |
1673 | shade: null,
1674 |
1675 | boxWidth: 0,
1676 | boxHeight: 0,
1677 | boundary: 2,
1678 | fadeTime: 400,
1679 | animationDelay: 20,
1680 | swingSpeed: 3,
1681 |
1682 | minSelect: [0, 0],
1683 | maxSize: [0, 0],
1684 | minSize: [0, 0],
1685 |
1686 | // Callbacks / Event Handlers
1687 | onChange: function () {},
1688 | onSelect: function () {},
1689 | onDblClick: function () {},
1690 | onRelease: function () {}
1691 | };
1692 |
1693 | // }}}
1694 | }(jQuery));
1695 |
--------------------------------------------------------------------------------
/assets/js/jquery.Jcrop.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.Jcrop.min.js v0.9.12 (build:20130202)
3 | * jQuery Image Cropping Plugin - released under MIT License
4 | * Copyright (c) 2008-2013 Tapmodo Interactive LLC
5 | * https://github.com/tapmodo/Jcrop
6 | */
7 | (function(a){a.Jcrop=function(b,c){function i(a){return Math.round(a)+"px"}function j(a){return d.baseClass+"-"+a}function k(){return a.fx.step.hasOwnProperty("backgroundColor")}function l(b){var c=a(b).offset();return[c.left,c.top]}function m(a){return[a.pageX-e[0],a.pageY-e[1]]}function n(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function o(a,b,c){e=l(D),bc.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bc.activateHandlers(q(b),v,c);var d=_.getFixed(),f=r(a),g=_.getCorner(r(f));_.setPressed(_.getCorner(f)),_.setCurrent(g),bc.activateHandlers(p(a,d),v,c)}function p(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}_.setCurrent(c),bb.update()}}function q(a){var b=a;return bd.watchKeys
8 | (),function(a){_.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bb.update()}}function r(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function s(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=l(D),W=!0,o(a,m(b)),b.stopPropagation(),b.preventDefault(),!1)}}function t(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),T=a.width()/d,U=a.height()/e,a.width(d).height(e)}function u(a){return{x:a.x*T,y:a.y*U,x2:a.x2*T,y2:a.y2*U,w:a.w*T,h:a.h*U}}function v(a){var b=_.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bb.enableHandles(),bb.done()):bb.release(),bc.setCursor(d.allowSelect?"crosshair":"default")}function w(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;W=!0,e=l(D),bb.disableHandles(),bc.setCursor("crosshair");var b=m(a);return _.setPressed(b),bb.update(),bc.activateHandlers(x,v,a.type.substring
9 | (0,5)==="touch"),bd.watchKeys(),a.stopPropagation(),a.preventDefault(),!1}function x(a){_.setCurrent(a),bb.update()}function y(){var b=a("").addClass(j("tracker"));return g&&b.css({opacity:0,backgroundColor:"white"}),b}function be(a){G.removeClass().addClass(j("holder")).addClass(a)}function bf(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/T,e=a[1]/U,f=a[2]/T,g=a[3]/U;if(X)return;var h=_.flipCoords(c,e,f,g),i=_.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;c=k[0],e=k[1],f=k[2],g=k[3],bb.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=Math.round(c+q/100*m),k[1]=Math.round(e+q/100*n),k[2]=Math.round(f+q/100*o),k[3]=Math.round(g+q/100*p),q>=99.8&&(q=100),q<100?(bh(k),t()):(bb.done(),bb.animMode(!1),typeof b=="function"&&b.call(bs))}}();t()}function bg(a){bh([a[0]/T,a[1]/U,a[2]/T,a[3]/U]),d.onSelect.call(bs,u(_.getFixed())),bb.enableHandles()}function bh(a){_.setPressed([a[0],a[1]]),_.setCurrent([a[2],
10 | a[3]]),bb.update()}function bi(){return u(_.getFixed())}function bj(){return _.getFixed()}function bk(a){n(a),br()}function bl(){d.disabled=!0,bb.disableHandles(),bb.setCursor("default"),bc.setCursor("default")}function bm(){d.disabled=!1,br()}function bn(){bb.done(),bc.activateHandlers(null,null)}function bo(){G.remove(),A.show(),A.css("visibility","visible"),a(b).removeData("Jcrop")}function bp(a,b){bb.release(),bl();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;D.width(e).height(f),D.attr("src",a),H.attr("src",a),t(D,g,h),E=D.width(),F=D.height(),H.width(E).height(F),M.width(E+L*2).height(F+L*2),G.width(E).height(F),ba.resize(E,F),bm(),typeof b=="function"&&b.call(bs)},c.src=a}function bq(a,b,c){var e=b||d.bgColor;d.bgFade&&k()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function br(a){d.allowResize?a?bb.enableOnly():bb.enableHandles():bb.disableHandles(),bc.setCursor(d.allowSelect?"crosshair":"default"),bb
11 | .setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(T=d.trueSize[0]/E,U=d.trueSize[1]/F),d.hasOwnProperty("setSelect")&&(bg(d.setSelect),bb.done(),delete d.setSelect),ba.refresh(),d.bgColor!=N&&(bq(d.shade?ba.getShades():G,d.shade?d.shadeColor||d.bgColor:d.bgColor),N=d.bgColor),O!=d.bgOpacity&&(O=d.bgOpacity,d.shade?ba.refresh():bb.setBgOpacity(O)),P=d.maxSize[0]||0,Q=d.maxSize[1]||0,R=d.minSize[0]||0,S=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(D.attr("src",d.outerImage),delete d.outerImage),bb.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f=navigator.userAgent.toLowerCase(),g=/msie/.test(f),h=/msie [1-6]\./.test(f);typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),n(c);var z={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},A=a(b),B=!0;if(b.tagName=="IMG"){if(A[0].width!=0&&A[0].height!=0)A.width(A[0].width),A.height(A[0].height);else{var C=new Image;C.src=A[0].src,A.width(C.width),A.height(C.height)}var D=A.clone().removeAttr("id").
12 | css(z).show();D.width(A.width()),D.height(A.height()),A.after(D).hide()}else D=A.css(z).show(),B=!1,d.shade===null&&(d.shade=!0);t(D,d.boxWidth,d.boxHeight);var E=D.width(),F=D.height(),G=a("").width(E).height(F).addClass(j("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(A).append(D);d.addClass&&G.addClass(d.addClass);var H=a(""),I=a("").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),J=a("").width("100%").height("100%").css("zIndex",320),K=a("").css({position:"absolute",zIndex:600}).dblclick(function(){var a=_.getFixed();d.onDblClick.call(bs,a)}).insertBefore(D).append(I,J);B&&(H=a("
").attr("src",D.attr("src")).css(z).width(E).height(F),I.append(H)),h&&K.css({overflowY:"hidden"});var L=d.boundary,M=y().width(E+L*2).height(F+L*2).css({position:"absolute",top:i(-L),left:i(-L),zIndex:290}).mousedown(w),N=d.bgColor,O=d.bgOpacity,P,Q,R,S,T,U,V=!0,W,X,Y;e=l(D);var Z=function(){function a(){var a={},b=["touchstart"
13 | ,"touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;da+f&&(f-=f+a),0>b+g&&(g-=g+b),FE&&(r=E,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>F&&(s=F,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-ah&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):rh&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>E&&(a-=r-E,r=E),s<0?(b-=s,s=0):s>F&&(b-=s-F,s=F),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>E&&(a[0]=E),a[1]>F&&(a[1]=F),[Math.round(a[0]),Math.round(a[1])]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return cP&&(c=d>0?a+P:a-P),Q&&Math.abs
15 | (f)>Q&&(e=f>0?b+Q:b-Q),S/U&&Math.abs(f)0?b+S/U:b-S/U),R/T&&Math.abs(d)0?a+R/T:a-R/T),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&(a-=c,c-=c),e<0&&(b-=e,e-=e),c>E&&(g=c-E,a-=g,c-=g),e>F&&(g=e-F,b-=g,e-=g),a>E&&(g=a-F,e-=g,b-=g),b>F&&(g=b-F,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),ba=function(){function f(a,b){e.left.css({height:i(b)}),e.right.css({height:i(b)})}function g(){return h(_.getFixed())}function h(a){e.top.css({left:i(a.x),width:i(a.w),height:i(a.y)}),e.bottom.css({top:i(a.y2),left:i(a.x),width:i(a.w),height:i(F-a.y2)}),e.right.css({left:i(a.x2),width:i(E-a.x2)}),e.left.css({width:i(a.x)})}function j(){return a("").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(D),g(),bb.setBgOpacity(1,0,1),H.hide(),l(d.shadeColor||d.bgColor,1),bb.
16 | isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){bq(p(),a,b)}function m(){b&&(c.remove(),H.show(),b=!1,bb.isAwake()?bb.setBgOpacity(d.bgOpacity,1,1):(bb.setBgOpacity(1,1,1),bb.disableHandles()),bq(G,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bb.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(F),right:j().height(F),bottom:j()};return{update:g,updateRaw:h,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bb=function(){function k(b){var c=a("").css({position:"absolute",opacity:d.borderOpacity}).addClass(j(b));return I.append(c),c}function l(b,c){var d=a("").mousedown(s(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return Z.support&&d.bind("touchstart.jcrop",Z.createDragger(b)),J.append(d),d}function m(a){var b=d.handleSize,e=l(a,c++
17 | ).css({opacity:d.handleOpacity}).addClass(j("handle"));return b&&e.width(b).height(b),e}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o(a){var b;for(b=0;b').css({position:"fixed",left:"-120px",width:"12px"}).addClass("jcrop-keymgr"),c=a("").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),h||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(D)):b.insertBefore(D)),{watchKeys:e}}();Z.support&&M.bind("touchstart.jcrop",Z.newSelection),J.hide(),br(!0);var bs={setImage:bp,animateTo:bf,setSelect:bg,setOptions:bk,tellSelect:bi,tellScaled:bj,setClass:be,disable:bl,enable:bm,cancel:bn,release:bb.release,destroy:bo,focus:bd.watchKeys,getBounds:function(){return[E*T,F*U]},getWidgetSize:function(){return[E,F]},getScaleFactor:function(){return[T,U]},getOptions:function(){return d},ui:{holder:G,selection:K}};return g&&G.bind("selectstart",function(){return!1}),A.data("Jcrop",bs),bs},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if(
21 | b==="api")return a(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:null,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges
22 | :!0,fixedSupport:!0,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery);
--------------------------------------------------------------------------------
/assets/js/jquery.color.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Color Animations v2.0pre
3 | * http://jquery.org/
4 | *
5 | * Copyright 2011 John Resig
6 | * Dual licensed under the MIT or GPL Version 2 licenses.
7 | * http://jquery.org/license
8 | */
9 |
10 | (function( jQuery, undefined ){
11 | var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color outlineColor".split(" "),
12 |
13 | // plusequals test for += 100 -= 100
14 | rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
15 | // a set of RE's that can match strings and generate color tuples.
16 | stringParsers = [{
17 | re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
18 | parse: function( execResult ) {
19 | return [
20 | execResult[ 1 ],
21 | execResult[ 2 ],
22 | execResult[ 3 ],
23 | execResult[ 4 ]
24 | ];
25 | }
26 | }, {
27 | re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
28 | parse: function( execResult ) {
29 | return [
30 | 2.55 * execResult[1],
31 | 2.55 * execResult[2],
32 | 2.55 * execResult[3],
33 | execResult[ 4 ]
34 | ];
35 | }
36 | }, {
37 | re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,
38 | parse: function( execResult ) {
39 | return [
40 | parseInt( execResult[ 1 ], 16 ),
41 | parseInt( execResult[ 2 ], 16 ),
42 | parseInt( execResult[ 3 ], 16 )
43 | ];
44 | }
45 | }, {
46 | re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,
47 | parse: function( execResult ) {
48 | return [
49 | parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
50 | parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
51 | parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
52 | ];
53 | }
54 | }, {
55 | re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/,
56 | space: "hsla",
57 | parse: function( execResult ) {
58 | return [
59 | execResult[1],
60 | execResult[2] / 100,
61 | execResult[3] / 100,
62 | execResult[4]
63 | ];
64 | }
65 | }],
66 |
67 | // jQuery.Color( )
68 | color = jQuery.Color = function( color, green, blue, alpha ) {
69 | return new jQuery.Color.fn.parse( color, green, blue, alpha );
70 | },
71 | spaces = {
72 | rgba: {
73 | cache: "_rgba",
74 | props: {
75 | red: {
76 | idx: 0,
77 | type: "byte",
78 | empty: true
79 | },
80 | green: {
81 | idx: 1,
82 | type: "byte",
83 | empty: true
84 | },
85 | blue: {
86 | idx: 2,
87 | type: "byte",
88 | empty: true
89 | },
90 | alpha: {
91 | idx: 3,
92 | type: "percent",
93 | def: 1
94 | }
95 | }
96 | },
97 | hsla: {
98 | cache: "_hsla",
99 | props: {
100 | hue: {
101 | idx: 0,
102 | type: "degrees",
103 | empty: true
104 | },
105 | saturation: {
106 | idx: 1,
107 | type: "percent",
108 | empty: true
109 | },
110 | lightness: {
111 | idx: 2,
112 | type: "percent",
113 | empty: true
114 | }
115 | }
116 | }
117 | },
118 | propTypes = {
119 | "byte": {
120 | floor: true,
121 | min: 0,
122 | max: 255
123 | },
124 | "percent": {
125 | min: 0,
126 | max: 1
127 | },
128 | "degrees": {
129 | mod: 360,
130 | floor: true
131 | }
132 | },
133 | rgbaspace = spaces.rgba.props,
134 | support = color.support = {},
135 |
136 | // colors = jQuery.Color.names
137 | colors,
138 |
139 | // local aliases of functions called often
140 | each = jQuery.each;
141 |
142 | spaces.hsla.props.alpha = rgbaspace.alpha;
143 |
144 | function clamp( value, prop, alwaysAllowEmpty ) {
145 | var type = propTypes[ prop.type ] || {},
146 | allowEmpty = prop.empty || alwaysAllowEmpty;
147 |
148 | if ( allowEmpty && value == null ) {
149 | return null;
150 | }
151 | if ( prop.def && value == null ) {
152 | return prop.def;
153 | }
154 | if ( type.floor ) {
155 | value = ~~value;
156 | } else {
157 | value = parseFloat( value );
158 | }
159 | if ( value == null || isNaN( value ) ) {
160 | return prop.def;
161 | }
162 | if ( type.mod ) {
163 | value = value % type.mod;
164 | // -10 -> 350
165 | return value < 0 ? type.mod + value : value;
166 | }
167 |
168 | // for now all property types without mod have min and max
169 | return type.min > value ? type.min : type.max < value ? type.max : value;
170 | }
171 |
172 | function stringParse( string ) {
173 | var inst = color(),
174 | rgba = inst._rgba = [];
175 |
176 | string = string.toLowerCase();
177 |
178 | each( stringParsers, function( i, parser ) {
179 | var match = parser.re.exec( string ),
180 | values = match && parser.parse( match ),
181 | parsed,
182 | spaceName = parser.space || "rgba",
183 | cache = spaces[ spaceName ].cache;
184 |
185 |
186 | if ( values ) {
187 | parsed = inst[ spaceName ]( values );
188 |
189 | // if this was an rgba parse the assignment might happen twice
190 | // oh well....
191 | inst[ cache ] = parsed[ cache ];
192 | rgba = inst._rgba = parsed._rgba;
193 |
194 | // exit each( stringParsers ) here because we matched
195 | return false;
196 | }
197 | });
198 |
199 | // Found a stringParser that handled it
200 | if ( rgba.length !== 0 ) {
201 |
202 | // if this came from a parsed string, force "transparent" when alpha is 0
203 | // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
204 | if ( Math.max.apply( Math, rgba ) === 0 ) {
205 | jQuery.extend( rgba, colors.transparent );
206 | }
207 | return inst;
208 | }
209 |
210 | // named colors / default - filter back through parse function
211 | if ( string = colors[ string ] ) {
212 | return string;
213 | }
214 | }
215 |
216 | color.fn = color.prototype = {
217 | constructor: color,
218 | parse: function( red, green, blue, alpha ) {
219 | if ( red === undefined ) {
220 | this._rgba = [ null, null, null, null ];
221 | return this;
222 | }
223 | if ( red instanceof jQuery || red.nodeType ) {
224 | red = red instanceof jQuery ? red.css( green ) : jQuery( red ).css( green );
225 | green = undefined;
226 | }
227 |
228 | var inst = this,
229 | type = jQuery.type( red ),
230 | rgba = this._rgba = [],
231 | source;
232 |
233 | // more than 1 argument specified - assume ( red, green, blue, alpha )
234 | if ( green !== undefined ) {
235 | red = [ red, green, blue, alpha ];
236 | type = "array";
237 | }
238 |
239 | if ( type === "string" ) {
240 | return this.parse( stringParse( red ) || colors._default );
241 | }
242 |
243 | if ( type === "array" ) {
244 | each( rgbaspace, function( key, prop ) {
245 | rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
246 | });
247 | return this;
248 | }
249 |
250 | if ( type === "object" ) {
251 | if ( red instanceof color ) {
252 | each( spaces, function( spaceName, space ) {
253 | if ( red[ space.cache ] ) {
254 | inst[ space.cache ] = red[ space.cache ].slice();
255 | }
256 | });
257 | } else {
258 | each( spaces, function( spaceName, space ) {
259 | each( space.props, function( key, prop ) {
260 | var cache = space.cache;
261 |
262 | // if the cache doesn't exist, and we know how to convert
263 | if ( !inst[ cache ] && space.to ) {
264 |
265 | // if the value was null, we don't need to copy it
266 | // if the key was alpha, we don't need to copy it either
267 | if ( red[ key ] == null || key === "alpha") {
268 | return;
269 | }
270 | inst[ cache ] = space.to( inst._rgba );
271 | }
272 |
273 | // this is the only case where we allow nulls for ALL properties.
274 | // call clamp with alwaysAllowEmpty
275 | inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
276 | });
277 | });
278 | }
279 | return this;
280 | }
281 | },
282 | is: function( compare ) {
283 | var is = color( compare ),
284 | same = true,
285 | myself = this;
286 |
287 | each( spaces, function( _, space ) {
288 | var isCache = is[ space.cache ],
289 | localCache;
290 | if (isCache) {
291 | localCache = myself[ space.cache ] || space.to && space.to( myself._rgba ) || [];
292 | each( space.props, function( _, prop ) {
293 | if ( isCache[ prop.idx ] != null ) {
294 | same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
295 | return same;
296 | }
297 | });
298 | }
299 | return same;
300 | });
301 | return same;
302 | },
303 | _space: function() {
304 | var used = [],
305 | inst = this;
306 | each( spaces, function( spaceName, space ) {
307 | if ( inst[ space.cache ] ) {
308 | used.push( spaceName );
309 | }
310 | });
311 | return used.pop();
312 | },
313 | transition: function( other, distance ) {
314 | var end = color( other ),
315 | spaceName = end._space(),
316 | space = spaces[ spaceName ],
317 | start = this[ space.cache ] || space.to( this._rgba ),
318 | result = start.slice();
319 |
320 | end = end[ space.cache ];
321 | each( space.props, function( key, prop ) {
322 | var index = prop.idx,
323 | startValue = start[ index ],
324 | endValue = end[ index ],
325 | type = propTypes[ prop.type ] || {};
326 |
327 | // if null, don't override start value
328 | if ( endValue === null ) {
329 | return;
330 | }
331 | // if null - use end
332 | if ( startValue === null ) {
333 | result[ index ] = endValue;
334 | } else {
335 | if ( type.mod ) {
336 | if ( endValue - startValue > type.mod / 2 ) {
337 | startValue += type.mod;
338 | } else if ( startValue - endValue > type.mod / 2 ) {
339 | startValue -= type.mod;
340 | }
341 | }
342 | result[ prop.idx ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
343 | }
344 | });
345 | return this[ spaceName ]( result );
346 | },
347 | blend: function( opaque ) {
348 | // if we are already opaque - return ourself
349 | if ( this._rgba[ 3 ] === 1 ) {
350 | return this;
351 | }
352 |
353 | var rgb = this._rgba.slice(),
354 | a = rgb.pop(),
355 | blend = color( opaque )._rgba;
356 |
357 | return color( jQuery.map( rgb, function( v, i ) {
358 | return ( 1 - a ) * blend[ i ] + a * v;
359 | }));
360 | },
361 | toRgbaString: function() {
362 | var prefix = "rgba(",
363 | rgba = jQuery.map( this._rgba, function( v, i ) {
364 | return v == null ? ( i > 2 ? 1 : 0 ) : v;
365 | });
366 |
367 | if ( rgba[ 3 ] === 1 ) {
368 | rgba.pop();
369 | prefix = "rgb(";
370 | }
371 |
372 | return prefix + rgba.join(",") + ")";
373 | },
374 | toHslaString: function() {
375 | var prefix = "hsla(",
376 | hsla = jQuery.map( this.hsla(), function( v, i ) {
377 | if ( v == null ) {
378 | v = i > 2 ? 1 : 0;
379 | }
380 |
381 | // catch 1 and 2
382 | if ( i && i < 3 ) {
383 | v = Math.round( v * 100 ) + "%";
384 | }
385 | return v;
386 | });
387 |
388 | if ( hsla[ 3 ] === 1 ) {
389 | hsla.pop();
390 | prefix = "hsl(";
391 | }
392 | return prefix + hsla.join(",") + ")";
393 | },
394 | toHexString: function( includeAlpha ) {
395 | var rgba = this._rgba.slice(),
396 | alpha = rgba.pop();
397 |
398 | if ( includeAlpha ) {
399 | rgba.push( ~~( alpha * 255 ) );
400 | }
401 |
402 | return "#" + jQuery.map( rgba, function( v, i ) {
403 |
404 | // default to 0 when nulls exist
405 | v = ( v || 0 ).toString( 16 );
406 | return v.length === 1 ? "0" + v : v;
407 | }).join("");
408 | },
409 | toString: function() {
410 | return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
411 | }
412 | };
413 | color.fn.parse.prototype = color.fn;
414 |
415 | // hsla conversions adapted from:
416 | // http://www.google.com/codesearch/p#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/inspector/front-end/Color.js&d=7&l=193
417 |
418 | function hue2rgb( p, q, h ) {
419 | h = ( h + 1 ) % 1;
420 | if ( h * 6 < 1 ) {
421 | return p + (q - p) * 6 * h;
422 | }
423 | if ( h * 2 < 1) {
424 | return q;
425 | }
426 | if ( h * 3 < 2 ) {
427 | return p + (q - p) * ((2/3) - h) * 6;
428 | }
429 | return p;
430 | }
431 |
432 | spaces.hsla.to = function ( rgba ) {
433 | if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
434 | return [ null, null, null, rgba[ 3 ] ];
435 | }
436 | var r = rgba[ 0 ] / 255,
437 | g = rgba[ 1 ] / 255,
438 | b = rgba[ 2 ] / 255,
439 | a = rgba[ 3 ],
440 | max = Math.max( r, g, b ),
441 | min = Math.min( r, g, b ),
442 | diff = max - min,
443 | add = max + min,
444 | l = add * 0.5,
445 | h, s;
446 |
447 | if ( min === max ) {
448 | h = 0;
449 | } else if ( r === max ) {
450 | h = ( 60 * ( g - b ) / diff ) + 360;
451 | } else if ( g === max ) {
452 | h = ( 60 * ( b - r ) / diff ) + 120;
453 | } else {
454 | h = ( 60 * ( r - g ) / diff ) + 240;
455 | }
456 |
457 | if ( l === 0 || l === 1 ) {
458 | s = l;
459 | } else if ( l <= 0.5 ) {
460 | s = diff / add;
461 | } else {
462 | s = diff / ( 2 - add );
463 | }
464 | return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
465 | };
466 |
467 | spaces.hsla.from = function ( hsla ) {
468 | if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
469 | return [ null, null, null, hsla[ 3 ] ];
470 | }
471 | var h = hsla[ 0 ] / 360,
472 | s = hsla[ 1 ],
473 | l = hsla[ 2 ],
474 | a = hsla[ 3 ],
475 | q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
476 | p = 2 * l - q,
477 | r, g, b;
478 |
479 | return [
480 | Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
481 | Math.round( hue2rgb( p, q, h ) * 255 ),
482 | Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
483 | a
484 | ];
485 | };
486 |
487 |
488 | each( spaces, function( spaceName, space ) {
489 | var props = space.props,
490 | cache = space.cache,
491 | to = space.to,
492 | from = space.from;
493 |
494 | // makes rgba() and hsla()
495 | color.fn[ spaceName ] = function( value ) {
496 |
497 | // generate a cache for this space if it doesn't exist
498 | if ( to && !this[ cache ] ) {
499 | this[ cache ] = to( this._rgba );
500 | }
501 | if ( value === undefined ) {
502 | return this[ cache ].slice();
503 | }
504 |
505 | var type = jQuery.type( value ),
506 | arr = ( type === "array" || type === "object" ) ? value : arguments,
507 | local = this[ cache ].slice(),
508 | ret;
509 |
510 | each( props, function( key, prop ) {
511 | var val = arr[ type === "object" ? key : prop.idx ];
512 | if ( val == null ) {
513 | val = local[ prop.idx ];
514 | }
515 | local[ prop.idx ] = clamp( val, prop );
516 | });
517 |
518 | if ( from ) {
519 | ret = color( from( local ) );
520 | ret[ cache ] = local;
521 | return ret;
522 | } else {
523 | return color( local );
524 | }
525 | };
526 |
527 | // makes red() green() blue() alpha() hue() saturation() lightness()
528 | each( props, function( key, prop ) {
529 | // alpha is included in more than one space
530 | if ( color.fn[ key ] ) {
531 | return;
532 | }
533 | color.fn[ key ] = function( value ) {
534 | var vtype = jQuery.type( value ),
535 | fn = ( key === 'alpha' ? ( this._hsla ? 'hsla' : 'rgba' ) : spaceName ),
536 | local = this[ fn ](),
537 | cur = local[ prop.idx ],
538 | match;
539 |
540 | if ( vtype === "undefined" ) {
541 | return cur;
542 | }
543 |
544 | if ( vtype === "function" ) {
545 | value = value.call( this, cur );
546 | vtype = jQuery.type( value );
547 | }
548 | if ( value == null && prop.empty ) {
549 | return this;
550 | }
551 | if ( vtype === "string" ) {
552 | match = rplusequals.exec( value );
553 | if ( match ) {
554 | value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
555 | }
556 | }
557 | local[ prop.idx ] = value;
558 | return this[ fn ]( local );
559 | };
560 | });
561 | });
562 |
563 | // add .fx.step functions
564 | each( stepHooks, function( i, hook ) {
565 | jQuery.cssHooks[ hook ] = {
566 | set: function( elem, value ) {
567 | var parsed, backgroundColor, curElem;
568 |
569 | if ( jQuery.type( value ) !== 'string' || ( parsed = stringParse( value ) ) )
570 | {
571 | value = color( parsed || value );
572 | if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
573 | curElem = hook === "backgroundColor" ? elem.parentNode : elem;
574 | do {
575 | backgroundColor = jQuery.curCSS( curElem, "backgroundColor" );
576 | } while (
577 | ( backgroundColor === "" || backgroundColor === "transparent" ) &&
578 | ( curElem = curElem.parentNode ) &&
579 | curElem.style
580 | );
581 |
582 | value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
583 | backgroundColor :
584 | "_default" );
585 | }
586 |
587 | value = value.toRgbaString();
588 | }
589 | elem.style[ hook ] = value;
590 | }
591 | };
592 | jQuery.fx.step[ hook ] = function( fx ) {
593 | if ( !fx.colorInit ) {
594 | fx.start = color( fx.elem, hook );
595 | fx.end = color( fx.end );
596 | fx.colorInit = true;
597 | }
598 | jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
599 | };
600 | });
601 |
602 | // detect rgba support
603 | jQuery(function() {
604 | var div = document.createElement( "div" ),
605 | div_style = div.style;
606 |
607 | div_style.cssText = "background-color:rgba(1,1,1,.5)";
608 | support.rgba = div_style.backgroundColor.indexOf( "rgba" ) > -1;
609 | });
610 |
611 | // Some named colors to work with
612 | // From Interface by Stefan Petre
613 | // http://interface.eyecon.ro/
614 | colors = jQuery.Color.names = {
615 | aqua: "#00ffff",
616 | azure: "#f0ffff",
617 | beige: "#f5f5dc",
618 | black: "#000000",
619 | blue: "#0000ff",
620 | brown: "#a52a2a",
621 | cyan: "#00ffff",
622 | darkblue: "#00008b",
623 | darkcyan: "#008b8b",
624 | darkgrey: "#a9a9a9",
625 | darkgreen: "#006400",
626 | darkkhaki: "#bdb76b",
627 | darkmagenta: "#8b008b",
628 | darkolivegreen: "#556b2f",
629 | darkorange: "#ff8c00",
630 | darkorchid: "#9932cc",
631 | darkred: "#8b0000",
632 | darksalmon: "#e9967a",
633 | darkviolet: "#9400d3",
634 | fuchsia: "#ff00ff",
635 | gold: "#ffd700",
636 | green: "#008000",
637 | indigo: "#4b0082",
638 | khaki: "#f0e68c",
639 | lightblue: "#add8e6",
640 | lightcyan: "#e0ffff",
641 | lightgreen: "#90ee90",
642 | lightgrey: "#d3d3d3",
643 | lightpink: "#ffb6c1",
644 | lightyellow: "#ffffe0",
645 | lime: "#00ff00",
646 | magenta: "#ff00ff",
647 | maroon: "#800000",
648 | navy: "#000080",
649 | olive: "#808000",
650 | orange: "#ffa500",
651 | pink: "#ffc0cb",
652 | purple: "#800080",
653 | violet: "#800080",
654 | red: "#ff0000",
655 | silver: "#c0c0c0",
656 | white: "#ffffff",
657 | yellow: "#ffff00",
658 | transparent: [ null, null, null, 0 ],
659 | _default: "#ffffff"
660 | };
661 | })( jQuery );
662 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "karpoff/yii2-crop-image-upload",
3 | "description": "Yii 2 Crop image upload widget",
4 | "homepage": "https://github.com/karpoff/yii2-crop-image-upload",
5 | "license": "BSD-3-Clause",
6 | "type": "yii2-extension",
7 | "version": "0.3.0",
8 | "keywords": ["yii2", "crop", "image", "upload"],
9 | "authors": [
10 | {
11 | "name": "Anton Karpov",
12 | "email": "karpoff@bk.ru"
13 | }
14 | ],
15 | "autoload": {
16 | "psr-4": {
17 | "karpoff\\icrop\\": ""
18 | }
19 | },
20 | "require": {
21 | "yiisoft/yii2": "*",
22 | "yiisoft/yii2-imagine": "*",
23 | "mohorev/yii2-upload-behavior": "*"
24 | }
25 | }
--------------------------------------------------------------------------------