Commit dd15bb0cf0bf8cbd554d467df799b4b1653abeff

Authored by alex
2 parents b987812e db8fc84f

Merge branches 'clinica_khonko' and 'master' of gitlab.artweb.com.ua:steska/clin…

…ica into clinica_khonko
Showing 49 changed files with 2749 additions and 4 deletions   Show diff stats
backend/components/imagemanager/.gitignore 0 → 100644
  1 +/nbproject
0 2 \ No newline at end of file
... ...
backend/components/imagemanager/LICENSE 0 → 100644
  1 +MIT License
  2 +
  3 +Copyright (c) 2016 noam148
  4 +
  5 +Permission is hereby granted, free of charge, to any person obtaining a copy
  6 +of this software and associated documentation files (the "Software"), to deal
  7 +in the Software without restriction, including without limitation the rights
  8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 +copies of the Software, and to permit persons to whom the Software is
  10 +furnished to do so, subject to the following conditions:
  11 +
  12 +The above copyright notice and this permission notice shall be included in all
  13 +copies or substantial portions of the Software.
  14 +
  15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21 +SOFTWARE.
... ...
backend/components/imagemanager/Module.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager;
  4 +
  5 +use Yii;
  6 +use yii\base\UnknownClassException;
  7 +use yii\base\InvalidConfigException;
  8 +use yii\web\AssetManager;
  9 +use noam148\imagemanager\assets\ImageManagerModuleAsset;
  10 +
  11 +/**
  12 + * imagemanager module definition class
  13 + */
  14 +class Module extends \yii\base\Module {
  15 +
  16 + public $defaultRoute = 'manager';
  17 + //stylesheet for modal iframe
  18 + public $cssFiles = [];
  19 + //allowed Extensions for upload
  20 + public $allowedFileExtensions = ['jpg', 'jpeg', 'gif', 'png'];
  21 + //set assetPublishedUrl
  22 + public $assetPublishedUrl;
  23 +
  24 + /**
  25 + * @var bool|callable Variable that defines if the upload action will be available
  26 + * This variable defaults to true, to enable uploading by default
  27 + * It is also possible to give a callable function, in which case the function will be executed
  28 + */
  29 + public $canUploadImage = true;
  30 +
  31 + /**
  32 + * @var bool|callable Variable that defines if the delete action will be available
  33 + * This variable default to true, to enable removal if image
  34 + * It is also possible to give a callable function, in which case the function will be executed
  35 + */
  36 + public $canRemoveImage = true;
  37 +
  38 + /**
  39 + * @var bool|callable Variable that defines if blameable behavior is used.
  40 + * This can be a boolean, or a callable function that returns a boolean
  41 + */
  42 + public $setBlameableBehavior = false;
  43 +
  44 + /**
  45 + * @var bool|callable Variable that defines if the original image that was used to make the crop will be deleted after the cropped image has been saved
  46 + * By default the original and the cropped image will both be saved, this function can also be a callable.
  47 + */
  48 + public $deleteOriginalAfterEdit = false;
  49 +
  50 + /**
  51 + * @inheritdoc
  52 + */
  53 + public function init() {
  54 + parent::init();
  55 + //set language
  56 + if (!isset(Yii::$app->i18n->translations['imagemanager'])) {
  57 + Yii::$app->i18n->translations['imagemanager'] = [
  58 + 'class' => 'yii\i18n\PhpMessageSource',
  59 + 'sourceLanguage' => 'en',
  60 + 'basePath' => '@noam148/imagemanager/messages'
  61 + ];
  62 + }
  63 + //check extensions
  64 + $this->_checkExtensionsExists();
  65 + //check mediaPath isset
  66 + if (Yii::$app->imagemanager->mediaPath === null) {
  67 + throw new InvalidConfigException("Component param 'mediaPath' need to be set to a location");
  68 + }
  69 + //set asset path
  70 + $this->assetPublishedUrl = (new AssetManager)->getPublishedUrl("@vendor/noam148/yii2-image-manager/assets/source");
  71 +
  72 + // Check if the canRemoveImage variable is callable
  73 + if (is_callable($this->canRemoveImage)) {
  74 + $this->canRemoveImage = call_user_func($this->canRemoveImage);
  75 + }
  76 +
  77 + // Check if the canUploadImage variable is callable
  78 + if (is_callable($this->canUploadImage)) {
  79 + $this->canUploadImage = call_user_func($this->canUploadImage);
  80 + }
  81 +
  82 + // Check if blameable behavior is callable
  83 + if (is_callable($this->setBlameableBehavior))
  84 + $this->setBlameableBehavior = call_user_func($this->setBlameableBehavior);
  85 +
  86 + // Check if the Delete original after crop variable is callable
  87 + if (is_callable($this->deleteOriginalAfterEdit))
  88 + $this->deleteOriginalAfterEdit = call_user_func($this->deleteOriginalAfterEdit);
  89 +
  90 + // Check if the variable configuration is correct in order for the module to function
  91 + $this->_checkVariableConfiguration();
  92 + }
  93 +
  94 + /**
  95 + * Check if extensions exists
  96 + * @throws UnknownClassException Throw error if extension is not found
  97 + */
  98 + private function _checkExtensionsExists() {
  99 + //kartik file uploaded is installed
  100 + if (!class_exists('kartik\file\FileInput')) {
  101 + throw new UnknownClassException("Can't find: kartik\\file\FileInput. Install \"kartik-v/yii2-widget-fileinput\": \"@dev\"");
  102 + }
  103 + //check Yii imagine is installed
  104 + if (!class_exists('yii\imagine\Image')) {
  105 + throw new UnknownClassException("Can't find: yii\imagine\Image. Install \"yiisoft/yii2-imagine\": \"~2.0.0\"");
  106 + }
  107 + }
  108 +
  109 + /**
  110 + * Check if the module variables have the content that is expected
  111 + * @throws InvalidConfigException
  112 + */
  113 + private function _checkVariableConfiguration() {
  114 + // Check if the canUploadImage is boolean
  115 + if (!is_bool($this->canUploadImage)) {
  116 + throw new InvalidConfigException('$canUploadImage variable only supports a boolean value, if you have a custom function you must return a boolean.');
  117 + }
  118 + // Check if the canRemoveImage is boolean
  119 + if (!is_bool($this->canRemoveImage)) {
  120 + throw new InvalidConfigException('$removeImageAllowed variable only supports a boolean value, if you have a custom function you must return a boolean.');
  121 + }
  122 + // Check if the setBlamableBehavior is boolean
  123 + if (! is_bool($this->setBlameableBehavior))
  124 + throw new InvalidConfigException('$setBlameableBehavior only supports a boolean value, if you have a custom function make sure that you return a boolean.');
  125 + // Check if the deleteOriginalAfterEdit is boolean
  126 + if (! is_bool($this->deleteOriginalAfterEdit))
  127 + throw new InvalidConfigException('$deleteOriginalAfterEdit only supports boolean value, if you have a custom function make sure that your return a boolean.');
  128 +
  129 + // Check if the blameable behavior is set to true
  130 + if ($this->setBlameableBehavior) {
  131 + // Get the migration record
  132 + $mRecordMigrationRun = Yii::$app->db->createCommand('SELECT * FROM {{%migration}} WHERE `version` = \'m170223_113221_addBlameableBehavior\'')->queryOne();
  133 + if ($mRecordMigrationRun === false) {
  134 + throw new InvalidConfigException('Image Manager: You have not run the latest migration, see the documentation how to do this.');
  135 + }
  136 + }
  137 + }
  138 +
  139 +}
