├── .gitignore ├── assets ├── source │ ├── img │ │ └── img_no-image.png │ ├── css │ │ ├── imagemanager.input.css │ │ ├── imagemanager.module.css │ │ └── cropper.min.css │ └── js │ │ ├── script.imagemanager.input.js │ │ ├── script.imagemanager.module.js │ │ └── cropper.min.js ├── ImageManagerInputAsset.php └── ImageManagerModuleAsset.php ├── docs └── images │ ├── img_doc-image-manager.jpg │ ├── img_doc-image-widget.jpg │ ├── img_doc-image-manager-crop.jpg │ └── img_doc-image-widget-popup.jpg ├── views ├── manager │ ├── _item.php │ └── index.php ├── default │ └── index.php └── layouts │ └── blank.php ├── controllers ├── DefaultController.php └── ManagerController.php ├── migrations ├── m170223_113221_addBlameableBehavior.php └── m160622_085710_create_ImageManager_table.php ├── messages ├── ru │ └── imagemanager.php ├── en │ └── imagemanager.php ├── it │ └── imagemanager.php ├── fr │ └── imagemanager.php ├── de │ └── imagemanager.php ├── pt-BR │ └── imagemanager.php └── nl │ └── imagemanager.php ├── composer.json ├── LICENSE ├── models ├── ImageManagerSearch.php └── ImageManager.php ├── components ├── ImageManagerGetPath.php └── ImageManagerInputWidget.php ├── README.md ├── Module.php └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject 2 | /.idea/ 3 | /vendor/ -------------------------------------------------------------------------------- /assets/source/img/img_no-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noam148/yii2-image-manager/HEAD/assets/source/img/img_no-image.png -------------------------------------------------------------------------------- /docs/images/img_doc-image-manager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noam148/yii2-image-manager/HEAD/docs/images/img_doc-image-manager.jpg -------------------------------------------------------------------------------- /docs/images/img_doc-image-widget.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noam148/yii2-image-manager/HEAD/docs/images/img_doc-image-widget.jpg -------------------------------------------------------------------------------- /docs/images/img_doc-image-manager-crop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noam148/yii2-image-manager/HEAD/docs/images/img_doc-image-manager-crop.jpg -------------------------------------------------------------------------------- /docs/images/img_doc-image-widget-popup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noam148/yii2-image-manager/HEAD/docs/images/img_doc-image-widget-popup.jpg -------------------------------------------------------------------------------- /views/manager/_item.php: -------------------------------------------------------------------------------- 1 |
2 | <?=$model->fileName?> 3 |
fileName?>
4 |
5 | -------------------------------------------------------------------------------- /views/default/index.php: -------------------------------------------------------------------------------- 1 | title = "Image manager"; 3 | ?> 4 |
5 |

Welcome to image manager

6 |

Install run migrate:

7 |

yii migrate --migrationPath=@noam148/imagemanager/migrations

8 | 9 |

By noam148

