diff --git a/CHANGELOG.md b/CHANGELOG.md index efcfb8d..53acfe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,16 @@ yii2-widget-cropbox =================== -v? [?] ------- +v5.0.0 [2017-05-07] +------------------- - Fixed headers style of markdown. (bryant1410) +- Removed `bupy7\cropbox\Cropbox` and `bupy7\cropbox\MouseWheelAsset` class. +- Added `bupy7\cropbox\CropboxWidget` class. +- Removed `assets` directory. +- Replaced `bower-asset/jq-cropbox` to `bower-asset/js-cropbox` dependency. +- Added jQuery wrapper for `js-cropbox` extension. +- Rewrite `README.md`. v4.1.2 [2016-09-28] ------------------- diff --git a/Cropbox.php b/Cropbox.php deleted file mode 100755 index 29685f4..0000000 --- a/Cropbox.php +++ /dev/null @@ -1,159 +0,0 @@ -name === null && !$this->hasModel()) { - throw new InvalidConfigException("Either 'name', or 'model' and 'attribute' properties must be specified."); - } - if (!isset($this->options['id'])) { - $this->options['id'] = $this->hasModel() ? Html::getInputId($this->model, $this->attribute) : false; - } - parent::init(); - - WidgetAsset::register($this->view); - $this->registerTranslations(); - - $this->options = array_merge([ - 'accept' => 'image/*', - ], $this->options); - $this->pluginOptions = array_merge([ - 'selectors' => [ - 'inputFile' => '#' . $this->id . ' input[type="file"]', - 'btnCrop' => '#' . $this->id . ' .btn-crop', - 'btnReset' => '#' . $this->id . ' .btn-reset', - 'resultContainer' => '#' . $this->id . ' .cropped', - 'messageBlock' => '#' . $this->id . ' .alert', - ], - 'imageOptions' => [ - 'class' => 'img-thumbnail', - ], - ], $this->pluginOptions); - $this->pluginOptions['selectors']['inputInfo'] = '#' - . $this->id - . ' input[name="' - . Html::getInputName($this->model, $this->attributeCropInfo) - . '"]'; - $optionsCropbox = Json::encode($this->pluginOptions); - - $js = "$('#{$this->id}').cropbox({$optionsCropbox});"; - $this->view->registerJs($js, View::POS_READY); - } - - /** - * @inheritdoc - */ - public function run() - { - return $this->render($this->pathToView); - } - - /** - * Translates a message to the specified language. - * - * @param string $message the message to be translated. - * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. - * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current of application - * language. - * @return string - */ - public static function t($message, $params = [], $language = null) - { - return Yii::t('bupy7/cropbox', $message, $params, $language); - } - - /** - * Registration of translation class. - */ - protected function registerTranslations() - { - Yii::$app->i18n->translations['bupy7/cropbox'] = [ - 'class' => 'yii\i18n\PhpMessageSource', - 'sourceLanguage' => 'en', - 'basePath' => '@bupy7/cropbox/messages', - 'fileMap' => [ - 'bupy7/cropbox' => 'core.php', - ], - ]; - } - - /** - * @return boolean whether this widget is associated with a data model. - */ - protected function hasModel() - { - return $this->model instanceof Model && $this->attribute !== null; - } -} diff --git a/CropboxAsset.php b/CropboxAsset.php deleted file mode 100644 index 0b35504..0000000 --- a/CropboxAsset.php +++ /dev/null @@ -1,31 +0,0 @@ - - * @since 1.0.0 - */ -class CropboxAsset extends AssetBundle -{ - public $depends = [ - 'bupy7\cropbox\MouseWheelAsset', - ]; - - /** - * @inheritdoc - */ - public function init() - { - $this->sourcePath = '@bower/jq-cropbox/' . (!YII_DEBUG ? 'dist' : 'src'); - $this->css = ['jquery.cropbox' . (!YII_DEBUG ? '.min' : '') . '.css']; - $this->js = ['jquery.cropbox' . (!YII_DEBUG ? '.min' : '') . '.js']; - parent::init(); - } -} diff --git a/CropboxWidget.php b/CropboxWidget.php new file mode 100755 index 0000000..2657096 --- /dev/null +++ b/CropboxWidget.php @@ -0,0 +1,137 @@ +view); + $this->registerTranslations(); + $this->configuration(); + } + + public function run() + { + $pluginOptions = Json::encode($this->pluginOptions); + $this->view->registerJs("$('#{$this->id} .plugin').cropbox({$pluginOptions});", View::POS_READY); + return $this->render($this->pathToView, [ + 'hasModel' => $this->hasModel(), + ]); + } + + /** + * Translates a message to the specified language. + * + * @param string $message the message to be translated. + * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. + * @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current of application + * language. + * @return string + */ + public static function t($message, $params = [], $language = null) + { + return Yii::t('bupy7/cropbox', $message, $params, $language); + } + + /** + * Registration of translation class. + */ + protected function registerTranslations() + { + Yii::$app->i18n->translations['bupy7/cropbox'] = [ + 'class' => 'yii\i18n\PhpMessageSource', + 'sourceLanguage' => 'en', + 'basePath' => '@bupy7/cropbox/messages', + 'fileMap' => [ + 'bupy7/cropbox' => 'core.php', + ], + ]; + } + + /** + * Configuration the widget. + */ + protected function configuration() + { + $this->options = array_merge(['accept' => 'image/*'], $this->options); + $croppedDataInput = $this->croppedDataAttribute; + if ($this->hasModel()) { + $croppedDataInput = Html::getInputName($this->model, $croppedDataInput); + } else { + $croppedDataInput = $this->croppedDataName; + } + $this->pluginOptions = array_merge([ + 'selectors' => [ + 'fileInput' => sprintf('#%s input[type="file"]', $this->id), + 'btnCrop' => sprintf('#%s .btn-crop', $this->id), + 'btnReset' => sprintf('#%s .btn-reset', $this->id), + 'btnScaleIn' => sprintf('#%s .btn-scale-in', $this->id), + 'btnScaleOut' => sprintf('#%s .btn-scale-out', $this->id), + 'croppedContainer' => sprintf('#%s .cropped-images-cropbox', $this->id), + 'croppedDataInput' => sprintf('#%s input[name="%s"]', $this->id, $croppedDataInput), + 'messageContainer' => sprintf('#%s .message-container-cropbox', $this->id), + ], + ], $this->pluginOptions); + } +} diff --git a/MouseWheelAsset.php b/MouseWheelAsset.php deleted file mode 100644 index 9276f43..0000000 --- a/MouseWheelAsset.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 4.0.0 - */ -class MouseWheelAsset extends AssetBundle -{ - public $sourcePath = '@bower/jquery-mousewheel'; - public $js = [ - 'jquery.mousewheel.min.js', - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapPluginAsset', - ]; -} diff --git a/README.md b/README.md index 06fb289..02440b0 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,22 @@ yii2-widget-cropbox -============ +=================== [![Latest Stable Version](https://poser.pugx.org/bupy7/yii2-widget-cropbox/v/stable)](https://packagist.org/packages/bupy7/yii2-widget-cropbox) [![Total Downloads](https://poser.pugx.org/bupy7/yii2-widget-cropbox/downloads)](https://packagist.org/packages/bupy7/yii2-widget-cropbox) [![License](https://poser.pugx.org/bupy7/yii2-widget-cropbox/license)](https://packagist.org/packages/bupy7/yii2-widget-cropbox) -This is widget wrapper of [jquery-cropbox](https://github.com/bupy7/jquery-cropbox). +This is Yii2 widget wrapper for [js-cropbox](https://github.com/bupy7/js-cropbox). -This widget allows crop image before upload to server and send informations about crop in JSON format. +Demo and documentation of plugin +-------------------------------- -## Functional +[js-cropbox Demo](http://bupy7.github.io/js-cropbox/) -- Simple! =) -- Cropping image before upload to server. -- Cropping more **once** option. -- Labels for settings of crop. -- You can use custom view. -- Resizing cropping image on-the-fly. +[js-cropbox README](https://github.com/bupy7/js-cropbox/blob/master/README.md) -## Demo and documentation of plugin +Installation +------------ -[jQuery-Cropbox Demo](http://bupy7.github.io/jquery-cropbox/) - -[jquery-cropbox README](https://github.com/bupy7/jquery-cropbox/blob/master/README.md) - -## Installation The preferred way to install this extension is through [composer](http://getcomposer.org/download/). Either run @@ -39,17 +31,44 @@ or add to the **require** section of your **composer.json** file. +If you use v4.1.2 then go to [v4.1.2](https://github.com/bupy7/yii2-widget-cropbox/tree/v4.1.2). + If you use v3.0.1 then go to [v3.0.1](https://github.com/bupy7/yii2-widget-cropbox/tree/v3.0.1). If you use v2.2 then go to [v2.2](https://github.com/bupy7/yii2-widget-cropbox/tree/v2.2). If you use v1.0 then go to [v1.0](https://github.com/bupy7/yii2-widget-cropbox/tree/v1.0). -## How use +Options +------- + +#### `$pluginOptions` + +Contain configuration of js-cropbox wrapper. + +##### (array) `$variants`: Variants of cropping image. +More info: https://github.com/bupy7/js-cropbox#object-variants + +##### (array) `[$selectors]`: CSS selectors for attach events of cropbox. -For example I will be use **Imagine extensions for Yii2** https://github.com/yiisoft/yii2-imagine . You can use something other. +- (string) fileInput +- (string) btnCrop +- (string) btnReset +- (string) btnScaleIn +- (string) btnScaleOut +- (string) croppedContainer +- (string) croppedDataInput +- (string) messageContainer + +##### (array) `[$messages]`: Alert messages for each a variant. + +Usage +----- + +For example, I will use **Imagine extensions for Yii2** https://github.com/yiisoft/yii2-imagine . You can use something other. + +**Add in action to your controller:** -Add to action of controller ```php ... @@ -66,9 +85,10 @@ if ($model->load(Yii::$app->request->post())) ... ``` -Add to view +**Add to your view:** + ```php -use bupy7\cropbox\Cropbox; +use bupy7\cropbox\CropboxWidget; $form = ActiveForm::begin([ 'options' => ['enctype'=>'multipart/form-data'], @@ -76,14 +96,15 @@ $form = ActiveForm::begin([ ... -echo $form->field($model, 'image')->widget(Cropbox::className(), [ - 'attributeCropInfo' => 'crop_info', +echo $form->field($model, 'image')->widget(CropboxWidget::className(), [ + 'croppedDataAttribute' => 'crop_info', ]); ... ``` -Add to model: +**Add to your model:** + ```php ... @@ -175,31 +196,33 @@ public function afterSave($insert, $changedAttributes) ... ``` -## Configuration +Configuration +------------- -#### Preview exist image of item +### Preview exist image of item -If you want showing uploaded and cropped image, you must add following code: +If you want to show uploaded and cropped image, you must add following code: ```php -echo $form->field($model, 'image')->widget(Cropbox::className(), [ +echo $form->field($model, 'image')->widget(CropboxWidget::className(), [ ... - 'previewUrl' => [ + 'croppedImagesUrl' => [ 'url/to/small/image' ], - 'originalUrl' => 'url/to/original/image', + 'originalImageUrl' => 'url/to/original/image', ]); ``` -If you click to preview image then you see original image. +If you will click on preview image you see original image. -#### Crop with save real size of image +### Crop with save real size of image -The difference from previous methods in that we do not resize of image before crop it. Here we crop of image as we see it in editor box with saving real size. +Difference from previous methods in that we don't resize image before crop it. +We cropped image as we see it in editor box with saving real size. -For this we will use of property `ratio` from `$cropInfo`. +For this we will use property `ratio` from `$cropInfo`. ```php $cropInfo = Json::decode($this->crop_info)[0]; @@ -219,11 +242,11 @@ $image->crop($cropPointLarge, $cropSizeLarge) ->save($pathLargeImage, ['quality' => $module->qualityLarge]); ``` -#### Cropping more once option +### Cropping more once option -If you set few veriants crop to plugin, then you need make following: +If you will set few veriants crop on plugin you need make following: -Model: +**In model:** ```php ... @@ -284,11 +307,11 @@ public function afterSave($insert, $changedAttributes) ``` -#### Use resizing +### Use resizing -If you want use resizing then you need pointer min and max size of image to "variants" of "pluginOptions". +If you want use resizing you need pointer min and max size of image in `variants` of `pluginOptions`. -To model: +**In model:** ```php // open image diff --git a/WidgetAsset.php b/WidgetAsset.php deleted file mode 100644 index 69c8006..0000000 --- a/WidgetAsset.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @since 4.0.0 - */ -class WidgetAsset extends AssetBundle -{ - public $sourcePath = '@bupy7/cropbox/assets'; - public $css = [ - 'style.css', - ]; - public $depends = [ - 'bupy7\cropbox\CropboxAsset', - ]; -} - diff --git a/assets/CropboxAsset.php b/assets/CropboxAsset.php new file mode 100644 index 0000000..27f066e --- /dev/null +++ b/assets/CropboxAsset.php @@ -0,0 +1,20 @@ + + * @since 5.0.0 + */ +class CropboxAsset extends AssetBundle +{ + public function init() + { + $this->sourcePath = '@bower/js-cropbox/build'; + $this->css = ['cropbox' . (!YII_DEBUG ? '.min' : '') . '.css']; + $this->js = ['cropbox' . (!YII_DEBUG ? '.min' : '') . '.js']; + parent::init(); + } +} diff --git a/assets/WidgetAsset.php b/assets/WidgetAsset.php new file mode 100644 index 0000000..7ce1c9f --- /dev/null +++ b/assets/WidgetAsset.php @@ -0,0 +1,26 @@ + + * @since 5.0.0 + */ +class WidgetAsset extends AssetBundle +{ + public $sourcePath = '@bupy7/cropbox/resources'; + public $css = [ + 'cropbox.css', + ]; + public $js = [ + 'cropbox.js', + ]; + public $depends = [ + 'yii\web\JqueryAsset', + 'yii\bootstrap\BootstrapAsset', + 'bupy7\cropbox\assets\CropboxAsset', + ]; +} + diff --git a/composer.json b/composer.json index 4c3764b..d939532 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,11 @@ { "name": "bupy7/yii2-widget-cropbox", - "description": "This is widget wrapper of https://github.com/bupy7/jquery-cropbox. This widget allows crop image before upload to server and send informations about crop in JSON format.", - "keywords": ["yii2", "extension", "widget", "crop image", "image"], + "description": "This is widget wrapper of https://github.com/bupy7/js-cropbox. This widget allows crop image before to upload to server and send informations about crop as JSON string.", + "keywords": ["yii2", "extension", "widget", "crop", "image"], "homepage": "https://github.com/bupy7/yii2-widget-cropbox", - "version": "4.1.1", + "version": "5.0.0", "type": "yii2-extension", - "license": "BSD 3-Clause", + "license": "BSD-3-Clause", "authors": [ { "name": "Vasilij Belosludcev", @@ -15,8 +15,9 @@ ], "minimum-stability": "stable", "require": { + "yiisoft/yii2": "*", "yiisoft/yii2-bootstrap": "*", - "bower-asset/jq-cropbox": "1.0.*" + "bower-asset/js-cropbox": "0.11.0" }, "autoload": { "psr-4": { diff --git a/assets/style.css b/resources/cropbox.css similarity index 58% rename from assets/style.css rename to resources/cropbox.css index 267f854..215be2e 100755 --- a/assets/style.css +++ b/resources/cropbox.css @@ -1,10 +1,10 @@ @charset "UTF-8"; -div.cropbox .btn-file { +.cropbox .btn-file { position: relative; overflow: hidden; } -div.cropbox .btn-file input[type=file] { +.cropbox .btn-file input[type=file] { position: absolute; top: 0; right: 0; @@ -19,10 +19,20 @@ div.cropbox .btn-file input[type=file] { cursor: inherit; display: block; } -div.cropbox .cropped { +.cropped-images-cropbox { padding: 10px 0 5px 0; } -div.cropbox .img-thumbnail { +.cropped-images-cropbox .img-thumbnail { margin-right: 5px; margin-bottom: 5px; -} \ No newline at end of file +} +.workarea-cropbox, +.bg-cropbox { + height: 500px; + min-height: 500px; + width: 500px; + min-width: 500px; +} +.message-container-cropbox { + display: none; +} diff --git a/resources/cropbox.js b/resources/cropbox.js new file mode 100644 index 0000000..35bb981 --- /dev/null +++ b/resources/cropbox.js @@ -0,0 +1,118 @@ +(function($, Cropbox) { + $.fn.cropbox = function(options) { + // call public method + if (typeof options === 'string') { + var method = options.replace(/^[_]*/, ''); + if (Cropbox.prototype[method]) { + var cb = $(this).data('cropbox'); + return cb[method].apply(cb, Array.prototype.slice.call(arguments, 1)); + } + // create new instance of Cropbox class + } else if (typeof options === 'object' || ! options) { + var selectors = options.selectors, + messages = options.messages || []; + delete options.selectors; + delete options.messages; + return this.each(function() { + $(this).data('cropbox', new Cropbox(this, options)); + attachEvents.call(this, selectors, messages); + }); + // throw an error + } else { + $.error('Method Cropbox::"' + options + '()" not exists.'); + } + }; + + /** + * @param {Object} s + * @param {Array} m + */ + function attachEvents(s, m) { + var $th = $(this); + // scaling + $(s.btnScaleIn).on('click', function() { + $th.cropbox('scale', 1.05); + }); + $(s.btnScaleOut).on('click', function() { + $th.cropbox('scale', 0.95); + }); + $($th.cropbox('getMembrane')).on('wheel', function(event) { + if (event.originalEvent.deltaY < 0) { + $th.cropbox('scale', 1.01); + } else { + $th.cropbox('scale', 0.99); + } + if (event.preventDefault) { + event.preventDefault(); + } + }); + // image loading from a file + $(s.fileInput).on('change', function() { + var fileReader = new FileReader(); + fileReader.readAsDataURL(this.files[0]); + fileReader.onload = function(event) { + $th.cropbox('load', event.target.result); + }; + }); + // reset + $(s.btnReset).on('click', function() { + $th.cropbox('reset'); + }); + // crop + $(s.btnCrop).on('click', function() { + $th.cropbox('crop'); + }); + // the cropped event + $th.on('cb:cropped', function(event) { + var $img = $('', { + src: event.detail.data.image, + class: 'img-thumbnail' + }); + $(s.croppedContainer).append($img); + $(s.croppedDataInput).val(JSON.stringify($th.cropbox('getData'))); + }); + // the reset event + function resetHandler() { + $(s.croppedContainer).html(''); + $(s.croppedDataInput).val(''); + }; + $th.on('cb:reset', resetHandler); + // the loaded event + $th.on('cb:loaded', resetHandler); + // the disabled/enabled event + function disabledHandler() { + $(s.btnScaleIn).attr('disabled', 'disabled'); + $(s.btnScaleOut).attr('disabled', 'disabled'); + $(s.btnCrop).attr('disabled', 'disabled'); + }; + disabledHandler(); + $th.on('cb:disabledCtrls', disabledHandler); + $th.on('cb:enabledCtrls', function() { + $(s.btnScaleIn).removeAttr('disabled'); + $(s.btnScaleOut).removeAttr('disabled'); + $(s.btnCrop).removeAttr('disabled'); + }); + // messages + function showMessage(reset) { + var index = 0; + if (typeof $th.data('mi-cropbox') !== 'undefined' && !(reset || false)) { + index = $th.data('mi-cropbox'); + } + if (typeof m[index] !== 'undefined') { + $(s.messageContainer).html(m[index]).show(); + } else { + $(s.messageContainer).hide(); + } + $th.data('mi-cropbox', ++index); + } + $th.on('cb:cropped', function() { + showMessage(); + }); + $(s.fileInput).on('change', function() { + showMessage(true); + }); + $th.on('cb:reset', function() { + $(s.messageContainer).hide(); + }); + } +})(jQuery, Cropbox); diff --git a/views/field.php b/views/field.php index 87f426e..1423c7e 100755 --- a/views/field.php +++ b/views/field.php @@ -1,38 +1,41 @@ +use bupy7\cropbox\CropboxWidget; +?>
context->originalImageUrl)) { echo Html::a( - ' ' . Cropbox::t('Show original'), + ' ' . CropboxWidget::t('Show original'), $this->context->originalImageUrl, [ 'target' => '_blank', @@ -43,14 +46,17 @@ ?>
context->previewImagesUrl)) { - foreach ($this->context->previewImagesUrl as $url) { - if (!empty($url)) { - echo Html::img($url, ['class' => 'img-thumbnail']); - } - } + $croppedImagesUrl = (array) $this->context->croppedImagesUrl; + foreach ($croppedImagesUrl as $url) { + echo Html::img($url, ['class' => 'img-thumbnail']); } ?>