... ...
backend/components/imagemanager/README.md 0 → 100644
  1 +Image manager for Yii2
  2 +========================
  3 +
  4 +A Yii2 module/widget for upload, manage and cropping images
  5 +
  6 +Installation
  7 +------------
  8 +The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
  9 +
  10 +* Either run
  11 +
  12 +```
  13 +php composer.phar require "noam148/yii2-image-manager" "*"
  14 +```
  15 +or add
  16 +
  17 +```json
  18 +"noam148/yii2-image-manager" : "*"
  19 +```
  20 +
  21 +to the require section of your application's `composer.json` file.
  22 +
  23 +* Run the migrate to create the ImageManager table
  24 +```
  25 +yii migrate --migrationPath=@noam148/imagemanager/migrations
  26 +```
  27 +
  28 +* Add a new component in `components` section of your application's configuration file, for example:
  29 +
  30 +```php
  31 +'components' => [
  32 + 'imagemanager' => [
  33 + 'class' => 'noam148\imagemanager\components\ImageManagerGetPath',
  34 + //set media path (outside the web folder is possible)
  35 + 'mediaPath' => '/path/where/to/store/images/media/imagemanager',
  36 + //path relative web folder to store the cache images
  37 + 'cachePath' => 'assets/images',
  38 + //use filename (seo friendly) for resized images else use a hash
  39 + 'useFilename' => true,
  40 + //show full url (for example in case of a API)
  41 + 'absoluteUrl' => false,
  42 + 'databaseComponent' => 'db' // The used database component by the image manager, this defaults to the Yii::$app->db component
  43 + ],
  44 +],
  45 +```
  46 +
  47 +and in `modules` section, for example:
  48 +
  49 +```php
  50 +'modules' => [
  51 + 'imagemanager' => [
  52 + 'class' => 'noam148\imagemanager\Module',
  53 + //set accces rules ()
  54 + 'canUploadImage' => true,
  55 + 'canRemoveImage' => function(){
  56 + return true;
  57 + },
  58 + 'deleteOriginalAfterEdit' => false, // false: keep original image after edit. true: delete original image after edit
  59 + // Set if blameable behavior is used, if it is, callable function can also be used
  60 + 'setBlameableBehavior' => false,
  61 + //add css files (to use in media manage selector iframe)
  62 + 'cssFiles' => [
  63 + 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css',
  64 + ],
  65 + ],
  66 +],
  67 +```
  68 +
  69 +Usage
  70 +-----
  71 +To reach the imagemanager module go to:
  72 +```
  73 +http://www.example.com/imagemanager
  74 +```
  75 +![Image manager module](/docs/images/img_doc-image-manager.jpg)
  76 +![Image manager module cropper](/docs/images/img_doc-image-manager-crop.jpg)
  77 +
  78 +To load the image picker see below (make sure you have a field in you table where the module can store 'id' of the ImageManager table):
  79 +
  80 +```php
  81 +echo $form->field($model, 'ImageManager_id_avatar')->widget(\noam148\imagemanager\components\ImageManagerInputWidget::className(), [
  82 + 'aspectRatio' => (16/9), //set the aspect ratio
  83 + 'cropViewMode' => 1, //crop mode, option info: https://github.com/fengyuanchen/cropper/#viewmode
  84 + 'showPreview' => true, //false to hide the preview
  85 + 'showDeletePickedImageConfirm' => false, //on true show warning before detach image
  86 +]);
  87 +```
  88 +![Image widget](/docs/images/img_doc-image-widget.jpg)
  89 +![Image widget popup](/docs/images/img_doc-image-widget-popup.jpg)
  90 +
  91 +If you want to use a image:
  92 +
  93 +```php
  94 +/*
  95 + * $ImageManager_id (id that is store in the ImageManager table)
  96 + * $width/$height width height of the image
  97 + * $thumbnailMode = "outbound" or "inset"
  98 + */
  99 +\Yii::$app->imagemanager->getImagePath($ImageManager_id, $width, $height,$thumbnailMode)
  100 +```
  101 +
  102 +Support CKEditor & TinyMce
  103 +-----
  104 +For using the filebrowser in CKEditor add the filebrowserImageBrowseUrl to the clientOptions of the CKEditor widget. I test it only for the CKEditor from 2amigOS but it need to work on other CKEditor widgets.
  105 +
  106 +```php
  107 +use dosamigos\ckeditor\CKEditor;
  108 +
  109 + echo $form->field($model, 'text')->widget(CKEditor::className(), [
  110 + 'options' => ['rows' => 6],
  111 + 'preset' => 'basic',
  112 + 'clientOptions' => [
  113 + 'filebrowserImageBrowseUrl' => yii\helpers\Url::to(['imagemanager/manager', 'view-mode'=>'iframe', 'select-type'=>'ckeditor']),
  114 + ]
  115 +]);
  116 +```
  117 +
  118 +For using the filebrowser in TinyMce add the file_browser_callback to the clientOptions of the TinyMce widget. I test it only for the TinyMce from 2amigOS but it need to work on other TinyMce widgets. (don't forget add 'image' to your 'plugins' array)
  119 +
  120 +```php
  121 +use dosamigos\tinymce\TinyMce;
  122 +
  123 +echo $form->field($model, 'text')->widget(TinyMce::className(), [
  124 + 'options' => ['rows' => 6],
  125 + 'language' => 'nl',
  126 + 'clientOptions' => [
  127 + 'file_browser_callback' => new yii\web\JsExpression("function(field_name, url, type, win) {
  128 + window.open('".yii\helpers\Url::to(['imagemanager/manager', 'view-mode'=>'iframe', 'select-type'=>'tinymce'])."&tag_name='+field_name,'','width=800,height=540 ,toolbar=no,status=no,menubar=no,scrollbars=no,resizable=no');
  129 + }"),
  130 + 'plugins' => [
  131 + "advlist autolink lists link charmap print preview anchor",
  132 + "searchreplace visualblocks code fullscreen",
  133 + "insertdatetime media table contextmenu paste image"
  134 + ],
  135 + 'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
  136 + ]
  137 +]);
  138 +```
  139 +
  140 +**If you got questions, tips or feedback? Please, let me know!**
0 141 \ No newline at end of file
... ...
backend/components/imagemanager/assets/ImageManagerInputAsset.php 0 → 100644
  1 +<?php
  2 +namespace backend\components\imagemanager\assets;
  3 +use yii\web\AssetBundle;
  4 +
  5 +/**
  6 + * ImageManagerInputAsset.
  7 + */
  8 +class ImageManagerInputAsset extends AssetBundle
  9 +{
  10 + public $sourcePath = '@backend/components/imagemanager/assets/source';
  11 + public $css = [
  12 + 'css/imagemanager.input.css',
  13 + ];
  14 + public $js = [
  15 + 'js/script.imagemanager.input.js',
  16 + ];
  17 + public $depends = [
  18 + 'yii\web\JqueryAsset',
  19 + 'yii\bootstrap\BootstrapPluginAsset',
  20 + ];
  21 +}
0 22 \ No newline at end of file
... ...
backend/components/imagemanager/assets/ImageManagerModuleAsset.php 0 → 100644
  1 +<?php
  2 +namespace backend\components\imagemanager\assets;
  3 +use yii\web\AssetBundle;
  4 +
  5 +/**
  6 + * ImageManagerModuleAsset.
  7 + */
  8 +class ImageManagerModuleAsset extends AssetBundle
  9 +{
  10 + public $sourcePath = '@backend/components/imagemanager/assets/source';
  11 + public $css = [
  12 + 'css/cropper.min.css',
  13 + 'css/imagemanager.module.css',
  14 + ];
  15 + public $js = [
  16 + 'js/cropper.min.js',
  17 + 'js/script.imagemanager.module.js',
  18 + ];
  19 + public $depends = [
  20 + 'yii\web\JqueryAsset',
  21 + 'yii\bootstrap\BootstrapPluginAsset',
  22 + ];
  23 +}
0 24 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/css/cropper.min.css 0 → 100644
  1 +/*!
  2 + * Cropper v2.3.2
  3 + * https://github.com/fengyuanchen/cropper
  4 + *
  5 + * Copyright (c) 2014-2016 Fengyuan Chen and contributors
  6 + * Released under the MIT license
  7 + *
  8 + * Date: 2016-06-08T12:14:46.286Z
  9 + */.cropper-container{font-size:0;line-height:0;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;direction:ltr!important;-ms-touch-action:none;touch-action:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.cropper-container img{display:block;width:100%;min-width:0!important;max-width:none!important;height:100%;min-height:0!important;max-height:none!important;image-orientation:0deg!important}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{position:absolute;top:0;right:0;bottom:0;left:0}.cropper-wrap-box{overflow:hidden}.cropper-drag-box{opacity:0;background-color:#fff;filter:alpha(opacity=0)}.cropper-dashed,.cropper-modal{opacity:.5;filter:alpha(opacity=50)}.cropper-modal{background-color:#000}.cropper-view-box{display:block;overflow:hidden;width:100%;height:100%;outline:#39f solid 1px;outline-color:rgba(51,153,255,.75)}.cropper-dashed{position:absolute;display:block;border:0 dashed #eee}.cropper-dashed.dashed-h{top:33.33333%;left:0;width:100%;height:33.33333%;border-top-width:1px;border-bottom-width:1px}.cropper-dashed.dashed-v{top:0;left:33.33333%;width:33.33333%;height:100%;border-right-width:1px;border-left-width:1px}.cropper-center{position:absolute;top:50%;left:50%;display:block;width:0;height:0;opacity:.75;filter:alpha(opacity=75)}.cropper-center:after,.cropper-center:before{position:absolute;display:block;content:' ';background-color:#eee}.cropper-center:before{top:0;left:-3px;width:7px;height:1px}.cropper-center:after{top:-3px;left:0;width:1px;height:7px}.cropper-face,.cropper-line,.cropper-point{position:absolute;display:block;width:100%;height:100%;opacity:.1;filter:alpha(opacity=10)}.cropper-face{top:0;left:0;background-color:#fff}.cropper-line,.cropper-point{background-color:#39f}.cropper-line.line-e{top:0;right:-3px;width:5px;cursor:e-resize}.cropper-line.line-n{top:-3px;left:0;height:5px;cursor:n-resize}.cropper-line.line-w{top:0;left:-3px;width:5px;cursor:w-resize}.cropper-line.line-s{bottom:-3px;left:0;height:5px;cursor:s-resize}.cropper-point{width:5px;height:5px;opacity:.75;filter:alpha(opacity=75)}.cropper-point.point-e{top:50%;right:-3px;margin-top:-3px;cursor:e-resize}.cropper-point.point-n{top:-3px;left:50%;margin-left:-3px;cursor:n-resize}.cropper-point.point-w{top:50%;left:-3px;margin-top:-3px;cursor:w-resize}.cropper-point.point-s{bottom:-3px;left:50%;margin-left:-3px;cursor:s-resize}.cropper-point.point-ne{top:-3px;right:-3px;cursor:ne-resize}.cropper-point.point-nw{top:-3px;left:-3px;cursor:nw-resize}.cropper-point.point-sw{bottom:-3px;left:-3px;cursor:sw-resize}.cropper-point.point-se{right:-3px;bottom:-3px;width:20px;height:20px;cursor:se-resize;opacity:1;filter:alpha(opacity=100)}.cropper-point.point-se:before{position:absolute;right:-50%;bottom:-50%;display:block;width:200%;height:200%;content:' ';opacity:0;background-color:#39f;filter:alpha(opacity=0)}@media (min-width:768px){.cropper-point.point-se{width:15px;height:15px}}@media (min-width:992px){.cropper-point.point-se{width:10px;height:10px}}@media (min-width:1200px){.cropper-point.point-se{width:5px;height:5px;opacity:.75;filter:alpha(opacity=75)}}.cropper-invisible{opacity:0;filter:alpha(opacity=0)}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-hide{position:absolute;display:block;width:0;height:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
0 10 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/css/imagemanager.input.css 0 → 100644
  1 +#modal-imagemanager{ z-index: 999999; }
  2 +#modal-imagemanager .modal-header h4{ margin: 0; }
  3 +#modal-imagemanager iframe{ border: none; width: 100%; min-height: 500px; }
  4 +
  5 +.image-manager-input{}
  6 +.image-manager-input .image-wrapper{ margin-top: 10px; border: 1px solid #ddd; border-radius: 4px; display: inline-block; padding: 4px; background: #FFF; }
  7 +.image-manager-input .image-wrapper .img-preview{ background: #dadada; max-width: 200px; max-height: 200px; height: auto; line-height: 1.42857; }
0 8 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/css/imagemanager.module.css 0 → 100644
  1 +/*CSS for module*/
  2 +#module-imagemanager{ padding-left: 0; padding-right: 0; }
  3 +#module-imagemanager > .row{ margin: 0; }
  4 +#module-imagemanager.tinymce,
  5 +#module-imagemanager.ckeditor{ padding: 15px; }
  6 +
  7 +/*overview*/
  8 +#module-imagemanager > .row .col-overview{ padding-left: 0; padding-right: 0; border-right: 1px solid #ddd; height: 100%; overflow: auto; }
  9 +#module-imagemanager > .row .col-overview .item-overview{ max-height: 500px; overflow: auto; }
  10 +#module-imagemanager > .row .col-overview .item-overview .item{ position: relative; overflow: hidden; width: 128px; height: 128px; cursor: pointer; }
  11 +#module-imagemanager > .row .col-overview .item-overview .item.selected{ background: #00ac24; }
  12 +#module-imagemanager > .row .col-overview .item-overview .item .thumbnail{ margin-bottom: 0; }
  13 +#module-imagemanager > .row .col-overview .item-overview .item .thumbnail img{ max-height: 118px; background: #dadada; }
  14 +#module-imagemanager > .row .col-overview .item-overview .item .thumbnail .filename{ background-color: rgba(255, 255, 255, 0.9); position: absolute; bottom: 4px; left: 4px; right: 4px; max-height: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 10px; }
  15 +/*edit column*/
  16 +#module-imagemanager > .row .col-image-editor{ padding-left: 0; display: none; }
  17 +/*cropper*/
  18 +#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper{ max-height: 460px; }
  19 +#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper{ max-width: 100%; }
  20 +/*options*/
  21 +#module-imagemanager > .row .col-options{ padding-right: 0; }
  22 +/*File upload*/
  23 +#module-imagemanager > .row .col-options .file-input .form-control{ display: none; }
  24 +#module-imagemanager > .row .col-options .form-group .file-input .input-group,
  25 +#module-imagemanager > .row .col-options .form-group .file-input .input-group .input-group-btn{ float: left; }
  26 +#module-imagemanager > .row .col-options .form-group .btn-add-flyleaf{ float: left; }
  27 +/*details*/
  28 +#module-imagemanager > .row .col-options .image-info{ margin-top: 10px; }
  29 +#module-imagemanager > .row .col-options .image-info .thumbnail{ margin-bottom: 10px; }
  30 +#module-imagemanager > .row .col-options .image-info .thumbnail img{ max-width: 100%; background: #dadada; }
  31 +#module-imagemanager > .row .col-options .image-info .edit-buttons{ margin-bottom: 10px; }
  32 +#module-imagemanager > .row .col-options .image-info .details{}
  33 +#module-imagemanager > .row .col-options .image-info .details .fileName{ font-weight: bold; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  34 +#module-imagemanager > .row .col-options .image-info .pick-image-item{ margin-top: 10px; }
  35 +
  36 +#module-imagemanager a.delete-image-item { margin-top: 5px; }
0 37 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/img/img_no-image.png 0 → 100644

8.26 KB

backend/components/imagemanager/assets/source/js/cropper.min.js 0 → 100644
  1 +/*!
  2 + * Cropper v2.3.2
  3 + * https://github.com/fengyuanchen/cropper
  4 + *
  5 + * Copyright (c) 2014-2016 Fengyuan Chen and contributors
  6 + * Released under the MIT license
  7 + *
  8 + * Date: 2016-06-08T12:14:46.286Z
  9 + */
  10 +!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){"use strict";function i(t){return"number"==typeof t&&!isNaN(t)}function e(t){return"undefined"==typeof t}function s(t,e){var s=[];return i(e)&&s.push(e),s.slice.apply(t,s)}function a(t,i){var e=s(arguments,2);return function(){return t.apply(i,e.concat(s(arguments)))}}function o(t){var i=t.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return i&&(i[1]!==C.protocol||i[2]!==C.hostname||i[3]!==C.port)}function h(t){var i="timestamp="+(new Date).getTime();return t+(-1===t.indexOf("?")?"?":"&")+i}function n(t){return t?' crossOrigin="'+t+'"':""}function r(t,i){var e;return t.naturalWidth&&!mt?i(t.naturalWidth,t.naturalHeight):(e=document.createElement("img"),e.onload=function(){i(this.width,this.height)},void(e.src=t.src))}function p(t){var e=[],s=t.rotate,a=t.scaleX,o=t.scaleY;return i(a)&&i(o)&&e.push("scale("+a+","+o+")"),i(s)&&e.push("rotate("+s+"deg)"),e.length?e.join(" "):"none"}function c(t,i){var e,s,a=Ct(t.degree)%180,o=(a>90?180-a:a)*Math.PI/180,h=bt(o),n=Bt(o),r=t.width,p=t.height,c=t.aspectRatio;return i?(e=r/(n+h/c),s=e/c):(e=r*n+p*h,s=r*h+p*n),{width:e,height:s}}function l(e,s){var a,o,h,n=t("<canvas>")[0],r=n.getContext("2d"),p=0,l=0,d=s.naturalWidth,g=s.naturalHeight,u=s.rotate,f=s.scaleX,m=s.scaleY,v=i(f)&&i(m)&&(1!==f||1!==m),w=i(u)&&0!==u,x=w||v,C=d*Ct(f||1),b=g*Ct(m||1);return v&&(a=C/2,o=b/2),w&&(h=c({width:C,height:b,degree:u}),C=h.width,b=h.height,a=C/2,o=b/2),n.width=C,n.height=b,x&&(p=-d/2,l=-g/2,r.save(),r.translate(a,o)),v&&r.scale(f,m),w&&r.rotate(u*Math.PI/180),r.drawImage(e,$t(p),$t(l),$t(d),$t(g)),x&&r.restore(),n}function d(i){var e=i.length,s=0,a=0;return e&&(t.each(i,function(t,i){s+=i.pageX,a+=i.pageY}),s/=e,a/=e),{pageX:s,pageY:a}}function g(t,i,e){var s,a="";for(s=i,e+=i;e>s;s++)a+=Lt(t.getUint8(s));return a}function u(t){var i,e,s,a,o,h,n,r,p,c,l=new D(t),d=l.byteLength;if(255===l.getUint8(0)&&216===l.getUint8(1))for(p=2;d>p;){if(255===l.getUint8(p)&&225===l.getUint8(p+1)){n=p;break}p++}if(n&&(e=n+4,s=n+10,"Exif"===g(l,e,4)&&(h=l.getUint16(s),o=18761===h,(o||19789===h)&&42===l.getUint16(s+2,o)&&(a=l.getUint32(s+4,o),a>=8&&(r=s+a)))),r)for(d=l.getUint16(r,o),c=0;d>c;c++)if(p=r+12*c+2,274===l.getUint16(p,o)){p+=8,i=l.getUint16(p,o),mt&&l.setUint16(p,1,o);break}return i}function f(t){var i,e=t.replace(G,""),s=atob(e),a=s.length,o=new B(a),h=new y(o);for(i=0;a>i;i++)h[i]=s.charCodeAt(i);return o}function m(t){var i,e=new y(t),s=e.length,a="";for(i=0;s>i;i++)a+=Lt(e[i]);return"data:image/jpeg;base64,"+$(a)}function v(i,e){this.$element=t(i),this.options=t.extend({},v.DEFAULTS,t.isPlainObject(e)&&e),this.isLoaded=!1,this.isBuilt=!1,this.isCompleted=!1,this.isRotated=!1,this.isCropped=!1,this.isDisabled=!1,this.isReplaced=!1,this.isLimited=!1,this.wheeling=!1,this.isImg=!1,this.originalUrl="",this.canvas=null,this.cropBox=null,this.init()}var w=t(window),x=t(document),C=window.location,b=window.navigator,B=window.ArrayBuffer,y=window.Uint8Array,D=window.DataView,$=window.btoa,L="cropper",T="cropper-modal",X="cropper-hide",Y="cropper-hidden",k="cropper-invisible",M="cropper-move",W="cropper-crop",H="cropper-disabled",R="cropper-bg",z="mousedown touchstart pointerdown MSPointerDown",O="mousemove touchmove pointermove MSPointerMove",P="mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel",E="wheel mousewheel DOMMouseScroll",U="dblclick",I="load."+L,F="error."+L,j="resize."+L,A="build."+L,S="built."+L,N="cropstart."+L,_="cropmove."+L,q="cropend."+L,K="crop."+L,Z="zoom."+L,Q=/e|w|s|n|se|sw|ne|nw|all|crop|move|zoom/,V=/^data\:/,G=/^data\:([^\;]+)\;base64,/,J=/^data\:image\/jpeg.*;base64,/,tt="preview",it="action",et="e",st="w",at="s",ot="n",ht="se",nt="sw",rt="ne",pt="nw",ct="all",lt="crop",dt="move",gt="zoom",ut="none",ft=t.isFunction(t("<canvas>")[0].getContext),mt=b&&/(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(b.userAgent),vt=Number,wt=Math.min,xt=Math.max,Ct=Math.abs,bt=Math.sin,Bt=Math.cos,yt=Math.sqrt,Dt=Math.round,$t=Math.floor,Lt=String.fromCharCode;v.prototype={constructor:v,init:function(){var t,i=this.$element;if(i.is("img")){if(this.isImg=!0,this.originalUrl=t=i.attr("src"),!t)return;t=i.prop("src")}else i.is("canvas")&&ft&&(t=i[0].toDataURL());this.load(t)},trigger:function(i,e){var s=t.Event(i,e);return this.$element.trigger(s),s},load:function(i){var e,s,a=this.options,n=this.$element;if(i&&(n.one(A,a.build),!this.trigger(A).isDefaultPrevented())){if(this.url=i,this.image={},!a.checkOrientation||!B)return this.clone();if(e=t.proxy(this.read,this),V.test(i))return J.test(i)?e(f(i)):this.clone();s=new XMLHttpRequest,s.onerror=s.onabort=t.proxy(function(){this.clone()},this),s.onload=function(){e(this.response)},a.checkCrossOrigin&&o(i)&&n.prop("crossOrigin")&&(i=h(i)),s.open("get",i),s.responseType="arraybuffer",s.send()}},read:function(t){var i,e,s,a=this.options,o=u(t),h=this.image;if(o>1)switch(this.url=m(t),o){case 2:e=-1;break;case 3:i=-180;break;case 4:s=-1;break;case 5:i=90,s=-1;break;case 6:i=90;break;case 7:i=90,e=-1;break;case 8:i=-90}a.rotatable&&(h.rotate=i),a.scalable&&(h.scaleX=e,h.scaleY=s),this.clone()},clone:function(){var i,e,s=this.options,a=this.$element,r=this.url,p="";s.checkCrossOrigin&&o(r)&&(p=a.prop("crossOrigin"),p?i=r:(p="anonymous",i=h(r))),this.crossOrigin=p,this.crossOriginUrl=i,this.$clone=e=t("<img"+n(p)+' src="'+(i||r)+'">'),this.isImg?a[0].complete?this.start():a.one(I,t.proxy(this.start,this)):e.one(I,t.proxy(this.start,this)).one(F,t.proxy(this.stop,this)).addClass(X).insertAfter(a)},start:function(){var i=this.$element,e=this.$clone;this.isImg||(e.off(F,this.stop),i=e),r(i[0],t.proxy(function(i,e){t.extend(this.image,{naturalWidth:i,naturalHeight:e,aspectRatio:i/e}),this.isLoaded=!0,this.build()},this))},stop:function(){this.$clone.remove(),this.$clone=null},build:function(){var i,e,s,a=this.options,o=this.$element,h=this.$clone;this.isLoaded&&(this.isBuilt&&this.unbuild(),this.$container=o.parent(),this.$cropper=i=t(v.TEMPLATE),this.$canvas=i.find(".cropper-canvas").append(h),this.$dragBox=i.find(".cropper-drag-box"),this.$cropBox=e=i.find(".cropper-crop-box"),this.$viewBox=i.find(".cropper-view-box"),this.$face=s=e.find(".cropper-face"),o.addClass(Y).after(i),this.isImg||h.removeClass(X),this.initPreview(),this.bind(),a.aspectRatio=xt(0,a.aspectRatio)||NaN,a.viewMode=xt(0,wt(3,Dt(a.viewMode)))||0,a.autoCrop?(this.isCropped=!0,a.modal&&this.$dragBox.addClass(T)):e.addClass(Y),a.guides||e.find(".cropper-dashed").addClass(Y),a.center||e.find(".cropper-center").addClass(Y),a.cropBoxMovable&&s.addClass(M).data(it,ct),a.highlight||s.addClass(k),a.background&&i.addClass(R),a.cropBoxResizable||e.find(".cropper-line, .cropper-point").addClass(Y),this.setDragMode(a.dragMode),this.render(),this.isBuilt=!0,this.setData(a.data),o.one(S,a.built),setTimeout(t.proxy(function(){this.trigger(S),this.trigger(K,this.getData()),this.isCompleted=!0},this),0))},unbuild:function(){this.isBuilt&&(this.isBuilt=!1,this.isCompleted=!1,this.initialImage=null,this.initialCanvas=null,this.initialCropBox=null,this.container=null,this.canvas=null,this.cropBox=null,this.unbind(),this.resetPreview(),this.$preview=null,this.$viewBox=null,this.$cropBox=null,this.$dragBox=null,this.$canvas=null,this.$container=null,this.$cropper.remove(),this.$cropper=null)},render:function(){this.initContainer(),this.initCanvas(),this.initCropBox(),this.renderCanvas(),this.isCropped&&this.renderCropBox()},initContainer:function(){var t=this.options,i=this.$element,e=this.$container,s=this.$cropper;s.addClass(Y),i.removeClass(Y),s.css(this.container={width:xt(e.width(),vt(t.minContainerWidth)||200),height:xt(e.height(),vt(t.minContainerHeight)||100)}),i.addClass(Y),s.removeClass(Y)},initCanvas:function(){var i,e=this.options.viewMode,s=this.container,a=s.width,o=s.height,h=this.image,n=h.naturalWidth,r=h.naturalHeight,p=90===Ct(h.rotate),c=p?r:n,l=p?n:r,d=c/l,g=a,u=o;o*d>a?3===e?g=o*d:u=a/d:3===e?u=a/d:g=o*d,i={naturalWidth:c,naturalHeight:l,aspectRatio:d,width:g,height:u},i.oldLeft=i.left=(a-g)/2,i.oldTop=i.top=(o-u)/2,this.canvas=i,this.isLimited=1===e||2===e,this.limitCanvas(!0,!0),this.initialImage=t.extend({},h),this.initialCanvas=t.extend({},i)},limitCanvas:function(t,i){var e,s,a,o,h=this.options,n=h.viewMode,r=this.container,p=r.width,c=r.height,l=this.canvas,d=l.aspectRatio,g=this.cropBox,u=this.isCropped&&g;t&&(e=vt(h.minCanvasWidth)||0,s=vt(h.minCanvasHeight)||0,n&&(n>1?(e=xt(e,p),s=xt(s,c),3===n&&(s*d>e?e=s*d:s=e/d)):e?e=xt(e,u?g.width:0):s?s=xt(s,u?g.height:0):u&&(e=g.width,s=g.height,s*d>e?e=s*d:s=e/d)),e&&s?s*d>e?s=e/d:e=s*d:e?s=e/d:s&&(e=s*d),l.minWidth=e,l.minHeight=s,l.maxWidth=1/0,l.maxHeight=1/0),i&&(n?(a=p-l.width,o=c-l.height,l.minLeft=wt(0,a),l.minTop=wt(0,o),l.maxLeft=xt(0,a),l.maxTop=xt(0,o),u&&this.isLimited&&(l.minLeft=wt(g.left,g.left+g.width-l.width),l.minTop=wt(g.top,g.top+g.height-l.height),l.maxLeft=g.left,l.maxTop=g.top,2===n&&(l.width>=p&&(l.minLeft=wt(0,a),l.maxLeft=xt(0,a)),l.height>=c&&(l.minTop=wt(0,o),l.maxTop=xt(0,o))))):(l.minLeft=-l.width,l.minTop=-l.height,l.maxLeft=p,l.maxTop=c))},renderCanvas:function(t){var i,e,s=this.canvas,a=this.image,o=a.rotate,h=a.naturalWidth,n=a.naturalHeight;this.isRotated&&(this.isRotated=!1,e=c({width:a.width,height:a.height,degree:o}),i=e.width/e.height,i!==s.aspectRatio&&(s.left-=(e.width-s.width)/2,s.top-=(e.height-s.height)/2,s.width=e.width,s.height=e.height,s.aspectRatio=i,s.naturalWidth=h,s.naturalHeight=n,o%180&&(e=c({width:h,height:n,degree:o}),s.naturalWidth=e.width,s.naturalHeight=e.height),this.limitCanvas(!0,!1))),(s.width>s.maxWidth||s.width<s.minWidth)&&(s.left=s.oldLeft),(s.height>s.maxHeight||s.height<s.minHeight)&&(s.top=s.oldTop),s.width=wt(xt(s.width,s.minWidth),s.maxWidth),s.height=wt(xt(s.height,s.minHeight),s.maxHeight),this.limitCanvas(!1,!0),s.oldLeft=s.left=wt(xt(s.left,s.minLeft),s.maxLeft),s.oldTop=s.top=wt(xt(s.top,s.minTop),s.maxTop),this.$canvas.css({width:s.width,height:s.height,left:s.left,top:s.top}),this.renderImage(),this.isCropped&&this.isLimited&&this.limitCropBox(!0,!0),t&&this.output()},renderImage:function(i){var e,s=this.canvas,a=this.image;a.rotate&&(e=c({width:s.width,height:s.height,degree:a.rotate,aspectRatio:a.aspectRatio},!0)),t.extend(a,e?{width:e.width,height:e.height,left:(s.width-e.width)/2,top:(s.height-e.height)/2}:{width:s.width,height:s.height,left:0,top:0}),this.$clone.css({width:a.width,height:a.height,marginLeft:a.left,marginTop:a.top,transform:p(a)}),i&&this.output()},initCropBox:function(){var i=this.options,e=this.canvas,s=i.aspectRatio,a=vt(i.autoCropArea)||.8,o={width:e.width,height:e.height};s&&(e.height*s>e.width?o.height=o.width/s:o.width=o.height*s),this.cropBox=o,this.limitCropBox(!0,!0),o.width=wt(xt(o.width,o.minWidth),o.maxWidth),o.height=wt(xt(o.height,o.minHeight),o.maxHeight),o.width=xt(o.minWidth,o.width*a),o.height=xt(o.minHeight,o.height*a),o.oldLeft=o.left=e.left+(e.width-o.width)/2,o.oldTop=o.top=e.top+(e.height-o.height)/2,this.initialCropBox=t.extend({},o)},limitCropBox:function(t,i){var e,s,a,o,h=this.options,n=h.aspectRatio,r=this.container,p=r.width,c=r.height,l=this.canvas,d=this.cropBox,g=this.isLimited;t&&(e=vt(h.minCropBoxWidth)||0,s=vt(h.minCropBoxHeight)||0,e=wt(e,p),s=wt(s,c),a=wt(p,g?l.width:p),o=wt(c,g?l.height:c),n&&(e&&s?s*n>e?s=e/n:e=s*n:e?s=e/n:s&&(e=s*n),o*n>a?o=a/n:a=o*n),d.minWidth=wt(e,a),d.minHeight=wt(s,o),d.maxWidth=a,d.maxHeight=o),i&&(g?(d.minLeft=xt(0,l.left),d.minTop=xt(0,l.top),d.maxLeft=wt(p,l.left+l.width)-d.width,d.maxTop=wt(c,l.top+l.height)-d.height):(d.minLeft=0,d.minTop=0,d.maxLeft=p-d.width,d.maxTop=c-d.height))},renderCropBox:function(){var t=this.options,i=this.container,e=i.width,s=i.height,a=this.cropBox;(a.width>a.maxWidth||a.width<a.minWidth)&&(a.left=a.oldLeft),(a.height>a.maxHeight||a.height<a.minHeight)&&(a.top=a.oldTop),a.width=wt(xt(a.width,a.minWidth),a.maxWidth),a.height=wt(xt(a.height,a.minHeight),a.maxHeight),this.limitCropBox(!1,!0),a.oldLeft=a.left=wt(xt(a.left,a.minLeft),a.maxLeft),a.oldTop=a.top=wt(xt(a.top,a.minTop),a.maxTop),t.movable&&t.cropBoxMovable&&this.$face.data(it,a.width===e&&a.height===s?dt:ct),this.$cropBox.css({width:a.width,height:a.height,left:a.left,top:a.top}),this.isCropped&&this.isLimited&&this.limitCanvas(!0,!0),this.isDisabled||this.output()},output:function(){this.preview(),this.isCompleted&&this.trigger(K,this.getData())},initPreview:function(){var i,e=n(this.crossOrigin),s=e?this.crossOriginUrl:this.url;this.$preview=t(this.options.preview),this.$clone2=i=t("<img"+e+' src="'+s+'">'),this.$viewBox.html(i),this.$preview.each(function(){var i=t(this);i.data(tt,{width:i.width(),height:i.height(),html:i.html()}),i.html("<img"+e+' src="'+s+'" style="display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;">')})},resetPreview:function(){this.$preview.each(function(){var i=t(this),e=i.data(tt);i.css({width:e.width,height:e.height}).html(e.html).removeData(tt)})},preview:function(){var i=this.image,e=this.canvas,s=this.cropBox,a=s.width,o=s.height,h=i.width,n=i.height,r=s.left-e.left-i.left,c=s.top-e.top-i.top;this.isCropped&&!this.isDisabled&&(this.$clone2.css({width:h,height:n,marginLeft:-r,marginTop:-c,transform:p(i)}),this.$preview.each(function(){var e=t(this),s=e.data(tt),l=s.width,d=s.height,g=l,u=d,f=1;a&&(f=l/a,u=o*f),o&&u>d&&(f=d/o,g=a*f,u=d),e.css({width:g,height:u}).find("img").css({width:h*f,height:n*f,marginLeft:-r*f,marginTop:-c*f,transform:p(i)})}))},bind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.on(N,i.cropstart),t.isFunction(i.cropmove)&&e.on(_,i.cropmove),t.isFunction(i.cropend)&&e.on(q,i.cropend),t.isFunction(i.crop)&&e.on(K,i.crop),t.isFunction(i.zoom)&&e.on(Z,i.zoom),s.on(z,t.proxy(this.cropStart,this)),i.zoomable&&i.zoomOnWheel&&s.on(E,t.proxy(this.wheel,this)),i.toggleDragModeOnDblclick&&s.on(U,t.proxy(this.dblclick,this)),x.on(O,this._cropMove=a(this.cropMove,this)).on(P,this._cropEnd=a(this.cropEnd,this)),i.responsive&&w.on(j,this._resize=a(this.resize,this))},unbind:function(){var i=this.options,e=this.$element,s=this.$cropper;t.isFunction(i.cropstart)&&e.off(N,i.cropstart),t.isFunction(i.cropmove)&&e.off(_,i.cropmove),t.isFunction(i.cropend)&&e.off(q,i.cropend),t.isFunction(i.crop)&&e.off(K,i.crop),t.isFunction(i.zoom)&&e.off(Z,i.zoom),s.off(z,this.cropStart),i.zoomable&&i.zoomOnWheel&&s.off(E,this.wheel),i.toggleDragModeOnDblclick&&s.off(U,this.dblclick),x.off(O,this._cropMove).off(P,this._cropEnd),i.responsive&&w.off(j,this._resize)},resize:function(){var i,e,s,a=this.options.restore,o=this.$container,h=this.container;!this.isDisabled&&h&&(s=o.width()/h.width,1===s&&o.height()===h.height||(a&&(i=this.getCanvasData(),e=this.getCropBoxData()),this.render(),a&&(this.setCanvasData(t.each(i,function(t,e){i[t]=e*s})),this.setCropBoxData(t.each(e,function(t,i){e[t]=i*s})))))},dblclick:function(){this.isDisabled||(this.$dragBox.hasClass(W)?this.setDragMode(dt):this.setDragMode(lt))},wheel:function(i){var e=i.originalEvent||i,s=vt(this.options.wheelZoomRatio)||.1,a=1;this.isDisabled||(i.preventDefault(),this.wheeling||(this.wheeling=!0,setTimeout(t.proxy(function(){this.wheeling=!1},this),50),e.deltaY?a=e.deltaY>0?1:-1:e.wheelDelta?a=-e.wheelDelta/120:e.detail&&(a=e.detail>0?1:-1),this.zoom(-a*s,i)))},cropStart:function(i){var e,s,a=this.options,o=i.originalEvent,h=o&&o.touches,n=i;if(!this.isDisabled){if(h){if(e=h.length,e>1){if(!a.zoomable||!a.zoomOnTouch||2!==e)return;n=h[1],this.startX2=n.pageX,this.startY2=n.pageY,s=gt}n=h[0]}if(s=s||t(n.target).data(it),Q.test(s)){if(this.trigger(N,{originalEvent:o,action:s}).isDefaultPrevented())return;i.preventDefault(),this.action=s,this.cropping=!1,this.startX=n.pageX||o&&o.pageX,this.startY=n.pageY||o&&o.pageY,s===lt&&(this.cropping=!0,this.$dragBox.addClass(T))}}},cropMove:function(t){var i,e=this.options,s=t.originalEvent,a=s&&s.touches,o=t,h=this.action;if(!this.isDisabled){if(a){if(i=a.length,i>1){if(!e.zoomable||!e.zoomOnTouch||2!==i)return;o=a[1],this.endX2=o.pageX,this.endY2=o.pageY}o=a[0]}if(h){if(this.trigger(_,{originalEvent:s,action:h}).isDefaultPrevented())return;t.preventDefault(),this.endX=o.pageX||s&&s.pageX,this.endY=o.pageY||s&&s.pageY,this.change(o.shiftKey,h===gt?t:null)}}},cropEnd:function(t){var i=t.originalEvent,e=this.action;this.isDisabled||e&&(t.preventDefault(),this.cropping&&(this.cropping=!1,this.$dragBox.toggleClass(T,this.isCropped&&this.options.modal)),this.action="",this.trigger(q,{originalEvent:i,action:e}))},change:function(t,i){var e,s,a=this.options,o=a.aspectRatio,h=this.action,n=this.container,r=this.canvas,p=this.cropBox,c=p.width,l=p.height,d=p.left,g=p.top,u=d+c,f=g+l,m=0,v=0,w=n.width,x=n.height,C=!0;switch(!o&&t&&(o=c&&l?c/l:1),this.isLimited&&(m=p.minLeft,v=p.minTop,w=m+wt(n.width,r.left+r.width),x=v+wt(n.height,r.top+r.height)),s={x:this.endX-this.startX,y:this.endY-this.startY},o&&(s.X=s.y*o,s.Y=s.x/o),h){case ct:d+=s.x,g+=s.y;break;case et:if(s.x>=0&&(u>=w||o&&(v>=g||f>=x))){C=!1;break}c+=s.x,o&&(l=c/o,g-=s.Y/2),0>c&&(h=st,c=0);break;case ot:if(s.y<=0&&(v>=g||o&&(m>=d||u>=w))){C=!1;break}l-=s.y,g+=s.y,o&&(c=l*o,d+=s.X/2),0>l&&(h=at,l=0);break;case st:if(s.x<=0&&(m>=d||o&&(v>=g||f>=x))){C=!1;break}c-=s.x,d+=s.x,o&&(l=c/o,g+=s.Y/2),0>c&&(h=et,c=0);break;case at:if(s.y>=0&&(f>=x||o&&(m>=d||u>=w))){C=!1;break}l+=s.y,o&&(c=l*o,d-=s.X/2),0>l&&(h=ot,l=0);break;case rt:if(o){if(s.y<=0&&(v>=g||u>=w)){C=!1;break}l-=s.y,g+=s.y,c=l*o}else s.x>=0?w>u?c+=s.x:s.y<=0&&v>=g&&(C=!1):c+=s.x,s.y<=0?g>v&&(l-=s.y,g+=s.y):(l-=s.y,g+=s.y);0>c&&0>l?(h=nt,l=0,c=0):0>c?(h=pt,c=0):0>l&&(h=ht,l=0);break;case pt:if(o){if(s.y<=0&&(v>=g||m>=d)){C=!1;break}l-=s.y,g+=s.y,c=l*o,d+=s.X}else s.x<=0?d>m?(c-=s.x,d+=s.x):s.y<=0&&v>=g&&(C=!1):(c-=s.x,d+=s.x),s.y<=0?g>v&&(l-=s.y,g+=s.y):(l-=s.y,g+=s.y);0>c&&0>l?(h=ht,l=0,c=0):0>c?(h=rt,c=0):0>l&&(h=nt,l=0);break;case nt:if(o){if(s.x<=0&&(m>=d||f>=x)){C=!1;break}c-=s.x,d+=s.x,l=c/o}else s.x<=0?d>m?(c-=s.x,d+=s.x):s.y>=0&&f>=x&&(C=!1):(c-=s.x,d+=s.x),s.y>=0?x>f&&(l+=s.y):l+=s.y;0>c&&0>l?(h=rt,l=0,c=0):0>c?(h=ht,c=0):0>l&&(h=pt,l=0);break;case ht:if(o){if(s.x>=0&&(u>=w||f>=x)){C=!1;break}c+=s.x,l=c/o}else s.x>=0?w>u?c+=s.x:s.y>=0&&f>=x&&(C=!1):c+=s.x,s.y>=0?x>f&&(l+=s.y):l+=s.y;0>c&&0>l?(h=pt,l=0,c=0):0>c?(h=nt,c=0):0>l&&(h=rt,l=0);break;case dt:this.move(s.x,s.y),C=!1;break;case gt:this.zoom(function(t,i,e,s){var a=yt(t*t+i*i),o=yt(e*e+s*s);return(o-a)/a}(Ct(this.startX-this.startX2),Ct(this.startY-this.startY2),Ct(this.endX-this.endX2),Ct(this.endY-this.endY2)),i),this.startX2=this.endX2,this.startY2=this.endY2,C=!1;break;case lt:if(!s.x||!s.y){C=!1;break}e=this.$cropper.offset(),d=this.startX-e.left,g=this.startY-e.top,c=p.minWidth,l=p.minHeight,s.x>0?h=s.y>0?ht:rt:s.x<0&&(d-=c,h=s.y>0?nt:pt),s.y<0&&(g-=l),this.isCropped||(this.$cropBox.removeClass(Y),this.isCropped=!0,this.isLimited&&this.limitCropBox(!0,!0))}C&&(p.width=c,p.height=l,p.left=d,p.top=g,this.action=h,this.renderCropBox()),this.startX=this.endX,this.startY=this.endY},crop:function(){this.isBuilt&&!this.isDisabled&&(this.isCropped||(this.isCropped=!0,this.limitCropBox(!0,!0),this.options.modal&&this.$dragBox.addClass(T),this.$cropBox.removeClass(Y)),this.setCropBoxData(this.initialCropBox))},reset:function(){this.isBuilt&&!this.isDisabled&&(this.image=t.extend({},this.initialImage),this.canvas=t.extend({},this.initialCanvas),this.cropBox=t.extend({},this.initialCropBox),this.renderCanvas(),this.isCropped&&this.renderCropBox())},clear:function(){this.isCropped&&!this.isDisabled&&(t.extend(this.cropBox,{left:0,top:0,width:0,height:0}),this.isCropped=!1,this.renderCropBox(),this.limitCanvas(!0,!0),this.renderCanvas(),this.$dragBox.removeClass(T),this.$cropBox.addClass(Y))},replace:function(t,i){!this.isDisabled&&t&&(this.isImg&&this.$element.attr("src",t),i?(this.url=t,this.$clone.attr("src",t),this.isBuilt&&this.$preview.find("img").add(this.$clone2).attr("src",t)):(this.isImg&&(this.isReplaced=!0),this.options.data=null,this.load(t)))},enable:function(){this.isBuilt&&(this.isDisabled=!1,this.$cropper.removeClass(H))},disable:function(){this.isBuilt&&(this.isDisabled=!0,this.$cropper.addClass(H))},destroy:function(){var t=this.$element;this.isLoaded?(this.isImg&&this.isReplaced&&t.attr("src",this.originalUrl),this.unbuild(),t.removeClass(Y)):this.isImg?t.off(I,this.start):this.$clone&&this.$clone.remove(),t.removeData(L)},move:function(t,i){var s=this.canvas;this.moveTo(e(t)?t:s.left+vt(t),e(i)?i:s.top+vt(i))},moveTo:function(t,s){var a=this.canvas,o=!1;e(s)&&(s=t),t=vt(t),s=vt(s),this.isBuilt&&!this.isDisabled&&this.options.movable&&(i(t)&&(a.left=t,o=!0),i(s)&&(a.top=s,o=!0),o&&this.renderCanvas(!0))},zoom:function(t,i){var e=this.canvas;t=vt(t),t=0>t?1/(1-t):1+t,this.zoomTo(e.width*t/e.naturalWidth,i)},zoomTo:function(t,i){var e,s,a,o,h,n=this.options,r=this.canvas,p=r.width,c=r.height,l=r.naturalWidth,g=r.naturalHeight;if(t=vt(t),t>=0&&this.isBuilt&&!this.isDisabled&&n.zoomable){if(s=l*t,a=g*t,i&&(e=i.originalEvent),this.trigger(Z,{originalEvent:e,oldRatio:p/l,ratio:s/l}).isDefaultPrevented())return;e?(o=this.$cropper.offset(),h=e.touches?d(e.touches):{pageX:i.pageX||e.pageX||0,pageY:i.pageY||e.pageY||0},r.left-=(s-p)*((h.pageX-o.left-r.left)/p),r.top-=(a-c)*((h.pageY-o.top-r.top)/c)):(r.left-=(s-p)/2,r.top-=(a-c)/2),r.width=s,r.height=a,this.renderCanvas(!0)}},rotate:function(t){this.rotateTo((this.image.rotate||0)+vt(t))},rotateTo:function(t){t=vt(t),i(t)&&this.isBuilt&&!this.isDisabled&&this.options.rotatable&&(this.image.rotate=t%360,this.isRotated=!0,this.renderCanvas(!0))},scale:function(t,s){var a=this.image,o=!1;e(s)&&(s=t),t=vt(t),s=vt(s),this.isBuilt&&!this.isDisabled&&this.options.scalable&&(i(t)&&(a.scaleX=t,o=!0),i(s)&&(a.scaleY=s,o=!0),o&&this.renderImage(!0))},scaleX:function(t){var e=this.image.scaleY;this.scale(t,i(e)?e:1)},scaleY:function(t){var e=this.image.scaleX;this.scale(i(e)?e:1,t)},getData:function(i){var e,s,a=this.options,o=this.image,h=this.canvas,n=this.cropBox;return this.isBuilt&&this.isCropped?(s={x:n.left-h.left,y:n.top-h.top,width:n.width,height:n.height},e=o.width/o.naturalWidth,t.each(s,function(t,a){a/=e,s[t]=i?Dt(a):a})):s={x:0,y:0,width:0,height:0},a.rotatable&&(s.rotate=o.rotate||0),a.scalable&&(s.scaleX=o.scaleX||1,s.scaleY=o.scaleY||1),s},setData:function(e){var s,a,o,h=this.options,n=this.image,r=this.canvas,p={};t.isFunction(e)&&(e=e.call(this.element)),this.isBuilt&&!this.isDisabled&&t.isPlainObject(e)&&(h.rotatable&&i(e.rotate)&&e.rotate!==n.rotate&&(n.rotate=e.rotate,this.isRotated=s=!0),h.scalable&&(i(e.scaleX)&&e.scaleX!==n.scaleX&&(n.scaleX=e.scaleX,a=!0),i(e.scaleY)&&e.scaleY!==n.scaleY&&(n.scaleY=e.scaleY,a=!0)),s?this.renderCanvas():a&&this.renderImage(),o=n.width/n.naturalWidth,i(e.x)&&(p.left=e.x*o+r.left),i(e.y)&&(p.top=e.y*o+r.top),i(e.width)&&(p.width=e.width*o),i(e.height)&&(p.height=e.height*o),this.setCropBoxData(p))},getContainerData:function(){return this.isBuilt?this.container:{}},getImageData:function(){return this.isLoaded?this.image:{}},getCanvasData:function(){var i=this.canvas,e={};return this.isBuilt&&t.each(["left","top","width","height","naturalWidth","naturalHeight"],function(t,s){e[s]=i[s]}),e},setCanvasData:function(e){var s=this.canvas,a=s.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.isBuilt&&!this.isDisabled&&t.isPlainObject(e)&&(i(e.left)&&(s.left=e.left),i(e.top)&&(s.top=e.top),i(e.width)?(s.width=e.width,s.height=e.width/a):i(e.height)&&(s.height=e.height,s.width=e.height*a),this.renderCanvas(!0))},getCropBoxData:function(){var t,i=this.cropBox;return this.isBuilt&&this.isCropped&&(t={left:i.left,top:i.top,width:i.width,height:i.height}),t||{}},setCropBoxData:function(e){var s,a,o=this.cropBox,h=this.options.aspectRatio;t.isFunction(e)&&(e=e.call(this.$element)),this.isBuilt&&this.isCropped&&!this.isDisabled&&t.isPlainObject(e)&&(i(e.left)&&(o.left=e.left),i(e.top)&&(o.top=e.top),i(e.width)&&(s=!0,o.width=e.width),i(e.height)&&(a=!0,o.height=e.height),h&&(s?o.height=o.width/h:a&&(o.width=o.height*h)),this.renderCropBox())},getCroppedCanvas:function(i){var e,s,a,o,h,n,r,p,c,d,g;return this.isBuilt&&ft?this.isCropped?(t.isPlainObject(i)||(i={}),g=this.getData(),e=g.width,s=g.height,p=e/s,t.isPlainObject(i)&&(h=i.width,n=i.height,h?(n=h/p,r=h/e):n&&(h=n*p,r=n/s)),a=$t(h||e),o=$t(n||s),c=t("<canvas>")[0],c.width=a,c.height=o,d=c.getContext("2d"),i.fillColor&&(d.fillStyle=i.fillColor,d.fillRect(0,0,a,o)),d.drawImage.apply(d,function(){var t,i,a,o,h,n,p=l(this.$clone[0],this.image),c=p.width,d=p.height,u=this.canvas,f=[p],m=g.x+u.naturalWidth*(Ct(g.scaleX||1)-1)/2,v=g.y+u.naturalHeight*(Ct(g.scaleY||1)-1)/2;return-e>=m||m>c?m=t=a=h=0:0>=m?(a=-m,m=0,t=h=wt(c,e+m)):c>=m&&(a=0,t=h=wt(e,c-m)),0>=t||-s>=v||v>d?v=i=o=n=0:0>=v?(o=-v,v=0,i=n=wt(d,s+v)):d>=v&&(o=0,i=n=wt(s,d-v)),f.push($t(m),$t(v),$t(t),$t(i)),r&&(a*=r,o*=r,h*=r,n*=r),h>0&&n>0&&f.push($t(a),$t(o),$t(h),$t(n)),f}.call(this)),c):l(this.$clone[0],this.image):void 0},setAspectRatio:function(t){var i=this.options;this.isDisabled||e(t)||(i.aspectRatio=xt(0,t)||NaN,this.isBuilt&&(this.initCropBox(),this.isCropped&&this.renderCropBox()))},setDragMode:function(t){var i,e,s=this.options;this.isLoaded&&!this.isDisabled&&(i=t===lt,e=s.movable&&t===dt,t=i||e?t:ut,this.$dragBox.data(it,t).toggleClass(W,i).toggleClass(M,e),s.cropBoxMovable||this.$face.data(it,t).toggleClass(W,i).toggleClass(M,e))}},v.DEFAULTS={viewMode:0,dragMode:"crop",aspectRatio:NaN,data:null,preview:"",responsive:!0,restore:!0,checkCrossOrigin:!0,checkOrientation:!0,modal:!0,guides:!0,center:!0,highlight:!0,background:!0,autoCrop:!0,autoCropArea:.8,movable:!0,rotatable:!0,scalable:!0,zoomable:!0,zoomOnTouch:!0,zoomOnWheel:!0,wheelZoomRatio:.1,cropBoxMovable:!0,cropBoxResizable:!0,toggleDragModeOnDblclick:!0,minCanvasWidth:0,minCanvasHeight:0,minCropBoxWidth:0,minCropBoxHeight:0,minContainerWidth:200,minContainerHeight:100,build:null,built:null,cropstart:null,cropmove:null,cropend:null,crop:null,zoom:null},v.setDefaults=function(i){t.extend(v.DEFAULTS,i)},v.TEMPLATE='<div class="cropper-container"><div class="cropper-wrap-box"><div class="cropper-canvas"></div></div><div class="cropper-drag-box"></div><div class="cropper-crop-box"><span class="cropper-view-box"></span><span class="cropper-dashed dashed-h"></span><span class="cropper-dashed dashed-v"></span><span class="cropper-center"></span><span class="cropper-face"></span><span class="cropper-line line-e" data-action="e"></span><span class="cropper-line line-n" data-action="n"></span><span class="cropper-line line-w" data-action="w"></span><span class="cropper-line line-s" data-action="s"></span><span class="cropper-point point-e" data-action="e"></span><span class="cropper-point point-n" data-action="n"></span><span class="cropper-point point-w" data-action="w"></span><span class="cropper-point point-s" data-action="s"></span><span class="cropper-point point-ne" data-action="ne"></span><span class="cropper-point point-nw" data-action="nw"></span><span class="cropper-point point-sw" data-action="sw"></span><span class="cropper-point point-se" data-action="se"></span></div></div>',v.other=t.fn.cropper,t.fn.cropper=function(i){var a,o=s(arguments,1);return this.each(function(){var e,s,h=t(this),n=h.data(L);if(!n){if(/destroy/.test(i))return;e=t.extend({},h.data(),t.isPlainObject(i)&&i),h.data(L,n=new v(this,e))}"string"==typeof i&&t.isFunction(s=n[i])&&(a=s.apply(n,o))}),e(a)?this:a},t.fn.cropper.Constructor=v,t.fn.cropper.setDefaults=v.setDefaults,t.fn.cropper.noConflict=function(){return t.fn.cropper=v.other,this}});
0 11 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/js/script.imagemanager.input.js 0 → 100644
  1 +var imageManagerInput = {
  2 + baseUrl: null, //language
  3 + message: null, //init imageManagerInput
  4 + init: function() {
  5 + //create modal
  6 + imageManagerInput.initModal();
  7 + }, //creat image Manager modal
  8 + initModal: function() {
  9 + //check if modal not jet exists
  10 + if ($("#modal-imagemanager").length === 0) {
  11 + //set html modal in var
  12 + var sModalHtml = '<div tabindex="-1" role="dialog" class="fade modal" id="modal-imagemanager">';
  13 + sModalHtml += '<div class="modal-dialog modal-lg">';
  14 + sModalHtml += '<div class="modal-content">';
  15 + sModalHtml += '<div class="modal-header">';
  16 + sModalHtml += '<button aria-hidden="true" data-dismiss="modal" class="close" type="button">&times;</button>';
  17 + sModalHtml += '<h4>Image manager</h4>';
  18 + sModalHtml += '</div>';
  19 + sModalHtml += '<div class="modal-body">';
  20 + sModalHtml += '<iframe src="#"></iframe>';
  21 + sModalHtml += '</div>';
  22 + sModalHtml += '</div>';
  23 + sModalHtml += '</div>';
  24 + sModalHtml += '</div>';
  25 + //prepend data to body
  26 + $('body')
  27 + .prepend(sModalHtml);
  28 + }
  29 + }, //open media manager modal
  30 + openModal: function(inputId, aspectRatio, cropViewMode) {
  31 + //get selected item
  32 + var iImageId = $("#" + inputId)
  33 + .val();
  34 + var srcImageIdQueryString = "";
  35 + if (iImageId !== "") {
  36 + srcImageIdQueryString = "&image-id=" + iImageId;
  37 + }
  38 + //create iframe url
  39 + var queryStringStartCharacter = ((imageManagerInput.baseUrl).indexOf('?') == -1) ? '?' : '&';
  40 + var imageManagerUrl = imageManagerInput.baseUrl + queryStringStartCharacter + "view-mode=iframe&input-id=" + inputId + "&aspect-ratio=" + aspectRatio + "&crop-view-mode=" + cropViewMode + srcImageIdQueryString;
  41 + //set iframe path
  42 + $("#modal-imagemanager iframe")
  43 + .attr("src", imageManagerUrl);
  44 + //set translation title for modal header
  45 + $("#modal-imagemanager .modal-dialog .modal-header h4")
  46 + .text(imageManagerInput.message.imageManager);
  47 + //open modal
  48 + $("#modal-imagemanager")
  49 + .modal("show");
  50 + }, //close media manager modal
  51 + closeModal: function() {
  52 + $("#modal-imagemanager")
  53 + .modal("hide");
  54 + }, //delete picked image
  55 + deletePickedImage: function(inputId) {
  56 + //remove value of the input field
  57 + var sFieldId = inputId;
  58 + var sFieldNameId = sFieldId + "_name";
  59 + var sImagePreviewId = sFieldId + "_image";
  60 + var bShowConfirm = JSON.parse(
  61 + $(".delete-selected-image[data-input-id='" + inputId + "']")
  62 + .data("show-delete-confirm")
  63 + );
  64 + //show warning if bShowConfirm == true
  65 + if (bShowConfirm) {
  66 + if (confirm(imageManagerInput.message.detachWarningMessage) == false) {
  67 + return false;
  68 + }
  69 + }
  70 + //set input data
  71 + $('#' + sFieldId)
  72 + .val("");
  73 + $('#' + sFieldNameId)
  74 + .val("");
  75 + //trigger change
  76 + $('#' + sFieldId)
  77 + .trigger("change");
  78 + //hide image
  79 + $('#' + sImagePreviewId)
  80 + .attr("src", "")
  81 + .parent()
  82 + .addClass("hide");
  83 + //delete hide class
  84 + $(".delete-selected-image[data-input-id='" + inputId + "']")
  85 + .addClass("hide");
  86 + }
  87 +};
  88 +
  89 +$(document)
  90 + .ready(
  91 + function() {
  92 + //init Image manage
  93 + imageManagerInput.init();
  94 +
  95 + //open media manager modal
  96 + $(document)
  97 + .on(
  98 + "click", ".open-modal-imagemanager", function() {
  99 + var aspectRatio = $(this)
  100 + .data("aspect-ratio");
  101 + var cropViewMode = $(this)
  102 + .data("crop-view-mode");
  103 + var inputId = $(this)
  104 + .data("input-id");
  105 + //open selector id
  106 + imageManagerInput.openModal(inputId, aspectRatio, cropViewMode);
  107 + }
  108 + );
  109 +
  110 + //delete picked image
  111 + $(document)
  112 + .on(
  113 + "click", ".delete-selected-image", function() {
  114 + var inputId = $(this)
  115 + .data("input-id");
  116 + //open selector id
  117 + imageManagerInput.deletePickedImage(inputId);
  118 + }
  119 + );
  120 + }
  121 + );
0 122 \ No newline at end of file
... ...
backend/components/imagemanager/assets/source/js/script.imagemanager.module.js 0 → 100644
  1 +var imageManagerModule = {
  2 + //params for input selector
  3 + fieldId: null,
  4 + cropRatio: null,
  5 + cropViewMode: 1,
  6 + defaultImageId: null,
  7 + selectType: null, //current selected image
  8 + selectedImage: null, //language
  9 + message: null, //init imageManager
  10 + init: function() {
  11 + //init cropper
  12 + $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper')
  13 + .cropper(
  14 + {
  15 + viewMode: imageManagerModule.cropViewMode
  16 + }
  17 + );
  18 +
  19 + //preselect image if image-id isset
  20 + if (imageManagerModule.defaultImageId !== "") {
  21 + imageManagerModule.selectImage(imageManagerModule.defaultImageId);
  22 + }
  23 +
  24 + //set selected after pjax complete
  25 + $('#pjax-mediamanager')
  26 + .on(
  27 + 'pjax:complete', function() {
  28 + if (imageManagerModule.selectedImage !== null) {
  29 + imageManagerModule.selectImage(imageManagerModule.selectedImage.id);
  30 + }
  31 + }
  32 + );
  33 +
  34 + $(document)
  35 + .on(
  36 + 'click', '#save-image-info', function() {
  37 + var form = $('#save-image-info-form');
  38 + $.ajax(
  39 + {
  40 + url: imageManagerModule.baseUrl + "/save-image-info",
  41 + type: "POST",
  42 + data: form.serialize(),
  43 + success: function(data) {
  44 + new PNotify(
  45 + {
  46 + title: "Notification",
  47 + text: "Image info saved",
  48 + type: "info",
  49 + styling: "bootstrap3",
  50 + icon: "glyphicon glyphicon-exclamation-sign"
  51 + }
  52 + );
  53 + }
  54 + }
  55 + );
  56 + }
  57 + );
  58 + }, //filter result
  59 + filterImageResult: function(searchTerm) {
  60 + //set new url
  61 + var newUrl = window.queryStringParameter.set(window.location.href, "ImageManagerSearch[globalSearch]", searchTerm);
  62 + //set pjax
  63 + $.pjax(
  64 + {
  65 + url: newUrl,
  66 + container: "#pjax-mediamanager",
  67 + push: false,
  68 + replace: false,
  69 + timeout: 5000,
  70 + scrollTo: false
  71 + }
  72 + );
  73 + }, //select an image
  74 + selectImage: function(id) {
  75 + //set selected class
  76 + $("#module-imagemanager .item-overview .item")
  77 + .removeClass("selected");
  78 + $("#module-imagemanager .item-overview .item[data-key='" + id + "']")
  79 + .addClass("selected");
  80 + //get details
  81 + imageManagerModule.getDetails(id);
  82 + }, //pick the selected image
  83 + pickImage: function() {
  84 + //switch between select type
  85 + switch (imageManagerModule.selectType) {
  86 + //default widget selector
  87 + case "input":
  88 + //get id data
  89 + var sFieldId = imageManagerModule.fieldId;
  90 + var sFieldNameId = sFieldId + "_name";
  91 + var sFieldImageId = sFieldId + "_image";
  92 + //set input data
  93 + $('#' + sFieldId, window.parent.document)
  94 + .val(imageManagerModule.selectedImage.id);
  95 + $('#' + sFieldNameId, window.parent.document)
  96 + .val(imageManagerModule.selectedImage.fileName);
  97 + $('#' + sFieldImageId, window.parent.document)
  98 + .attr("src", imageManagerModule.selectedImage.image)
  99 + .parent()
  100 + .removeClass("hide");
  101 + //trigger change
  102 + parent.$('#' + sFieldId)
  103 + .trigger('change');
  104 + //show delete button
  105 + $(".delete-selected-image[data-input-id='" + sFieldId + "']", window.parent.document)
  106 + .removeClass("hide");
  107 + //close the modal
  108 + window.parent.imageManagerInput.closeModal();
  109 + break;
  110 + //CKEditor selector
  111 + case "ckeditor":
  112 + //TinyMCE Selector
  113 + case "tinymce":
  114 + //check if isset image
  115 + if (imageManagerModule.selectedImage !== null) {
  116 + //call action by ajax
  117 + $.ajax(
  118 + {
  119 + url: imageManagerModule.baseUrl + "/get-original-image",
  120 + type: "POST",
  121 + data: {
  122 + ImageManager_id: imageManagerModule.selectedImage.id,
  123 + _csrf: $('meta[name=csrf-token]')
  124 + .prop('content')
  125 + },
  126 + dataType: "json",
  127 + success: function(responseData, textStatus, jqXHR) {
  128 + //set attributes for each selector
  129 + if (imageManagerModule.selectType == "ckeditor") {
  130 + var sField = window.queryStringParameter.get(window.location.href, "CKEditorFuncNum");
  131 + window.top.opener.CKEDITOR.tools.callFunction(sField, responseData);
  132 + window.self.close();
  133 + } else if (imageManagerModule.selectType == "tinymce") {
  134 + var sField = window.queryStringParameter.get(window.location.href, "tag_name");
  135 + window.opener.document.getElementById(sField).value = responseData;
  136 + window.close();
  137 + window.opener.focus();
  138 + }
  139 + },
  140 + error: function(jqXHR, textStatus, errorThrown) {
  141 + alert("Error: can't get item");
  142 + }
  143 + }
  144 + );
  145 + } else {
  146 + alert("Error: image can't picked");
  147 + }
  148 + break;
  149 + }
  150 +
  151 + }, //delete the selected image
  152 + deleteSelectedImage: function() {
  153 + //confirm message
  154 + if (confirm(imageManagerModule.message.deleteMessage)) {
  155 + //close editor
  156 + imageManagerModule.editor.close();
  157 + //check if isset image
  158 + if (imageManagerModule.selectedImage !== null) {
  159 + //call action by ajax
  160 + $.ajax(
  161 + {
  162 + url: imageManagerModule.baseUrl + "/delete",
  163 + type: "POST",
  164 + data: {
  165 + ImageManager_id: imageManagerModule.selectedImage.id,
  166 + _csrf: $('meta[name=csrf-token]')
  167 + .prop('content')
  168 + },
  169 + dataType: "json",
  170 + success: function(responseData, textStatus, jqXHR) {
  171 + //check if delete is true
  172 + if (responseData.delete === true) {
  173 + //delete item element
  174 + $("#module-imagemanager .item-overview .item[data-key='" + imageManagerModule.selectedImage.id + "']")
  175 + .remove();
  176 + //add hide class to info block
  177 + $("#module-imagemanager .image-info")
  178 + .addClass("hide");
  179 + //set selectedImage to null
  180 + imageManagerModule.selectedImage = null;
  181 + //close edit
  182 + } else {
  183 + alert("Error: item is not deleted");
  184 + }
  185 + },
  186 + error: function(jqXHR, textStatus, errorThrown) {
  187 + alert("Error: can't delete item");
  188 + }
  189 + }
  190 + );
  191 + } else {
  192 + alert("Error: image can't delete, no image isset set");
  193 + }
  194 + }
  195 + }, //get image details
  196 + getDetails: function(id, pickAfterGetDetails) {
  197 + //set propertie if not set
  198 + pickAfterGetDetails = pickAfterGetDetails !== undefined ? pickAfterGetDetails : false;
  199 + //call action by ajax
  200 + $.ajax(
  201 + {
  202 + url: imageManagerModule.baseUrl + "/view",
  203 + type: "POST",
  204 + data: {
  205 + ImageManager_id: id,
  206 + _csrf: $('meta[name=csrf-token]')
  207 + .prop('content')
  208 + },
  209 + dataType: "json",
  210 + success: function(responseData, textStatus, jqXHR) {
  211 + //set imageManagerModule.selectedImage property
  212 + imageManagerModule.selectedImage = responseData;
  213 +
  214 + //if need to pick image?
  215 + if (pickAfterGetDetails) {
  216 + imageManagerModule.pickImage();
  217 + //else set data
  218 + } else {
  219 + //set text elements
  220 + $("#module-imagemanager .image-info .fileName")
  221 + .text(responseData.fileName)
  222 + .attr("title", responseData.fileName);
  223 + $("#module-imagemanager .image-info .created")
  224 + .text(responseData.created);
  225 + $("#module-imagemanager .image-info .fileSize")
  226 + .text(responseData.fileSize);
  227 + $("#module-imagemanager .image-info .dimensions .dimension-width")
  228 + .text(responseData.dimensionWidth);
  229 + $("#module-imagemanager .image-info .dimensions .dimension-height")
  230 + .text(responseData.dimensionHeight);
  231 + $("#module-imagemanager .image-info .thumbnail")
  232 + .html("<img src='" + responseData.image + "' alt='" + responseData.fileName + "'/>");
  233 + $("#module-imagemanager .image-info .seo-info")
  234 + .html(responseData.div);
  235 + //remove hide class
  236 + $("#module-imagemanager .image-info")
  237 + .removeClass("hide");
  238 + }
  239 + },
  240 + error: function(jqXHR, textStatus, errorThrown) {
  241 + alert("Error: can't get ''data''");
  242 + }
  243 + }
  244 + );
  245 + }, //upload file
  246 + uploadSuccess: function(uploadResponse) {
  247 + //close editor
  248 + imageManagerModule.editor.close();
  249 + //reload pjax container
  250 + $.pjax.reload(
  251 + '#pjax-mediamanager', {
  252 + push: false,
  253 + replace: false,
  254 + timeout: 5000,
  255 + scrollTo: false
  256 + }
  257 + );
  258 + }, //editor functions
  259 + editor: {
  260 + //open editor block
  261 + open: function() {
  262 + //show editer / hide overview
  263 + $("#module-imagemanager > .row .col-image-editor")
  264 + .show();
  265 + $("#module-imagemanager > .row .col-overview")
  266 + .hide();
  267 + }, //close editor block
  268 + close: function() {
  269 + //show overview / hide editer
  270 + $("#module-imagemanager > .row .col-overview")
  271 + .show();
  272 + $("#module-imagemanager > .row .col-image-editor")
  273 + .hide();
  274 + }, //open cropper
  275 + openCropper: function() {
  276 + //check if isset image
  277 + if (imageManagerModule.selectedImage !== null) {
  278 + //call action by ajax
  279 + $.ajax(
  280 + {
  281 + url: imageManagerModule.baseUrl + "/get-original-image",
  282 + type: "POST",
  283 + data: {
  284 + ImageManager_id: imageManagerModule.selectedImage.id,
  285 + _csrf: $('meta[name=csrf-token]')
  286 + .prop('content')
  287 + },
  288 + dataType: "json",
  289 + success: function(responseData, textStatus, jqXHR) {
  290 + //hide cropper
  291 + $("#module-imagemanager > .row .col-image-cropper")
  292 + .css("visibility", "hidden");
  293 + //set image in cropper
  294 + $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper')
  295 + .one(
  296 + 'built.cropper', function() {
  297 + //show cropper
  298 + $("#module-imagemanager > .row .col-image-cropper")
  299 + .css("visibility", "visible");
  300 + }
  301 + )
  302 + .cropper('reset')
  303 + .cropper('setAspectRatio', parseFloat(imageManagerModule.cropRatio))
  304 + .cropper('replace', responseData);
  305 + //open editor
  306 + imageManagerModule.editor.open();
  307 + },
  308 + error: function(jqXHR, textStatus, errorThrown) {
  309 + alert("Error: can't get item");
  310 + }
  311 + }
  312 + );
  313 + } else {
  314 + alert("Error: image can't crop, no image isset set");
  315 + }
  316 + }, //apply crop
  317 + applyCrop: function(pickAfterCrop) {
  318 + //set propertie if not set
  319 + pickAfterCrop = pickAfterCrop !== undefined ? pickAfterCrop : false;
  320 + //check if isset image
  321 + if (imageManagerModule.selectedImage !== null) {
  322 + //set image in cropper
  323 + var oCropData = $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper')
  324 + .cropper("getData");
  325 + //call action by ajax
  326 + $.ajax(
  327 + {
  328 + url: imageManagerModule.baseUrl + "/crop",
  329 + type: "POST",
  330 + data: {
  331 + ImageManager_id: imageManagerModule.selectedImage.id,
  332 + CropData: oCropData,
  333 + _csrf: $('meta[name=csrf-token]')
  334 + .prop('content')
  335 + },
  336 + dataType: "json",
  337 + success: function(responseData, textStatus, jqXHR) {
  338 + //set cropped image
  339 + if (responseData !== null) {
  340 + //if pickAfterCrop is true? select directly else
  341 + if (pickAfterCrop) {
  342 + imageManagerModule.getDetails(responseData, true);
  343 + //else select the image only
  344 + } else {
  345 + //set new image
  346 + imageManagerModule.selectImage(responseData);
  347 + //reload pjax container
  348 + $.pjax.reload(
  349 + '#pjax-mediamanager', {
  350 + push: false,
  351 + replace: false,
  352 + timeout: 5000,
  353 + scrollTo: false
  354 + }
  355 + );
  356 + }
  357 + }
  358 + //close editor
  359 + imageManagerModule.editor.close();
  360 + },
  361 + error: function(jqXHR, textStatus, errorThrown) {
  362 + alert("Error: item is not cropped");
  363 + }
  364 + }
  365 + );
  366 + } else {
  367 + alert("Error: image can't crop, no image isset set");
  368 + }
  369 + }
  370 + }
  371 +};
  372 +
  373 +$(document)
  374 + .ready(
  375 + function() {
  376 + //init Image manage
  377 + imageManagerModule.init();
  378 + //on click select item (open view)
  379 + $(document)
  380 + .on(
  381 + "click", "#module-imagemanager .item-overview .item", function() {
  382 + //get id
  383 + var ImageManager_id = $(this)
  384 + .data("key");
  385 + //select image
  386 + imageManagerModule.selectImage(ImageManager_id);
  387 + }
  388 + );
  389 + //on click pick image
  390 + $(document)
  391 + .on(
  392 + "click", "#module-imagemanager .image-info .pick-image-item", function() {
  393 + imageManagerModule.pickImage();
  394 + return false;
  395 + }
  396 + );
  397 + //on click delete call "delete"
  398 + $(document)
  399 + .on(
  400 + "click", "#module-imagemanager .image-info .delete-image-item", function() {
  401 + imageManagerModule.deleteSelectedImage();
  402 + return false;
  403 + }
  404 + );
  405 + //on click crop call "crop"
  406 + $(document)
  407 + .on(
  408 + "click", "#module-imagemanager .image-info .crop-image-item", function() {
  409 + imageManagerModule.editor.openCropper();
  410 + return false;
  411 + }
  412 + );
  413 + //on click apply crop
  414 + $(document)
  415 + .on(
  416 + "click", "#module-imagemanager .image-cropper .apply-crop", function() {
  417 + imageManagerModule.editor.applyCrop();
  418 + return false;
  419 + }
  420 + );
  421 + //on click apply crop
  422 + $(document)
  423 + .on(
  424 + "click", "#module-imagemanager .image-cropper .apply-crop-select", function() {
  425 + imageManagerModule.editor.applyCrop(true);
  426 + return false;
  427 + }
  428 + );
  429 + //on click cancel crop
  430 + $(document)
  431 + .on(
  432 + "click", "#module-imagemanager .image-cropper .cancel-crop", function() {
  433 + imageManagerModule.editor.close();
  434 + return false;
  435 + }
  436 + );
  437 + //on keyup change set filter
  438 + $(document)
  439 + .on(
  440 + "keyup change", "#input-mediamanager-search", function() {
  441 + imageManagerModule.filterImageResult(
  442 + $(this)
  443 + .val()
  444 + );
  445 + }
  446 + );
  447 +
  448 + }
  449 + );
  450 +
  451 +/*
  452 + * return new get param to url
  453 + */
  454 +window.queryStringParameter = {
  455 + get: function(uri, key) {
  456 + var reParam = new RegExp('(?:[\?&]|&amp;)' + key + '=([^&]+)', 'i');
  457 + var match = uri.match(reParam);
  458 + return (match && match.length > 1) ? match[ 1 ] : null;
  459 + },
  460 + set: function(uri, key, value) {
  461 + //replace brackets
  462 + var keyReplace = key.replace("[]", "")
  463 + .replace(/\[/g, "%5B")
  464 + .replace(/\]/g, "%5D");
  465 + //replace data
  466 + var re = new RegExp("([?&])" + keyReplace + "=.*?(&|$)", "i");
  467 + var separator = uri.indexOf('?') !== -1 ? "&" : "?";
  468 + if (uri.match(re)) {
  469 + return uri.replace(re, '$1' + keyReplace + "=" + value + '$2');
  470 + } else {
  471 + return uri + separator + keyReplace + "=" + value;
  472 + }
  473 + }
  474 +};
0 475 \ No newline at end of file
... ...
backend/components/imagemanager/components/ImageManagerGetPath.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\components;
  4 +
  5 +use Yii;
  6 +use yii\base\Component;
  7 +use backend\components\imagemanager\models\ImageManager;
  8 +use yii\base\InvalidConfigException;
  9 +use yii\db\Connection;
  10 +
  11 +class ImageManagerGetPath extends Component {
  12 +
  13 + /**
  14 + * @var null|string $mediaPath Folder path in which the images are stored
  15 + */
  16 + public $mediaPath = null;
  17 +
  18 + /**
  19 + * @var string $cachePath cache path where store the resized images (relative from webroot (index.php))
  20 + */
  21 + public $cachePath = "assets/imagemanager";
  22 +
  23 + /**
  24 + * @var boolean $useFilename use original filename in generated cache file
  25 + */
  26 + public $useFilename = true;
  27 +
  28 + /**
  29 + * @var boolean $useFilename use original filename in generated cache file
  30 + */
  31 + public $absoluteUrl = false;
  32 +
  33 + /**
  34 + * @var string The DB component name that the image model uses
  35 + * This defaults to the default Yii DB component: Yii::$app->db
  36 + * If this component is not set, the model will default to DB
  37 + */
  38 + public $databaseComponent = 'db';
  39 +
  40 + /**
  41 + * Init set config
  42 + */
  43 + public function init() {
  44 + parent::init();
  45 + // initialize the compontent with the configuration loaded from config.php
  46 + \Yii::$app->set('imageresize', [
  47 + 'class' => 'noam148\imageresize\ImageResize',
  48 + 'cachePath' => $this->cachePath,
  49 + 'useFilename' => $this->useFilename,
  50 + 'absoluteUrl' => $this->absoluteUrl,
  51 + ]);
  52 +
  53 + if (is_callable($this->databaseComponent)) {
  54 + // The database component is callable, run the user function
  55 + $this->databaseComponent = call_user_func($this->databaseComponent);
  56 + }
  57 +
  58 + // Check if the user input is correct
  59 + $this->_checkVariables();
  60 + }
  61 +
  62 + /**
  63 + * Get the path for the given ImageManager_id record
  64 + * @param int $ImageManager_id ImageManager record for which the path needs to be generated
  65 + * @param int $width Thumbnail image width
  66 + * @param int $height Thumbnail image height
  67 + * @param string $thumbnailMode Thumbnail mode
  68 + * @return null|string Full path is returned when image is found, null if no image could be found
  69 + */
  70 + public function getImagePath($ImageManager_id, $width = 400, $height = 400, $thumbnailMode = "outbound") {
  71 + //default return
  72 + $return = null;
  73 + $mImageManager = ImageManager::findOne($ImageManager_id);
  74 +
  75 + //check if not empty
  76 + if ($mImageManager !== null) {
  77 + //set crop mode
  78 + $mode = $thumbnailMode == "outbound" ? "outbound" : "inset";
  79 +
  80 + $sMediaPath = null;
  81 + if ($this->mediaPath !== null) {
  82 + $sMediaPath = $this->mediaPath;
  83 + }
  84 +
  85 + $sFileExtension = pathinfo($mImageManager->fileName, PATHINFO_EXTENSION);
  86 + //get image file path
  87 + $sImageFilePath = $sMediaPath . '/' . $mImageManager->id . '_' . $mImageManager->fileHash . '.' . $sFileExtension;
  88 + //check file exists
  89 + if (file_exists($sImageFilePath)) {
  90 + $return = \Yii::$app->imageresize->getUrl($sImageFilePath, $width, $height, $mode, null, $mImageManager->fileName);
  91 + } else {
  92 + $return = null; //isset(\Yii::$app->controller->module->assetPublishedUrl) ? \Yii::$app->controller->module->assetPublishedUrl. "/img/img_no-image.png" : null;
  93 + }
  94 + }
  95 + return $return;
  96 + }
  97 +
  98 + /**
  99 + * Check if the user configurable variables match the criteria
  100 + * @throws InvalidConfigException
  101 + */
  102 + private function _checkVariables() {
  103 + // Check to make sure that the $databaseComponent is a string
  104 + if (! is_string($this->databaseComponent)) {
  105 + throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' is not a string");
  106 + }
  107 +
  108 + // Check to make sure that the $databaseComponent object exists
  109 + if (Yii::$app->get($this->databaseComponent, false) === null) {
  110 + throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' does not exists in application configuration");
  111 + }
  112 +
  113 + // Check to make sure that the $databaseComponent is a yii\db\Connection object
  114 + if (($databaseComponentClassName = get_class(Yii::$app->get($this->databaseComponent))) !== ($connectionClassName = Connection::className())) {
  115 + throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' is not of type '$connectionClassName' instead it is '$databaseComponentClassName'");
  116 + }
  117 + }
  118 +
  119 +}
... ...
backend/components/imagemanager/components/ImageManagerInputWidget.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\components;
  4 +
  5 +use Yii;
  6 +use yii\widgets\InputWidget;
  7 +use yii\helpers\Html;
  8 +use yii\helpers\Json;
  9 +use yii\helpers\Url;
  10 +use backend\components\imagemanager\models\ImageManager;
  11 +use backend\components\imagemanager\assets\ImageManagerInputAsset;
  12 +
  13 +class ImageManagerInputWidget extends InputWidget {
  14 +
  15 + /**
  16 + * @var null|integer The aspect ratio the image needs to be cropped in (optional)
  17 + */
  18 + public $aspectRatio = null; //option info: https://github.com/fengyuanchen/cropper/#aspectratio
  19 +
  20 + /**
  21 + * @var int Define the viewMode of the cropper
  22 + */
  23 + public $cropViewMode = 1; //option info: https://github.com/fengyuanchen/cropper/#viewmode
  24 +
  25 + /**
  26 + * @var bool Show a preview of the image under the input
  27 + */
  28 + public $showPreview = true;
  29 +
  30 + /**
  31 + * @var bool Show a confirmation message when de-linking a image from the input
  32 + */
  33 + public $showDeletePickedImageConfirm = false;
  34 +
  35 + /**
  36 + * @inheritdoc
  37 + */
  38 + public function init() {
  39 + parent::init();
  40 + //set language
  41 + if (!isset(Yii::$app->i18n->translations['imagemanager'])) {
  42 + Yii::$app->i18n->translations['imagemanager'] = [
  43 + 'class' => 'yii\i18n\PhpMessageSource',
  44 + 'sourceLanguage' => 'en',
  45 + 'basePath' => '@noam148/imagemanager/messages'
  46 + ];
  47 + }
  48 + }
  49 +
  50 + /**
  51 + * @inheritdoc
  52 + */
  53 + public function run() {
  54 + //default
  55 + $ImageManager_id = null;
  56 + $mImageManager = null;
  57 + $sFieldId = null;
  58 + //start input group
  59 + $field = "<div class='image-manager-input'>";
  60 + $field .= "<div class='input-group'>";
  61 + //set input fields
  62 + if ($this->hasModel()) {
  63 + //get field id
  64 + $sFieldId = Html::getInputId($this->model, $this->attribute);
  65 + $sFieldNameId = $sFieldId . "_name";
  66 + //get attribute name
  67 + $sFieldAttributeName = Html::getAttributeName($this->attribute);
  68 + //get filename from selected file
  69 + $ImageManager_id = $this->model->{$sFieldAttributeName};
  70 + $ImageManager_fileName = null;
  71 + $mImageManager = ImageManager::findOne($ImageManager_id);
  72 + if ($mImageManager !== null) {
  73 + $ImageManager_fileName = $mImageManager->fileName;
  74 + }
  75 + //create field
  76 + $field .= Html::textInput($this->attribute, $ImageManager_fileName, ['class' => 'form-control', 'id' => $sFieldNameId, 'readonly' => true]);
  77 + $field .= Html::activeHiddenInput($this->model, $this->attribute, $this->options);
  78 + } else {
  79 + $field .= Html::textInput($this->name . "_name", null, ['readonly' => true]);
  80 + $field .= Html::hiddenInput($this->name, $this->value, $this->options);
  81 + }
  82 + //end input group
  83 + $sHideClass = $ImageManager_id === null ? 'hide' : '';
  84 + $field .= "<a href='#' class='input-group-addon btn btn-primary delete-selected-image " . $sHideClass . "' data-input-id='" . $sFieldId . "' data-show-delete-confirm='" . ($this->showDeletePickedImageConfirm ? "true" : "false") . "'><i class='glyphicon glyphicon-remove' aria-hidden='true'></i></a>";
  85 + $field .= "<a href='#' class='input-group-addon btn btn-primary open-modal-imagemanager' data-aspect-ratio='" . $this->aspectRatio . "' data-crop-view-mode='" . $this->cropViewMode . "' data-input-id='" . $sFieldId . "'>";
  86 + $field .= "<i class='glyphicon glyphicon-folder-open' aria-hidden='true'></i>";
  87 + $field .= "</a></div>";
  88 +
  89 + //show preview if is true
  90 + if ($this->showPreview == true) {
  91 + $sHideClass = ($mImageManager == null) ? "hide" : "";
  92 + $sImageSource = isset($mImageManager->id) ? \Yii::$app->imagemanager->getImagePath($mImageManager->id, 500, 500, 'inset') : "";
  93 +
  94 + $field .= '<div class="image-wrapper ' . $sHideClass . '">'
  95 + . '<img id="' . $sFieldId . '_image" alt="Thumbnail" class="img-responsive img-preview" src="' . $sImageSource . '">'
  96 + . '</div>';
  97 + }
  98 +
  99 + //close image-manager-input div
  100 + $field .= "</div>";
  101 +
  102 + echo $field;
  103 +
  104 + $this->registerClientScript();
  105 + }
  106 +
  107 + /**
  108 + * Registers js Input
  109 + */
  110 + public function registerClientScript() {
  111 + $view = $this->getView();
  112 + ImageManagerInputAsset::register($view);
  113 +
  114 + //set baseUrl from image manager
  115 + $sBaseUrl = Url::to(['/imagemanager/manager']);
  116 + //set base url
  117 + $view->registerJs("imageManagerInput.baseUrl = '" . $sBaseUrl . "';");
  118 + $view->registerJs("imageManagerInput.message = " . Json::encode([
  119 + 'imageManager' => Yii::t('imagemanager','Image manager'),
  120 + 'detachWarningMessage' => Yii::t('imagemanager', 'Are you sure you want to detach the image?'),
  121 + ]) . ";");
  122 + }
  123 +
  124 +}
... ...
backend/components/imagemanager/composer.json 0 → 100644
  1 +{
  2 + "name": "noam148/yii2-image-manager",
  3 + "description": "A Yii2 module/widget for upload and cropping images",
  4 + "keywords": ["yii2", "extension", "widget", "module", "image", "upload", "crop", "manager"],
  5 + "homepage": "https://github.com/noam148/yii2-image-manager",
  6 + "type": "yii2-extension",
  7 + "license": "BSD-3-Clause",
  8 + "authors": [
  9 + {
  10 + "name": "Noam148",
  11 + "homepage": "https://github.com/noam148/"
  12 + }
  13 + ],
  14 + "require": {
  15 + "yiisoft/yii2": "*",
  16 + "noam148/yii2-image-resize" : "*",
  17 + "kartik-v/yii2-widget-fileinput": "@dev"
  18 + },
  19 + "autoload": {
  20 + "psr-4": {
  21 + "noam148\\imagemanager\\": ""
  22 + }
  23 + }
  24 +}
0 25 \ No newline at end of file
... ...
backend/components/imagemanager/controllers/DefaultController.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\controllers;
  4 +
  5 +use yii\web\Controller;
  6 +
  7 +/**
  8 + * Default controller for the `imagemanager` module
  9 + */
  10 +class DefaultController extends Controller
  11 +{
  12 + /**
  13 + * Renders the index view for the module
  14 + * @return string
  15 + */
  16 + public function actionIndex()
  17 + {
  18 + return $this->render('index');
  19 + }
  20 +}
... ...
backend/components/imagemanager/controllers/ManagerController.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\controllers;
  4 +
  5 +use Yii;
  6 +use backend\components\imagemanager\models\ImageManager;
  7 +use backend\components\imagemanager\models\ImageManagerSearch;
  8 +use backend\components\imagemanager\assets\ImageManagerModuleAsset;
  9 +use backend\components\imagemanager\models\ImageManagerLang;
  10 +use yii\web\Response;
  11 +use yii\web\Controller;
  12 +use yii\web\NotFoundHttpException;
  13 +use yii\base\ErrorException;
  14 +use yii\filters\VerbFilter;
  15 +use yii\helpers\Url;
  16 +use yii\helpers\Json;
  17 +use yii\helpers\BaseFileHelper;
  18 +use yii\imagine\Image;
  19 +use Imagine\Image\Box;
  20 +use Imagine\Image\Palette\RGB;
  21 +use Imagine\Image\Point;
  22 +use backend\components\imagemanager\Module;
  23 +use common\models\Language;
  24 +
  25 +/**
  26 + * Manager controller for the `imagemanager` module
  27 + * @property $module Module
  28 + */
  29 +class ManagerController extends Controller {
  30 +
  31 + /**
  32 + * @inheritdoc
  33 + */
  34 + public function behaviors() {
  35 + return [
  36 + 'verbs' => [
  37 + 'class' => VerbFilter::className(),
  38 + 'actions' => [
  39 + 'delete' => ['POST'],
  40 + ],
  41 + ],
  42 + ];
  43 + }
  44 +
  45 + /**
  46 + * @inheritdoc
  47 + */
  48 + public function beforeAction($action) {
  49 + //disable CSRF Validation
  50 + $this->enableCsrfValidation = false;
  51 + return parent::beforeAction($action);
  52 + }
  53 +
  54 + /**
  55 + * Lists all ImageManager models.
  56 + * @return mixed
  57 + */
  58 + public function actionIndex() {
  59 + //set asset
  60 + ImageManagerModuleAsset::register($this->view);
  61 +
  62 + //get iframe parameters
  63 + $viewMode = Yii::$app->request->get("view-mode", "page");
  64 + $selectType = Yii::$app->request->get("select-type", "input");
  65 + $inputFieldId = Yii::$app->request->get("input-id");
  66 + $cropAspectRatio = Yii::$app->request->get("aspect-ratio");
  67 + $cropViewMode = Yii::$app->request->get("crop-view-mode", 1);
  68 + $defaultImageId = Yii::$app->request->get("image-id");
  69 +
  70 + //set blank layout if viewMode = iframe
  71 + if ($viewMode == "iframe") {
  72 + //set layout
  73 + $this->layout = "blank";
  74 +
  75 + //set stylesheet for modal
  76 + $aCssFiles = \Yii::$app->controller->module->cssFiles;
  77 + if (is_array($aCssFiles) && count($aCssFiles) > 0) {
  78 + //if exists loop through files and add them to iframe mode
  79 + foreach ($aCssFiles AS $cssFile) {
  80 + //registrate file
  81 + $this->view->registerCssFile($cssFile, ['depends' => 'yii\bootstrap\BootstrapAsset']);
  82 + }
  83 + }
  84 + }
  85 +
  86 + //set baseUrl from image manager
  87 + $sBaseUrl = Url::to(['/imagemanager/manager']);
  88 + //set base url
  89 + $this->view->registerJs("imageManagerModule.baseUrl = '" . $sBaseUrl . "';", 3);
  90 + $this->view->registerJs("imageManagerModule.defaultImageId = '" . $defaultImageId . "';", 3);
  91 + $this->view->registerJs("imageManagerModule.fieldId = '" . $inputFieldId . "';", 3);
  92 + $this->view->registerJs("imageManagerModule.cropRatio = '" . $cropAspectRatio . "';", 3);
  93 + $this->view->registerJs("imageManagerModule.cropViewMode = '" . $cropViewMode . "';", 3);
  94 + $this->view->registerJs("imageManagerModule.selectType = '" . $selectType . "';", 3);
  95 + $this->view->registerJs("imageManagerModule.message = " . Json::encode([
  96 + 'deleteMessage' => Yii::t('imagemanager', 'Are you sure you want to delete this image?'),
  97 + ]) . ";", 3);
  98 +
  99 + $searchModel = new ImageManagerSearch();
  100 + $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
  101 +
  102 + //render template
  103 + return $this->render(
  104 + 'index', [
  105 + 'searchModel' => $searchModel,
  106 + 'dataProvider' => $dataProvider,
  107 + 'viewMode' => $viewMode,
  108 + 'selectType' => $selectType,
  109 + ]);
  110 + }
  111 +
  112 + /**
  113 + * Creates a new ImageManager model.
  114 + * If creation is successful, the browser will be redirected to the 'view' page.
  115 + * @return mixed
  116 + */
  117 + public function actionUpload() {
  118 + //set response header
  119 + Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  120 + // Check if the user is allowed to upload the image
  121 + if (Yii::$app->controller->module->canUploadImage == false) {
  122 + // Return the response array to prevent from the action being executed any further
  123 + return [];
  124 + }
  125 + // Create the transaction and set the success variable
  126 + $transaction = Yii::$app->db->beginTransaction();
  127 + $bSuccess = false;
  128 +
  129 + //disable Csrf
  130 + Yii::$app->controller->enableCsrfValidation = false;
  131 + //return default
  132 + $return = $_FILES;
  133 + //set media path
  134 + $sMediaPath = \Yii::$app->imagemanager->mediaPath;
  135 + //create the folder
  136 + BaseFileHelper::createDirectory($sMediaPath);
  137 +
  138 + //check file isset
  139 + if (isset($_FILES['imagemanagerFiles']['tmp_name'])) {
  140 + //loop through each uploaded file
  141 + foreach ($_FILES['imagemanagerFiles']['tmp_name'] AS $key => $sTempFile) {
  142 + //collect variables
  143 + $sFileName = $_FILES['imagemanagerFiles']['name'][$key];
  144 + $sFileExtension = pathinfo($sFileName, PATHINFO_EXTENSION);
  145 + $iErrorCode = $_FILES['imagemanagerFiles']['error'][$key];
  146 + //if uploaded file has no error code than continue;
  147 + if ($iErrorCode == 0) {
  148 + //create a file record
  149 + $model = new ImageManager();
  150 + $model->fileName = str_replace("_", "-", $sFileName);
  151 + $model->fileHash = Yii::$app->getSecurity()->generateRandomString(32);
  152 + //if file is saved add record
  153 + if ($model->save()) {
  154 + //move file to dir
  155 + $sSaveFileName = $model->id . "_" . $model->fileHash . "." . $sFileExtension;
  156 + //move_uploaded_file($sTempFile, $sMediaPath."/".$sFileName);
  157 + //save with Imagine class
  158 + Image::getImagine()->open($sTempFile)->save($sMediaPath . "/" . $sSaveFileName);
  159 + $bSuccess = true;
  160 + }
  161 + }
  162 + }
  163 + }
  164 +
  165 + if ($bSuccess) {
  166 + // The upload action went successful, save the transaction
  167 + $transaction->commit();
  168 + } else {
  169 + // There where problems during the upload, kill the transaction
  170 + $transaction->rollBack();
  171 + }
  172 +
  173 + //echo return json encoded
  174 + return $return;
  175 + }
  176 +
  177 + /**
  178 + * Crop image and create new ImageManager model.
  179 + * @return mixed
  180 + */
  181 + public function actionCrop() {
  182 + //return
  183 + $return = null;
  184 + //disable Csrf
  185 + Yii::$app->controller->enableCsrfValidation = false;
  186 + //set response header
  187 + Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  188 + //set media path
  189 + $sMediaPath = \Yii::$app->imagemanager->mediaPath;
  190 + //get post
  191 + $ImageManager_id = Yii::$app->request->post("ImageManager_id");
  192 + $aCropData = Yii::$app->request->post("CropData");
  193 + //get details
  194 + $modelOriginal = $this->findModel($ImageManager_id);
  195 + //check if path is not null
  196 + if ($modelOriginal->imagePathPrivate !== null && $aCropData !== null) {
  197 + //dimension
  198 + $iDimensionWidth = round($aCropData['width']);
  199 + $iDimensionHeight = round($aCropData['height']);
  200 + //collect variables
  201 + $sFileNameReplace = preg_replace("/_crop_\d+x\d+/", "", $modelOriginal->fileName);
  202 + $sFileName = pathinfo($sFileNameReplace, PATHINFO_FILENAME);
  203 + $sFileExtension = pathinfo($sFileNameReplace, PATHINFO_EXTENSION);
  204 + $sDisplayFileName = $sFileName . "_crop_" . $iDimensionWidth . "x" . $iDimensionHeight . "." . $sFileExtension;
  205 +
  206 + //start transaction
  207 + $transaction = Yii::$app->db->beginTransaction();
  208 + $bCropSuccess = false;
  209 +
  210 + //create a file record
  211 + $model = new ImageManager();
  212 + $model->fileName = $sDisplayFileName;
  213 + $model->fileHash = Yii::$app->getSecurity()->generateRandomString(32);
  214 + //if file is saved add record
  215 + if ($model->save()) {
  216 +
  217 + //do crop in try catch
  218 + try {
  219 + // create file name
  220 + $sSaveFileName = $model->id . "_" . $model->fileHash . "." . $sFileExtension;
  221 +
  222 + // get current/original image data
  223 + $imageOriginal = Image::getImagine()->open($modelOriginal->imagePathPrivate);
  224 + $imageOriginalSize = $imageOriginal->getSize();
  225 + $imageOriginalWidth = $imageOriginalSize->getWidth();
  226 + $imageOriginalHeight = $imageOriginalSize->getHeight();
  227 + $imageOriginalPositionX = 0;
  228 + $imageOriginalPositionY = 0;
  229 +
  230 + // create/calculate a canvas size (if canvas is out of the box)
  231 + $imageCanvasWidth = $imageOriginalWidth;
  232 + $imageCanvasHeight = $imageOriginalHeight;
  233 +
  234 + // update canvas width if X position of croparea is lower than 0
  235 + if($aCropData['x'] < 0){
  236 + //set x postion to Absolute value
  237 + $iAbsoluteXpos = abs($aCropData['x']);
  238 + //set x position of image
  239 + $imageOriginalPositionX = $iAbsoluteXpos;
  240 + //add x position to canvas size
  241 + $imageCanvasWidth += $iAbsoluteXpos;
  242 + //update canvas width if croparea is biger than original image
  243 + $iCropWidthWithoutAbsoluteXpos = ($aCropData['width'] - $iAbsoluteXpos);
  244 + if($iCropWidthWithoutAbsoluteXpos > $imageOriginalWidth){
  245 + //add ouside the box width
  246 + $imageCanvasWidth += ($iCropWidthWithoutAbsoluteXpos - $imageOriginalWidth);
  247 + }
  248 + } else {
  249 + // add if crop partly ouside image
  250 + $iCropWidthWithXpos = ($aCropData['width'] + $aCropData['x']);
  251 + if($iCropWidthWithXpos > $imageOriginalWidth){
  252 + //add ouside the box width
  253 + $imageCanvasWidth += ($iCropWidthWithXpos - $imageOriginalWidth);
  254 + }
  255 + }
  256 +
  257 + // update canvas height if Y position of croparea is lower than 0
  258 + if($aCropData['y'] < 0){
  259 + //set y postion to Absolute value
  260 + $iAbsoluteYpos = abs($aCropData['y']);
  261 + //set y position of image
  262 + $imageOriginalPositionY = $iAbsoluteYpos;
  263 + //add y position to canvas size
  264 + $imageCanvasHeight += $iAbsoluteYpos;
  265 + //update canvas height if croparea is biger than original image
  266 + $iCropHeightWithoutAbsoluteYpos = ($aCropData['height'] - $iAbsoluteYpos);
  267 + if($iCropHeightWithoutAbsoluteYpos > $imageOriginalHeight){
  268 + //add ouside the box height
  269 + $imageCanvasHeight += ($iCropHeightWithoutAbsoluteYpos - $imageOriginalHeight);
  270 + }
  271 + } else {
  272 + // add if crop partly ouside image
  273 + $iCropHeightWithYpos = ($aCropData['height'] + $aCropData['y']);
  274 + if($iCropHeightWithYpos > $imageOriginalHeight){
  275 + //add ouside the box height
  276 + $imageCanvasHeight += ($iCropHeightWithYpos - $imageOriginalHeight);
  277 + }
  278 + }
  279 +
  280 + // round values
  281 + $imageCanvasWidthRounded = round($imageCanvasWidth);
  282 + $imageCanvasHeightRounded = round($imageCanvasHeight);
  283 + $imageOriginalPositionXRounded = round($imageOriginalPositionX);
  284 + $imageOriginalPositionYRounded = round($imageOriginalPositionY);
  285 + $imageCropWidthRounded = round($aCropData['width']);
  286 + $imageCropHeightRounded = round($aCropData['height']);
  287 + // set postion to 0 if x or y is less than 0
  288 + $imageCropPositionXRounded = $aCropData['x'] < 0 ? 0 : round($aCropData['x']);
  289 + $imageCropPositionYRounded = $aCropData['y'] < 0 ? 0 : round($aCropData['y']);
  290 +
  291 +// echo "canvas: ". $imageCanvasWidth ." x ".$imageCanvasHeight ."<br />";
  292 +// echo "img pos x: ". $imageOriginalPositionX ." y ".$imageOriginalPositionY ."<br />";
  293 +// die();
  294 +//
  295 + //todo: check if rotaded resize canvas (http://stackoverflow.com/questions/9971230/calculate-rotated-rectangle-size-from-known-bounding-box-coordinates)
  296 +
  297 + // merge current image in canvas, crop image and save
  298 + $imagineRgb = new RGB();
  299 + $imagineColor = $imagineRgb->color('#FFF', 0);
  300 + // create image
  301 + Image::getImagine()->create(new Box($imageCanvasWidthRounded, $imageCanvasHeightRounded), $imagineColor)
  302 + ->paste($imageOriginal, new Point($imageOriginalPositionXRounded, $imageOriginalPositionYRounded))
  303 + ->crop(new Point($imageCropPositionXRounded, $imageCropPositionYRounded), new Box($imageCropWidthRounded, $imageCropHeightRounded))
  304 + ->save($sMediaPath . "/" . $sSaveFileName);
  305 +
  306 + //set boolean crop success to true
  307 + $bCropSuccess = true;
  308 +
  309 + //set return id
  310 + $return = $model->id;
  311 +
  312 + // Check if the original image must be delete
  313 + if ($this->module->deleteOriginalAfterEdit) {
  314 + $modelOriginal->delete();
  315 + }
  316 + } catch (ErrorException $e) {
  317 +
  318 + }
  319 + }
  320 +
  321 + //commit transaction if boolean is true
  322 + if($bCropSuccess){
  323 + $transaction->commit();
  324 + }
  325 + }
  326 +
  327 + //echo return json encoded
  328 + return $return;
  329 + }
  330 +
  331 + public function actionSaveImageInfo()
  332 + {
  333 + \Yii::$app->response->format = Response::FORMAT_JSON;
  334 +
  335 + if (\Yii::$app->request->isPost) {
  336 + $id = Yii::$app->request->post("image_id");
  337 +
  338 + $model = $this->findModel($id);
  339 +
  340 + $languages = ImageManagerLang::find()
  341 + ->where([ 'image_id' => $model->id ])
  342 + ->indexBy('language_id')
  343 + ->all();
  344 +
  345 + foreach (Language::getActive() as $lang_id => $language) {
  346 + if (empty($languages[ $lang_id ])) {
  347 + $lang = new ImageManagerLang();
  348 + } else {
  349 + $lang = $languages[ $lang_id ];
  350 + }
  351 + /**
  352 + * @var ImageManagerLang $lang
  353 + */
  354 +
  355 + $lang->alt = \Yii::$app->request->post('image_info')[ $lang_id ][ 'alt' ];
  356 + $lang->title = \Yii::$app->request->post('image_info')[ $lang_id ][ 'title' ];
  357 + $lang->description = \Yii::$app->request->post('image_info')[ $lang_id ][ 'description' ];
  358 + $lang->image_id = $model->id;
  359 + $lang->language_id = $lang_id;
  360 + $lang->save();
  361 + }
  362 + }
  363 +
  364 + return 'oki';
  365 + }
  366 +
  367 +
  368 +
  369 + /**
  370 + * Get view details
  371 + * @return mixed
  372 + */
  373 + public function actionView() {
  374 + //disable Csrf
  375 + Yii::$app->controller->enableCsrfValidation = false;
  376 + //return default
  377 + $return = [];
  378 + //set response header
  379 + Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  380 + //get post
  381 + $ImageManager_id = Yii::$app->request->post("ImageManager_id");
  382 + //get details
  383 + $model = $this->findModel($ImageManager_id);
  384 + //set return details
  385 + $return['id'] = $model->id;
  386 + $return['fileName'] = $model->fileName;
  387 + $return['created'] = Yii::$app->formatter->asDate($model->created);
  388 + $return['fileSize'] = $model->imageDetails['size'];
  389 + $return['dimensionWidth'] = $model->imageDetails['width'];
  390 + $return['dimensionHeight'] = $model->imageDetails['height'];
  391 + $return['image'] = \Yii::$app->imagemanager->getImagePath($model->id, 400, 400, "inset") . "?t=" . time();
  392 + $languages = ImageManagerLang::find()
  393 + ->where([ 'image_id' => $model->id ])
  394 + ->indexBy('language_id')
  395 + ->all();
  396 +
  397 + $div = $this->renderPartial(
  398 + '_image_info',
  399 + [
  400 + 'languages' => $languages,
  401 + 'model' => $model,
  402 + ]
  403 + );
  404 +
  405 + $return[ 'div' ] = $div;
  406 + //return json encoded
  407 + return $return;
  408 + }
  409 +
  410 + /**
  411 + * Get full image
  412 + * @return mixed
  413 + */
  414 + public function actionGetOriginalImage() {
  415 + //disable Csrf
  416 + Yii::$app->controller->enableCsrfValidation = false;
  417 + //set response header
  418 + Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  419 + //get post
  420 + $ImageManager_id = Yii::$app->request->post("ImageManager_id");
  421 + //get details
  422 + $model = $this->findModel($ImageManager_id);
  423 + //set return
  424 + $return = \Yii::$app->imagemanager->getImagePath($model->id, $model->imageDetails['width'], $model->imageDetails['height'], "inset");
  425 + //return json encoded
  426 + return $return;
  427 + }
  428 +
  429 + /**
  430 + * Deletes an existing ImageManager model.
  431 + * If deletion is successful, the browser will be redirected to the 'index' page.
  432 + * @return mixed
  433 + */
  434 + public function actionDelete() {
  435 + //return
  436 + $return = ['delete' => false];
  437 + //set response header
  438 + Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  439 +
  440 + if (Yii::$app->controller->module->canRemoveImage == false) {
  441 + // User can not remove this image, return false status
  442 + return $return;
  443 + }
  444 +
  445 + //get post
  446 + $ImageManager_id = Yii::$app->request->post("ImageManager_id");
  447 + //get details
  448 + $model = $this->findModel($ImageManager_id);
  449 +
  450 + //delete record
  451 + if ($model->delete()) {
  452 + $return['delete'] = true;
  453 + }
  454 + return $return;
  455 + }
  456 +
  457 + /**
  458 + * Finds the ImageManager model based on its primary key value.
  459 + * If the model is not found, a 404 HTTP exception will be thrown.
  460 + * @param integer $id
  461 + * @return ImageManager the loaded model
  462 + * @throws NotFoundHttpException if the model cannot be found
  463 + */
  464 + protected function findModel($id) {
  465 + if (($model = ImageManager::findOne($id)) !== null) {
  466 + /* @var $model ImageManager */
  467 + // Get the module instance
  468 + $module = Module::getInstance();
  469 +
  470 + // Check if the model belongs to this user
  471 + if ($module->setBlameableBehavior) {
  472 + // Check if the user and record ID match
  473 + if (Yii::$app->user->id != $model->createdBy) {
  474 + throw new NotFoundHttpException(Yii::t('imagemanager', 'The requested image does not exist.'));
  475 + }
  476 + }
  477 +
  478 + return $model;
  479 + } else {
  480 + throw new NotFoundHttpException(Yii::t('imagemanager', 'The requested image does not exist.'));
  481 + }
  482 + }
  483 +
  484 +}
... ...
backend/components/imagemanager/docs/images/img_doc-image-manager-crop.jpg 0 → 100644

75.7 KB

backend/components/imagemanager/docs/images/img_doc-image-manager.jpg 0 → 100644

62.9 KB

backend/components/imagemanager/docs/images/img_doc-image-widget-popup.jpg 0 → 100644

67.8 KB

backend/components/imagemanager/docs/images/img_doc-image-widget.jpg 0 → 100644

10 KB

backend/components/imagemanager/messages/de/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Wollen Sie dieses Bild wirklich löschen?',
  4 + 'Are you sure you want to detach the image?' => 'Wollen Sie dieses Bild wirklich lösen?',
  5 + 'Cancel' => 'Annullieren',
  6 + 'Created' => 'Erstellt',
  7 + 'Crop' => 'Zuschneiden',
  8 + 'Crop and select' => 'Zuschneiden und auswählen',
  9 + 'Delete' => 'Löschen',
  10 + 'File hash' => 'File hash',
  11 + 'File name' => 'File Name',
  12 + 'Modified' => 'Geändert',
  13 + 'Search' => 'Suchen',
  14 + 'Select' => 'Auswählen',
  15 + 'Image manager' => 'Image manager',
  16 + 'Upload' => 'Upload'
  17 +];
... ...
backend/components/imagemanager/messages/en/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Are you sure you want to delete this image?',
  4 + 'Are you sure you want to detach the image?' => 'Are you sure you want to detach the image?',
  5 + 'Cancel' => 'Cancel',
  6 + 'Created' => 'Created',
  7 + 'Crop' => 'Crop',
  8 + 'Crop and select' => 'Crop and select',
  9 + 'Delete' => 'Delete',
  10 + 'File hash' => 'File hash',
  11 + 'File name' => 'File name',
  12 + 'Modified' => 'Modified',
  13 + 'Search' => 'Search',
  14 + 'Select' => 'Select',
  15 + 'Image manager' => 'Image manager',
  16 + 'Upload' => 'Upload'
  17 +];
... ...
backend/components/imagemanager/messages/fr/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Voulez-vous vraiment effacer cet\'image?',
  4 + 'Are you sure you want to detach the image?' => 'Voules-vous détacher cet\'image?',
  5 + 'Cancel' => 'Annuler',
  6 + 'Created' => 'Crée',
  7 + 'Crop' => 'Ajuster',
  8 + 'Crop and select' => 'Ajuster et sélectionner',
  9 + 'Delete' => 'Effacer',
  10 + 'File hash' => 'Hash du fichier',
  11 + 'File name' => 'Nom du fichier',
  12 + 'Modified' => 'Modifié',
  13 + 'Search' => 'Rechercher',
  14 + 'Select' => 'Sélectionner',
  15 + 'Image manager' => 'Image manager',
  16 + 'Upload' => 'Upload'
  17 +];