10 |
11 | -------------------------------------------------------------------------------- /controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | render('index'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /assets/source/css/imagemanager.input.css: -------------------------------------------------------------------------------- 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; } -------------------------------------------------------------------------------- /assets/ImageManagerInputAsset.php: -------------------------------------------------------------------------------- 1 | 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 | $this->dropColumn('{{%ImageManager}}', 'createdBy'); 16 | $this->dropColumn('{{%ImageManager}}', 'modifiedBy'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /assets/ImageManagerModuleAsset.php: -------------------------------------------------------------------------------- 1 | 'Вы действительно хотите удалить изображение?', 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 | ]; 18 | -------------------------------------------------------------------------------- /messages/en/imagemanager.php: -------------------------------------------------------------------------------- 1 | '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 | ]; 18 | -------------------------------------------------------------------------------- /messages/it/imagemanager.php: -------------------------------------------------------------------------------- 1 | 'Vuole veramente eliminare questa immagine?', 4 | 'Are you sure you want to detach the image?' => 'Vuole distaccare questa immagine?', 5 | 'Cancel' => 'Annulla', 6 | 'Created' => 'Creato', 7 | 'Crop' => 'Ritaglia', 8 | 'Crop and select' => 'Ritaglia e seleziona', 9 | 'Delete' => 'Elimina', 10 | 'File hash' => 'File hash', 11 | 'File name' => 'Nome del file', 12 | 'Modified' => 'Modificato', 13 | 'Search' => 'Cerca', 14 | 'Select' => 'Seleziona', 15 | 'Image manager' => 'Image manager', 16 | 'Upload' => 'Carica' 17 | ]; -------------------------------------------------------------------------------- /messages/fr/imagemanager.php: -------------------------------------------------------------------------------- 1 | '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 | ]; 18 | -------------------------------------------------------------------------------- /messages/de/imagemanager.php: -------------------------------------------------------------------------------- 1 | '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 | ]; 18 | -------------------------------------------------------------------------------- /messages/pt-BR/imagemanager.php: -------------------------------------------------------------------------------- 1 | 'Você tem certeza que gostaria de excluir a imagem?', 4 | 'Are you sure you want to detach the image?' => 'Você tem certeza que gostaria de desanexar a imagem?', 5 | 'Cancel' => 'Cancelar', 6 | 'Created' => 'Criado', 7 | 'Crop' => 'Cortar', 8 | 'Crop and select' => 'Cortar e Selecionar', 9 | 'Delete' => 'Deletar', 10 | 'File hash' => 'Hash do Arquivo', 11 | 'File name' => 'Nome do Arquivo', 12 | 'Modified' => 'Modificado', 13 | 'Search' => 'Pesquisar', 14 | 'Select' => 'Selecionar', 15 | 'Image manager' => 'Gerenciador de Imagens', 16 | 'Upload' => 'Upload' 17 | ]; 18 | -------------------------------------------------------------------------------- /views/layouts/blank.php: -------------------------------------------------------------------------------- 1 | 9 | beginPage() ?> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <?= Html::encode($this->title) ?> 18 | head() ?> 19 | 20 | 21 | beginBody() ?> 22 | 23 | 24 | 25 | endBody() ?> 26 | 27 | 28 | endPage() ?> 29 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 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 | } 25 | -------------------------------------------------------------------------------- /messages/nl/imagemanager.php: -------------------------------------------------------------------------------- 1 | '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 | ]; -------------------------------------------------------------------------------- /migrations/m160622_085710_create_ImageManager_table.php: -------------------------------------------------------------------------------- 1 | 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 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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. 22 | -------------------------------------------------------------------------------- /models/ImageManagerSearch.php: -------------------------------------------------------------------------------- 1 | $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 | } 80 | -------------------------------------------------------------------------------- /assets/source/css/imagemanager.module.css: -------------------------------------------------------------------------------- 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; } -------------------------------------------------------------------------------- /assets/source/js/script.imagemanager.input.js: -------------------------------------------------------------------------------- 1 | var imageManagerInput = { 2 | baseUrl: null, 3 | //language 4 | message: null, 5 | //init imageManagerInput 6 | init: function(){ 7 | //create modal 8 | imageManagerInput.initModal(); 9 | }, 10 | //creat image Manager modal 11 | initModal: function(){ 12 | //check if modal not jet exists 13 | if($("#modal-imagemanager").length === 0){ 14 | //set html modal in var 15 | var sModalHtml = ''; 28 | //prepend data to body 29 | $('body').prepend(sModalHtml); 30 | } 31 | }, 32 | //open media manager modal 33 | openModal: function(inputId, aspectRatio, cropViewMode){ 34 | //get selected item 35 | var iImageId = $("#"+inputId).val(); 36 | var srcImageIdQueryString = ""; 37 | if(iImageId !== ""){ 38 | srcImageIdQueryString = "&image-id="+iImageId; 39 | } 40 | //create iframe url 41 | var queryStringStartCharacter = ((imageManagerInput.baseUrl).indexOf('?') == -1) ? '?' : '&'; 42 | var imageManagerUrl = imageManagerInput.baseUrl+queryStringStartCharacter+"view-mode=iframe&input-id="+inputId+"&aspect-ratio="+aspectRatio+"&crop-view-mode="+cropViewMode+srcImageIdQueryString; 43 | //set iframe path 44 | $("#modal-imagemanager iframe").attr("src",imageManagerUrl); 45 | //set translation title for modal header 46 | $("#modal-imagemanager .modal-dialog .modal-header h4").text(imageManagerInput.message.imageManager); 47 | //open modal 48 | $("#modal-imagemanager").modal("show"); 49 | }, 50 | //close media manager modal 51 | closeModal: function(){ 52 | $("#modal-imagemanager").modal("hide"); 53 | }, 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($(".delete-selected-image[data-input-id='"+inputId+"']").data("show-delete-confirm")); 61 | //show warning if bShowConfirm == true 62 | if(bShowConfirm){ 63 | if(confirm(imageManagerInput.message.detachWarningMessage) == false){ 64 | return false; 65 | } 66 | } 67 | //set input data 68 | $('#'+sFieldId).val(""); 69 | $('#'+sFieldNameId).val(""); 70 | //trigger change 71 | $('#'+sFieldId).trigger("change"); 72 | //hide image 73 | $('#'+sImagePreviewId).attr("src","").parent().addClass("hide"); 74 | //delete hide class 75 | $(".delete-selected-image[data-input-id='"+inputId+"']").addClass("hide"); 76 | } 77 | }; 78 | 79 | $(document).ready(function () { 80 | //init Image manage 81 | imageManagerInput.init(); 82 | 83 | //open media manager modal 84 | $(document).on("click", ".open-modal-imagemanager", function () { 85 | var aspectRatio = $(this).data("aspect-ratio"); 86 | var cropViewMode = $(this).data("crop-view-mode"); 87 | var inputId = $(this).data("input-id"); 88 | //open selector id 89 | imageManagerInput.openModal(inputId, aspectRatio, cropViewMode); 90 | }); 91 | 92 | //delete picked image 93 | $(document).on("click", ".delete-selected-image", function () { 94 | var inputId = $(this).data("input-id"); 95 | //open selector id 96 | imageManagerInput.deletePickedImage(inputId); 97 | }); 98 | }); -------------------------------------------------------------------------------- /assets/source/css/cropper.min.css: -------------------------------------------------------------------------------- 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} -------------------------------------------------------------------------------- /views/manager/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('imagemanager','Image manager'); 9 | 10 | ?> 11 |
12 |
13 |
14 |
15 |
16 | 17 |
18 | 34 |
35 |
36 |
37 | 'pjax-mediamanager', 39 | 'timeout'=>'5000' 40 | ]); ?> 41 | $dataProvider, 43 | 'itemOptions' => ['class' => 'item img-thumbnail'], 44 | 'layout' => "
{items}
{pager}", 45 | 'itemView' => function ($model, $key, $index, $widget) { 46 | return $this->render("_item", ['model' => $model]); 47 | }, 48 | ]) ?> 49 | 50 |
51 |
52 |
53 | 'input-mediamanager-search', 'class'=>'form-control', 'placeholder'=>Yii::t('imagemanager','Search').'...'])?> 54 |
55 | 56 | controller->module->canUploadImage): 58 | ?> 59 | 60 | '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' => ' ', 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 | 91 | 92 |
93 |
94 | 95 |
96 | 102 |
103 |
104 |
105 |
106 |
×
107 | controller->module->canRemoveImage): 109 | ?> 110 | 111 | 114 |
115 | 116 | 117 | 118 |
119 |
120 |
121 |
-------------------------------------------------------------------------------- /components/ImageManagerGetPath.php: -------------------------------------------------------------------------------- 1 | db 37 | * If this component is not set, the model will default to DB 38 | */ 39 | public $databaseComponent = 'db'; 40 | 41 | /** 42 | * Init set config 43 | */ 44 | public function init() { 45 | parent::init(); 46 | 47 | // If cachePath is not an array? Create an array 48 | if(!is_array($this->cachePath)){ 49 | $this->cachePath = [$this->cachePath]; 50 | } 51 | 52 | // Initialize the compontent with the configuration loaded from config.php 53 | \Yii::$app->set('imageresize', [ 54 | 'class' => 'noam148\imageresize\ImageResize', 55 | 'cachePath' => $this->cachePath, 56 | 'useFilename' => $this->useFilename, 57 | 'absoluteUrl' => $this->absoluteUrl, 58 | ]); 59 | 60 | if (is_callable($this->databaseComponent)) { 61 | // The database component is callable, run the user function 62 | $this->databaseComponent = call_user_func($this->databaseComponent); 63 | } 64 | 65 | // Check if the user input is correct 66 | $this->_checkVariables(); 67 | } 68 | 69 | /** 70 | * Get the path for the given ImageManager_id record 71 | * @param int $ImageManager_id ImageManager record for which the path needs to be generated 72 | * @param int $width Thumbnail image width 73 | * @param int $height Thumbnail image height 74 | * @param string $thumbnailMode Thumbnail mode 75 | * @return null|string Full path is returned when image is found, null if no image could be found 76 | */ 77 | public function getImagePath($ImageManager_id, $width = 400, $height = 400, $thumbnailMode = "outbound") { 78 | //default return 79 | $return = null; 80 | $mImageManager = ImageManager::findOne($ImageManager_id); 81 | 82 | //check if not empty 83 | if ($mImageManager !== null) { 84 | 85 | $sMediaPath = null; 86 | if ($this->mediaPath !== null) { 87 | $sMediaPath = $this->mediaPath; 88 | } 89 | 90 | $sFileExtension = pathinfo($mImageManager->fileName, PATHINFO_EXTENSION); 91 | //get image file path 92 | $sImageFilePath = $sMediaPath . '/' . $mImageManager->id . '_' . $mImageManager->fileHash . '.' . $sFileExtension; 93 | //check file exists 94 | if (file_exists($sImageFilePath)) { 95 | $return = \Yii::$app->imageresize->getUrl($sImageFilePath, $width, $height, $thumbnailMode, null, $mImageManager->fileName); 96 | } else { 97 | $return = null; //isset(\Yii::$app->controller->module->assetPublishedUrl) ? \Yii::$app->controller->module->assetPublishedUrl. "/img/img_no-image.png" : null; 98 | } 99 | } 100 | return $return; 101 | } 102 | 103 | /** 104 | * Check if the user configurable variables match the criteria 105 | * @throws InvalidConfigException 106 | */ 107 | private function _checkVariables() { 108 | // Check to make sure that the $databaseComponent is a string 109 | if (! is_string($this->databaseComponent)) { 110 | throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' is not a string"); 111 | } 112 | 113 | // Check to make sure that the $databaseComponent object exists 114 | if (Yii::$app->get($this->databaseComponent, false) === null) { 115 | throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' does not exists in application configuration"); 116 | } 117 | 118 | // Check to make sure that the $databaseComponent is a yii\db\Connection object 119 | if (($databaseComponentClassName = get_class(Yii::$app->get($this->databaseComponent))) !== ($connectionClassName = Connection::className())) { 120 | throw new InvalidConfigException("Image Manager Component - Init: Database component '$this->databaseComponent' is not of type '$connectionClassName' instead it is '$databaseComponentClassName'"); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /components/ImageManagerInputWidget.php: -------------------------------------------------------------------------------- 1 | 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 = "
"; 60 | $field .= "
"; 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 .= ""; 85 | $field .= ""; 86 | $field .= ""; 87 | $field .= "
"; 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 .= '
' 95 | . 'Thumbnail' 96 | . '
'; 97 | } 98 | 99 | //close image-manager-input div 100 | $field .= "
"; 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 | } 125 | -------------------------------------------------------------------------------- /models/ImageManager.php: -------------------------------------------------------------------------------- 1 | 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 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | !!! Sorry, the module is no longer maintained by me anymore !!! 2 | - 3 | !!! Feel free to further develop the module !!! 4 | - 5 | 6 | Image manager for Yii2 7 | ======================== 8 | 9 | A Yii2 module/widget for upload, manage and cropping images 10 | 11 | Installation 12 | ------------ 13 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 14 | 15 | * Either run 16 | 17 | ``` 18 | php composer.phar require "noam148/yii2-image-manager" "*" 19 | ``` 20 | or add 21 | 22 | ```json 23 | "noam148/yii2-image-manager" : "*" 24 | ``` 25 | 26 | to the require section of your application's `composer.json` file. 27 | 28 | * Run the migrate to create the ImageManager table 29 | ``` 30 | yii migrate --migrationPath=@noam148/imagemanager/migrations 31 | ``` 32 | 33 | * Add a new component in `components` section of your application's configuration file, for example: 34 | 35 | ```php 36 | 'components' => [ 37 | 'imagemanager' => [ 38 | 'class' => 'noam148\imagemanager\components\ImageManagerGetPath', 39 | //set media path (outside the web folder is possible) 40 | 'mediaPath' => '/path/where/to/store/images/media/imagemanager', 41 | //path relative web folder. In case of multiple environments (frontend, backend) add more paths 42 | 'cachePath' => ['assets/images', '../../frontend/web/assets/images'], 43 | //use filename (seo friendly) for resized images else use a hash 44 | 'useFilename' => true, 45 | //show full url (for example in case of a API) 46 | 'absoluteUrl' => false, 47 | 'databaseComponent' => 'db' // The used database component by the image manager, this defaults to the Yii::$app->db component 48 | ], 49 | ], 50 | ``` 51 | 52 | and in `modules` section, for example: 53 | 54 | ```php 55 | 'modules' => [ 56 | 'imagemanager' => [ 57 | 'class' => 'noam148\imagemanager\Module', 58 | //set accces rules () 59 | 'canUploadImage' => true, 60 | 'canRemoveImage' => function(){ 61 | return true; 62 | }, 63 | 'deleteOriginalAfterEdit' => false, // false: keep original image after edit. true: delete original image after edit 64 | // Set if blameable behavior is used, if it is, callable function can also be used 65 | 'setBlameableBehavior' => false, 66 | //add css files (to use in media manage selector iframe) 67 | 'cssFiles' => [ 68 | 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css', 69 | ], 70 | ], 71 | ], 72 | ``` 73 | 74 | Usage 75 | ----- 76 | To reach the imagemanager module go to: 77 | ``` 78 | http://www.example.com/imagemanager 79 | ``` 80 | ![Image manager module](/docs/images/img_doc-image-manager.jpg) 81 | ![Image manager module cropper](/docs/images/img_doc-image-manager-crop.jpg) 82 | 83 | 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): 84 | 85 | ```php 86 | echo $form->field($model, 'ImageManager_id_avatar')->widget(\noam148\imagemanager\components\ImageManagerInputWidget::className(), [ 87 | 'aspectRatio' => (16/9), //set the aspect ratio 88 | 'cropViewMode' => 1, //crop mode, option info: https://github.com/fengyuanchen/cropper/#viewmode 89 | 'showPreview' => true, //false to hide the preview 90 | 'showDeletePickedImageConfirm' => false, //on true show warning before detach image 91 | ]); 92 | ``` 93 | ![Image widget](/docs/images/img_doc-image-widget.jpg) 94 | ![Image widget popup](/docs/images/img_doc-image-widget-popup.jpg) 95 | 96 | If you want to use a image: 97 | 98 | ```php 99 | /* 100 | * $ImageManager_id (id that is store in the ImageManager table) 101 | * $width/$height width height of the image 102 | * $thumbnailMode: "outbound", "inset" or "{horz}:{vert}" where {horz} is one from "left", "center", "right" and {vert} is one from "top", "center", "bottom" 103 | */ 104 | \Yii::$app->imagemanager->getImagePath($ImageManager_id, $width, $height,$thumbnailMode) 105 | ``` 106 | 107 | Support CKEditor & TinyMce 108 | ----- 109 | 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. 110 | 111 | ```php 112 | use dosamigos\ckeditor\CKEditor; 113 | 114 | echo $form->field($model, 'text')->widget(CKEditor::className(), [ 115 | 'options' => ['rows' => 6], 116 | 'preset' => 'basic', 117 | 'clientOptions' => [ 118 | 'filebrowserImageBrowseUrl' => yii\helpers\Url::to(['imagemanager/manager', 'view-mode'=>'iframe', 'select-type'=>'ckeditor']), 119 | ] 120 | ]); 121 | ``` 122 | 123 | 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) 124 | 125 | ```php 126 | use dosamigos\tinymce\TinyMce; 127 | 128 | echo $form->field($model, 'text')->widget(TinyMce::className(), [ 129 | 'options' => ['rows' => 6], 130 | 'language' => 'nl', 131 | 'clientOptions' => [ 132 | 'file_browser_callback' => new yii\web\JsExpression("function(field_name, url, type, win) { 133 | 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'); 134 | }"), 135 | 'plugins' => [ 136 | "advlist autolink lists link charmap print preview anchor", 137 | "searchreplace visualblocks code fullscreen", 138 | "insertdatetime media table contextmenu paste image" 139 | ], 140 | 'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" 141 | ] 142 | ]); 143 | ``` 144 | -------------------------------------------------------------------------------- /Module.php: -------------------------------------------------------------------------------- 1 | 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 | } 140 | -------------------------------------------------------------------------------- /assets/source/js/script.imagemanager.module.js: -------------------------------------------------------------------------------- 1 | var imageManagerModule = { 2 | //params for input selector 3 | fieldId: null, 4 | cropRatio: null, 5 | cropViewMode: 1, 6 | defaultImageId: null, 7 | selectType: null, 8 | //current selected image 9 | selectedImage: null, 10 | //language 11 | message: null, 12 | //init imageManager 13 | init: function(){ 14 | //init cropper 15 | $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper').cropper({ 16 | viewMode: imageManagerModule.cropViewMode 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').on('pjax:complete', function() { 26 | if(imageManagerModule.selectedImage !== null){ 27 | imageManagerModule.selectImage(imageManagerModule.selectedImage.id); 28 | } 29 | }); 30 | }, 31 | //filter result 32 | filterImageResult: function(searchTerm){ 33 | //set new url 34 | var newUrl = window.queryStringParameter.set(window.location.href, "ImageManagerSearch[globalSearch]", searchTerm); 35 | //set pjax 36 | $.pjax({url: newUrl, container: "#pjax-mediamanager", push: false, replace: false, timeout: 5000, scrollTo:false}); 37 | }, 38 | //select an image 39 | selectImage: function(id){ 40 | //set selected class 41 | $("#module-imagemanager .item-overview .item").removeClass("selected"); 42 | $("#module-imagemanager .item-overview .item[data-key='"+id+"']").addClass("selected"); 43 | //get details 44 | imageManagerModule.getDetails(id); 45 | }, 46 | //pick the selected image 47 | pickImage: function(){ 48 | //switch between select type 49 | switch(imageManagerModule.selectType){ 50 | //default widget selector 51 | case "input": 52 | //get id data 53 | var sFieldId = imageManagerModule.fieldId; 54 | var sFieldNameId = sFieldId+"_name"; 55 | var sFieldImageId = sFieldId+"_image"; 56 | //set input data 57 | $('#'+sFieldId, window.parent.document).val(imageManagerModule.selectedImage.id); 58 | $('#'+sFieldNameId, window.parent.document).val(imageManagerModule.selectedImage.fileName); 59 | $('#'+sFieldImageId, window.parent.document).attr("src",imageManagerModule.selectedImage.image).parent().removeClass("hide"); 60 | //trigger change 61 | parent.$('#'+sFieldId).trigger('change'); 62 | //show delete button 63 | $(".delete-selected-image[data-input-id='"+sFieldId+"']", window.parent.document).removeClass("hide"); 64 | //close the modal 65 | window.parent.imageManagerInput.closeModal(); 66 | break; 67 | //CKEditor selector 68 | case "ckeditor": 69 | //TinyMCE Selector 70 | case "tinymce": 71 | //check if isset image 72 | if(imageManagerModule.selectedImage !== null){ 73 | //call action by ajax 74 | $.ajax({ 75 | url: imageManagerModule.baseUrl+"/get-original-image", 76 | type: "POST", 77 | data: { 78 | ImageManager_id: imageManagerModule.selectedImage.id, 79 | _csrf: $('meta[name=csrf-token]').prop('content') 80 | }, 81 | dataType: "json", 82 | success: function (responseData, textStatus, jqXHR) { 83 | //set attributes for each selector 84 | if(imageManagerModule.selectType == "ckeditor"){ 85 | var sField = window.queryStringParameter.get(window.location.href, "CKEditorFuncNum"); 86 | window.top.opener.CKEDITOR.tools.callFunction(sField, responseData); 87 | window.self.close(); 88 | }else if(imageManagerModule.selectType == "tinymce"){ 89 | var sField = window.queryStringParameter.get(window.location.href, "tag_name"); 90 | window.opener.document.getElementById(sField).value = responseData; 91 | window.close(); 92 | window.opener.focus(); 93 | } 94 | }, 95 | error: function (jqXHR, textStatus, errorThrown) { 96 | alert("Error: can't get item"); 97 | } 98 | }); 99 | }else{ 100 | alert("Error: image can't picked"); 101 | } 102 | break; 103 | } 104 | 105 | 106 | }, 107 | //delete the selected image 108 | deleteSelectedImage: function(){ 109 | //confirm message 110 | if(confirm(imageManagerModule.message.deleteMessage)){ 111 | //close editor 112 | imageManagerModule.editor.close(); 113 | //check if isset image 114 | if(imageManagerModule.selectedImage !== null){ 115 | //call action by ajax 116 | $.ajax({ 117 | url: imageManagerModule.baseUrl+"/delete", 118 | type: "POST", 119 | data: { 120 | ImageManager_id: imageManagerModule.selectedImage.id, 121 | _csrf: $('meta[name=csrf-token]').prop('content') 122 | }, 123 | dataType: "json", 124 | success: function (responseData, textStatus, jqXHR) { 125 | //check if delete is true 126 | if(responseData.delete === true){ 127 | //delete item element 128 | $("#module-imagemanager .item-overview .item[data-key='"+imageManagerModule.selectedImage.id+"']").remove(); 129 | //add hide class to info block 130 | $("#module-imagemanager .image-info").addClass("hide"); 131 | //set selectedImage to null 132 | imageManagerModule.selectedImage = null; 133 | //close edit 134 | }else{ 135 | alert("Error: item is not deleted"); 136 | } 137 | }, 138 | error: function (jqXHR, textStatus, errorThrown) { 139 | alert("Error: can't delete item"); 140 | } 141 | }); 142 | }else{ 143 | alert("Error: image can't delete, no image isset set"); 144 | } 145 | } 146 | }, 147 | //get image details 148 | getDetails: function(id, pickAfterGetDetails){ 149 | //set propertie if not set 150 | pickAfterGetDetails = pickAfterGetDetails !== undefined ? pickAfterGetDetails : false; 151 | //call action by ajax 152 | $.ajax({ 153 | url: imageManagerModule.baseUrl+"/view", 154 | type: "POST", 155 | data: { 156 | ImageManager_id: id, 157 | _csrf: $('meta[name=csrf-token]').prop('content') 158 | }, 159 | dataType: "json", 160 | success: function (responseData, textStatus, jqXHR) { 161 | //set imageManagerModule.selectedImage property 162 | imageManagerModule.selectedImage = responseData; 163 | 164 | //if need to pick image? 165 | if(pickAfterGetDetails){ 166 | imageManagerModule.pickImage(); 167 | //else set data 168 | }else{ 169 | //set text elements 170 | $("#module-imagemanager .image-info .fileName").text(responseData.fileName).attr("title",responseData.fileName); 171 | $("#module-imagemanager .image-info .created").text(responseData.created); 172 | $("#module-imagemanager .image-info .fileSize").text(responseData.fileSize); 173 | $("#module-imagemanager .image-info .dimensions .dimension-width").text(responseData.dimensionWidth); 174 | $("#module-imagemanager .image-info .dimensions .dimension-height").text(responseData.dimensionHeight); 175 | $("#module-imagemanager .image-info .thumbnail").html(""+responseData.fileName+""); 176 | //remove hide class 177 | $("#module-imagemanager .image-info").removeClass("hide"); 178 | } 179 | }, 180 | error: function (jqXHR, textStatus, errorThrown) { 181 | alert("Can't view image. Error: "+jqXHR.responseText); 182 | } 183 | }); 184 | }, 185 | //upload file 186 | uploadSuccess: function(uploadResponse){ 187 | //close editor 188 | imageManagerModule.editor.close(); 189 | //reload pjax container 190 | $.pjax.reload('#pjax-mediamanager', {push: false, replace: false, timeout: 5000, scrollTo: false}); 191 | }, 192 | //editor functions 193 | editor: { 194 | //open editor block 195 | open: function(){ 196 | //show editer / hide overview 197 | $("#module-imagemanager > .row .col-image-editor").show(); 198 | $("#module-imagemanager > .row .col-overview").hide(); 199 | }, 200 | //close editor block 201 | close: function(){ 202 | //show overview / hide editer 203 | $("#module-imagemanager > .row .col-overview").show(); 204 | $("#module-imagemanager > .row .col-image-editor").hide(); 205 | }, 206 | //open cropper 207 | openCropper: function(){ 208 | //check if isset image 209 | if(imageManagerModule.selectedImage !== null){ 210 | //call action by ajax 211 | $.ajax({ 212 | url: imageManagerModule.baseUrl+"/get-original-image", 213 | type: "POST", 214 | data: { 215 | ImageManager_id: imageManagerModule.selectedImage.id, 216 | _csrf: $('meta[name=csrf-token]').prop('content') 217 | }, 218 | dataType: "json", 219 | success: function (responseData, textStatus, jqXHR) { 220 | //hide cropper 221 | $("#module-imagemanager > .row .col-image-cropper").css("visibility","hidden"); 222 | //set image in cropper 223 | $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper').one('built.cropper', function () { 224 | //show cropper 225 | $("#module-imagemanager > .row .col-image-cropper").css("visibility","visible"); 226 | }) 227 | .cropper('reset') 228 | .cropper('setAspectRatio', parseFloat(imageManagerModule.cropRatio)) 229 | .cropper('replace', responseData); 230 | //open editor 231 | imageManagerModule.editor.open(); 232 | }, 233 | error: function (jqXHR, textStatus, errorThrown) { 234 | alert("Error: can't get item"); 235 | } 236 | }); 237 | }else{ 238 | alert("Error: image can't crop, no image isset set"); 239 | } 240 | }, 241 | //apply crop 242 | applyCrop: function(pickAfterCrop){ 243 | //set propertie if not set 244 | pickAfterCrop = pickAfterCrop !== undefined ? pickAfterCrop : false; 245 | //check if isset image 246 | if(imageManagerModule.selectedImage !== null){ 247 | //set image in cropper 248 | var oCropData = $('#module-imagemanager > .row .col-image-editor .image-cropper .image-wrapper img#image-cropper').cropper("getData"); 249 | //call action by ajax 250 | $.ajax({ 251 | url: imageManagerModule.baseUrl+"/crop", 252 | type: "POST", 253 | data: { 254 | ImageManager_id: imageManagerModule.selectedImage.id, 255 | CropData: oCropData, 256 | _csrf: $('meta[name=csrf-token]').prop('content') 257 | }, 258 | dataType: "json", 259 | success: function (responseData, textStatus, jqXHR) { 260 | //set cropped image 261 | if(responseData !== null){ 262 | //if pickAfterCrop is true? select directly else 263 | if(pickAfterCrop){ 264 | imageManagerModule.getDetails(responseData, true); 265 | //else select the image only 266 | }else{ 267 | //set new image 268 | imageManagerModule.selectImage(responseData); 269 | //reload pjax container 270 | $.pjax.reload('#pjax-mediamanager', {push: false, replace: false, timeout: 5000, scrollTo: false}); 271 | } 272 | } 273 | //close editor 274 | imageManagerModule.editor.close(); 275 | }, 276 | error: function (jqXHR, textStatus, errorThrown) { 277 | alert("Error: item is not cropped"); 278 | } 279 | }); 280 | }else{ 281 | alert("Error: image can't crop, no image isset set"); 282 | } 283 | } 284 | } 285 | }; 286 | 287 | $(document).ready(function () { 288 | //init Image manage 289 | imageManagerModule.init(); 290 | //on click select item (open view) 291 | $(document).on("click", "#module-imagemanager .item-overview .item", function (){ 292 | //get id 293 | var ImageManager_id = $(this).data("key"); 294 | //select image 295 | imageManagerModule.selectImage(ImageManager_id); 296 | }); 297 | //on click pick image 298 | $(document).on("click", "#module-imagemanager .image-info .pick-image-item", function (){ 299 | imageManagerModule.pickImage(); 300 | return false; 301 | }); 302 | //on click delete call "delete" 303 | $(document).on("click", "#module-imagemanager .image-info .delete-image-item", function (){ 304 | imageManagerModule.deleteSelectedImage(); 305 | return false; 306 | }); 307 | //on click crop call "crop" 308 | $(document).on("click", "#module-imagemanager .image-info .crop-image-item", function (){ 309 | imageManagerModule.editor.openCropper(); 310 | return false; 311 | }); 312 | //on click apply crop 313 | $(document).on("click", "#module-imagemanager .image-cropper .apply-crop", function (){ 314 | imageManagerModule.editor.applyCrop(); 315 | return false; 316 | }); 317 | //on click apply crop 318 | $(document).on("click", "#module-imagemanager .image-cropper .apply-crop-select", function (){ 319 | imageManagerModule.editor.applyCrop(true); 320 | return false; 321 | }); 322 | //on click cancel crop 323 | $(document).on("click", "#module-imagemanager .image-cropper .cancel-crop", function (){ 324 | imageManagerModule.editor.close(); 325 | return false; 326 | }); 327 | //on keyup change set filter 328 | $( document ).on("keyup change", "#input-mediamanager-search", function() { 329 | imageManagerModule.filterImageResult($(this).val()); 330 | }); 331 | 332 | }); 333 | 334 | /* 335 | * return new get param to url 336 | */ 337 | window.queryStringParameter = { 338 | get: function(uri, key){ 339 | var reParam = new RegExp('(?:[\?&]|&)' + key + '=([^&]+)', 'i'); 340 | var match = uri.match(reParam); 341 | return (match && match.length > 1) ? match[1] : null; 342 | }, 343 | set: function(uri, key, value){ 344 | //replace brackets 345 | var keyReplace = key.replace("[]", "").replace(/\[/g, "%5B").replace(/\]/g, "%5D"); 346 | //replace data 347 | var re = new RegExp("([?&])" + keyReplace + "=.*?(&|$)", "i"); 348 | var separator = uri.indexOf('?') !== -1 ? "&" : "?"; 349 | if (uri.match(re)) { 350 | return uri.replace(re, '$1' + keyReplace + "=" + value + '$2'); 351 | } 352 | else { 353 | return uri + separator + keyReplace + "=" + value; 354 | } 355 | } 356 | }; -------------------------------------------------------------------------------- /controllers/ManagerController.php: -------------------------------------------------------------------------------- 1 | [ 35 | 'class' => VerbFilter::className(), 36 | 'actions' => [ 37 | 'delete' => ['POST'], 38 | ], 39 | ], 40 | ]; 41 | } 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public function beforeAction($action) { 47 | //disable CSRF Validation 48 | $this->enableCsrfValidation = false; 49 | return parent::beforeAction($action); 50 | } 51 | 52 | /** 53 | * Lists all ImageManager models. 54 | * @return mixed 55 | */ 56 | public function actionIndex() { 57 | //set asset 58 | ImageManagerModuleAsset::register($this->view); 59 | 60 | //get iframe parameters 61 | $viewMode = Yii::$app->request->get("view-mode", "page"); 62 | $selectType = Yii::$app->request->get("select-type", "input"); 63 | $inputFieldId = Yii::$app->request->get("input-id"); 64 | $cropAspectRatio = Yii::$app->request->get("aspect-ratio"); 65 | $cropViewMode = Yii::$app->request->get("crop-view-mode", 1); 66 | $defaultImageId = Yii::$app->request->get("image-id"); 67 | 68 | //set blank layout if viewMode = iframe 69 | if ($viewMode == "iframe") { 70 | //set layout 71 | $this->layout = "blank"; 72 | 73 | //set stylesheet for modal 74 | $aCssFiles = \Yii::$app->controller->module->cssFiles; 75 | if (is_array($aCssFiles) && count($aCssFiles) > 0) { 76 | //if exists loop through files and add them to iframe mode 77 | foreach ($aCssFiles AS $cssFile) { 78 | //registrate file 79 | $this->view->registerCssFile($cssFile, ['depends' => 'yii\bootstrap\BootstrapAsset']); 80 | } 81 | } 82 | } 83 | 84 | //set baseUrl from image manager 85 | $sBaseUrl = Url::to(['/imagemanager/manager']); 86 | //set base url 87 | $this->view->registerJs("imageManagerModule.baseUrl = '" . $sBaseUrl . "';", 3); 88 | $this->view->registerJs("imageManagerModule.defaultImageId = '" . $defaultImageId . "';", 3); 89 | $this->view->registerJs("imageManagerModule.fieldId = '" . $inputFieldId . "';", 3); 90 | $this->view->registerJs("imageManagerModule.cropRatio = '" . $cropAspectRatio . "';", 3); 91 | $this->view->registerJs("imageManagerModule.cropViewMode = '" . $cropViewMode . "';", 3); 92 | $this->view->registerJs("imageManagerModule.selectType = '" . $selectType . "';", 3); 93 | $this->view->registerJs("imageManagerModule.message = " . Json::encode([ 94 | 'deleteMessage' => Yii::t('imagemanager', 'Are you sure you want to delete this image?'), 95 | ]) . ";", 3); 96 | 97 | $searchModel = new ImageManagerSearch(); 98 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 99 | 100 | //render template 101 | return $this->render( 102 | 'index', [ 103 | 'searchModel' => $searchModel, 104 | 'dataProvider' => $dataProvider, 105 | 'viewMode' => $viewMode, 106 | 'selectType' => $selectType, 107 | ]); 108 | } 109 | 110 | /** 111 | * Creates a new ImageManager model. 112 | * If creation is successful, the browser will be redirected to the 'view' page. 113 | * @return mixed 114 | */ 115 | public function actionUpload() { 116 | //set response header 117 | Yii::$app->getResponse()->format = Response::FORMAT_JSON; 118 | // Check if the user is allowed to upload the image 119 | if (Yii::$app->controller->module->canUploadImage == false) { 120 | // Return the response array to prevent from the action being executed any further 121 | return []; 122 | } 123 | // Create the transaction and set the success variable 124 | $transaction = Yii::$app->db->beginTransaction(); 125 | $bSuccess = false; 126 | 127 | //disable Csrf 128 | Yii::$app->controller->enableCsrfValidation = false; 129 | //return default 130 | $return = $_FILES; 131 | //set media path 132 | $sMediaPath = \Yii::$app->imagemanager->mediaPath; 133 | //create the folder 134 | BaseFileHelper::createDirectory($sMediaPath); 135 | 136 | //check file isset 137 | if (isset($_FILES['imagemanagerFiles']['tmp_name'])) { 138 | //loop through each uploaded file 139 | foreach ($_FILES['imagemanagerFiles']['tmp_name'] AS $key => $sTempFile) { 140 | //collect variables 141 | $sFileName = $_FILES['imagemanagerFiles']['name'][$key]; 142 | $sFileExtension = pathinfo($sFileName, PATHINFO_EXTENSION); 143 | $iErrorCode = $_FILES['imagemanagerFiles']['error'][$key]; 144 | //if uploaded file has no error code than continue; 145 | if ($iErrorCode == 0) { 146 | //create a file record 147 | $model = new ImageManager(); 148 | $model->fileName = str_replace("_", "-", $sFileName); 149 | $model->fileHash = Yii::$app->getSecurity()->generateRandomString(32); 150 | //if file is saved add record 151 | if ($model->save()) { 152 | //move file to dir 153 | $sSaveFileName = $model->id . "_" . $model->fileHash . "." . $sFileExtension; 154 | //move_uploaded_file($sTempFile, $sMediaPath."/".$sFileName); 155 | //save with Imagine class 156 | Image::getImagine()->open($sTempFile)->save($sMediaPath . "/" . $sSaveFileName); 157 | $bSuccess = true; 158 | } 159 | } 160 | } 161 | } 162 | 163 | if ($bSuccess) { 164 | // The upload action went successful, save the transaction 165 | $transaction->commit(); 166 | } else { 167 | // There where problems during the upload, kill the transaction 168 | $transaction->rollBack(); 169 | } 170 | 171 | //echo return json encoded 172 | return $return; 173 | } 174 | 175 | /** 176 | * Crop image and create new ImageManager model. 177 | * @return mixed 178 | */ 179 | public function actionCrop() { 180 | //return 181 | $return = null; 182 | //disable Csrf 183 | Yii::$app->controller->enableCsrfValidation = false; 184 | //set response header 185 | Yii::$app->getResponse()->format = Response::FORMAT_JSON; 186 | //set media path 187 | $sMediaPath = \Yii::$app->imagemanager->mediaPath; 188 | //get post 189 | $ImageManager_id = Yii::$app->request->post("ImageManager_id"); 190 | $aCropData = Yii::$app->request->post("CropData"); 191 | //get details 192 | $modelOriginal = $this->findModel($ImageManager_id); 193 | //check if path is not null 194 | if ($modelOriginal->imagePathPrivate !== null && $aCropData !== null) { 195 | //dimension 196 | $iDimensionWidth = round($aCropData['width']); 197 | $iDimensionHeight = round($aCropData['height']); 198 | //collect variables 199 | $sFileNameReplace = preg_replace("/_crop_\d+x\d+/", "", $modelOriginal->fileName); 200 | $sFileName = pathinfo($sFileNameReplace, PATHINFO_FILENAME); 201 | $sFileExtension = pathinfo($sFileNameReplace, PATHINFO_EXTENSION); 202 | $sDisplayFileName = $sFileName . "_crop_" . $iDimensionWidth . "x" . $iDimensionHeight . "." . $sFileExtension; 203 | 204 | //start transaction 205 | $transaction = Yii::$app->db->beginTransaction(); 206 | $bCropSuccess = false; 207 | 208 | //create a file record 209 | $model = new ImageManager(); 210 | $model->fileName = $sDisplayFileName; 211 | $model->fileHash = Yii::$app->getSecurity()->generateRandomString(32); 212 | //if file is saved add record 213 | if ($model->save()) { 214 | 215 | //do crop in try catch 216 | try { 217 | // create file name 218 | $sSaveFileName = $model->id . "_" . $model->fileHash . "." . $sFileExtension; 219 | 220 | // get current/original image data 221 | $imageOriginal = Image::getImagine()->open($modelOriginal->imagePathPrivate); 222 | $imageOriginalSize = $imageOriginal->getSize(); 223 | $imageOriginalWidth = $imageOriginalSize->getWidth(); 224 | $imageOriginalHeight = $imageOriginalSize->getHeight(); 225 | $imageOriginalPositionX = 0; 226 | $imageOriginalPositionY = 0; 227 | 228 | // create/calculate a canvas size (if canvas is out of the box) 229 | $imageCanvasWidth = $imageOriginalWidth; 230 | $imageCanvasHeight = $imageOriginalHeight; 231 | 232 | // update canvas width if X position of croparea is lower than 0 233 | if($aCropData['x'] < 0){ 234 | //set x postion to Absolute value 235 | $iAbsoluteXpos = abs($aCropData['x']); 236 | //set x position of image 237 | $imageOriginalPositionX = $iAbsoluteXpos; 238 | //add x position to canvas size 239 | $imageCanvasWidth += $iAbsoluteXpos; 240 | //update canvas width if croparea is biger than original image 241 | $iCropWidthWithoutAbsoluteXpos = ($aCropData['width'] - $iAbsoluteXpos); 242 | if($iCropWidthWithoutAbsoluteXpos > $imageOriginalWidth){ 243 | //add ouside the box width 244 | $imageCanvasWidth += ($iCropWidthWithoutAbsoluteXpos - $imageOriginalWidth); 245 | } 246 | } else { 247 | // add if crop partly ouside image 248 | $iCropWidthWithXpos = ($aCropData['width'] + $aCropData['x']); 249 | if($iCropWidthWithXpos > $imageOriginalWidth){ 250 | //add ouside the box width 251 | $imageCanvasWidth += ($iCropWidthWithXpos - $imageOriginalWidth); 252 | } 253 | } 254 | 255 | // update canvas height if Y position of croparea is lower than 0 256 | if($aCropData['y'] < 0){ 257 | //set y postion to Absolute value 258 | $iAbsoluteYpos = abs($aCropData['y']); 259 | //set y position of image 260 | $imageOriginalPositionY = $iAbsoluteYpos; 261 | //add y position to canvas size 262 | $imageCanvasHeight += $iAbsoluteYpos; 263 | //update canvas height if croparea is biger than original image 264 | $iCropHeightWithoutAbsoluteYpos = ($aCropData['height'] - $iAbsoluteYpos); 265 | if($iCropHeightWithoutAbsoluteYpos > $imageOriginalHeight){ 266 | //add ouside the box height 267 | $imageCanvasHeight += ($iCropHeightWithoutAbsoluteYpos - $imageOriginalHeight); 268 | } 269 | } else { 270 | // add if crop partly ouside image 271 | $iCropHeightWithYpos = ($aCropData['height'] + $aCropData['y']); 272 | if($iCropHeightWithYpos > $imageOriginalHeight){ 273 | //add ouside the box height 274 | $imageCanvasHeight += ($iCropHeightWithYpos - $imageOriginalHeight); 275 | } 276 | } 277 | 278 | // round values 279 | $imageCanvasWidthRounded = round($imageCanvasWidth); 280 | $imageCanvasHeightRounded = round($imageCanvasHeight); 281 | $imageOriginalPositionXRounded = round($imageOriginalPositionX); 282 | $imageOriginalPositionYRounded = round($imageOriginalPositionY); 283 | $imageCropWidthRounded = round($aCropData['width']); 284 | $imageCropHeightRounded = round($aCropData['height']); 285 | // set postion to 0 if x or y is less than 0 286 | $imageCropPositionXRounded = $aCropData['x'] < 0 ? 0 : round($aCropData['x']); 287 | $imageCropPositionYRounded = $aCropData['y'] < 0 ? 0 : round($aCropData['y']); 288 | 289 | // echo "canvas: ". $imageCanvasWidth ." x ".$imageCanvasHeight ."
"; 290 | // echo "img pos x: ". $imageOriginalPositionX ." y ".$imageOriginalPositionY ."
"; 291 | // die(); 292 | // 293 | //todo: check if rotaded resize canvas (http://stackoverflow.com/questions/9971230/calculate-rotated-rectangle-size-from-known-bounding-box-coordinates) 294 | 295 | // merge current image in canvas, crop image and save 296 | $imagineRgb = new RGB(); 297 | $imagineColor = $imagineRgb->color('#FFF', 0); 298 | // create image 299 | Image::getImagine()->create(new Box($imageCanvasWidthRounded, $imageCanvasHeightRounded), $imagineColor) 300 | ->paste($imageOriginal, new Point($imageOriginalPositionXRounded, $imageOriginalPositionYRounded)) 301 | ->crop(new Point($imageCropPositionXRounded, $imageCropPositionYRounded), new Box($imageCropWidthRounded, $imageCropHeightRounded)) 302 | ->save($sMediaPath . "/" . $sSaveFileName); 303 | 304 | //set boolean crop success to true 305 | $bCropSuccess = true; 306 | 307 | //set return id 308 | $return = $model->id; 309 | 310 | // Check if the original image must be delete 311 | if ($this->module->deleteOriginalAfterEdit) { 312 | $modelOriginal->delete(); 313 | } 314 | } catch (ErrorException $e) { 315 | 316 | } 317 | } 318 | 319 | //commit transaction if boolean is true 320 | if($bCropSuccess){ 321 | $transaction->commit(); 322 | } 323 | } 324 | 325 | //echo return json encoded 326 | return $return; 327 | } 328 | 329 | /** 330 | * Get view details 331 | * @return mixed 332 | */ 333 | public function actionView() { 334 | //disable Csrf 335 | Yii::$app->controller->enableCsrfValidation = false; 336 | //return default 337 | $return = []; 338 | //set response header 339 | Yii::$app->getResponse()->format = Response::FORMAT_JSON; 340 | //get post 341 | $ImageManager_id = Yii::$app->request->post("ImageManager_id"); 342 | //get details 343 | $model = $this->findModel($ImageManager_id); 344 | //set return details 345 | $return['id'] = $model->id; 346 | $return['fileName'] = $model->fileName; 347 | $return['created'] = Yii::$app->formatter->asDate($model->created); 348 | $return['fileSize'] = $model->imageDetails['size']; 349 | $return['dimensionWidth'] = $model->imageDetails['width']; 350 | $return['dimensionHeight'] = $model->imageDetails['height']; 351 | $return['image'] = \Yii::$app->imagemanager->getImagePath($model->id, 400, 400, "inset"); 352 | //add extra URL argument to prevent browser caching 353 | $return['image'] .= (strpos($return['image'], '?') === false ? '?' : '&' ) . "t=" . time(); 354 | 355 | //return json encoded 356 | return $return; 357 | } 358 | 359 | /** 360 | * Get full image 361 | * @return mixed 362 | */ 363 | public function actionGetOriginalImage() { 364 | //disable Csrf 365 | Yii::$app->controller->enableCsrfValidation = false; 366 | //set response header 367 | Yii::$app->getResponse()->format = Response::FORMAT_JSON; 368 | //get post 369 | $ImageManager_id = Yii::$app->request->post("ImageManager_id"); 370 | //get details 371 | $model = $this->findModel($ImageManager_id); 372 | //set return 373 | $return = \Yii::$app->imagemanager->getImagePath($model->id, $model->imageDetails['width'], $model->imageDetails['height'], "inset"); 374 | //return json encoded 375 | return $return; 376 | } 377 | 378 | /** 379 | * Deletes an existing ImageManager model. 380 | * If deletion is successful, the browser will be redirected to the 'index' page. 381 | * @return mixed 382 | */ 383 | public function actionDelete() { 384 | //return 385 | $return = ['delete' => false]; 386 | //set response header 387 | Yii::$app->getResponse()->format = Response::FORMAT_JSON; 388 | 389 | if (Yii::$app->controller->module->canRemoveImage == false) { 390 | // User can not remove this image, return false status 391 | return $return; 392 | } 393 | 394 | //get post 395 | $ImageManager_id = Yii::$app->request->post("ImageManager_id"); 396 | //get details 397 | $model = $this->findModel($ImageManager_id); 398 | 399 | //delete record 400 | if ($model->delete()) { 401 | $return['delete'] = true; 402 | } 403 | return $return; 404 | } 405 | 406 | /** 407 | * Finds the ImageManager model based on its primary key value. 408 | * If the model is not found, a 404 HTTP exception will be thrown. 409 | * @param integer $id 410 | * @return ImageManager the loaded model 411 | * @throws NotFoundHttpException if the model cannot be found 412 | */ 413 | protected function findModel($id) { 414 | if (($model = ImageManager::findOne($id)) !== null) { 415 | /* @var $model ImageManager */ 416 | // Get the module instance 417 | $module = Module::getInstance(); 418 | 419 | // Check if the model belongs to this user 420 | if ($module->setBlameableBehavior) { 421 | // Check if the user and record ID match 422 | if (Yii::$app->user->id != $model->createdBy) { 423 | throw new NotFoundHttpException(Yii::t('imagemanager', 'The requested image does not exist.')); 424 | } 425 | } 426 | 427 | return $model; 428 | } else { 429 | throw new NotFoundHttpException(Yii::t('imagemanager', 'The requested image does not exist.')); 430 | } 431 | } 432 | 433 | } 434 | -------------------------------------------------------------------------------- /assets/source/js/cropper.min.js: -------------------------------------------------------------------------------- 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("")[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("")[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("'),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.widths.maxHeight||s.heighte.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.widtha.maxHeight||a.height'),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("')})},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("")[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='
',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}}); -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "c80cdb863644a089e1bd2b74f2d6b735", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/bootstrap", 11 | "version": "v3.3.5", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/twbs/bootstrap.git", 15 | "reference": "16b48259a62f576e52c903c476bd42b90ab22482" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/twbs/bootstrap/zipball/16b48259a62f576e52c903c476bd42b90ab22482", 20 | "reference": "16b48259a62f576e52c903c476bd42b90ab22482", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "bower-asset/jquery": ">=1.9.1" 25 | }, 26 | "type": "bower-asset-library", 27 | "extra": { 28 | "bower-asset-main": [ 29 | "less/bootstrap.less", 30 | "dist/js/bootstrap.js" 31 | ], 32 | "bower-asset-ignore": [ 33 | "/.*", 34 | "_config.yml", 35 | "CNAME", 36 | "composer.json", 37 | "CONTRIBUTING.md", 38 | "docs", 39 | "js/tests", 40 | "test-infra" 41 | ] 42 | }, 43 | "license": [ 44 | "MIT" 45 | ], 46 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 47 | "keywords": [ 48 | "css", 49 | "framework", 50 | "front-end", 51 | "js", 52 | "less", 53 | "mobile-first", 54 | "responsive", 55 | "web" 56 | ] 57 | }, 58 | { 59 | "name": "bower-asset/inputmask", 60 | "version": "3.3.11", 61 | "source": { 62 | "type": "git", 63 | "url": "https://github.com/RobinHerbots/Inputmask.git", 64 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" 65 | }, 66 | "dist": { 67 | "type": "zip", 68 | "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b", 69 | "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b", 70 | "shasum": "" 71 | }, 72 | "require": { 73 | "bower-asset/jquery": ">=1.7" 74 | }, 75 | "type": "bower-asset-library", 76 | "extra": { 77 | "bower-asset-main": [ 78 | "./dist/inputmask/inputmask.js", 79 | "./dist/inputmask/inputmask.extensions.js", 80 | "./dist/inputmask/inputmask.date.extensions.js", 81 | "./dist/inputmask/inputmask.numeric.extensions.js", 82 | "./dist/inputmask/inputmask.phone.extensions.js", 83 | "./dist/inputmask/jquery.inputmask.js", 84 | "./dist/inputmask/global/document.js", 85 | "./dist/inputmask/global/window.js", 86 | "./dist/inputmask/phone-codes/phone.js", 87 | "./dist/inputmask/phone-codes/phone-be.js", 88 | "./dist/inputmask/phone-codes/phone-nl.js", 89 | "./dist/inputmask/phone-codes/phone-ru.js", 90 | "./dist/inputmask/phone-codes/phone-uk.js", 91 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jqlite.js", 92 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.jquery.js", 93 | "./dist/inputmask/dependencyLibs/inputmask.dependencyLib.js", 94 | "./dist/inputmask/bindings/inputmask.binding.js" 95 | ], 96 | "bower-asset-ignore": [ 97 | "**/*", 98 | "!dist/*", 99 | "!dist/inputmask/*", 100 | "!dist/min/*", 101 | "!dist/min/inputmask/*" 102 | ] 103 | }, 104 | "license": [ 105 | "http://opensource.org/licenses/mit-license.php" 106 | ], 107 | "description": "Inputmask is a javascript library which creates an input mask. Inputmask can run against vanilla javascript, jQuery and jqlite.", 108 | "keywords": [ 109 | "form", 110 | "input", 111 | "inputmask", 112 | "jquery", 113 | "mask", 114 | "plugins" 115 | ] 116 | }, 117 | { 118 | "name": "bower-asset/jquery", 119 | "version": "3.2.1", 120 | "source": { 121 | "type": "git", 122 | "url": "https://github.com/jquery/jquery-dist.git", 123 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e" 124 | }, 125 | "dist": { 126 | "type": "zip", 127 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/77d2a51d0520d2ee44173afdf4e40a9201f5964e", 128 | "reference": "77d2a51d0520d2ee44173afdf4e40a9201f5964e", 129 | "shasum": "" 130 | }, 131 | "type": "bower-asset-library", 132 | "extra": { 133 | "bower-asset-main": "dist/jquery.js", 134 | "bower-asset-ignore": [ 135 | "package.json" 136 | ] 137 | }, 138 | "license": [ 139 | "MIT" 140 | ], 141 | "keywords": [ 142 | "browser", 143 | "javascript", 144 | "jquery", 145 | "library" 146 | ] 147 | }, 148 | { 149 | "name": "bower-asset/punycode", 150 | "version": "v1.3.2", 151 | "source": { 152 | "type": "git", 153 | "url": "https://github.com/bestiejs/punycode.js.git", 154 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 155 | }, 156 | "dist": { 157 | "type": "zip", 158 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 159 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 160 | "shasum": "" 161 | }, 162 | "type": "bower-asset-library", 163 | "extra": { 164 | "bower-asset-main": "punycode.js", 165 | "bower-asset-ignore": [ 166 | "coverage", 167 | "tests", 168 | ".*", 169 | "component.json", 170 | "Gruntfile.js", 171 | "node_modules", 172 | "package.json" 173 | ] 174 | } 175 | }, 176 | { 177 | "name": "bower-asset/yii2-pjax", 178 | "version": "2.0.7.1", 179 | "source": { 180 | "type": "git", 181 | "url": "https://github.com/yiisoft/jquery-pjax.git", 182 | "reference": "aef7b953107264f00234902a3880eb50dafc48be" 183 | }, 184 | "dist": { 185 | "type": "zip", 186 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/aef7b953107264f00234902a3880eb50dafc48be", 187 | "reference": "aef7b953107264f00234902a3880eb50dafc48be", 188 | "shasum": "" 189 | }, 190 | "require": { 191 | "bower-asset/jquery": ">=1.8" 192 | }, 193 | "type": "bower-asset-library", 194 | "extra": { 195 | "bower-asset-main": "./jquery.pjax.js", 196 | "bower-asset-ignore": [ 197 | ".travis.yml", 198 | "Gemfile", 199 | "Gemfile.lock", 200 | "CONTRIBUTING.md", 201 | "vendor/", 202 | "script/", 203 | "test/" 204 | ] 205 | }, 206 | "license": [ 207 | "MIT" 208 | ] 209 | }, 210 | { 211 | "name": "cebe/markdown", 212 | "version": "1.1.2", 213 | "source": { 214 | "type": "git", 215 | "url": "https://github.com/cebe/markdown.git", 216 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e" 217 | }, 218 | "dist": { 219 | "type": "zip", 220 | "url": "https://api.github.com/repos/cebe/markdown/zipball/25b28bae8a6f185b5030673af77b32e1163d5c6e", 221 | "reference": "25b28bae8a6f185b5030673af77b32e1163d5c6e", 222 | "shasum": "" 223 | }, 224 | "require": { 225 | "lib-pcre": "*", 226 | "php": ">=5.4.0" 227 | }, 228 | "require-dev": { 229 | "cebe/indent": "*", 230 | "facebook/xhprof": "*@dev", 231 | "phpunit/phpunit": "4.1.*" 232 | }, 233 | "bin": [ 234 | "bin/markdown" 235 | ], 236 | "type": "library", 237 | "extra": { 238 | "branch-alias": { 239 | "dev-master": "1.1.x-dev" 240 | } 241 | }, 242 | "autoload": { 243 | "psr-4": { 244 | "cebe\\markdown\\": "" 245 | } 246 | }, 247 | "notification-url": "https://packagist.org/downloads/", 248 | "license": [ 249 | "MIT" 250 | ], 251 | "authors": [ 252 | { 253 | "name": "Carsten Brandt", 254 | "email": "mail@cebe.cc", 255 | "homepage": "http://cebe.cc/", 256 | "role": "Creator" 257 | } 258 | ], 259 | "description": "A super fast, highly extensible markdown parser for PHP", 260 | "homepage": "https://github.com/cebe/markdown#readme", 261 | "keywords": [ 262 | "extensible", 263 | "fast", 264 | "gfm", 265 | "markdown", 266 | "markdown-extra" 267 | ], 268 | "time": "2017-07-16T21:13:23+00:00" 269 | }, 270 | { 271 | "name": "ezyang/htmlpurifier", 272 | "version": "v4.10.0", 273 | "source": { 274 | "type": "git", 275 | "url": "https://github.com/ezyang/htmlpurifier.git", 276 | "reference": "d85d39da4576a6934b72480be6978fb10c860021" 277 | }, 278 | "dist": { 279 | "type": "zip", 280 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", 281 | "reference": "d85d39da4576a6934b72480be6978fb10c860021", 282 | "shasum": "" 283 | }, 284 | "require": { 285 | "php": ">=5.2" 286 | }, 287 | "require-dev": { 288 | "simpletest/simpletest": "^1.1" 289 | }, 290 | "type": "library", 291 | "autoload": { 292 | "psr-0": { 293 | "HTMLPurifier": "library/" 294 | }, 295 | "files": [ 296 | "library/HTMLPurifier.composer.php" 297 | ] 298 | }, 299 | "notification-url": "https://packagist.org/downloads/", 300 | "license": [ 301 | "LGPL" 302 | ], 303 | "authors": [ 304 | { 305 | "name": "Edward Z. Yang", 306 | "email": "admin@htmlpurifier.org", 307 | "homepage": "http://ezyang.com" 308 | } 309 | ], 310 | "description": "Standards compliant HTML filter written in PHP", 311 | "homepage": "http://htmlpurifier.org/", 312 | "keywords": [ 313 | "html" 314 | ], 315 | "time": "2018-02-23T01:58:20+00:00" 316 | }, 317 | { 318 | "name": "imagine/imagine", 319 | "version": "v0.7.1", 320 | "source": { 321 | "type": "git", 322 | "url": "https://github.com/avalanche123/Imagine.git", 323 | "reference": "a9a702a946073cbca166718f1b02a1e72d742daa" 324 | }, 325 | "dist": { 326 | "type": "zip", 327 | "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/a9a702a946073cbca166718f1b02a1e72d742daa", 328 | "reference": "a9a702a946073cbca166718f1b02a1e72d742daa", 329 | "shasum": "" 330 | }, 331 | "require": { 332 | "php": ">=5.3.2" 333 | }, 334 | "require-dev": { 335 | "sami/sami": "^3.3", 336 | "symfony/phpunit-bridge": "^3.2" 337 | }, 338 | "suggest": { 339 | "ext-gd": "to use the GD implementation", 340 | "ext-gmagick": "to use the Gmagick implementation", 341 | "ext-imagick": "to use the Imagick implementation" 342 | }, 343 | "type": "library", 344 | "extra": { 345 | "branch-alias": { 346 | "dev-develop": "0.7-dev" 347 | } 348 | }, 349 | "autoload": { 350 | "psr-0": { 351 | "Imagine": "lib/" 352 | } 353 | }, 354 | "notification-url": "https://packagist.org/downloads/", 355 | "license": [ 356 | "MIT" 357 | ], 358 | "authors": [ 359 | { 360 | "name": "Bulat Shakirzyanov", 361 | "email": "mallluhuct@gmail.com", 362 | "homepage": "http://avalanche123.com" 363 | } 364 | ], 365 | "description": "Image processing for PHP 5.3", 366 | "homepage": "http://imagine.readthedocs.org/", 367 | "keywords": [ 368 | "drawing", 369 | "graphics", 370 | "image manipulation", 371 | "image processing" 372 | ], 373 | "time": "2017-05-16T10:31:22+00:00" 374 | }, 375 | { 376 | "name": "kartik-v/bootstrap-fileinput", 377 | "version": "v4.4.8", 378 | "source": { 379 | "type": "git", 380 | "url": "https://github.com/kartik-v/bootstrap-fileinput.git", 381 | "reference": "7a2191d2b7ae65f5ca4ddb090a69d65805eb7edf" 382 | }, 383 | "dist": { 384 | "type": "zip", 385 | "url": "https://api.github.com/repos/kartik-v/bootstrap-fileinput/zipball/7a2191d2b7ae65f5ca4ddb090a69d65805eb7edf", 386 | "reference": "7a2191d2b7ae65f5ca4ddb090a69d65805eb7edf", 387 | "shasum": "" 388 | }, 389 | "type": "library", 390 | "extra": { 391 | "branch-alias": { 392 | "dev-master": "4.4.x-dev" 393 | } 394 | }, 395 | "autoload": { 396 | "psr-4": { 397 | "kartik\\plugins\\fileinput\\": "" 398 | } 399 | }, 400 | "notification-url": "https://packagist.org/downloads/", 401 | "license": [ 402 | "BSD-3-Clause" 403 | ], 404 | "authors": [ 405 | { 406 | "name": "Kartik Visweswaran", 407 | "email": "kartikv2@gmail.com", 408 | "homepage": "http://www.krajee.com/" 409 | } 410 | ], 411 | "description": "An enhanced HTML 5 file input for Bootstrap 3.x with features for file preview for many file types, multiple selection, ajax uploads, and more.", 412 | "homepage": "https://github.com/kartik-v/bootstrap-fileinput", 413 | "keywords": [ 414 | "ajax", 415 | "bootstrap", 416 | "delete", 417 | "file", 418 | "image", 419 | "input", 420 | "jquery", 421 | "multiple", 422 | "preview", 423 | "progress", 424 | "upload" 425 | ], 426 | "time": "2018-04-11T10:34:10+00:00" 427 | }, 428 | { 429 | "name": "kartik-v/yii2-krajee-base", 430 | "version": "v1.8.9", 431 | "source": { 432 | "type": "git", 433 | "url": "https://github.com/kartik-v/yii2-krajee-base.git", 434 | "reference": "0cafe6376780cedcd00f52c9d82b172d5851f6b0" 435 | }, 436 | "dist": { 437 | "type": "zip", 438 | "url": "https://api.github.com/repos/kartik-v/yii2-krajee-base/zipball/0cafe6376780cedcd00f52c9d82b172d5851f6b0", 439 | "reference": "0cafe6376780cedcd00f52c9d82b172d5851f6b0", 440 | "shasum": "" 441 | }, 442 | "require": { 443 | "yiisoft/yii2-bootstrap": "@dev" 444 | }, 445 | "type": "yii2-extension", 446 | "extra": { 447 | "branch-alias": { 448 | "dev-master": "1.8.x-dev" 449 | } 450 | }, 451 | "autoload": { 452 | "psr-4": { 453 | "kartik\\base\\": "" 454 | } 455 | }, 456 | "notification-url": "https://packagist.org/downloads/", 457 | "license": [ 458 | "BSD-3-Clause" 459 | ], 460 | "authors": [ 461 | { 462 | "name": "Kartik Visweswaran", 463 | "email": "kartikv2@gmail.com", 464 | "homepage": "http://www.krajee.com/" 465 | } 466 | ], 467 | "description": "Base library and foundation components for all Yii2 Krajee extensions.", 468 | "homepage": "https://github.com/kartik-v/yii2-krajee-base", 469 | "keywords": [ 470 | "base", 471 | "extension", 472 | "foundation", 473 | "krajee", 474 | "widget", 475 | "yii2" 476 | ], 477 | "time": "2017-09-29T06:18:14+00:00" 478 | }, 479 | { 480 | "name": "kartik-v/yii2-widget-fileinput", 481 | "version": "dev-master", 482 | "source": { 483 | "type": "git", 484 | "url": "https://github.com/kartik-v/yii2-widget-fileinput.git", 485 | "reference": "c5495641c8a86690713eb562e544bf5eaaf727cb" 486 | }, 487 | "dist": { 488 | "type": "zip", 489 | "url": "https://api.github.com/repos/kartik-v/yii2-widget-fileinput/zipball/c5495641c8a86690713eb562e544bf5eaaf727cb", 490 | "reference": "c5495641c8a86690713eb562e544bf5eaaf727cb", 491 | "shasum": "" 492 | }, 493 | "require": { 494 | "kartik-v/bootstrap-fileinput": "~4.4", 495 | "kartik-v/yii2-krajee-base": "~1.7" 496 | }, 497 | "type": "yii2-extension", 498 | "extra": { 499 | "branch-alias": { 500 | "dev-master": "1.0.x-dev" 501 | } 502 | }, 503 | "autoload": { 504 | "psr-4": { 505 | "kartik\\file\\": "" 506 | } 507 | }, 508 | "notification-url": "https://packagist.org/downloads/", 509 | "license": [ 510 | "BSD-3-Clause" 511 | ], 512 | "authors": [ 513 | { 514 | "name": "Kartik Visweswaran", 515 | "email": "kartikv2@gmail.com", 516 | "homepage": "http://www.krajee.com/" 517 | } 518 | ], 519 | "description": "An enhanced FileInput widget for Bootstrap 3.x with file preview, multiple selection, and more features (sub repo split from yii2-widgets)", 520 | "homepage": "https://github.com/kartik-v/yii2-widget-fileinput", 521 | "keywords": [ 522 | "extension", 523 | "file", 524 | "form", 525 | "input", 526 | "jquery", 527 | "plugin", 528 | "upload", 529 | "widget", 530 | "yii2" 531 | ], 532 | "time": "2017-12-06T12:34:31+00:00" 533 | }, 534 | { 535 | "name": "noam148/yii2-image-resize", 536 | "version": "1.1.0", 537 | "source": { 538 | "type": "git", 539 | "url": "https://github.com/noam148/yii2-image-resize.git", 540 | "reference": "32c5adf7211e06cefc6861a2164855573e968038" 541 | }, 542 | "dist": { 543 | "type": "zip", 544 | "url": "https://api.github.com/repos/noam148/yii2-image-resize/zipball/32c5adf7211e06cefc6861a2164855573e968038", 545 | "reference": "32c5adf7211e06cefc6861a2164855573e968038", 546 | "shasum": "" 547 | }, 548 | "require": { 549 | "yiisoft/yii2": "*", 550 | "yiisoft/yii2-imagine": "*" 551 | }, 552 | "type": "yii2-extension", 553 | "autoload": { 554 | "psr-4": { 555 | "noam148\\imageresize\\": "" 556 | } 557 | }, 558 | "notification-url": "https://packagist.org/downloads/", 559 | "license": [ 560 | "BSD-3-Clause" 561 | ], 562 | "authors": [ 563 | { 564 | "name": "Noam148", 565 | "homepage": "https://github.com/noam148/" 566 | } 567 | ], 568 | "description": "A Yii2 component for resizing images (on the fly)", 569 | "homepage": "https://github.com/noam148/yii2-image-resize", 570 | "keywords": [ 571 | "component", 572 | "extension", 573 | "image", 574 | "on-the-fly", 575 | "resize", 576 | "yii2" 577 | ], 578 | "time": "2018-02-18T19:23:04+00:00" 579 | }, 580 | { 581 | "name": "yiisoft/yii2", 582 | "version": "2.0.15.1", 583 | "source": { 584 | "type": "git", 585 | "url": "https://github.com/yiisoft/yii2-framework.git", 586 | "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d" 587 | }, 588 | "dist": { 589 | "type": "zip", 590 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ed3a9e1c4abe206e1c3ce48a6b3624119b79850d", 591 | "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d", 592 | "shasum": "" 593 | }, 594 | "require": { 595 | "bower-asset/inputmask": "~3.2.2 | ~3.3.5", 596 | "bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", 597 | "bower-asset/punycode": "1.3.*", 598 | "bower-asset/yii2-pjax": "~2.0.1", 599 | "cebe/markdown": "~1.0.0 | ~1.1.0", 600 | "ext-ctype": "*", 601 | "ext-mbstring": "*", 602 | "ezyang/htmlpurifier": "~4.6", 603 | "lib-pcre": "*", 604 | "php": ">=5.4.0", 605 | "yiisoft/yii2-composer": "~2.0.4" 606 | }, 607 | "bin": [ 608 | "yii" 609 | ], 610 | "type": "library", 611 | "extra": { 612 | "branch-alias": { 613 | "dev-master": "2.0.x-dev" 614 | } 615 | }, 616 | "autoload": { 617 | "psr-4": { 618 | "yii\\": "" 619 | } 620 | }, 621 | "notification-url": "https://packagist.org/downloads/", 622 | "license": [ 623 | "BSD-3-Clause" 624 | ], 625 | "authors": [ 626 | { 627 | "name": "Qiang Xue", 628 | "email": "qiang.xue@gmail.com", 629 | "homepage": "http://www.yiiframework.com/", 630 | "role": "Founder and project lead" 631 | }, 632 | { 633 | "name": "Alexander Makarov", 634 | "email": "sam@rmcreative.ru", 635 | "homepage": "http://rmcreative.ru/", 636 | "role": "Core framework development" 637 | }, 638 | { 639 | "name": "Maurizio Domba", 640 | "homepage": "http://mdomba.info/", 641 | "role": "Core framework development" 642 | }, 643 | { 644 | "name": "Carsten Brandt", 645 | "email": "mail@cebe.cc", 646 | "homepage": "http://cebe.cc/", 647 | "role": "Core framework development" 648 | }, 649 | { 650 | "name": "Timur Ruziev", 651 | "email": "resurtm@gmail.com", 652 | "homepage": "http://resurtm.com/", 653 | "role": "Core framework development" 654 | }, 655 | { 656 | "name": "Paul Klimov", 657 | "email": "klimov.paul@gmail.com", 658 | "role": "Core framework development" 659 | }, 660 | { 661 | "name": "Dmitry Naumenko", 662 | "email": "d.naumenko.a@gmail.com", 663 | "role": "Core framework development" 664 | }, 665 | { 666 | "name": "Boudewijn Vahrmeijer", 667 | "email": "info@dynasource.eu", 668 | "homepage": "http://dynasource.eu", 669 | "role": "Core framework development" 670 | } 671 | ], 672 | "description": "Yii PHP Framework Version 2", 673 | "homepage": "http://www.yiiframework.com/", 674 | "keywords": [ 675 | "framework", 676 | "yii2" 677 | ], 678 | "time": "2018-03-21T18:36:53+00:00" 679 | }, 680 | { 681 | "name": "yiisoft/yii2-bootstrap", 682 | "version": "2.0.8", 683 | "source": { 684 | "type": "git", 685 | "url": "https://github.com/yiisoft/yii2-bootstrap.git", 686 | "reference": "3f49c47924bb9fa5363c3fc7b073d954168cf438" 687 | }, 688 | "dist": { 689 | "type": "zip", 690 | "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/3f49c47924bb9fa5363c3fc7b073d954168cf438", 691 | "reference": "3f49c47924bb9fa5363c3fc7b073d954168cf438", 692 | "shasum": "" 693 | }, 694 | "require": { 695 | "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", 696 | "yiisoft/yii2": "~2.0.6" 697 | }, 698 | "type": "yii2-extension", 699 | "extra": { 700 | "branch-alias": { 701 | "dev-master": "2.0.x-dev" 702 | } 703 | }, 704 | "autoload": { 705 | "psr-4": { 706 | "yii\\bootstrap\\": "src" 707 | } 708 | }, 709 | "notification-url": "https://packagist.org/downloads/", 710 | "license": [ 711 | "BSD-3-Clause" 712 | ], 713 | "authors": [ 714 | { 715 | "name": "Paul Klimov", 716 | "email": "klimov.paul@gmail.com" 717 | }, 718 | { 719 | "name": "Alexander Makarov", 720 | "email": "sam@rmcreative.ru", 721 | "homepage": "http://rmcreative.ru/" 722 | }, 723 | { 724 | "name": "Antonio Ramirez", 725 | "email": "amigo.cobos@gmail.com" 726 | }, 727 | { 728 | "name": "Qiang Xue", 729 | "email": "qiang.xue@gmail.com", 730 | "homepage": "http://www.yiiframework.com/" 731 | } 732 | ], 733 | "description": "The Twitter Bootstrap extension for the Yii framework", 734 | "keywords": [ 735 | "bootstrap", 736 | "yii2" 737 | ], 738 | "time": "2018-02-16T10:41:52+00:00" 739 | }, 740 | { 741 | "name": "yiisoft/yii2-composer", 742 | "version": "2.0.6", 743 | "source": { 744 | "type": "git", 745 | "url": "https://github.com/yiisoft/yii2-composer.git", 746 | "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80" 747 | }, 748 | "dist": { 749 | "type": "zip", 750 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/163419f1f197e02f015713b0d4f85598d8f8aa80", 751 | "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80", 752 | "shasum": "" 753 | }, 754 | "require": { 755 | "composer-plugin-api": "^1.0" 756 | }, 757 | "require-dev": { 758 | "composer/composer": "^1.0" 759 | }, 760 | "type": "composer-plugin", 761 | "extra": { 762 | "class": "yii\\composer\\Plugin", 763 | "branch-alias": { 764 | "dev-master": "2.0.x-dev" 765 | } 766 | }, 767 | "autoload": { 768 | "psr-4": { 769 | "yii\\composer\\": "" 770 | } 771 | }, 772 | "notification-url": "https://packagist.org/downloads/", 773 | "license": [ 774 | "BSD-3-Clause" 775 | ], 776 | "authors": [ 777 | { 778 | "name": "Qiang Xue", 779 | "email": "qiang.xue@gmail.com" 780 | }, 781 | { 782 | "name": "Carsten Brandt", 783 | "email": "mail@cebe.cc" 784 | } 785 | ], 786 | "description": "The composer plugin for Yii extension installer", 787 | "keywords": [ 788 | "composer", 789 | "extension installer", 790 | "yii2" 791 | ], 792 | "time": "2018-03-21T16:15:55+00:00" 793 | }, 794 | { 795 | "name": "yiisoft/yii2-imagine", 796 | "version": "2.1.1", 797 | "source": { 798 | "type": "git", 799 | "url": "https://github.com/yiisoft/yii2-imagine.git", 800 | "reference": "a8a1a068862a86e3395e665bc86e63d5c9b60841" 801 | }, 802 | "dist": { 803 | "type": "zip", 804 | "url": "https://api.github.com/repos/yiisoft/yii2-imagine/zipball/a8a1a068862a86e3395e665bc86e63d5c9b60841", 805 | "reference": "a8a1a068862a86e3395e665bc86e63d5c9b60841", 806 | "shasum": "" 807 | }, 808 | "require": { 809 | "imagine/imagine": "~0.6.0 | ~0.7.1", 810 | "yiisoft/yii2": "~2.0.0" 811 | }, 812 | "type": "yii2-extension", 813 | "extra": { 814 | "branch-alias": { 815 | "dev-master": "2.0.x-dev" 816 | } 817 | }, 818 | "autoload": { 819 | "psr-4": { 820 | "yii\\imagine\\": "src" 821 | } 822 | }, 823 | "notification-url": "https://packagist.org/downloads/", 824 | "license": [ 825 | "BSD-3-Clause" 826 | ], 827 | "authors": [ 828 | { 829 | "name": "Antonio Ramirez", 830 | "email": "amigo.cobos@gmail.com" 831 | } 832 | ], 833 | "description": "The Imagine integration for the Yii framework", 834 | "keywords": [ 835 | "helper", 836 | "image", 837 | "imagine", 838 | "yii2" 839 | ], 840 | "time": "2018-02-22T11:57:06+00:00" 841 | } 842 | ], 843 | "packages-dev": [], 844 | "aliases": [], 845 | "minimum-stability": "stable", 846 | "stability-flags": { 847 | "kartik-v/yii2-widget-fileinput": 20 848 | }, 849 | "prefer-stable": false, 850 | "prefer-lowest": false, 851 | "platform": [], 852 | "platform-dev": [] 853 | } 854 | --------------------------------------------------------------------------------