... ...
backend/components/imagemanager/messages/it/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Vuole veramente cancellare questa immagine?',
  4 + 'Are you sure you want to detach the image?' => 'Vuole distaccare questa immagine?',
  5 + 'Cancel' => 'Cancellre',
  6 + 'Created' => 'Creato',
  7 + 'Crop' => 'Tagliare a formato',
  8 + 'Crop and select' => 'Tagliare a formato e selezionare',
  9 + 'Delete' => 'Cancellare',
  10 + 'File hash' => 'File hash',
  11 + 'File name' => 'Nome del file',
  12 + 'Modified' => 'Modificato',
  13 + 'Search' => 'Ricerca',
  14 + 'Select' => 'Selezionare',
  15 + 'Image manager' => 'Image manager',
  16 + 'Upload' => 'Upload'
  17 +];
... ...
backend/components/imagemanager/messages/nl/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Weet je zeker dat je de afbeelding wilt verwijderen?',
  4 + 'Are you sure you want to detach the image?' => 'Weet je zeker dat je de afbeelding wilt losmaken?',
  5 + 'The requested image does not exist.' => 'De gevraagde afbeelding bestaat niet.',
  6 + 'Cancel' => 'Annuleer',
  7 + 'Created' => 'Aangemaakt',
  8 + 'Created by' => 'Gemaakt door',
  9 + 'Crop' => 'Bijsnijden',
  10 + 'Crop and select' => 'Bijsnijden en selecteren',
  11 + 'Delete' => 'Verwijderen',
  12 + 'File hash' => 'Bestand hash',
  13 + 'File name' => 'Bestandsnaam',
  14 + 'Modified' => 'Gewijzigd',
  15 + 'Modified by' => 'Gewijzigd door',
  16 + 'Search' => 'Zoeken',
  17 + 'Select' => 'Selecteer',
  18 + 'Image manager' => 'Image manager',
  19 + 'Upload' => 'Upload'
  20 +];
0 21 \ No newline at end of file
... ...
backend/components/imagemanager/messages/ru/imagemanager.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'Are you sure you want to delete this image?' => 'Вы действительно хотите удалить изображение?',
  4 + 'Are you sure you want to detach the image?' => 'Вы действительно хотите открепить изображение?',
  5 + 'Cancel' => 'Отменить',
  6 + 'Created' => 'Создано',
  7 + 'Crop' => 'Обрезать',
  8 + 'Crop and select' => 'Обрезать и выбрать',
  9 + 'Delete' => 'Удалить',
  10 + 'File hash' => 'Хеш файла',
  11 + 'File name' => 'Имя файла',
  12 + 'Modified' => 'Измененл',
  13 + 'Search' => 'Поиск',
  14 + 'Select' => 'Выбрать',
  15 + 'Image manager' => 'Менеджер изображений',
  16 + 'Upload' => 'Загрузить'
  17 +];
0 18 \ No newline at end of file
... ...
backend/components/imagemanager/migrations/m160622_085710_create_ImageManager_table.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +/**
  6 + * Handles the creation for table `ImageManager`.
  7 + */
  8 +class m160622_085710_create_ImageManager_table extends Migration
  9 +{
  10 + /**
  11 + * @inheritdoc
  12 + */
  13 + public function up()
  14 + {
  15 + //ImageManager: create table
  16 + $this->createTable('ImageManager', [
  17 + 'id' => $this->primaryKey(),
  18 + 'fileName' => $this->string(128)->notNull(),
  19 + 'fileHash' => $this->string(32)->notNull(),
  20 + 'created' => $this->datetime()->notNull(),
  21 + 'modified' => $this->datetime(),
  22 + ]);
  23 +
  24 + //ImageManager: alter id column
  25 + $this->alterColumn('ImageManager', 'id', 'INT(10) UNSIGNED NOT NULL AUTO_INCREMENT');
  26 +
  27 + }
  28 +
  29 + /**
  30 + * @inheritdoc
  31 + */
  32 + public function down()
  33 + {
  34 + $this->dropTable('ImageManager');
  35 + }
  36 +}
0 37 \ No newline at end of file
... ...
backend/components/imagemanager/migrations/m170223_113221_addBlameableBehavior.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +class m170223_113221_addBlameableBehavior extends Migration
  6 +{
  7 + public function up()
  8 + {
  9 + $this->addColumn('ImageManager', 'createdBy', $this->integer(10)->unsigned()->null()->defaultValue(null));
  10 + $this->addColumn('ImageManager', 'modifiedBy', $this->integer(10)->unsigned()->null()->defaultValue(null));
  11 + }
  12 +
  13 + public function down()
  14 + {
  15 + echo "m170223_113221_addBlameableBehavior cannot be reverted.\n";
  16 +
  17 + return false;
  18 + }
  19 +}
... ...
backend/components/imagemanager/migrations/m180530_131113_create_ImageManagerLant_table.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\db\Migration;
  4 +
  5 +/**
  6 + * Handles the creation of table `ImageManagerLant`.
  7 + */
  8 +class m180530_131113_create_ImageManagerLant_table extends Migration
  9 +{
  10 + public function up()
  11 + {
  12 + $this->createTable(
  13 + 'ImageManagerLang',
  14 + [
  15 + 'image_id' => $this->integer(),
  16 + 'language_id' => $this->integer(),
  17 + 'title' => $this->string(),
  18 + 'alt' => $this->string(),
  19 + 'description' => $this->string(),
  20 + ]
  21 + );
  22 +
  23 + $this->addForeignKey(
  24 + 'image_fk',
  25 + 'ImageManagerLang',
  26 + 'image_id',
  27 + 'ImageManager',
  28 + 'id',
  29 + 'CASCADE',
  30 + 'CASCADE'
  31 + );
  32 +
  33 + $this->addForeignKey(
  34 + 'language_fk',
  35 + 'ImageManagerLang',
  36 + 'language_id',
  37 + 'language',
  38 + 'id',
  39 + 'CASCADE',
  40 + 'CASCADE'
  41 + );
  42 +
  43 + $this->createIndex(
  44 + 'img_lang_uk',
  45 + 'ImageManagerLang',
  46 + [
  47 + 'language_id',
  48 + 'image_id',
  49 + ],
  50 + true
  51 + );
  52 + }
  53 +
  54 + /**
  55 + * @inheritdoc
  56 + */
  57 + public function down()
  58 + {
  59 + $this->dropTable('ImageManagerLang');
  60 + }
  61 +}
... ...
backend/components/imagemanager/models/ImageManager.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\models;
  4 +
  5 +use backend\components\imagemanager\Module;
  6 +use Yii;
  7 +use yii\db\Expression;
  8 +use yii\behaviors\TimestampBehavior;
  9 +use yii\behaviors\BlameableBehavior;
  10 +
  11 +/**
  12 + * This is the model class for table "ImageManager".
  13 + *
  14 + * @property integer $id
  15 + * @property string $fileName
  16 + * @property string $fileHash
  17 + * @property string $created
  18 + * @property string $modified
  19 + * @property string $createdBy
  20 + * @property string $modifiedBy
  21 + */
  22 +class ImageManager extends \yii\db\ActiveRecord {
  23 +
  24 + /**
  25 + * Set Created date to now
  26 + */
  27 + public function behaviors() {
  28 + $aBehaviors = [];
  29 +
  30 + // Add the time stamp behavior
  31 + $aBehaviors[] = [
  32 + 'class' => TimestampBehavior::className(),
  33 + 'createdAtAttribute' => 'created',
  34 + 'updatedAtAttribute' => 'modified',
  35 + 'value' => new Expression('NOW()'),
  36 + ];
  37 +
  38 + // Get the imagemanager module from the application
  39 + $moduleImageManager = Yii::$app->getModule('imagemanager');
  40 + /* @var $moduleImageManager Module */
  41 + if ($moduleImageManager !== null) {
  42 + // Module has been loaded
  43 + if ($moduleImageManager->setBlameableBehavior) {
  44 + // Module has blame able behavior
  45 + $aBehaviors[] = [
  46 + 'class' => BlameableBehavior::className(),
  47 + 'createdByAttribute' => 'createdBy',
  48 + 'updatedByAttribute' => 'modifiedBy',
  49 + ];
  50 + }
  51 + }
  52 +
  53 + return $aBehaviors;
  54 + }
  55 +
  56 + /**
  57 + * @inheritdoc
  58 + */
  59 + public static function tableName() {
  60 + return 'ImageManager';
  61 + }
  62 +
  63 + /**
  64 + * Get the DB component that the model uses
  65 + * This function will throw error if object could not be found
  66 + * The DB connection defaults to DB
  67 + * @return null|object
  68 + */
  69 + public static function getDb() {
  70 + // Get the image manager object
  71 + $oImageManager = Yii::$app->get('imagemanager', false);
  72 +
  73 + if($oImageManager === null) {
  74 + // The image manager object has not been set
  75 + // The normal DB object will be returned, error will be thrown if not found
  76 + return Yii::$app->get('db');
  77 + }
  78 +
  79 + // The image manager component has been loaded, the DB component that has been entered will be loaded
  80 + // By default this is the Yii::$app->db connection, the user can specify any other connection if needed
  81 + return Yii::$app->get($oImageManager->databaseComponent);
  82 + }
  83 +
  84 + /**
  85 + * @inheritdoc
  86 + */
  87 + public function rules() {
  88 + return [
  89 + [['fileName', 'fileHash'], 'required'],
  90 + [['created', 'modified'], 'safe'],
  91 + [['fileName'], 'string', 'max' => 128],
  92 + [['fileHash'], 'string', 'max' => 32],
  93 + ];
  94 + }
  95 +
  96 + /**
  97 + * @inheritdoc
  98 + */
  99 + public function attributeLabels() {
  100 + return [
  101 + 'id' => Yii::t('imagemanager', 'ID'),
  102 + 'fileName' => Yii::t('imagemanager', 'File Name'),
  103 + 'fileHash' => Yii::t('imagemanager', 'File Hash'),
  104 + 'created' => Yii::t('imagemanager', 'Created'),
  105 + 'modified' => Yii::t('imagemanager', 'Modified'),
  106 + 'createdBy' => Yii::t('imagemanager', 'Created by'),
  107 + 'modifiedBy' => Yii::t('imagemanager', 'Modified by'),
  108 + ];
  109 + }
  110 +
  111 + public function afterDelete()
  112 + {
  113 + parent::afterDelete();
  114 +
  115 + // Check if file exists
  116 + if (file_exists($this->getImagePathPrivate())) {
  117 + unlink($this->getImagePathPrivate());
  118 + }
  119 + }
  120 +
  121 + /**
  122 + * Get image path private
  123 + * @return string|null If image file exists the path to the image, if file does not exists null
  124 + */
  125 + public function getImagePathPrivate() {
  126 + //set default return
  127 + $return = null;
  128 + //set media path
  129 + $sMediaPath = \Yii::$app->imagemanager->mediaPath;
  130 + $sFileExtension = pathinfo($this->fileName, PATHINFO_EXTENSION);
  131 + //get image file path
  132 + $sImageFilePath = $sMediaPath . '/' . $this->id . '_' . $this->fileHash . '.' . $sFileExtension;
  133 + //check file exists
  134 + if (file_exists($sImageFilePath)) {
  135 + $return = $sImageFilePath;
  136 + }
  137 + return $return;
  138 + }
  139 +
  140 + /**
  141 + * Get image data dimension/size
  142 + * @return array The image sizes
  143 + */
  144 + public function getImageDetails() {
  145 + //set default return
  146 + $return = ['width' => 0, 'height' => 0, 'size' => 0];
  147 + //set media path
  148 + $sMediaPath = \Yii::$app->imagemanager->mediaPath;
  149 + $sFileExtension = pathinfo($this->fileName, PATHINFO_EXTENSION);
  150 + //get image file path
  151 + $sImageFilePath = $sMediaPath . '/' . $this->id . '_' . $this->fileHash . '.' . $sFileExtension;
  152 + //check file exists
  153 + if (file_exists($sImageFilePath)) {
  154 + $aImageDimension = getimagesize($sImageFilePath);
  155 + $return['width'] = isset($aImageDimension[0]) ? $aImageDimension[0] : 0;
  156 + $return['height'] = isset($aImageDimension[1]) ? $aImageDimension[1] : 0;
  157 + $return['size'] = Yii::$app->formatter->asShortSize(filesize($sImageFilePath), 2);
  158 + }
  159 + return $return;
  160 + }
  161 +
  162 +}
... ...
backend/components/imagemanager/models/ImageManagerLang.php 0 → 100755
  1 +<?php
  2 +
  3 + namespace backend\components\imagemanager\models;
  4 +
  5 + use artbox\core\models\Language;
  6 + use Yii;
  7 + use yii\db\ActiveRecord;
  8 +
  9 + /**
  10 + * This is the model class for table "ImageManagerLang".
  11 + *
  12 + * @property integer $image_id
  13 + * @property integer $language_id
  14 + * @property string $title
  15 + * @property string $alt
  16 + * @property string $description
  17 + * @property ImageManager $image
  18 + * @property Language $language
  19 + */
  20 + class ImageManagerLang extends ActiveRecord
  21 + {
  22 + /**
  23 + * @inheritdoc
  24 + */
  25 + public static function tableName()
  26 + {
  27 + return 'ImageManagerLang';
  28 + }
  29 +
  30 + /**
  31 + * @inheritdoc
  32 + */
  33 + public static function primaryKey()
  34 + {
  35 + return [
  36 + 'image_id',
  37 + 'language_id',
  38 + ];
  39 + }
  40 +
  41 + /**
  42 + * @inheritdoc
  43 + */
  44 + public function rules()
  45 + {
  46 + return [
  47 + [
  48 + [
  49 + 'image_id',
  50 + 'language_id',
  51 + ],
  52 + 'integer',
  53 + ],
  54 + [
  55 + [
  56 + 'title',
  57 + 'alt',
  58 + 'description',
  59 + ],
  60 + 'string',
  61 + 'max' => 255,
  62 + ],
  63 + [
  64 + [
  65 + 'language_id',
  66 + 'image_id',
  67 + ],
  68 + 'unique',
  69 + 'targetAttribute' => [
  70 + 'language_id',
  71 + 'image_id',
  72 + ],
  73 + 'message' => 'The combination of Image ID and Language ID has already been taken.',
  74 + ],
  75 + [
  76 + [ 'image_id' ],
  77 + 'exist',
  78 + 'skipOnError' => true,
  79 + 'targetClass' => ImageManager::className(),
  80 + 'targetAttribute' => [ 'image_id' => 'id' ],
  81 + ],
  82 + [
  83 + [ 'language_id' ],
  84 + 'exist',
  85 + 'skipOnError' => true,
  86 + 'targetClass' => Language::className(),
  87 + 'targetAttribute' => [ 'language_id' => 'id' ],
  88 + ],
  89 + ];
  90 + }
  91 +
  92 + /**
  93 + * @inheritdoc
  94 + */
  95 + public function attributeLabels()
  96 + {
  97 + return [
  98 + 'image_id' => Yii::t('app', 'Image ID'),
  99 + 'language_id' => Yii::t('app', 'Language ID'),
  100 + 'title' => Yii::t('app', 'Title'),
  101 + 'alt' => Yii::t('app', 'Alt'),
  102 + 'description' => Yii::t('app', 'Description'),
  103 + ];
  104 + }
  105 +
  106 + /**
  107 + * @return \yii\db\ActiveQuery
  108 + */
  109 + public function getImage()
  110 + {
  111 + return $this->hasOne(ImageManager::className(), [ 'id' => 'image_id' ]);
  112 + }
  113 +
  114 + /**
  115 + * @return \yii\db\ActiveQuery
  116 + */
  117 + public function getLanguage()
  118 + {
  119 + return $this->hasOne(Language::className(), [ 'id' => 'language_id' ]);
  120 + }
  121 + }
... ...
backend/components/imagemanager/models/ImageManagerSearch.php 0 → 100644
  1 +<?php
  2 +
  3 +namespace backend\components\imagemanager\models;
  4 +
  5 +use Yii;
  6 +use yii\base\Model;
  7 +use yii\data\ActiveDataProvider;
  8 +use backend\components\imagemanager\models\ImageManager;
  9 +use backend\components\imagemanager\Module;
  10 +
  11 +/**
  12 + * ImageManagerSearch represents the model behind the search form about `common\modules\imagemanager\models\ImageManager`.
  13 + */
  14 +class ImageManagerSearch extends ImageManager
  15 +{
  16 + public $globalSearch;
  17 +
  18 + /**
  19 + * @inheritdoc
  20 + */
  21 + public function rules()
  22 + {
  23 + return [
  24 + [['globalSearch'], 'safe'],
  25 + ];
  26 + }
  27 +
  28 + /**
  29 + * @inheritdoc
  30 + */
  31 + public function scenarios()
  32 + {
  33 + // bypass scenarios() implementation in the parent class
  34 + return Model::scenarios();
  35 + }
  36 +
  37 + /**
  38 + * Creates data provider instance with search query applied
  39 + *
  40 + * @param array $params
  41 + *
  42 + * @return ActiveDataProvider
  43 + */
  44 + public function search($params)
  45 + {
  46 + $query = ImageManager::find();
  47 +
  48 + // add conditions that should always apply here
  49 +
  50 + $dataProvider = new ActiveDataProvider([
  51 + 'query' => $query,
  52 + 'pagination' => [
  53 + 'pagesize' => 100,
  54 + ],
  55 + 'sort'=> ['defaultOrder' => ['created'=>SORT_DESC]]
  56 + ]);
  57 +
  58 + $this->load($params);
  59 +
  60 + if (!$this->validate()) {
  61 + // uncomment the following line if you do not want to return any records when validation fails
  62 + // $query->where('0=1');
  63 + return $dataProvider;
  64 + }
  65 +
  66 + // Get the module instance
  67 + $module = Module::getInstance();
  68 +
  69 + if ($module->setBlameableBehavior) {
  70 + $query->andWhere(['createdBy' => Yii::$app->user->id]);
  71 + }
  72 +
  73 + $query->orFilterWhere(['like', 'fileName', $this->globalSearch])
  74 + ->orFilterWhere(['like', 'created', $this->globalSearch])
  75 + ->orFilterWhere(['like', 'modified', $this->globalSearch]);
  76 +
  77 + return $dataProvider;
  78 + }
  79 +}
... ...
backend/components/imagemanager/views/default/index.php 0 → 100644
  1 +<?php
  2 +$this->title = "Image manager";
  3 +?>
  4 +<div class="imagemanager-default-index">
  5 + <p>Welcome to image manager</p>
  6 + <p>Install run migrate:</p>
  7 + <p><code>yii migrate --migrationPath=@noam148/imagemanager/migrations</code></p>
  8 +
  9 + <p><em>By noam148</em></p>
  10 +</div>
... ...
backend/components/imagemanager/views/layouts/blank.php 0 → 100644
  1 +<?php
  2 +
  3 +/* @var $this \yii\web\View */
  4 +/* @var $content string */
  5 +
  6 +use yii\helpers\Html;
  7 +
  8 +?>
  9 +<?php $this->beginPage() ?>
  10 +<!DOCTYPE html>
  11 +<html lang="<?= Yii::$app->language ?>">
  12 +<head>
  13 + <meta charset="<?= Yii::$app->charset ?>">
  14 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
  15 + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
  16 + <?= Html::csrfMetaTags() ?>
  17 + <title><?= Html::encode($this->title) ?></title>
  18 + <?php $this->head() ?>
  19 +</head>
  20 +<body>
  21 +<?php $this->beginBody() ?>
  22 +
  23 +<?= $content; ?>
  24 +
  25 +<?php $this->endBody() ?>
  26 +</body>
  27 +</html>
  28 +<?php $this->endPage() ?>
... ...
backend/components/imagemanager/views/manager/_image_info.php 0 → 100755
  1 +<?php
  2 +
  3 + /**
  4 + * @var View $this
  5 + * @var ImageManager $model
  6 + * @var ImageManagerLang $languages
  7 + */
  8 +
  9 + use artbox\core\components\imagemanager\models\ImageManager;
  10 + use artbox\core\components\imagemanager\models\ImageManagerLang;
  11 + use common\models\Language;
  12 + use yii\helpers\Html;
  13 + use yii\web\View;
  14 +
  15 +?>
  16 +
  17 +
  18 +<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
  19 +
  20 +
  21 + <?php
  22 +
  23 + foreach (Language::getActive() as $id => $language) { ?>
  24 +
  25 +
  26 + <div class="panel panel-default">
  27 + <div class="panel-heading" role="tab" id="heading<?= $id ?>">
  28 + <h4 class="panel-title">
  29 + <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse<?= $id ?>" aria-expanded="true" aria-controls="collapseOne">
  30 + <?= $language->name ?>
  31 + </a>
  32 + </h4>
  33 + </div>
  34 + <div id="collapse<?= $id ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading<?= $id ?>">
  35 + <div class="panel-body">
  36 +
  37 + <?php
  38 + if (empty($languages[ $id ])) { ?>
  39 +
  40 + <div class="form-group">
  41 + <label for="title<?= $id ?>">Title</label>
  42 + <input name="image_info[<?= $language->id ?>][title]" type="text" class="form-control" id="title<?= $id ?>">
  43 + </div>
  44 +
  45 + <div class="form-group">
  46 + <label for="alt<?= $id ?>">Alt</label>
  47 + <input name="image_info[<?= $language->id ?>][alt]" type="text" class="form-control" id="alt<?= $id ?>">
  48 + </div>
  49 +
  50 + <div class="form-group">
  51 + <label for="description<?= $id ?>">Description</label>
  52 + <textarea class="form-control" name="image_info[<?= $language->id ?>][description]" id="description<?= $id ?>" cols="30" rows="10"></textarea>
  53 + </div>
  54 +
  55 + <?php } else { ?>
  56 +
  57 + <div class="form-group">
  58 + <label for="title<?= $id ?>">Title</label>
  59 + <input value="<?= $languages[ $id ]->title ?>" name="image_info[<?= $language->id ?>][title]" type="text" class="form-control" id="title<?= $id ?>">
  60 + </div>
  61 +
  62 + <div class="form-group">
  63 + <label for="alt<?= $id ?>">Alt</label>
  64 + <input value="<?= $languages[ $id ]->alt ?>" name="image_info[<?= $language->id ?>][alt]" type="text" class="form-control" id="alt<?= $id ?>">
  65 + </div>
  66 +
  67 + <div class="form-group">
  68 + <label for="description<?= $id ?>">Description</label>
  69 + <textarea class="form-control" name="image_info[<?= $language->id ?>][description]" id="description<?= $id ?>" cols="30" rows="10"><?= $languages[ $id ]->description ?></textarea>
  70 + </div>
  71 +
  72 + <?php } ?>
  73 + </div>
  74 + </div>
  75 + </div>
  76 +
  77 + <?php
  78 + }
  79 + echo Html::hiddenInput(
  80 + 'image_id',
  81 + $model->id
  82 + );
  83 +
  84 + ?>
  85 +
  86 +</div>
  87 +
  88 +
  89 +
... ...
backend/components/imagemanager/views/manager/_item.php 0 → 100644
  1 +<div class="thumbnail">
  2 + <img src="<?=\Yii::$app->imagemanager->getImagePath($model->id, 300, 300)?>" alt="<?=$model->fileName?>">
  3 + <div class="filename"><?=$model->fileName?></div>
  4 +</div>
... ...
backend/components/imagemanager/views/manager/index.php 0 → 100644
  1 +<?php
  2 +use yii\helpers\Url;
  3 +use yii\helpers\Html;
  4 +use yii\widgets\ListView;
  5 +use yii\widgets\Pjax;
  6 +use kartik\file\FileInput;
  7 +
  8 +$this->title = Yii::t('imagemanager','Image manager');
  9 +
  10 +?>
  11 +<div id="module-imagemanager" class="container-fluid <?=$selectType?>">
  12 + <div class="row">
  13 + <div class="col-xs-6 col-sm-10 col-image-editor">
  14 + <div class="image-cropper">
  15 + <div class="image-wrapper">
  16 + <img id="image-cropper" />
  17 + </div>
  18 + <div class="action-buttons">
  19 + <a href="#" class="btn btn-primary apply-crop">
  20 + <i class="fa fa-crop"></i>
  21 + <span class="hidden-xs"><?=Yii::t('imagemanager','Crop')?></span>
  22 + </a>
  23 + <?php if($viewMode === "iframe"): ?>
  24 + <a href="#" class="btn btn-primary apply-crop-select">
  25 + <i class="fa fa-crop"></i>
  26 + <span class="hidden-xs"><?=Yii::t('imagemanager','Crop and select')?></span>
  27 + </a>
  28 + <?php endif; ?>
  29 + <a href="#" class="btn btn-default cancel-crop">
  30 + <i class="fa fa-undo"></i>
  31 + <span class="hidden-xs"><?=Yii::t('imagemanager','Cancel')?></span>
  32 + </a>
  33 + </div>
  34 + </div>
  35 + </div>
  36 + <div class="col-xs-6 col-sm-10 col-overview">
  37 + <?php Pjax::begin([
  38 + 'id'=>'pjax-mediamanager',
  39 + 'timeout'=>'5000'
  40 + ]); ?>
  41 + <?= ListView::widget([
  42 + 'dataProvider' => $dataProvider,
  43 + 'itemOptions' => ['class' => 'item img-thumbnail'],
  44 + 'layout' => "<div class='item-overview'>{items}</div> {pager}",
  45 + 'itemView' => function ($model, $key, $index, $widget) {
  46 + return $this->render("_item", ['model' => $model]);
  47 + },
  48 + ]) ?>
  49 + <?php Pjax::end(); ?>
  50 + </div>
  51 + <div class="col-xs-6 col-sm-2 col-options">
  52 + <div class="form-group">
  53 + <?=Html::textInput('input-mediamanager-search', null, ['id'=>'input-mediamanager-search', 'class'=>'form-control', 'placeholder'=>Yii::t('imagemanager','Search').'...'])?>
  54 + </div>
  55 +
  56 + <?php
  57 + if (Yii::$app->controller->module->canUploadImage):
  58 + ?>
  59 +
  60 + <?=FileInput::widget([
  61 + 'name' => 'imagemanagerFiles[]',
  62 + 'id' => 'imagemanager-files',
  63 + 'options' => [
  64 + 'multiple' => true,
  65 + 'accept' => 'image/*'
  66 + ],
  67 + 'pluginOptions' => [
  68 + 'uploadUrl' => Url::to(['manager/upload']),
  69 + 'allowedFileExtensions' => \Yii::$app->controller->module->allowedFileExtensions,
  70 + 'uploadAsync' => false,
  71 + 'showPreview' => false,
  72 + 'showRemove' => false,
  73 + 'showUpload' => false,
  74 + 'showCancel' => false,
  75 + 'browseClass' => 'btn btn-primary btn-block',
  76 + 'browseIcon' => '<i class="fa fa-upload"></i> ',
  77 + 'browseLabel' => Yii::t('imagemanager','Upload')
  78 + ],
  79 + 'pluginEvents' => [
  80 + "filebatchselected" => "function(event, files){ $('.msg-invalid-file-extension').addClass('hide'); $(this).fileinput('upload'); }",
  81 + "filebatchuploadsuccess" => "function(event, data, previewId, index) {
  82 + imageManagerModule.uploadSuccess(data.jqXHR.responseJSON.imagemanagerFiles);
  83 + }",
  84 + "fileuploaderror" => "function(event, data) { $('.msg-invalid-file-extension').removeClass('hide'); }",
  85 + ],
  86 + ]) ?>
  87 +
  88 + <?php
  89 + endif;
  90 + ?>
  91 +
  92 + <div class="image-info hide">
  93 + <div class="thumbnail">
  94 + <img src="#">
  95 + </div>
  96 + <div class="edit-buttons">
  97 + <a href="#" class="btn btn-primary btn-block crop-image-item">
  98 + <i class="fa fa-crop"></i>
  99 + <span class="hidden-xs"><?=Yii::t('imagemanager','Crop')?></span>
  100 + </a>
  101 + </div>
  102 + <div class="details">
  103 + <div class="fileName"></div>
  104 + <div class="created"></div>
  105 + <div class="fileSize"></div>
  106 + <div class="dimensions"><span class="dimension-width"></span> &times; <span class="dimension-height"></span></div>
  107 + <?php
  108 + if (Yii::$app->controller->module->canRemoveImage):
  109 + ?>
  110 + <a href="#" class="btn btn-xs btn-danger delete-image-item" >
  111 + <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
  112 + <?=Yii::t('imagemanager','Delete')?></a>
  113 + <?php
  114 + endif;
  115 + ?>
  116 +
  117 + <form id="save-image-info-form">
  118 + <div class="seo-info">
  119 +
  120 + </div>
  121 + <?= Html::button(
  122 + '<i class="glyphicon glyphicon-floppy-disk"></i> ' . \Yii::t('imagemanager', 'Save'),
  123 + [
  124 + 'class' => 'btn btn-success btn-xs',
  125 + 'id' => 'save-image-info',
  126 + ]
  127 + ) ?>
  128 + </form>
  129 + </div>
  130 + <?php if($viewMode === "iframe"): ?>
  131 + <a href="#" class="btn btn-primary btn-block pick-image-item"><?=Yii::t('imagemanager','Select')?></a>
  132 + <?php endif; ?>
  133 + </div>
  134 + </div>
  135 + </div>
  136 +</div>
0 137 \ No newline at end of file
... ...
backend/controllers/PackageController.php
... ... @@ -164,6 +164,13 @@
164 164 'name' => 'sort',
165 165 'type' => Form::NUMBER,
166 166 ],
  167 + [
  168 + 'name' => 'service_id',
  169 + 'type' => Form::RELATION,
  170 + 'relationAttribute' => 'title',
  171 + 'relationName' => 'service',
  172 + 'multiple' => false,
  173 + ]
167 174 ],
168 175 ];
169 176 }
... ...
common/models/Article.php 0 → 100644
  1 +<?php
  2 +/**
  3 + * =====================================================================================================================
  4 + * Отнаследовал, потому что мне нужно было прокинуть новые значения для моделей
  5 + * Image
  6 + * ImageLang
  7 + * не трогая кор
  8 + * =====================================================================================================================
  9 + */
  10 +
  11 +namespace common\models;
  12 +use artbox\weblog\models\Article as CoreArticle;
  13 +use common\models\Image as I;
  14 +
  15 +
  16 +
  17 +class Article extends CoreArticle
  18 +{
  19 + public function getImage()
  20 + {
  21 + return $this->hasOne(I::className(), [ 'id' => 'image_id' ]);
  22 + }
  23 +}
0 24 \ No newline at end of file
... ...
common/models/ArticleLang.php 0 → 100644
  1 +<?php
  2 +/**
  3 + * =====================================================================================================================
  4 + * LanguageBehavio при обращении к $this->owner выдавал exception, потому что искал common\models\ArticleLang
  5 + * =====================================================================================================================
  6 + */
  7 +
  8 +namespace common\models;
  9 +use artbox\weblog\models\ArticleLang as CoreLang;
  10 +
  11 +class ArticleLang extends CoreLang
  12 +{
  13 +
  14 +}
0 15 \ No newline at end of file
... ...
common/models/Language.php 0 → 100644
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: alex
  5 + * Date: 30.05.18
  6 + * Time: 16:20
  7 + */
  8 +
  9 +namespace common\models;
  10 +use artbox\core\models\Language as CoreLanguage;
  11 +
  12 +class Language extends CoreLanguage
  13 +{
  14 +
  15 + public static $active=null;
  16 +
  17 + /**
  18 + * Get active Languages and cache them
  19 + *
  20 + * @return array|\artbox\core\models\Language[]|null|\yii\db\ActiveRecord[]
  21 + */
  22 + public static function getActive()
  23 + {
  24 + if (empty(self::$active)) {
  25 + self::$active = self::find()
  26 + ->where([ 'status' => true ])
  27 + ->indexBy('id')
  28 + ->all();
  29 + }
  30 + return self::$active;
  31 + }
  32 +
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
common/models/Package.php
... ... @@ -79,7 +79,7 @@ class Package extends ActiveRecord
79 79 {
80 80 return [
81 81 [['sort', 'created_at', 'updated_at'], 'default', 'value' => null],
82   - [['sort', 'created_at', 'updated_at', 'image_id'], 'integer'],
  82 + [['sort', 'created_at', 'updated_at', 'image_id', 'service_id'], 'integer'],
83 83 [['status'], 'boolean'],
84 84 ];
85 85 }
... ... @@ -130,4 +130,8 @@ class Package extends ActiveRecord
130 130 return $this->hasOne(Image::className(), ['id' => 'image_id']);
131 131 }
132 132  
  133 + public function getService(){
  134 + return $this->hasOne(Service::className(), ['id' => 'service_id']);
  135 + }
  136 +
133 137 }
... ...
common/models/Service.php
... ... @@ -162,4 +162,8 @@ class Service extends ActiveRecord
162 162 public function getQuestions(){
163 163 return $this->hasMany(Question::className(), ['service_id' => 'id']);
164 164 }
  165 +
  166 + public function getPackages(){
  167 + return $this->hasMany(Package::className(), ['service_id' => 'id']);
  168 + }
165 169 }
... ...
frontend/assets/AppAsset.php
... ... @@ -13,7 +13,7 @@
13 13 public $baseUrl = '@web';
14 14 public $css = [
15 15 'css/style.css',
16   -// '//fonts.googleapis.com/css?family=Ubuntu:400,500,700&amp;subset=cyrillic,cyrillic-ext,latin-ext'
  16 + '//fonts.googleapis.com/css?family=Ubuntu:400,500,700&amp;subset=cyrillic,cyrillic-ext,latin-ext'
17 17 ];
18 18 public $js = [
19 19 'js/script.js',
... ...
frontend/controllers/ServiceController.php
... ... @@ -20,6 +20,9 @@
20 20 $model = $this->findModel($id);
21 21 if ($model->parent_id == null){
22 22 $others = Service::find()->where(['parent_id' => $model->id])->with('services.language.alias')->all();
  23 + if (empty($others)){
  24 + $others = Service::find()->where(['parent_id' => null, 'status' => true])->all();
  25 + }
23 26 }elseif ($model->level == 1){
24 27 $others = Service::find()->where(['parent_id' => $model->parent_id])->with('services.language.alias')->all();
25 28 }else{
... ... @@ -42,6 +45,8 @@
42 45 $query->where(['status' => true]);
43 46 }, 'questions' => function (ActiveQuery $query){
44 47 $query->where(['status' => true])->with('doctor');
  48 + },'packages' => function (ActiveQuery $query){
  49 + $query->with(['image', 'language'])->where(['status' => true]);
45 50 }])->one();
46 51 if (empty($model)){
47 52 throw new NotFoundHttpException('Model not found');
... ...
frontend/views/service/view.php
... ... @@ -7,6 +7,7 @@
7 7 * @var \yii\web\View $this
8 8 * @var \artbox\core\components\SeoComponent $seo;
9 9 */
  10 + use artbox\core\helpers\ImageHelper;
10 11 use artbox\core\helpers\Url;
11 12 use common\models\Service;
12 13 use artbox\core\models\Alias;
... ... @@ -88,6 +89,36 @@
88 89 <?php }?>
89 90 </ul>
90 91 </div>
  92 + <div class="style">
  93 + <?php if (!empty($model->packages)){
  94 + foreach ($model->packages as $package){?>
  95 + <div class="packages-page-col">
  96 + <a class="packages-page-link" href="<?=Url::to(['alias' => $package->language->alias])?>">
  97 + <div class="img-packages-page">
  98 + <!--555x344-->
  99 + <?=ImageHelper::set(($package->image) ? $package->image->getPath() : null)
  100 + ->resize(262, 135)
  101 + ->quality(84)
  102 + ->renderImage()?>
  103 + </div>
  104 + <div class="table-packages-wr">
  105 + <table cellspacing="0" cellpadding="0" border="0">
  106 + <tr>
  107 + <td><span class="title-packages"><?=$package->title?></span></td>
  108 + </tr>
  109 + <tr>
  110 + <td>
  111 + <span class="btn_ packages-btn"><?=\Yii::t('app','More info');?></span>
  112 + </td>
  113 + </tr>
  114 + </table>
  115 + </div>
  116 + </a>
  117 + </div>
  118 + <?php }
  119 +
  120 + }?>
  121 + </div>
91 122 </div>
92 123 <div class="col-xs-12 col-sm-8 col-md-8 col-lg-9">
93 124 <div class="row">
... ...
frontend/views/site/comments.php
... ... @@ -14,7 +14,7 @@
14 14 use yii\widgets\ActiveForm;
15 15 use yii\widgets\ListView;
16 16  
17   - $this->params[ 'breadcrumbs'][] = \Yii::t('app', 'Quest/Answer');
  17 + $this->params[ 'breadcrumbs'][] = \Yii::t('app', 'Отзывы');
18 18  
19 19 $model = new Comment(['entity_id' => $service_id, 'entity' => Service::className()]);
20 20  
... ... @@ -75,7 +75,7 @@
75 75 <ul class="answers-category-list">
76 76 <li <?=($service_id == null ? 'class="active"' : '')?>>
77 77 <a href="<?=Url::current(['service_id' => null])?>">
78   - <span><?=\Yii::t('app','General issues');?></span></a></li>
  78 + <span><?=\Yii::t('app','Общие отзывы');?></span></a></li>
79 79 <?php foreach ($services as $service){?>
80 80 <li <?=($service_id == $service->id ? 'class="active"' : '')?>>
81 81 <a href="<?=Url::current(['service_id' => $service->id])?>"><span><?=$service->title?></span></a></li>
... ...