├── .babelrc ├── .editorconfig ├── .gitignore ├── .travis.yml ├── Module.php ├── README.md ├── assets ├── FileUploadAssets.php ├── FilemanagerAssets.php ├── FilemanagerPreactAssets.php └── FilemanagerTinyAssets.php ├── composer.json ├── composer.lock ├── controllers ├── DefaultController.php ├── FileTagController.php └── FilesController.php ├── css ├── context.bootstrap.css ├── context.standalone.css ├── filemanager.css └── jquery.contextMenu.css ├── helpers ├── Html.php ├── ModuleTrait.php └── StringHelper.php ├── js ├── bundle.js ├── context.js ├── filemanager.js ├── filemanager_modal.js ├── filemanager_plugin.js ├── filemanagertiny.js ├── fileupload.js ├── jquery-1.4.2.min.js ├── jquery.contextMenu.js └── jquery.filemanager.js ├── migrations ├── m140723_010511_filemanager_init.php ├── m141107_062947_update_titles.php ├── m150327_233853_create_file_tag.php └── m150327_233907_create_file_tag_relationships.php ├── models ├── FileTag.php ├── FileTagRelationships.php ├── FileTagSearch.php ├── FileTerms.php ├── Files.php └── FilesSearch.php ├── package-lock.json ├── package.json ├── src └── js │ ├── components │ ├── Button.js │ ├── Close.js │ ├── Pagination.js │ ├── Search.js │ ├── Selected.js │ ├── Thumbnail.js │ └── Uploader.js │ ├── index.js │ ├── store │ └── FilePickerStore.js │ └── views │ └── FilePicker.js ├── tests └── functional │ ├── TestCase.php │ └── bootstrap.php ├── views ├── default │ └── index.php ├── file-tag │ ├── _form.php │ ├── _search.php │ ├── create.php │ ├── index.php │ ├── update.php │ └── view.php ├── files │ ├── _form.php │ ├── _properties.php │ ├── _search.php │ ├── create.php │ ├── fileModal.php │ ├── index.php │ ├── update.php │ └── view.php └── layouts │ ├── modal.php │ └── tinymce.php ├── webpack.config.js └── widgets ├── FilePicker.php ├── FileSelect.php ├── FileTagSelect.php └── Fileupload.php /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": [ 4 | ["@babel/plugin-transform-react-jsx", { "pragma":"h" }], 5 | ["@babel/plugin-proposal-class-properties", { 6 | "loose": true 7 | }] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [*.php] 19 | indent_size = 4 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | node_modules 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 5.5 5 | - 5.4 6 | install: 7 | - composer self-update 8 | - composer global require "fxp/composer-asset-plugin:~1.0" 9 | - composer install --prefer-dist --dev 10 | - composer require --dev "codeception/codeception:2.0.*@dev" 11 | before_script: 12 | - cd tests 13 | script: ../vendor/bin/codecept run 14 | -------------------------------------------------------------------------------- /Module.php: -------------------------------------------------------------------------------- 1 | false, 25 | 'key' => '', 26 | 'secret' => '', 27 | 'bucket' => '', 28 | ]; 29 | 30 | public function init() 31 | { 32 | parent::init(); 33 | 34 | // custom initialization code goes here 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yii2 File Manager 2 | ================= 3 | A file manager for Yii2. Allow you to dynamically manager images and files from any location. Also TinyMCE plugin included. 4 | 5 | 6 | Installation 7 | =============== 8 | 9 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 10 | 11 | Either run 12 | 13 | ``` 14 | php composer.phar require --prefer-dist linchpinstudios/yii2-filemanager "*" 15 | ``` 16 | 17 | or add 18 | 19 | ``` 20 | "linchpinstudios/yii2-filemanager": "*" 21 | ``` 22 | 23 | to the require section of your `composer.json` file. 24 | 25 | 26 |
3) Run Migrations
27 | ``` 28 | ./yii migrate/up --migrationPath=@vendor/linchpinstudios/yii2-filemanager/migrations 29 | ``` 30 | 31 | 32 | Configure 33 | =============== 34 | 35 | Add the module to the main configuration. 36 | 37 | ``` 38 | [ 42 | //... 43 | 'filemanager' => [ 44 | 'class' => 'linchpinstudios\filemanager\Module', 45 | 'thumbnails' => [[100,100]], // Optional: array 46 | 'path' => '/images/uploads/', // Default relative to your web directory or AWS 47 | 'thumbPath' => '/images/uploads/thumb/', // Default relative to your web directory or AWS 48 | 'url' => '/', // either s3 buket URL or CloudFront (can be changed) 49 | 'aws' => [ 50 | 'enable' => true, 51 | 'key' => 'YOURAWS_KEY', 52 | 'secret' => 'YOURAWS_SECRET', 53 | 'bucket' => 'your-bucket', 54 | ], 55 | ], 56 | //... 57 | ], 58 | ?> 59 | ``` 60 | 61 | 62 | 63 | Usage 64 | =============== 65 | 66 | Once the extension is installed, you can access the Module by navigating to http://yourdomain.com/index.php?r=filemanager 67 | 68 | 69 | 70 | 71 | Tiny MCE 72 | =============== 73 | 74 | To use the File Manager with Tiny MCE you need to register the scripts with Yii. 75 | 76 | Add Use to head of controller. 77 | ``` 78 | use linchpinstudios\filemanager\assets\FilemanagerTinyAssets; 79 | ``` 80 | 81 | Add Register to controller action. 82 | ``` 83 | FilemanagerTinyAssets::register($this->view); 84 | ``` 85 | 86 | Then add the 'filemanager' plugin to the Tiny MCE plugin. (Example using 2amigos Tiny MCE Package [found HERE](https://github.com/2amigos/yii2-tinymce-widget)) 87 | 88 | ``` 89 | field($model, 'text')->widget(TinyMce::className(), [ 90 | 'options' => ['rows' => 6], 91 | 'language' => 'en', 92 | 'clientOptions' => [ 93 | 'plugins' => [ 94 | "advlist autolink lists link charmap print preview anchor", 95 | "searchreplace visualblocks code fullscreen", 96 | "insertdatetime media table contextmenu paste filemanager" 97 | ], 98 | 'toolbar' => "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | filemanager" 99 | ] 100 | ]);?> 101 | ``` 102 | 103 | 104 | Notes 105 | =============== 106 | 107 | Widget and other items still in development. 108 | -------------------------------------------------------------------------------- /assets/FileUploadAssets.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class FileUploadAssets extends AssetBundle 19 | { 20 | public $sourcePath = '@vendor/linchpinstudios/yii2-filemanager/'; 21 | public $css = [ 22 | 'css/filemanager.css', 23 | ]; 24 | public $js = [ 25 | 'js/filemanager.js', 26 | 'js/jquery.filemanager.js', 27 | 'js/bundle.js', 28 | ]; 29 | public $depends = [ 30 | 'yii\web\JqueryAsset', 31 | 'yii\bootstrap\BootstrapAsset', 32 | ]; 33 | } 34 | -------------------------------------------------------------------------------- /assets/FilemanagerAssets.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class FilemanagerAssets extends AssetBundle 19 | { 20 | public $sourcePath = '@vendor/linchpinstudios/yii2-filemanager/'; 21 | public $css = [ 22 | 'css/filemanager.css', 23 | ]; 24 | public $js = [ 25 | 'js/context.js', 26 | 'js/filemanager.js', 27 | 'js/bundle.js', 28 | ]; 29 | public $depends = [ 30 | 'yii\web\JqueryAsset', 31 | 'yii\bootstrap\BootstrapAsset', 32 | ]; 33 | } 34 | -------------------------------------------------------------------------------- /assets/FilemanagerPreactAssets.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class FilemanagerPreactAssets extends AssetBundle 19 | { 20 | public $sourcePath = '@vendor/linchpinstudios/yii2-filemanager/'; 21 | public $css = [ 22 | 'css/filemanager.css', 23 | ]; 24 | public $js = [ 25 | 'js/bundle.js', 26 | ]; 27 | } 28 | -------------------------------------------------------------------------------- /assets/FilemanagerTinyAssets.php: -------------------------------------------------------------------------------- 1 | 16 | * @since 2.0 17 | */ 18 | class FilemanagerTinyAssets extends AssetBundle 19 | { 20 | public $sourcePath = '@vendor/linchpinstudios/yii2-filemanager/'; 21 | public $css = [ 22 | /*'css/filemanager.css',*/ 23 | ]; 24 | public $js = [ 25 | 'js/filemanager.js', 26 | 'js/filemanagertiny.js', 27 | 'js/filemanager_plugin.js', 28 | ]; 29 | public $depends = [ 30 | 'dosamigos\tinymce\TinyMceAsset', ]; 31 | } 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linchpinstudios/yii2-filemanager", 3 | "description": "A file manager for Yii2. Allow you to dynamically manager images and files from any location", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","extension","file","manager","aws"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Josh Hagel", 10 | "email": "joshhagel@linchpinstudios.com" 11 | } 12 | ], 13 | "require-dev": { 14 | "phpspec/phpspec": "~2.0" 15 | }, 16 | "require": { 17 | "aws/aws-sdk-php": "2.*", 18 | "2amigos/yii2-file-upload-widget" : "*", 19 | "yiisoft/yii2-imagine": "*" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "linchpinstudios\\filemanager\\": "" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "ec3de1716849b1a22107901fe4d79cdd", 8 | "packages": [ 9 | { 10 | "name": "2amigos/yii2-file-upload-widget", 11 | "version": "0.1.2", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/2amigos/yii2-file-upload-widget.git", 15 | "reference": "50b592a960f13924f5da715ec5d398d4d9ef0d8e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/2amigos/yii2-file-upload-widget/zipball/50b592a960f13924f5da715ec5d398d4d9ef0d8e", 20 | "reference": "50b592a960f13924f5da715ec5d398d4d9ef0d8e", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "2amigos/yii2-gallery-widget": "0.1.*", 25 | "yiisoft/yii2": "*" 26 | }, 27 | "type": "yii2-extension", 28 | "autoload": { 29 | "psr-4": { 30 | "dosamigos\\fileupload\\": "" 31 | } 32 | }, 33 | "notification-url": "https://packagist.org/downloads/", 34 | "license": [ 35 | "BSD-3-Clause" 36 | ], 37 | "authors": [ 38 | { 39 | "name": "Antonio Ramirez", 40 | "email": "ramirez.cobos@gmail.com", 41 | "homepage": "http://2amigos.us" 42 | } 43 | ], 44 | "description": "BlueImp jQuery File Upload Widget for Yii2.", 45 | "keywords": [ 46 | "extension", 47 | "upload", 48 | "widget", 49 | "yii" 50 | ], 51 | "time": "2014-11-27 19:49:27" 52 | }, 53 | { 54 | "name": "2amigos/yii2-gallery-widget", 55 | "version": "0.1.0", 56 | "source": { 57 | "type": "git", 58 | "url": "https://github.com/2amigos/yii2-gallery-widget.git", 59 | "reference": "9a9808c26df93e5a07cdde88b27b55b3c27a9a51" 60 | }, 61 | "dist": { 62 | "type": "zip", 63 | "url": "https://api.github.com/repos/2amigos/yii2-gallery-widget/zipball/9a9808c26df93e5a07cdde88b27b55b3c27a9a51", 64 | "reference": "9a9808c26df93e5a07cdde88b27b55b3c27a9a51", 65 | "shasum": "" 66 | }, 67 | "require": { 68 | "yiisoft/yii2": "*" 69 | }, 70 | "type": "yii2-extension", 71 | "autoload": { 72 | "psr-4": { 73 | "dosamigos\\gallery\\": "" 74 | } 75 | }, 76 | "notification-url": "https://packagist.org/downloads/", 77 | "license": [ 78 | "BSD-3-Clause" 79 | ], 80 | "authors": [ 81 | { 82 | "name": "Antonio Ramirez", 83 | "email": "ramirez.cobos@gmail.com", 84 | "homepage": "http://www.ramirezcobos.com" 85 | } 86 | ], 87 | "description": "BlueImp Gallery Widget for Yii2.", 88 | "keywords": [ 89 | "extension", 90 | "gallery", 91 | "widget", 92 | "yii" 93 | ], 94 | "time": "2014-04-07 22:24:40" 95 | }, 96 | { 97 | "name": "aws/aws-sdk-php", 98 | "version": "2.7.23", 99 | "source": { 100 | "type": "git", 101 | "url": "https://github.com/aws/aws-sdk-php.git", 102 | "reference": "a31871763cef5e2d46ad793d994a46dc700d4d55" 103 | }, 104 | "dist": { 105 | "type": "zip", 106 | "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a31871763cef5e2d46ad793d994a46dc700d4d55", 107 | "reference": "a31871763cef5e2d46ad793d994a46dc700d4d55", 108 | "shasum": "" 109 | }, 110 | "require": { 111 | "guzzle/guzzle": "~3.7", 112 | "php": ">=5.3.3" 113 | }, 114 | "require-dev": { 115 | "doctrine/cache": "~1.0", 116 | "ext-openssl": "*", 117 | "monolog/monolog": "~1.4", 118 | "phpunit/phpunit": "~4.0", 119 | "symfony/yaml": "~2.1" 120 | }, 121 | "suggest": { 122 | "doctrine/cache": "Adds support for caching of credentials and responses", 123 | "ext-apc": "Allows service description opcode caching, request and response caching, and credentials caching", 124 | "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", 125 | "monolog/monolog": "Adds support for logging HTTP requests and responses", 126 | "symfony/yaml": "Eases the ability to write manifests for creating jobs in AWS Import/Export" 127 | }, 128 | "type": "library", 129 | "extra": { 130 | "branch-alias": { 131 | "dev-master": "2.7-dev" 132 | } 133 | }, 134 | "autoload": { 135 | "psr-0": { 136 | "Aws": "src/" 137 | } 138 | }, 139 | "notification-url": "https://packagist.org/downloads/", 140 | "license": [ 141 | "Apache-2.0" 142 | ], 143 | "authors": [ 144 | { 145 | "name": "Amazon Web Services", 146 | "homepage": "http://aws.amazon.com" 147 | } 148 | ], 149 | "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", 150 | "homepage": "http://aws.amazon.com/sdkforphp", 151 | "keywords": [ 152 | "amazon", 153 | "aws", 154 | "cloud", 155 | "dynamodb", 156 | "ec2", 157 | "glacier", 158 | "s3", 159 | "sdk" 160 | ], 161 | "time": "2015-03-19 21:42:28" 162 | }, 163 | { 164 | "name": "bower-asset/jquery", 165 | "version": "2.1.3", 166 | "source": { 167 | "type": "git", 168 | "url": "https://github.com/jquery/jquery.git", 169 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0" 170 | }, 171 | "dist": { 172 | "type": "zip", 173 | "url": "https://api.github.com/repos/jquery/jquery/zipball/8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 174 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 175 | "shasum": "" 176 | }, 177 | "require-dev": { 178 | "bower-asset/qunit": "1.14.0", 179 | "bower-asset/requirejs": "2.1.10", 180 | "bower-asset/sinon": "1.8.1", 181 | "bower-asset/sizzle": "2.1.1-patch2" 182 | }, 183 | "type": "bower-asset-library", 184 | "extra": { 185 | "bower-asset-main": "dist/jquery.js", 186 | "bower-asset-ignore": [ 187 | "**/.*", 188 | "build", 189 | "speed", 190 | "test", 191 | "*.md", 192 | "AUTHORS.txt", 193 | "Gruntfile.js", 194 | "package.json" 195 | ] 196 | }, 197 | "license": [ 198 | "MIT" 199 | ], 200 | "keywords": [ 201 | "javascript", 202 | "jquery", 203 | "library" 204 | ] 205 | }, 206 | { 207 | "name": "bower-asset/jquery.inputmask", 208 | "version": "3.1.61", 209 | "source": { 210 | "type": "git", 211 | "url": "https://github.com/RobinHerbots/jquery.inputmask.git", 212 | "reference": "f2c086411d2557fc485c47afb3cecfa6c1de9ee2" 213 | }, 214 | "dist": { 215 | "type": "zip", 216 | "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/f2c086411d2557fc485c47afb3cecfa6c1de9ee2", 217 | "reference": "f2c086411d2557fc485c47afb3cecfa6c1de9ee2", 218 | "shasum": "" 219 | }, 220 | "require": { 221 | "bower-asset/jquery": ">=1.7" 222 | }, 223 | "type": "bower-asset-library", 224 | "extra": { 225 | "bower-asset-main": [ 226 | "./dist/inputmask/jquery.inputmask.js", 227 | "./dist/inputmask/jquery.inputmask.extensions.js", 228 | "./dist/inputmask/jquery.inputmask.date.extensions.js", 229 | "./dist/inputmask/jquery.inputmask.numeric.extensions.js", 230 | "./dist/inputmask/jquery.inputmask.phone.extensions.js", 231 | "./dist/inputmask/jquery.inputmask.regex.extensions.js" 232 | ], 233 | "bower-asset-ignore": [ 234 | "**/.*", 235 | "qunit/", 236 | "nuget/", 237 | "tools/", 238 | "js/", 239 | "*.md", 240 | "build.properties", 241 | "build.xml", 242 | "jquery.inputmask.jquery.json" 243 | ] 244 | }, 245 | "license": [ 246 | "http://opensource.org/licenses/mit-license.php" 247 | ], 248 | "description": "jquery.inputmask is a jquery plugin which create an input mask.", 249 | "keywords": [ 250 | "form", 251 | "input", 252 | "inputmask", 253 | "jquery", 254 | "mask", 255 | "plugins" 256 | ] 257 | }, 258 | { 259 | "name": "bower-asset/punycode", 260 | "version": "v1.3.2", 261 | "source": { 262 | "type": "git", 263 | "url": "https://github.com/bestiejs/punycode.js.git", 264 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 265 | }, 266 | "dist": { 267 | "type": "zip", 268 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 269 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 270 | "shasum": "" 271 | }, 272 | "type": "bower-asset-library", 273 | "extra": { 274 | "bower-asset-main": "punycode.js", 275 | "bower-asset-ignore": [ 276 | "coverage", 277 | "tests", 278 | ".*", 279 | "component.json", 280 | "Gruntfile.js", 281 | "node_modules", 282 | "package.json" 283 | ] 284 | } 285 | }, 286 | { 287 | "name": "bower-asset/yii2-pjax", 288 | "version": "v2.0.4", 289 | "source": { 290 | "type": "git", 291 | "url": "https://github.com/yiisoft/jquery-pjax.git", 292 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0" 293 | }, 294 | "dist": { 295 | "type": "zip", 296 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/3f20897307cca046fca5323b318475ae9dac0ca0", 297 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0", 298 | "shasum": "" 299 | }, 300 | "require": { 301 | "bower-asset/jquery": ">=1.8" 302 | }, 303 | "type": "bower-asset-library", 304 | "extra": { 305 | "bower-asset-main": "./jquery.pjax.js", 306 | "bower-asset-ignore": [ 307 | ".travis.yml", 308 | "Gemfile", 309 | "Gemfile.lock", 310 | "vendor/", 311 | "script/", 312 | "test/" 313 | ] 314 | }, 315 | "license": [ 316 | "MIT" 317 | ] 318 | }, 319 | { 320 | "name": "cebe/markdown", 321 | "version": "1.0.2", 322 | "source": { 323 | "type": "git", 324 | "url": "https://github.com/cebe/markdown.git", 325 | "reference": "f681fee8303310415b746f3758eeda0a7ad08bda" 326 | }, 327 | "dist": { 328 | "type": "zip", 329 | "url": "https://api.github.com/repos/cebe/markdown/zipball/f681fee8303310415b746f3758eeda0a7ad08bda", 330 | "reference": "f681fee8303310415b746f3758eeda0a7ad08bda", 331 | "shasum": "" 332 | }, 333 | "require": { 334 | "lib-pcre": "*", 335 | "php": ">=5.4.0" 336 | }, 337 | "require-dev": { 338 | "cebe/indent": "*", 339 | "facebook/xhprof": "*@dev", 340 | "phpunit/phpunit": "3.7.*" 341 | }, 342 | "bin": [ 343 | "bin/markdown" 344 | ], 345 | "type": "library", 346 | "extra": { 347 | "branch-alias": { 348 | "dev-master": "1.0.x-dev" 349 | } 350 | }, 351 | "autoload": { 352 | "psr-4": { 353 | "cebe\\markdown\\": "" 354 | } 355 | }, 356 | "notification-url": "https://packagist.org/downloads/", 357 | "license": [ 358 | "MIT" 359 | ], 360 | "authors": [ 361 | { 362 | "name": "Carsten Brandt", 363 | "email": "mail@cebe.cc", 364 | "homepage": "http://cebe.cc/", 365 | "role": "Creator" 366 | } 367 | ], 368 | "description": "A super fast, highly extensible markdown parser for PHP", 369 | "homepage": "https://github.com/cebe/markdown#readme", 370 | "keywords": [ 371 | "extensible", 372 | "fast", 373 | "gfm", 374 | "markdown", 375 | "markdown-extra" 376 | ], 377 | "time": "2015-03-06 05:21:16" 378 | }, 379 | { 380 | "name": "ezyang/htmlpurifier", 381 | "version": "v4.6.0", 382 | "source": { 383 | "type": "git", 384 | "url": "https://github.com/ezyang/htmlpurifier.git", 385 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd" 386 | }, 387 | "dist": { 388 | "type": "zip", 389 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd", 390 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd", 391 | "shasum": "" 392 | }, 393 | "require": { 394 | "php": ">=5.2" 395 | }, 396 | "type": "library", 397 | "autoload": { 398 | "psr-0": { 399 | "HTMLPurifier": "library/" 400 | }, 401 | "files": [ 402 | "library/HTMLPurifier.composer.php" 403 | ] 404 | }, 405 | "notification-url": "https://packagist.org/downloads/", 406 | "license": [ 407 | "LGPL" 408 | ], 409 | "authors": [ 410 | { 411 | "name": "Edward Z. Yang", 412 | "email": "admin@htmlpurifier.org", 413 | "homepage": "http://ezyang.com" 414 | } 415 | ], 416 | "description": "Standards compliant HTML filter written in PHP", 417 | "homepage": "http://htmlpurifier.org/", 418 | "keywords": [ 419 | "html" 420 | ], 421 | "time": "2013-11-30 08:25:19" 422 | }, 423 | { 424 | "name": "guzzle/guzzle", 425 | "version": "v3.9.3", 426 | "source": { 427 | "type": "git", 428 | "url": "https://github.com/guzzle/guzzle3.git", 429 | "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" 430 | }, 431 | "dist": { 432 | "type": "zip", 433 | "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", 434 | "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", 435 | "shasum": "" 436 | }, 437 | "require": { 438 | "ext-curl": "*", 439 | "php": ">=5.3.3", 440 | "symfony/event-dispatcher": "~2.1" 441 | }, 442 | "replace": { 443 | "guzzle/batch": "self.version", 444 | "guzzle/cache": "self.version", 445 | "guzzle/common": "self.version", 446 | "guzzle/http": "self.version", 447 | "guzzle/inflection": "self.version", 448 | "guzzle/iterator": "self.version", 449 | "guzzle/log": "self.version", 450 | "guzzle/parser": "self.version", 451 | "guzzle/plugin": "self.version", 452 | "guzzle/plugin-async": "self.version", 453 | "guzzle/plugin-backoff": "self.version", 454 | "guzzle/plugin-cache": "self.version", 455 | "guzzle/plugin-cookie": "self.version", 456 | "guzzle/plugin-curlauth": "self.version", 457 | "guzzle/plugin-error-response": "self.version", 458 | "guzzle/plugin-history": "self.version", 459 | "guzzle/plugin-log": "self.version", 460 | "guzzle/plugin-md5": "self.version", 461 | "guzzle/plugin-mock": "self.version", 462 | "guzzle/plugin-oauth": "self.version", 463 | "guzzle/service": "self.version", 464 | "guzzle/stream": "self.version" 465 | }, 466 | "require-dev": { 467 | "doctrine/cache": "~1.3", 468 | "monolog/monolog": "~1.0", 469 | "phpunit/phpunit": "3.7.*", 470 | "psr/log": "~1.0", 471 | "symfony/class-loader": "~2.1", 472 | "zendframework/zend-cache": "2.*,<2.3", 473 | "zendframework/zend-log": "2.*,<2.3" 474 | }, 475 | "suggest": { 476 | "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." 477 | }, 478 | "type": "library", 479 | "extra": { 480 | "branch-alias": { 481 | "dev-master": "3.9-dev" 482 | } 483 | }, 484 | "autoload": { 485 | "psr-0": { 486 | "Guzzle": "src/", 487 | "Guzzle\\Tests": "tests/" 488 | } 489 | }, 490 | "notification-url": "https://packagist.org/downloads/", 491 | "license": [ 492 | "MIT" 493 | ], 494 | "authors": [ 495 | { 496 | "name": "Michael Dowling", 497 | "email": "mtdowling@gmail.com", 498 | "homepage": "https://github.com/mtdowling" 499 | }, 500 | { 501 | "name": "Guzzle Community", 502 | "homepage": "https://github.com/guzzle/guzzle/contributors" 503 | } 504 | ], 505 | "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", 506 | "homepage": "http://guzzlephp.org/", 507 | "keywords": [ 508 | "client", 509 | "curl", 510 | "framework", 511 | "http", 512 | "http client", 513 | "rest", 514 | "web service" 515 | ], 516 | "time": "2015-03-18 18:23:50" 517 | }, 518 | { 519 | "name": "imagine/imagine", 520 | "version": "v0.5.0", 521 | "source": { 522 | "type": "git", 523 | "url": "https://github.com/avalanche123/Imagine.git", 524 | "reference": "f64ec666baaa800edcbf237db41121a569230709" 525 | }, 526 | "dist": { 527 | "type": "zip", 528 | "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/f64ec666baaa800edcbf237db41121a569230709", 529 | "reference": "f64ec666baaa800edcbf237db41121a569230709", 530 | "shasum": "" 531 | }, 532 | "require": { 533 | "php": ">=5.3.2" 534 | }, 535 | "require-dev": { 536 | "sami/sami": "dev-master" 537 | }, 538 | "suggest": { 539 | "ext-gd": "to use the GD implementation", 540 | "ext-gmagick": "to use the Gmagick implementation", 541 | "ext-imagick": "to use the Imagick implementation" 542 | }, 543 | "type": "library", 544 | "autoload": { 545 | "psr-0": { 546 | "Imagine": "lib/" 547 | } 548 | }, 549 | "notification-url": "https://packagist.org/downloads/", 550 | "license": [ 551 | "MIT" 552 | ], 553 | "authors": [ 554 | { 555 | "name": "Bulat Shakirzyanov", 556 | "email": "mallluhuct@gmail.com", 557 | "homepage": "http://avalanche123.com" 558 | } 559 | ], 560 | "description": "Image processing for PHP 5.3", 561 | "homepage": "http://imagine.readthedocs.org/", 562 | "keywords": [ 563 | "drawing", 564 | "graphics", 565 | "image manipulation", 566 | "image processing" 567 | ], 568 | "time": "2013-07-10 17:25:36" 569 | }, 570 | { 571 | "name": "symfony/event-dispatcher", 572 | "version": "v2.6.5", 573 | "target-dir": "Symfony/Component/EventDispatcher", 574 | "source": { 575 | "type": "git", 576 | "url": "https://github.com/symfony/EventDispatcher.git", 577 | "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284" 578 | }, 579 | "dist": { 580 | "type": "zip", 581 | "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/70f7c8478739ad21e3deef0d977b38c77f1fb284", 582 | "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284", 583 | "shasum": "" 584 | }, 585 | "require": { 586 | "php": ">=5.3.3" 587 | }, 588 | "require-dev": { 589 | "psr/log": "~1.0", 590 | "symfony/config": "~2.0,>=2.0.5", 591 | "symfony/dependency-injection": "~2.6", 592 | "symfony/expression-language": "~2.6", 593 | "symfony/phpunit-bridge": "~2.7", 594 | "symfony/stopwatch": "~2.3" 595 | }, 596 | "suggest": { 597 | "symfony/dependency-injection": "", 598 | "symfony/http-kernel": "" 599 | }, 600 | "type": "library", 601 | "extra": { 602 | "branch-alias": { 603 | "dev-master": "2.6-dev" 604 | } 605 | }, 606 | "autoload": { 607 | "psr-0": { 608 | "Symfony\\Component\\EventDispatcher\\": "" 609 | } 610 | }, 611 | "notification-url": "https://packagist.org/downloads/", 612 | "license": [ 613 | "MIT" 614 | ], 615 | "authors": [ 616 | { 617 | "name": "Symfony Community", 618 | "homepage": "http://symfony.com/contributors" 619 | }, 620 | { 621 | "name": "Fabien Potencier", 622 | "email": "fabien@symfony.com" 623 | } 624 | ], 625 | "description": "Symfony EventDispatcher Component", 626 | "homepage": "http://symfony.com", 627 | "time": "2015-03-13 17:37:22" 628 | }, 629 | { 630 | "name": "yiisoft/yii2", 631 | "version": "2.0.3", 632 | "source": { 633 | "type": "git", 634 | "url": "https://github.com/yiisoft/yii2-framework.git", 635 | "reference": "85b773a384f3894d558905cb13522bb338c99dba" 636 | }, 637 | "dist": { 638 | "type": "zip", 639 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/85b773a384f3894d558905cb13522bb338c99dba", 640 | "reference": "85b773a384f3894d558905cb13522bb338c99dba", 641 | "shasum": "" 642 | }, 643 | "require": { 644 | "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable", 645 | "bower-asset/jquery.inputmask": "3.1.*", 646 | "bower-asset/punycode": "1.3.*", 647 | "bower-asset/yii2-pjax": ">=2.0.1", 648 | "cebe/markdown": "~1.0.0", 649 | "ext-mbstring": "*", 650 | "ezyang/htmlpurifier": "4.6.*", 651 | "lib-pcre": "*", 652 | "php": ">=5.4.0", 653 | "yiisoft/yii2-composer": "*" 654 | }, 655 | "bin": [ 656 | "yii" 657 | ], 658 | "type": "library", 659 | "extra": { 660 | "branch-alias": { 661 | "dev-master": "2.0.x-dev" 662 | } 663 | }, 664 | "autoload": { 665 | "psr-4": { 666 | "yii\\": "" 667 | } 668 | }, 669 | "notification-url": "https://packagist.org/downloads/", 670 | "license": [ 671 | "BSD-3-Clause" 672 | ], 673 | "authors": [ 674 | { 675 | "name": "Qiang Xue", 676 | "email": "qiang.xue@gmail.com", 677 | "homepage": "http://www.yiiframework.com/", 678 | "role": "Founder and project lead" 679 | }, 680 | { 681 | "name": "Alexander Makarov", 682 | "email": "sam@rmcreative.ru", 683 | "homepage": "http://rmcreative.ru/", 684 | "role": "Core framework development" 685 | }, 686 | { 687 | "name": "Maurizio Domba", 688 | "homepage": "http://mdomba.info/", 689 | "role": "Core framework development" 690 | }, 691 | { 692 | "name": "Carsten Brandt", 693 | "email": "mail@cebe.cc", 694 | "homepage": "http://cebe.cc/", 695 | "role": "Core framework development" 696 | }, 697 | { 698 | "name": "Timur Ruziev", 699 | "email": "resurtm@gmail.com", 700 | "homepage": "http://resurtm.com/", 701 | "role": "Core framework development" 702 | }, 703 | { 704 | "name": "Paul Klimov", 705 | "email": "klimov.paul@gmail.com", 706 | "role": "Core framework development" 707 | } 708 | ], 709 | "description": "Yii PHP Framework Version 2", 710 | "homepage": "http://www.yiiframework.com/", 711 | "keywords": [ 712 | "framework", 713 | "yii2" 714 | ], 715 | "time": "2015-03-01 06:22:44" 716 | }, 717 | { 718 | "name": "yiisoft/yii2-composer", 719 | "version": "2.0.3", 720 | "source": { 721 | "type": "git", 722 | "url": "https://github.com/yiisoft/yii2-composer.git", 723 | "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be" 724 | }, 725 | "dist": { 726 | "type": "zip", 727 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/ca8d23707ae47d20b0454e4b135c156f6da6d7be", 728 | "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be", 729 | "shasum": "" 730 | }, 731 | "require": { 732 | "composer-plugin-api": "1.0.0" 733 | }, 734 | "type": "composer-plugin", 735 | "extra": { 736 | "class": "yii\\composer\\Plugin", 737 | "branch-alias": { 738 | "dev-master": "2.0.x-dev" 739 | } 740 | }, 741 | "autoload": { 742 | "psr-4": { 743 | "yii\\composer\\": "" 744 | } 745 | }, 746 | "notification-url": "https://packagist.org/downloads/", 747 | "license": [ 748 | "BSD-3-Clause" 749 | ], 750 | "authors": [ 751 | { 752 | "name": "Qiang Xue", 753 | "email": "qiang.xue@gmail.com" 754 | } 755 | ], 756 | "description": "The composer plugin for Yii extension installer", 757 | "keywords": [ 758 | "composer", 759 | "extension installer", 760 | "yii2" 761 | ], 762 | "time": "2015-03-01 06:22:44" 763 | }, 764 | { 765 | "name": "yiisoft/yii2-imagine", 766 | "version": "2.0.3", 767 | "source": { 768 | "type": "git", 769 | "url": "https://github.com/yiisoft/yii2-imagine.git", 770 | "reference": "0961343138b65bba447de84b2b300899617e6acc" 771 | }, 772 | "dist": { 773 | "type": "zip", 774 | "url": "https://api.github.com/repos/yiisoft/yii2-imagine/zipball/0961343138b65bba447de84b2b300899617e6acc", 775 | "reference": "0961343138b65bba447de84b2b300899617e6acc", 776 | "shasum": "" 777 | }, 778 | "require": { 779 | "imagine/imagine": "0.5.*", 780 | "yiisoft/yii2": "*" 781 | }, 782 | "type": "yii2-extension", 783 | "extra": { 784 | "branch-alias": { 785 | "dev-master": "2.0.x-dev" 786 | } 787 | }, 788 | "autoload": { 789 | "psr-4": { 790 | "yii\\imagine\\": "" 791 | } 792 | }, 793 | "notification-url": "https://packagist.org/downloads/", 794 | "license": [ 795 | "BSD-3-Clause" 796 | ], 797 | "authors": [ 798 | { 799 | "name": "Antonio Ramirez", 800 | "email": "amigo.cobos@gmail.com" 801 | } 802 | ], 803 | "description": "The Imagine integration for the Yii framework", 804 | "keywords": [ 805 | "helper", 806 | "image", 807 | "imagine", 808 | "yii2" 809 | ], 810 | "time": "2015-03-01 06:22:44" 811 | } 812 | ], 813 | "packages-dev": [ 814 | { 815 | "name": "doctrine/instantiator", 816 | "version": "1.0.4", 817 | "source": { 818 | "type": "git", 819 | "url": "https://github.com/doctrine/instantiator.git", 820 | "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" 821 | }, 822 | "dist": { 823 | "type": "zip", 824 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", 825 | "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", 826 | "shasum": "" 827 | }, 828 | "require": { 829 | "php": ">=5.3,<8.0-DEV" 830 | }, 831 | "require-dev": { 832 | "athletic/athletic": "~0.1.8", 833 | "ext-pdo": "*", 834 | "ext-phar": "*", 835 | "phpunit/phpunit": "~4.0", 836 | "squizlabs/php_codesniffer": "2.0.*@ALPHA" 837 | }, 838 | "type": "library", 839 | "extra": { 840 | "branch-alias": { 841 | "dev-master": "1.0.x-dev" 842 | } 843 | }, 844 | "autoload": { 845 | "psr-0": { 846 | "Doctrine\\Instantiator\\": "src" 847 | } 848 | }, 849 | "notification-url": "https://packagist.org/downloads/", 850 | "license": [ 851 | "MIT" 852 | ], 853 | "authors": [ 854 | { 855 | "name": "Marco Pivetta", 856 | "email": "ocramius@gmail.com", 857 | "homepage": "http://ocramius.github.com/" 858 | } 859 | ], 860 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 861 | "homepage": "https://github.com/doctrine/instantiator", 862 | "keywords": [ 863 | "constructor", 864 | "instantiate" 865 | ], 866 | "time": "2014-10-13 12:58:55" 867 | }, 868 | { 869 | "name": "phpdocumentor/reflection-docblock", 870 | "version": "2.0.4", 871 | "source": { 872 | "type": "git", 873 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 874 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" 875 | }, 876 | "dist": { 877 | "type": "zip", 878 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", 879 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", 880 | "shasum": "" 881 | }, 882 | "require": { 883 | "php": ">=5.3.3" 884 | }, 885 | "require-dev": { 886 | "phpunit/phpunit": "~4.0" 887 | }, 888 | "suggest": { 889 | "dflydev/markdown": "~1.0", 890 | "erusev/parsedown": "~1.0" 891 | }, 892 | "type": "library", 893 | "extra": { 894 | "branch-alias": { 895 | "dev-master": "2.0.x-dev" 896 | } 897 | }, 898 | "autoload": { 899 | "psr-0": { 900 | "phpDocumentor": [ 901 | "src/" 902 | ] 903 | } 904 | }, 905 | "notification-url": "https://packagist.org/downloads/", 906 | "license": [ 907 | "MIT" 908 | ], 909 | "authors": [ 910 | { 911 | "name": "Mike van Riel", 912 | "email": "mike.vanriel@naenius.com" 913 | } 914 | ], 915 | "time": "2015-02-03 12:10:50" 916 | }, 917 | { 918 | "name": "phpspec/php-diff", 919 | "version": "v1.0.2", 920 | "source": { 921 | "type": "git", 922 | "url": "https://github.com/phpspec/php-diff.git", 923 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a" 924 | }, 925 | "dist": { 926 | "type": "zip", 927 | "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a", 928 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a", 929 | "shasum": "" 930 | }, 931 | "type": "library", 932 | "autoload": { 933 | "psr-0": { 934 | "Diff": "lib/" 935 | } 936 | }, 937 | "notification-url": "https://packagist.org/downloads/", 938 | "license": [ 939 | "BSD-3-Clause" 940 | ], 941 | "authors": [ 942 | { 943 | "name": "Chris Boulton", 944 | "homepage": "http://github.com/chrisboulton", 945 | "role": "Original developer" 946 | } 947 | ], 948 | "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", 949 | "time": "2013-11-01 13:02:21" 950 | }, 951 | { 952 | "name": "phpspec/phpspec", 953 | "version": "2.1.1", 954 | "source": { 955 | "type": "git", 956 | "url": "https://github.com/phpspec/phpspec.git", 957 | "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d" 958 | }, 959 | "dist": { 960 | "type": "zip", 961 | "url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d", 962 | "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d", 963 | "shasum": "" 964 | }, 965 | "require": { 966 | "doctrine/instantiator": "~1.0,>=1.0.1", 967 | "php": ">=5.3.3", 968 | "phpspec/php-diff": "~1.0.0", 969 | "phpspec/prophecy": "~1.1", 970 | "sebastian/exporter": "~1.0", 971 | "symfony/console": "~2.3", 972 | "symfony/event-dispatcher": "~2.1", 973 | "symfony/finder": "~2.1", 974 | "symfony/process": "~2.1", 975 | "symfony/yaml": "~2.1" 976 | }, 977 | "require-dev": { 978 | "behat/behat": "~3.0,>=3.0.11", 979 | "bossa/phpspec2-expect": "~1.0", 980 | "symfony/filesystem": "~2.1" 981 | }, 982 | "suggest": { 983 | "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters" 984 | }, 985 | "bin": [ 986 | "bin/phpspec" 987 | ], 988 | "type": "library", 989 | "extra": { 990 | "branch-alias": { 991 | "dev-master": "2.1.x-dev" 992 | } 993 | }, 994 | "autoload": { 995 | "psr-0": { 996 | "PhpSpec": "src/" 997 | } 998 | }, 999 | "notification-url": "https://packagist.org/downloads/", 1000 | "license": [ 1001 | "MIT" 1002 | ], 1003 | "authors": [ 1004 | { 1005 | "name": "Konstantin Kudryashov", 1006 | "email": "ever.zet@gmail.com", 1007 | "homepage": "http://everzet.com" 1008 | }, 1009 | { 1010 | "name": "Marcello Duarte", 1011 | "homepage": "http://marcelloduarte.net/" 1012 | } 1013 | ], 1014 | "description": "Specification-oriented BDD framework for PHP 5.3+", 1015 | "homepage": "http://phpspec.net/", 1016 | "keywords": [ 1017 | "BDD", 1018 | "SpecBDD", 1019 | "TDD", 1020 | "spec", 1021 | "specification", 1022 | "testing", 1023 | "tests" 1024 | ], 1025 | "time": "2015-01-09 13:21:45" 1026 | }, 1027 | { 1028 | "name": "phpspec/prophecy", 1029 | "version": "v1.3.1", 1030 | "source": { 1031 | "type": "git", 1032 | "url": "https://github.com/phpspec/prophecy.git", 1033 | "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" 1034 | }, 1035 | "dist": { 1036 | "type": "zip", 1037 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", 1038 | "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", 1039 | "shasum": "" 1040 | }, 1041 | "require": { 1042 | "doctrine/instantiator": "~1.0,>=1.0.2", 1043 | "phpdocumentor/reflection-docblock": "~2.0" 1044 | }, 1045 | "require-dev": { 1046 | "phpspec/phpspec": "~2.0" 1047 | }, 1048 | "type": "library", 1049 | "extra": { 1050 | "branch-alias": { 1051 | "dev-master": "1.2.x-dev" 1052 | } 1053 | }, 1054 | "autoload": { 1055 | "psr-0": { 1056 | "Prophecy\\": "src/" 1057 | } 1058 | }, 1059 | "notification-url": "https://packagist.org/downloads/", 1060 | "license": [ 1061 | "MIT" 1062 | ], 1063 | "authors": [ 1064 | { 1065 | "name": "Konstantin Kudryashov", 1066 | "email": "ever.zet@gmail.com", 1067 | "homepage": "http://everzet.com" 1068 | }, 1069 | { 1070 | "name": "Marcello Duarte", 1071 | "email": "marcello.duarte@gmail.com" 1072 | } 1073 | ], 1074 | "description": "Highly opinionated mocking framework for PHP 5.3+", 1075 | "homepage": "http://phpspec.org", 1076 | "keywords": [ 1077 | "Double", 1078 | "Dummy", 1079 | "fake", 1080 | "mock", 1081 | "spy", 1082 | "stub" 1083 | ], 1084 | "time": "2014-11-17 16:23:49" 1085 | }, 1086 | { 1087 | "name": "sebastian/exporter", 1088 | "version": "1.2.0", 1089 | "source": { 1090 | "type": "git", 1091 | "url": "https://github.com/sebastianbergmann/exporter.git", 1092 | "reference": "84839970d05254c73cde183a721c7af13aede943" 1093 | }, 1094 | "dist": { 1095 | "type": "zip", 1096 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", 1097 | "reference": "84839970d05254c73cde183a721c7af13aede943", 1098 | "shasum": "" 1099 | }, 1100 | "require": { 1101 | "php": ">=5.3.3", 1102 | "sebastian/recursion-context": "~1.0" 1103 | }, 1104 | "require-dev": { 1105 | "phpunit/phpunit": "~4.4" 1106 | }, 1107 | "type": "library", 1108 | "extra": { 1109 | "branch-alias": { 1110 | "dev-master": "1.2.x-dev" 1111 | } 1112 | }, 1113 | "autoload": { 1114 | "classmap": [ 1115 | "src/" 1116 | ] 1117 | }, 1118 | "notification-url": "https://packagist.org/downloads/", 1119 | "license": [ 1120 | "BSD-3-Clause" 1121 | ], 1122 | "authors": [ 1123 | { 1124 | "name": "Jeff Welch", 1125 | "email": "whatthejeff@gmail.com" 1126 | }, 1127 | { 1128 | "name": "Volker Dusch", 1129 | "email": "github@wallbash.com" 1130 | }, 1131 | { 1132 | "name": "Bernhard Schussek", 1133 | "email": "bschussek@2bepublished.at" 1134 | }, 1135 | { 1136 | "name": "Sebastian Bergmann", 1137 | "email": "sebastian@phpunit.de" 1138 | }, 1139 | { 1140 | "name": "Adam Harvey", 1141 | "email": "aharvey@php.net" 1142 | } 1143 | ], 1144 | "description": "Provides the functionality to export PHP variables for visualization", 1145 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1146 | "keywords": [ 1147 | "export", 1148 | "exporter" 1149 | ], 1150 | "time": "2015-01-27 07:23:06" 1151 | }, 1152 | { 1153 | "name": "sebastian/recursion-context", 1154 | "version": "1.0.0", 1155 | "source": { 1156 | "type": "git", 1157 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1158 | "reference": "3989662bbb30a29d20d9faa04a846af79b276252" 1159 | }, 1160 | "dist": { 1161 | "type": "zip", 1162 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", 1163 | "reference": "3989662bbb30a29d20d9faa04a846af79b276252", 1164 | "shasum": "" 1165 | }, 1166 | "require": { 1167 | "php": ">=5.3.3" 1168 | }, 1169 | "require-dev": { 1170 | "phpunit/phpunit": "~4.4" 1171 | }, 1172 | "type": "library", 1173 | "extra": { 1174 | "branch-alias": { 1175 | "dev-master": "1.0.x-dev" 1176 | } 1177 | }, 1178 | "autoload": { 1179 | "classmap": [ 1180 | "src/" 1181 | ] 1182 | }, 1183 | "notification-url": "https://packagist.org/downloads/", 1184 | "license": [ 1185 | "BSD-3-Clause" 1186 | ], 1187 | "authors": [ 1188 | { 1189 | "name": "Jeff Welch", 1190 | "email": "whatthejeff@gmail.com" 1191 | }, 1192 | { 1193 | "name": "Sebastian Bergmann", 1194 | "email": "sebastian@phpunit.de" 1195 | }, 1196 | { 1197 | "name": "Adam Harvey", 1198 | "email": "aharvey@php.net" 1199 | } 1200 | ], 1201 | "description": "Provides functionality to recursively process PHP variables", 1202 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1203 | "time": "2015-01-24 09:48:32" 1204 | }, 1205 | { 1206 | "name": "symfony/console", 1207 | "version": "v2.6.5", 1208 | "target-dir": "Symfony/Component/Console", 1209 | "source": { 1210 | "type": "git", 1211 | "url": "https://github.com/symfony/Console.git", 1212 | "reference": "53f86497ccd01677e22435cfb7262599450a90d1" 1213 | }, 1214 | "dist": { 1215 | "type": "zip", 1216 | "url": "https://api.github.com/repos/symfony/Console/zipball/53f86497ccd01677e22435cfb7262599450a90d1", 1217 | "reference": "53f86497ccd01677e22435cfb7262599450a90d1", 1218 | "shasum": "" 1219 | }, 1220 | "require": { 1221 | "php": ">=5.3.3" 1222 | }, 1223 | "require-dev": { 1224 | "psr/log": "~1.0", 1225 | "symfony/event-dispatcher": "~2.1", 1226 | "symfony/phpunit-bridge": "~2.7", 1227 | "symfony/process": "~2.1" 1228 | }, 1229 | "suggest": { 1230 | "psr/log": "For using the console logger", 1231 | "symfony/event-dispatcher": "", 1232 | "symfony/process": "" 1233 | }, 1234 | "type": "library", 1235 | "extra": { 1236 | "branch-alias": { 1237 | "dev-master": "2.6-dev" 1238 | } 1239 | }, 1240 | "autoload": { 1241 | "psr-0": { 1242 | "Symfony\\Component\\Console\\": "" 1243 | } 1244 | }, 1245 | "notification-url": "https://packagist.org/downloads/", 1246 | "license": [ 1247 | "MIT" 1248 | ], 1249 | "authors": [ 1250 | { 1251 | "name": "Symfony Community", 1252 | "homepage": "http://symfony.com/contributors" 1253 | }, 1254 | { 1255 | "name": "Fabien Potencier", 1256 | "email": "fabien@symfony.com" 1257 | } 1258 | ], 1259 | "description": "Symfony Console Component", 1260 | "homepage": "http://symfony.com", 1261 | "time": "2015-03-13 17:37:22" 1262 | }, 1263 | { 1264 | "name": "symfony/finder", 1265 | "version": "v2.6.5", 1266 | "target-dir": "Symfony/Component/Finder", 1267 | "source": { 1268 | "type": "git", 1269 | "url": "https://github.com/symfony/Finder.git", 1270 | "reference": "bebc7479c566fa4f14b9bcef9e32e719eabec74e" 1271 | }, 1272 | "dist": { 1273 | "type": "zip", 1274 | "url": "https://api.github.com/repos/symfony/Finder/zipball/bebc7479c566fa4f14b9bcef9e32e719eabec74e", 1275 | "reference": "bebc7479c566fa4f14b9bcef9e32e719eabec74e", 1276 | "shasum": "" 1277 | }, 1278 | "require": { 1279 | "php": ">=5.3.3" 1280 | }, 1281 | "require-dev": { 1282 | "symfony/phpunit-bridge": "~2.7" 1283 | }, 1284 | "type": "library", 1285 | "extra": { 1286 | "branch-alias": { 1287 | "dev-master": "2.6-dev" 1288 | } 1289 | }, 1290 | "autoload": { 1291 | "psr-0": { 1292 | "Symfony\\Component\\Finder\\": "" 1293 | } 1294 | }, 1295 | "notification-url": "https://packagist.org/downloads/", 1296 | "license": [ 1297 | "MIT" 1298 | ], 1299 | "authors": [ 1300 | { 1301 | "name": "Symfony Community", 1302 | "homepage": "http://symfony.com/contributors" 1303 | }, 1304 | { 1305 | "name": "Fabien Potencier", 1306 | "email": "fabien@symfony.com" 1307 | } 1308 | ], 1309 | "description": "Symfony Finder Component", 1310 | "homepage": "http://symfony.com", 1311 | "time": "2015-03-12 10:28:44" 1312 | }, 1313 | { 1314 | "name": "symfony/process", 1315 | "version": "v2.6.5", 1316 | "target-dir": "Symfony/Component/Process", 1317 | "source": { 1318 | "type": "git", 1319 | "url": "https://github.com/symfony/Process.git", 1320 | "reference": "4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc" 1321 | }, 1322 | "dist": { 1323 | "type": "zip", 1324 | "url": "https://api.github.com/repos/symfony/Process/zipball/4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc", 1325 | "reference": "4d717f34f3d1d6ab30fbe79f7132960a27f4a0dc", 1326 | "shasum": "" 1327 | }, 1328 | "require": { 1329 | "php": ">=5.3.3" 1330 | }, 1331 | "require-dev": { 1332 | "symfony/phpunit-bridge": "~2.7" 1333 | }, 1334 | "type": "library", 1335 | "extra": { 1336 | "branch-alias": { 1337 | "dev-master": "2.6-dev" 1338 | } 1339 | }, 1340 | "autoload": { 1341 | "psr-0": { 1342 | "Symfony\\Component\\Process\\": "" 1343 | } 1344 | }, 1345 | "notification-url": "https://packagist.org/downloads/", 1346 | "license": [ 1347 | "MIT" 1348 | ], 1349 | "authors": [ 1350 | { 1351 | "name": "Symfony Community", 1352 | "homepage": "http://symfony.com/contributors" 1353 | }, 1354 | { 1355 | "name": "Fabien Potencier", 1356 | "email": "fabien@symfony.com" 1357 | } 1358 | ], 1359 | "description": "Symfony Process Component", 1360 | "homepage": "http://symfony.com", 1361 | "time": "2015-03-12 10:28:44" 1362 | }, 1363 | { 1364 | "name": "symfony/yaml", 1365 | "version": "v2.6.5", 1366 | "target-dir": "Symfony/Component/Yaml", 1367 | "source": { 1368 | "type": "git", 1369 | "url": "https://github.com/symfony/Yaml.git", 1370 | "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d" 1371 | }, 1372 | "dist": { 1373 | "type": "zip", 1374 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/0cd8e72071e46e15fc072270ae39ea1b66b10a9d", 1375 | "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d", 1376 | "shasum": "" 1377 | }, 1378 | "require": { 1379 | "php": ">=5.3.3" 1380 | }, 1381 | "require-dev": { 1382 | "symfony/phpunit-bridge": "~2.7" 1383 | }, 1384 | "type": "library", 1385 | "extra": { 1386 | "branch-alias": { 1387 | "dev-master": "2.6-dev" 1388 | } 1389 | }, 1390 | "autoload": { 1391 | "psr-0": { 1392 | "Symfony\\Component\\Yaml\\": "" 1393 | } 1394 | }, 1395 | "notification-url": "https://packagist.org/downloads/", 1396 | "license": [ 1397 | "MIT" 1398 | ], 1399 | "authors": [ 1400 | { 1401 | "name": "Symfony Community", 1402 | "homepage": "http://symfony.com/contributors" 1403 | }, 1404 | { 1405 | "name": "Fabien Potencier", 1406 | "email": "fabien@symfony.com" 1407 | } 1408 | ], 1409 | "description": "Symfony Yaml Component", 1410 | "homepage": "http://symfony.com", 1411 | "time": "2015-03-12 10:28:44" 1412 | } 1413 | ], 1414 | "aliases": [], 1415 | "minimum-stability": "stable", 1416 | "stability-flags": [], 1417 | "prefer-stable": false, 1418 | "prefer-lowest": false, 1419 | "platform": [], 1420 | "platform-dev": [] 1421 | } 1422 | -------------------------------------------------------------------------------- /controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | getView(); 13 | /* 14 | DateTimePickerAssets::register($view); 15 | 16 | $id = $this->options['id']; 17 | 18 | $options = Json::encode($this->clientOptions); 19 | */ 20 | $view->registerJs("\$(function(){\$('#filemanager-upload').modal();});"); 21 | 22 | return $this->redirect(['files/index']); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /controllers/FileTagController.php: -------------------------------------------------------------------------------- 1 | [ 23 | 'class' => VerbFilter::className(), 24 | 'actions' => [ 25 | 'delete' => ['post'], 26 | ], 27 | ], 28 | ]; 29 | } 30 | 31 | /** 32 | * Lists all FileTag models. 33 | * @return mixed 34 | */ 35 | public function actionIndex() 36 | { 37 | $searchModel = new FileTagSearch(); 38 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 39 | 40 | return $this->render('index', [ 41 | 'searchModel' => $searchModel, 42 | 'dataProvider' => $dataProvider, 43 | ]); 44 | } 45 | 46 | /** 47 | * Displays a single FileTag model. 48 | * @param integer $id 49 | * @return mixed 50 | */ 51 | public function actionView($id) 52 | { 53 | return $this->render('view', [ 54 | 'model' => $this->findModel($id), 55 | ]); 56 | } 57 | 58 | /** 59 | * Creates a new FileTag model. 60 | * If creation is successful, the browser will be redirected to the 'view' page. 61 | * @return mixed 62 | */ 63 | public function actionCreate() 64 | { 65 | $model = new FileTag(); 66 | 67 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 68 | return $this->redirect(['view', 'id' => $model->id]); 69 | } else { 70 | return $this->render('create', [ 71 | 'model' => $model, 72 | ]); 73 | } 74 | } 75 | 76 | /** 77 | * Updates an existing FileTag model. 78 | * If update is successful, the browser will be redirected to the 'view' page. 79 | * @param integer $id 80 | * @return mixed 81 | */ 82 | public function actionUpdate($id) 83 | { 84 | $model = $this->findModel($id); 85 | 86 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 87 | return $this->redirect(['view', 'id' => $model->id]); 88 | } else { 89 | return $this->render('update', [ 90 | 'model' => $model, 91 | ]); 92 | } 93 | } 94 | 95 | /** 96 | * Deletes an existing FileTag model. 97 | * If deletion is successful, the browser will be redirected to the 'index' page. 98 | * @param integer $id 99 | * @return mixed 100 | */ 101 | public function actionDelete($id) 102 | { 103 | $this->findModel($id)->delete(); 104 | 105 | return $this->redirect(['index']); 106 | } 107 | 108 | 109 | public function actionCreatetag() 110 | { 111 | 112 | Yii::$app->response->getHeaders()->set('Vary', 'Accept'); 113 | Yii::$app->response->format = Response::FORMAT_JSON; 114 | 115 | $model = new FileTag(); 116 | 117 | if($model->load(Yii::$app->request->post())){ 118 | if ($model->validate() && $model->save()) { 119 | return ['success' => true, 'model' => $model]; 120 | } 121 | } 122 | 123 | return ['error' => $model->errors]; 124 | 125 | } 126 | 127 | 128 | /** 129 | * Finds the FileTag model based on its primary key value. 130 | * If the model is not found, a 404 HTTP exception will be thrown. 131 | * @param integer $id 132 | * @return FileTag the loaded model 133 | * @throws NotFoundHttpException if the model cannot be found 134 | */ 135 | protected function findModel($id) 136 | { 137 | if (($model = FileTag::findOne($id)) !== null) { 138 | return $model; 139 | } else { 140 | throw new NotFoundHttpException('The requested page does not exist.'); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /controllers/FilesController.php: -------------------------------------------------------------------------------- 1 | '.pdf', 35 | 'application/zip' => '.zip', 36 | 'image/gif' => '.gif', 37 | 'image/jpeg' => '.jpg', 38 | 'image/png' => '.png', 39 | 'text/css' => '.css', 40 | 'text/html' => '.html', 41 | 'text/javascript' => '.js', 42 | 'text/plain' => '.txt', 43 | 'text/xml' => '.xml', 44 | 'application/vnd.google-earth.kml+xml' => '.kml', 45 | 'application/vnd.google-earth.kmz' => '.kmz', 46 | ]; 47 | 48 | private $extentionMap = [ 49 | '.kml' => 'application/vnd.google-earth.kml+xml', 50 | '.kmz' => 'application/vnd.google-earth.kmz', 51 | 'pdf' => 'application/pdf', 52 | 'zip' => 'application/zip', 53 | 'gif' => 'image/gif', 54 | 'jpg' => 'image/jpeg', 55 | 'jpeg' => 'image/jpeg', 56 | 'png' => 'image/png', 57 | 'css' => 'text/css', 58 | 'html' => 'text/html', 59 | 'js' => 'text/javascript', 60 | 'txt' => 'text/plain', 61 | 'xml' => 'text/xml', 62 | ]; 63 | 64 | public function behaviors() 65 | { 66 | return [ 67 | 'verbs' => [ 68 | 'class' => VerbFilter::className(), 69 | 'actions' => [ 70 | 'delete' => ['post'], 71 | 'upload' => ['post'], 72 | ], 73 | ], 74 | ]; 75 | } 76 | 77 | 78 | 79 | public function __construct($id, $module, $config = []) 80 | { 81 | $this->accept = Yii::$app->request->getHeaders()->get('Accept'); 82 | parent::__construct($id, $module, $config); 83 | } 84 | 85 | 86 | 87 | /** 88 | * beforeAction function. 89 | * 90 | * @access public 91 | * @param mixed $action 92 | * @return void 93 | */ 94 | public function beforeAction($action) { 95 | 96 | $result = parent::beforeAction($action); 97 | 98 | $options = [ 99 | 'tinymce' => \Yii::$app->urlManager->createUrl('/filemanager/files/tinymce'), 100 | 'properties' => \Yii::$app->urlManager->createUrl('/filemanager/files/properties'), 101 | ]; 102 | $this->getView()->registerJs("filemanager.init(".json_encode($options).");", \yii\web\View::POS_END, 'my-options'); 103 | 104 | return $result; 105 | } 106 | 107 | 108 | 109 | 110 | /** 111 | * Lists all Files models. 112 | * @return mixed 113 | */ 114 | public function actionIndex() 115 | { 116 | 117 | FilemanagerAssets::register($this->view); 118 | 119 | $searchModel = new FilesSearch(); 120 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 121 | $model = new Files(); 122 | 123 | if ($this->accept == 'application/json') { 124 | $models = $dataProvider->getModels(); 125 | 126 | foreach ($models as $model) { 127 | $model->thumbnail_url = \Yii::$app->getModule('filemanager')->url . $model->thumbnail_url; 128 | $model->url = \Yii::$app->getModule('filemanager')->url . $model->url; 129 | } 130 | $pagination = $dataProvider->pagination; 131 | $data = [ 132 | 'links' => $pagination->links, 133 | 'page' => $pagination->page++, 134 | 'pageCount' => $pagination->pageCount, 135 | 'images' => $dataProvider->getModels(), 136 | ]; 137 | \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; 138 | return $data; 139 | } 140 | 141 | return $this->render('index', [ 142 | 'searchModel' => $searchModel, 143 | 'dataProvider' => $dataProvider, 144 | 'model' => $model, 145 | ]); 146 | } 147 | 148 | /** 149 | * Lists all Files models. 150 | * @return mixed 151 | */ 152 | public function actionTinymce() 153 | { 154 | 155 | $this->layout = 'tinymce'; 156 | 157 | FilemanagerAssets::register($this->view); 158 | 159 | $searchModel = new FilesSearch(); 160 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 161 | $model = new Files(); 162 | 163 | return $this->render('index', [ 164 | 'searchModel' => $searchModel, 165 | 'dataProvider' => $dataProvider, 166 | 'model' => $model, 167 | ]); 168 | } 169 | 170 | 171 | 172 | /** 173 | * actionFilemodal function. 174 | * 175 | * @access public 176 | * @return void 177 | */ 178 | public function actionFilemodal(){ 179 | 180 | $this->layout = 'tinymce'; 181 | 182 | FilemanagerAssets::register($this->view); 183 | 184 | $searchModel = new FilesSearch(); 185 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 186 | $model = new Files(); 187 | 188 | return $this->render('index', [ 189 | 'searchModel' => $searchModel, 190 | 'dataProvider' => $dataProvider, 191 | 'model' => $model, 192 | ]); 193 | } 194 | 195 | 196 | /** 197 | * [actionGetimage description] 198 | * @param [type] $id [description] 199 | */ 200 | public function actionGetimage($id){ 201 | 202 | Yii::$app->response->getHeaders()->set('Vary', 'Accept'); 203 | Yii::$app->response->format = Response::FORMAT_JSON; 204 | 205 | $model = $this->findModel($id); 206 | 207 | $awsConfig = $this->module->aws; 208 | 209 | if($awsConfig['enable']){ 210 | $model->url = $this->module->url.$model->url; 211 | }else{ 212 | $model->url = '/'.$model->url; 213 | } 214 | 215 | return $model; 216 | } 217 | 218 | 219 | 220 | /** 221 | * actionUpload function. 222 | * 223 | * @access public 224 | * @return string JSON 225 | */ 226 | public function actionUpload() 227 | { 228 | Yii::$app->response->getHeaders()->set('Vary', 'Accept'); 229 | Yii::$app->response->format = Response::FORMAT_JSON; 230 | 231 | $model = new Files(); 232 | 233 | $path = $this->module->path; 234 | $thumbPath = $this->module->thumbPath; 235 | $directory = Yii::getAlias( $this->module->directory ); 236 | $url = $this->module->url; 237 | $awsConfig = $this->module->aws; 238 | $thumbnails = $this->module->thumbnails; 239 | 240 | $file = UploadedFile::getInstance($model,'file_name'); 241 | 242 | $name = time().'-'.md5($file->name) . $this->typeMap[$file->type]; 243 | 244 | //Upload file 245 | if($awsConfig['enable']){ 246 | $this->uploadAws($file,$name); 247 | }else{ 248 | if ( !file_exists( $directory . $path ) ) { 249 | //FileHelper::createDirectory( $directory . $path, 775); 250 | mkdir($directory . $path, 0755, true); 251 | } 252 | 253 | $file->saveAs( $directory . $path . $name); 254 | } 255 | 256 | //Create Thumbnails 257 | if(!empty($thumbnails) && ($file->type == 'image/gif' || $file->type == 'image/jpeg' || $file->type == 'image/png')){ 258 | $this->createThumbnails($file,$name); 259 | } 260 | 261 | 262 | $model->user_id = 0; 263 | $model->url = $path.$name; 264 | $model->thumbnail_url = $thumbPath.$name; 265 | $model->file_name = $name; 266 | $model->title = $file->name; 267 | $model->type = $file->type; 268 | $model->title = $file->name; 269 | $model->size = $file->size; 270 | /*$model->width = $size[0]; 271 | $model->height = $size[1];*/ 272 | 273 | if($model->save()){ 274 | 275 | // $response['files'][] = [ 276 | // 'id' => $model->id, 277 | // 'url' => $url.$model->url, 278 | // 'thumbnailUrl' => $url.$model->thumbnail_url, 279 | // 'name' => $model->title, 280 | // 'type' => $model->type, 281 | // 'size' => $model->size, 282 | // 'deleteUrl' => \Yii::$app->urlManager->createUrl(['filemanager/files/delete']), 283 | // 'deleteType' => 'POST', 284 | // ]; 285 | 286 | $model->thumbnail_url = \Yii::$app->getModule('filemanager')->url . $model->thumbnail_url; 287 | $model->url = \Yii::$app->getModule('filemanager')->url . $model->url; 288 | 289 | return $model; 290 | 291 | }else{ 292 | 293 | error_log(print_r($model->getErrors(),true)); 294 | 295 | return false; 296 | } 297 | 298 | } 299 | 300 | 301 | /** 302 | * actionUpload function. 303 | * 304 | * @access public 305 | * @return string JSON 306 | */ 307 | public function actionUploadpicker() 308 | { 309 | Yii::$app->response->getHeaders()->set('Vary', 'Accept'); 310 | Yii::$app->response->format = Response::FORMAT_JSON; 311 | 312 | $model = new Files(); 313 | 314 | $path = $this->module->path; 315 | $thumbPath = $this->module->thumbPath; 316 | $directory = Yii::getAlias( $this->module->directory ); 317 | $url = $this->module->url; 318 | $awsConfig = $this->module->aws; 319 | $thumbnails = $this->module->thumbnails; 320 | 321 | $file = UploadedFile::getInstance($model,'file_name'); 322 | 323 | $name = time().'-'.md5($file->name) . $this->typeMap[$file->type]; 324 | 325 | //Upload file 326 | if($awsConfig['enable']){ 327 | $this->uploadAws($file,$name); 328 | }else{ 329 | if ( !file_exists( $directory . $path ) ) { 330 | //FileHelper::createDirectory( $directory . $path, 775); 331 | mkdir($directory . $path, 0755, true); 332 | } 333 | 334 | $file->saveAs( $directory . $path . $name); 335 | } 336 | 337 | //Create Thumbnails 338 | if(!empty($thumbnails) && ($file->type == 'image/gif' || $file->type == 'image/jpeg' || $file->type == 'image/png')){ 339 | $this->createThumbnails($file,$name); 340 | } 341 | 342 | 343 | $model->user_id = 0; 344 | $model->url = $path.$name; 345 | $model->thumbnail_url = $thumbPath.$name; 346 | $model->file_name = $name; 347 | $model->title = $file->name; 348 | $model->type = $file->type; 349 | $model->title = $file->name; 350 | $model->size = $file->size; 351 | 352 | if($model->save()){ 353 | 354 | $model->thumbnail_url = \Yii::$app->getModule('filemanager')->url . $model->thumbnail_url; 355 | $model->url = \Yii::$app->getModule('filemanager')->url . $model->url; 356 | 357 | return $model; 358 | 359 | }else{ 360 | 361 | error_log(print_r($model->getErrors(),true)); 362 | 363 | return false; 364 | } 365 | 366 | } 367 | 368 | 369 | 370 | 371 | /** 372 | * Displays a single Files model. 373 | * @param integer $id 374 | * @return mixed 375 | */ 376 | public function actionView($id) 377 | { 378 | $model = $this->findModel($id); 379 | 380 | if ($this->accept == 'application/json') { 381 | 382 | $model->thumbnail_url = \Yii::$app->getModule('filemanager')->url . $model->thumbnail_url; 383 | $model->url = \Yii::$app->getModule('filemanager')->url . $model->url; 384 | 385 | \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; 386 | return $model; 387 | } 388 | 389 | return $this->render('view', [ 390 | 'model' => $model, 391 | ]); 392 | } 393 | 394 | /** 395 | * Creates a new Files model. 396 | * If creation is successful, the browser will be redirected to the 'view' page. 397 | * @return mixed 398 | */ 399 | public function actionCreate() 400 | { 401 | 402 | FilemanagerAssets::register($this->view); 403 | 404 | $model = new Files(); 405 | $tags = FileTag::find()->orderBy('name')->all(); 406 | $newTag = new FileTag; 407 | 408 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 409 | 410 | FileTagRelationships::deleteAll('file_id = '.$model->id); 411 | $fielTags = new FileTagRelationships; 412 | $data = Yii::$app->request->post(); 413 | 414 | if ( isset($data['tags']) ) { 415 | foreach ($data['tags'] as $value) { 416 | $fielTags->isNewRecord = true; 417 | $fielTags->id = null; 418 | $fielTags->file_id = $model->id; 419 | $fielTags->tag_id = $value; 420 | $fielTags->save(); 421 | } 422 | } 423 | 424 | return $this->redirect(['view', 'id' => $model->id]); 425 | } else { 426 | return $this->render('create', [ 427 | 'model' => $model, 428 | 'tags' => $tags, 429 | 'newTag' => $newTag, 430 | ]); 431 | } 432 | } 433 | 434 | /** 435 | * Updates an existing Files model. 436 | * If update is successful, the browser will be redirected to the 'view' page. 437 | * @param integer $id 438 | * @return mixed 439 | */ 440 | public function actionUpdate($id) 441 | { 442 | 443 | FilemanagerAssets::register($this->view); 444 | 445 | $model = $this->findModel($id); 446 | $tags = FileTag::find()->orderBy('name')->all(); 447 | $newTag = new FileTag; 448 | 449 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 450 | FileTagRelationships::deleteAll('file_id = '.$model->id); 451 | $fielTags = new FileTagRelationships; 452 | $data = Yii::$app->request->post(); 453 | 454 | if ( isset($data['tags']) ) { 455 | foreach ($data['tags'] as $value) { 456 | $fielTags->isNewRecord = true; 457 | $fielTags->id = null; 458 | $fielTags->file_id = $model->id; 459 | $fielTags->tag_id = $value; 460 | $fielTags->save(); 461 | } 462 | } 463 | 464 | return $this->redirect(['view', 'id' => $model->id]); 465 | } else { 466 | return $this->render('update', [ 467 | 'model' => $model, 468 | 'tags' => $tags, 469 | 'newTag' => $newTag, 470 | ]); 471 | } 472 | } 473 | 474 | /** 475 | * Deletes an existing Files model. 476 | * If deletion is successful, the browser will be redirected to the 'index' page. 477 | * @param integer $id 478 | * @return mixed 479 | */ 480 | public function actionDelete($id) 481 | { 482 | Yii::$app->response->getHeaders()->set('Vary', 'Accept'); 483 | Yii::$app->response->format = Response::FORMAT_JSON; 484 | 485 | $model = $this->findModel($id); 486 | 487 | $awsConfig = $this->module->aws; 488 | 489 | 490 | $files = [ 491 | ['Key' => $model->url], 492 | ['Key' => $model->thumbnail_url], 493 | ]; 494 | 495 | if($awsConfig['enable']){ 496 | 497 | $this->deleteAws($files); 498 | 499 | }else{ 500 | 501 | foreach($files as $f){ 502 | 503 | if( file_exists( Yii::getAlias( $this->module->directory ) . $f['Key'] ) ){ 504 | unlink( Yii::getAlias( $this->module->directory ) . $f['Key']); 505 | } 506 | 507 | } 508 | 509 | } 510 | 511 | $model->delete(); 512 | 513 | $this->redirect(['index']); 514 | } 515 | 516 | 517 | 518 | 519 | 520 | public function actionProperties() 521 | { 522 | 523 | 524 | return $this->renderPartial('_properties'); 525 | } 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | /** 535 | * Finds the Files model based on its primary key value. 536 | * If the model is not found, a 404 HTTP exception will be thrown. 537 | * @param integer $id 538 | * @return Files the loaded model 539 | * @throws NotFoundHttpException if the model cannot be found 540 | */ 541 | protected function findModel($id) 542 | { 543 | if (($model = Files::findOne($id)) !== null) { 544 | return $model; 545 | } else { 546 | throw new NotFoundHttpException('The requested page does not exist.'); 547 | } 548 | } 549 | 550 | 551 | 552 | protected function createThumbnails($file,$name = null) 553 | { 554 | 555 | if(is_null($name)){ 556 | $name = $file->name; 557 | } 558 | 559 | $awsConfig = $this->module->aws; 560 | 561 | $thumbnails = $this->module->thumbnails; 562 | 563 | $path = $this->module->path; 564 | 565 | $directory = Yii::getAlias( $this->module->directory ); 566 | 567 | if($awsConfig['enable']){ 568 | $path = 'https:' . $this->module->url . $path; 569 | } 570 | 571 | foreach($thumbnails as $tn){ 572 | 573 | $thumb = Image::thumbnail($path.$name, $tn[0], $tn[1], \Imagine\Image\ManipulatorInterface::THUMBNAIL_INSET); 574 | 575 | //Upload file 576 | if($awsConfig['enable']){ 577 | 578 | if (!file_exists('temp')) { 579 | mkdir('temp', 0777, true); 580 | } 581 | 582 | $thumb->save('temp/'.$name); 583 | 584 | $fileInfo = pathinfo($file); 585 | 586 | $fc = new \stdClass(); 587 | $fc->tempName = 'temp/'.$name; 588 | $fc->type = $this->extentionMap[strtolower($fileInfo['extension'])]; 589 | 590 | $this->uploadAws($fc,$name,true); 591 | 592 | unlink($fc->tempName); 593 | 594 | }else{ 595 | 596 | if ( !file_exists( $directory . $this->module->thumbPath) ) { 597 | mkdir($directory . $this->module->thumbPath, 0755, true); 598 | } 599 | 600 | $thumb->save( $directory . $this->module->thumbPath . $name ); 601 | 602 | } 603 | 604 | } 605 | 606 | return true; 607 | } 608 | 609 | 610 | 611 | /** 612 | * [awsInit description] 613 | */ 614 | protected function awsInit(){ 615 | 616 | $awsConfig = $this->module->aws; 617 | 618 | if($awsConfig['key'] == ''){ 619 | throw new InvalidConfigException('Key cannot be empty!'); 620 | } 621 | if($awsConfig['secret'] == ''){ 622 | throw new InvalidConfigException('Secret cannot be empty!'); 623 | } 624 | if($awsConfig['bucket'] == ''){ 625 | throw new InvalidConfigException('Bucket cannot be empty!'); 626 | } 627 | 628 | $config = [ 629 | 'key' => $awsConfig['key'], 630 | 'secret' => $awsConfig['secret'], 631 | ]; 632 | $aws = S3Client::factory($config); 633 | 634 | return $aws; 635 | } 636 | 637 | 638 | 639 | 640 | protected function uploadAws($file,$name = null,$thumb = false,$path = null){ 641 | 642 | if(is_null($path)){ 643 | $path = $this->module->path; 644 | } 645 | 646 | if(is_null($name)){ 647 | $name = $file->name; 648 | } 649 | 650 | if($thumb){ 651 | $path = $this->module->thumbPath; 652 | } 653 | 654 | $awsConfig = $this->module->aws; 655 | 656 | $aws = $this->awsInit(); 657 | 658 | $aws->get('S3'); 659 | 660 | $aws->putObject([ 661 | 'Key' => $path.$name, 662 | 'Bucket' => $awsConfig['bucket'], 663 | 'SourceFile' => $file->tempName, 664 | 'ContentType' => $file->type, 665 | ]); 666 | 667 | } 668 | 669 | 670 | 671 | 672 | protected function deleteAws($files){ 673 | 674 | $awsConfig = $this->module->aws; 675 | 676 | $aws = $this->awsInit(); 677 | 678 | $aws->get('S3'); 679 | 680 | $aws->deleteObjects([ 681 | 'Bucket' => $awsConfig['bucket'], 682 | 'Objects' => $files, 683 | ]); 684 | 685 | } 686 | 687 | 688 | 689 | 690 | protected function convertPHPSizeToBytes($sSize) 691 | { 692 | if ( is_numeric( $sSize) ) { 693 | return $sSize; 694 | } 695 | $sSuffix = substr($sSize, -1); 696 | $iValue = substr($sSize, 0, -1); 697 | switch(strtoupper($sSuffix)){ 698 | case 'P': 699 | $iValue *= 1024; 700 | case 'T': 701 | $iValue *= 1024; 702 | case 'G': 703 | $iValue *= 1024; 704 | case 'M': 705 | $iValue *= 1024; 706 | case 'K': 707 | $iValue *= 1024; 708 | break; 709 | } 710 | return $iValue; 711 | } 712 | 713 | protected function getMaximumFileUploadSize() 714 | { 715 | return min(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize'))); 716 | } 717 | 718 | 719 | } 720 | -------------------------------------------------------------------------------- /css/context.bootstrap.css: -------------------------------------------------------------------------------- 1 | /** 2 | * ContextJS Styles 3 | * For use with Twitters Bootstrap CSS 4 | */ 5 | 6 | .dropdown-context .nav-header{ 7 | cursor:default; 8 | z-index: 1100; 9 | } 10 | .dropdown-context:before, .dropdown-context-up:before { 11 | position: absolute; 12 | top: -7px; 13 | left: 9px; 14 | display: inline-block; 15 | border-right: 7px solid transparent; 16 | border-bottom: 7px solid #ccc; 17 | border-left: 7px solid transparent; 18 | border-bottom-color: rgba(0, 0, 0, 0.2); 19 | content: ''; 20 | } 21 | .dropdown-context:after, .dropdown-context-up:after{ 22 | position: absolute; 23 | top: -6px; 24 | left: 10px; 25 | display: inline-block; 26 | border-right: 6px solid transparent; 27 | border-bottom: 6px solid #ffffff; 28 | border-left: 6px solid transparent; 29 | content: ''; 30 | } 31 | .dropdown-context-up:before, .dropdown-context-up:after{ 32 | top:auto; 33 | bottom:-7px; 34 | z-index:9999; 35 | } 36 | .dropdown-context-up:before{ 37 | border-right: 7px solid transparent; 38 | border-top: 7px solid #ccc; 39 | border-bottom:none; 40 | border-left: 7px solid transparent; 41 | } 42 | .dropdown-context-up:after{ 43 | border-right: 6px solid transparent; 44 | border-top: 6px solid #ffffff; 45 | border-left: 6px solid transparent; 46 | border-bottom:none; 47 | } 48 | 49 | .dropdown-context-sub:before, .dropdown-context-sub:after{ 50 | display:none; 51 | } 52 | .dropdown-context .dropdown-submenu:hover .dropdown-menu { 53 | display: none; 54 | } 55 | 56 | .dropdown-context .dropdown-submenu:hover > .dropdown-menu { 57 | display: block; 58 | } 59 | 60 | 61 | .compressed-context a{ 62 | padding-left: 14px; 63 | padding-top: 0; 64 | padding-bottom: 0; 65 | font-size: 13px; 66 | } 67 | .compressed-context .divider{ 68 | margin: 5px 1px; 69 | } 70 | .compressed-context .nav-header{ 71 | padding:1px 13px; 72 | } 73 | -------------------------------------------------------------------------------- /css/context.standalone.css: -------------------------------------------------------------------------------- 1 | /** 2 | * ContextJS Styles 3 | * For use WITHOUT Twitters Bootstrap CSS 4 | */ 5 | 6 | .nav-header { 7 | display: block; 8 | padding: 3px 15px; 9 | font-size: 11px; 10 | font-weight: bold; 11 | line-height: 20px; 12 | color: #999; 13 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 14 | text-transform: uppercase; 15 | } 16 | .dropdown-menu { 17 | position: absolute; 18 | top: 100%; 19 | left: 0; 20 | z-index: 1000; 21 | display: none; 22 | float: left; 23 | min-width: 160px; 24 | padding: 5px 0; 25 | margin: 2px 0 0; 26 | list-style: none; 27 | background-color: #ffffff; 28 | border: 1px solid #ccc; 29 | border: 1px solid rgba(0, 0, 0, 0.2); 30 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 31 | font-size: 14px; 32 | *border-right-width: 2px; 33 | *border-bottom-width: 2px; 34 | -webkit-border-radius: 6px; 35 | -moz-border-radius: 6px; 36 | border-radius: 6px; 37 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 38 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 39 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 40 | -webkit-background-clip: padding-box; 41 | -moz-background-clip: padding; 42 | background-clip: padding-box; 43 | text-align:left; 44 | } 45 | .dropdown-menu.pull-right { 46 | right: 0; 47 | left: auto; 48 | } 49 | .dropdown-menu .divider { 50 | *width: 100%; 51 | height: 1px; 52 | margin: 9px 1px; 53 | *margin: -5px 0 5px; 54 | overflow: hidden; 55 | background-color: #e5e5e5; 56 | border-bottom: 1px solid #ffffff; 57 | } 58 | .dropdown-menu a { 59 | display: block; 60 | padding: 3px 20px; 61 | clear: both; 62 | font-weight: normal; 63 | line-height: 20px; 64 | color: #333333; 65 | white-space: nowrap; 66 | text-decoration: none; 67 | } 68 | .dropdown-menu li > a:hover, .dropdown-menu li > a:focus, .dropdown-submenu:hover > a { 69 | color: #ffffff; 70 | text-decoration: none; 71 | background-color: #0088cc; 72 | background-color: #0081c2; 73 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 74 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 75 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 76 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 77 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 78 | background-repeat: repeat-x; 79 | filter: progid: dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); 80 | } 81 | .dropdown-menu .active > a, .dropdown-menu .active > a:hover { 82 | color: #ffffff; 83 | text-decoration: none; 84 | background-color: #0088cc; 85 | background-color: #0081c2; 86 | background-image: linear-gradient(to bottom, #0088cc, #0077b3); 87 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3); 88 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); 89 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); 90 | background-image: -o-linear-gradient(top, #0088cc, #0077b3); 91 | background-repeat: repeat-x; 92 | outline: 0; 93 | filter: progid 94 | : dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); 95 | } 96 | .dropdown-menu .disabled > a, .dropdown-menu .disabled > a:hover { 97 | color: #999999; 98 | } 99 | .dropdown-menu .disabled > a:hover { 100 | text-decoration: none; 101 | cursor: default; 102 | background-color: transparent; 103 | } 104 | .open { 105 | *z-index: 1000; 106 | } 107 | .open > .dropdown-menu { 108 | display: block; 109 | } 110 | .pull-right > .dropdown-menu { 111 | right: 0; 112 | left: auto; 113 | } 114 | .dropup .caret, .navbar-fixed-bottom .dropdown .caret { 115 | border-top: 0; 116 | border-bottom: 4px solid #000000; 117 | content: "\2191"; 118 | } 119 | .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { 120 | top: auto; 121 | bottom: 100%; 122 | margin-bottom: 1px; 123 | } 124 | .dropdown-submenu { 125 | position: relative; 126 | } 127 | .dropdown-submenu > .dropdown-menu { 128 | top: 0; 129 | left: 100%; 130 | margin-top: -6px; 131 | margin-left: -1px; 132 | -webkit-border-radius: 0 6px 6px 6px; 133 | -moz-border-radius: 0 6px 6px 6px; 134 | border-radius: 0 6px 6px 6px; 135 | } 136 | .dropdown-submenu > .dropdown-menu.drop-left{ 137 | left:-100%; 138 | } 139 | .dropdown-submenu:hover .dropdown-menu { 140 | display: block; 141 | } 142 | .dropdown-submenu > a:after { 143 | display: block; 144 | float: right; 145 | width: 0; 146 | height: 0; 147 | margin-top: 5px; 148 | margin-right: -10px; 149 | border-color: transparent; 150 | border-left-color: #cccccc; 151 | border-style: solid; 152 | border-width: 5px 0 5px 5px; 153 | content: " "; 154 | } 155 | .dropdown-submenu:hover > a:after { 156 | border-left-color: #ffffff; 157 | } 158 | .dropdown .dropdown-menu .nav-header { 159 | padding-right: 20px; 160 | padding-left: 20px; 161 | } 162 | /** 163 | * Context Styles 164 | */ 165 | 166 | .dropdown-context .nav-header { 167 | cursor: default; 168 | } 169 | .dropdown-context:before, .dropdown-context-up:before { 170 | position: absolute; 171 | top: -7px; 172 | left: 9px; 173 | display: inline-block; 174 | border-right: 7px solid transparent; 175 | border-bottom: 7px solid #ccc; 176 | border-left: 7px solid transparent; 177 | border-bottom-color: rgba(0, 0, 0, 0.2); 178 | content: ''; 179 | } 180 | .dropdown-context:after, .dropdown-context-up:after { 181 | position: absolute; 182 | top: -6px; 183 | left: 10px; 184 | display: inline-block; 185 | border-right: 6px solid transparent; 186 | border-bottom: 6px solid #ffffff; 187 | border-left: 6px solid transparent; 188 | content: ''; 189 | } 190 | .dropdown-context-up:before, .dropdown-context-up:after { 191 | top: auto; 192 | bottom: -7px; 193 | z-index: 9999; 194 | } 195 | .dropdown-context-up:before { 196 | border-right: 7px solid transparent; 197 | border-top: 7px solid #ccc; 198 | border-bottom: none; 199 | border-left: 7px solid transparent; 200 | } 201 | .dropdown-context-up:after { 202 | border-right: 6px solid transparent; 203 | border-top: 6px solid #ffffff; 204 | border-left: 6px solid transparent; 205 | border-bottom: none; 206 | } 207 | .dropdown-context-sub:before, .dropdown-context-sub:after { 208 | display: none; 209 | } 210 | .dropdown-context .dropdown-submenu:hover .dropdown-menu { 211 | display: none; 212 | } 213 | .dropdown-context .dropdown-submenu:hover > .dropdown-menu { 214 | display: block; 215 | } 216 | 217 | .compressed-context a{ 218 | padding-left: 14px; 219 | padding-top: 0; 220 | padding-bottom: 0; 221 | font-size: 13px; 222 | } 223 | .compressed-context .divider{ 224 | margin: 5px 1px; 225 | } 226 | .compressed-context .nav-header{ 227 | padding:1px 13px; 228 | } 229 | -------------------------------------------------------------------------------- /css/filemanager.css: -------------------------------------------------------------------------------- 1 | 2 | .thumbnails{ 3 | height: auto; 4 | } 5 | 6 | #filemanagerUpload{ 7 | display: none; 8 | } 9 | 10 | .image-thumbnail.selected a{ 11 | background: #0072c6; 12 | } -------------------------------------------------------------------------------- /css/jquery.contextMenu.css: -------------------------------------------------------------------------------- 1 | /* Generic context menu styles */ 2 | .contextMenu { 3 | position: absolute; 4 | width: 120px; 5 | z-index: 99999; 6 | border: solid 1px #CCC; 7 | background: #EEE; 8 | padding: 0px; 9 | margin: 0px; 10 | display: none; 11 | } 12 | 13 | .contextMenu LI { 14 | list-style: none; 15 | padding: 0px; 16 | margin: 0px; 17 | } 18 | 19 | .contextMenu A { 20 | color: #333; 21 | text-decoration: none; 22 | display: block; 23 | line-height: 20px; 24 | height: 20px; 25 | background-position: 6px center; 26 | background-repeat: no-repeat; 27 | outline: none; 28 | padding: 1px 5px; 29 | padding-left: 28px; 30 | } 31 | 32 | .contextMenu LI.hover A { 33 | color: #FFF; 34 | background-color: #3399FF; 35 | } 36 | 37 | .contextMenu LI.disabled A { 38 | color: #AAA; 39 | cursor: default; 40 | } 41 | 42 | .contextMenu LI.hover.disabled A { 43 | background-color: transparent; 44 | } 45 | 46 | .contextMenu LI.separator { 47 | border-top: solid 1px #CCC; 48 | } 49 | 50 | /* 51 | Adding Icons 52 | 53 | You can add icons to the context menu by adding 54 | classes to the respective LI element(s) 55 | */ 56 | 57 | .contextMenu LI.edit A { background-image: url(images/page_white_edit.png); } 58 | .contextMenu LI.cut A { background-image: url(images/cut.png); } 59 | .contextMenu LI.copy A { background-image: url(images/page_white_copy.png); } 60 | .contextMenu LI.paste A { background-image: url(images/page_white_paste.png); } 61 | .contextMenu LI.delete A { background-image: url(images/page_white_delete.png); } 62 | .contextMenu LI.quit A { background-image: url(images/door.png); } 63 | -------------------------------------------------------------------------------- /helpers/Html.php: -------------------------------------------------------------------------------- 1 | 19 | * @since 0.1 20 | */ 21 | 22 | class Html extends \yii\helpers\Html 23 | { 24 | 25 | /** 26 | * run function. 27 | * 28 | * @access public 29 | * @return string 30 | */ 31 | public static function FileOutput($id = 0, $options = [], $urlOnly = false, $thumbnail = false) 32 | { 33 | 34 | $awsConfig = \Yii::$app->getModule('filemanager')->aws; 35 | 36 | $url = \Yii::$app->getModule('filemanager')->url; 37 | 38 | $path = \Yii::$app->getModule('filemanager')->path; 39 | 40 | $terms = []; 41 | 42 | $file = Files::findOne($id); 43 | 44 | if(!$file){ 45 | return null; 46 | } 47 | 48 | if( !empty($file->fileTerms) ) { 49 | foreach ($file->fileTerms as $v) { 50 | $terms[$v->type] = $v->value; 51 | } 52 | } 53 | 54 | $options = ArrayHelper::merge( $options, $terms ); 55 | 56 | if($thumbnail){ 57 | if($urlOnly){ 58 | $return = $url.$file->thumbnail_url; 59 | }else{ 60 | $return = Html::img($url.$file->thumbnail_url,$options); 61 | } 62 | }else{ 63 | if($urlOnly){ 64 | $return = $url.$file->url; 65 | }else{ 66 | $return = Html::img($url.$file->url,$options); 67 | } 68 | } 69 | 70 | return $return; 71 | } 72 | 73 | 74 | 75 | public static function TagFirstFileOutput( $id = 0, $options = [], $urlOnly = false ) 76 | { 77 | 78 | $awsConfig = \Yii::$app->getModule('filemanager')->aws; 79 | 80 | $url = \Yii::$app->getModule('filemanager')->url; 81 | 82 | $path = \Yii::$app->getModule('filemanager')->path; 83 | 84 | $fileTag = FileTag::findOne($id); 85 | 86 | if ( !$fileTag ) { 87 | return null; 88 | } 89 | 90 | if ( !isset($fileTag->firstfile[0]) ) { 91 | return null; 92 | } 93 | 94 | if ( $urlOnly ) { 95 | $return = $url.$fileTag->firstfile[0]->url; 96 | } else { 97 | $return = Html::img( $url.$fileTag->firstfile[0]->url, $options ); 98 | } 99 | 100 | return $return; 101 | 102 | } 103 | 104 | 105 | 106 | 107 | 108 | 109 | /** 110 | * FileTerms function. 111 | * 112 | * @access public 113 | * @static 114 | * @param int $id (default: 0) 115 | * @return array 116 | */ 117 | public static function FileTerms($id = 0) 118 | { 119 | 120 | $file = Files::findOne($id); 121 | 122 | $terms = []; 123 | 124 | if( !empty($file->fileTerms) ) { 125 | foreach ($file->fileTerms as $v) { 126 | $terms[$v->type] = $v->value; 127 | } 128 | } 129 | 130 | return $terms; 131 | 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /helpers/ModuleTrait.php: -------------------------------------------------------------------------------- 1 | _module == null) { 21 | $this->_module = \Yii::$app->getModule('filemanager'); 22 | } 23 | 24 | return $this->_module; 25 | } 26 | } -------------------------------------------------------------------------------- /helpers/StringHelper.php: -------------------------------------------------------------------------------- 1 | window.innerWidth; 38 | if(collision){ 39 | $sub.addClass('drop-left'); 40 | } 41 | }); 42 | 43 | } 44 | 45 | function updateOptions(opts){ 46 | options = $.extend({}, options, opts); 47 | } 48 | 49 | function buildMenu(data, id, subMenu) { 50 | var subClass = (subMenu) ? ' dropdown-context-sub' : '', 51 | compressed = options.compress ? ' compressed-context' : '', 52 | $menu = $(''); 53 | var i = 0, linkTarget = ''; 54 | for(i; i'); 57 | } else if (typeof data[i].header !== 'undefined') { 58 | $menu.append(''); 59 | } else { 60 | if (typeof data[i].href == 'undefined') { 61 | data[i].href = '#'; 62 | } 63 | if (typeof data[i].target !== 'undefined') { 64 | linkTarget = ' target="'+data[i].target+'"'; 65 | } 66 | if (typeof data[i].subMenu !== 'undefined') { 67 | $sub = (''); 68 | } else { 69 | $sub = $('
  • ' + data[i].text + '
  • '); 70 | } 71 | if (typeof data[i].action !== 'undefined') { 72 | var actiond = new Date(), 73 | actionID = 'event-' + actiond.getTime() * Math.floor(Math.random()*100000), 74 | eventAction = data[i].action; 75 | $sub.find('a').attr('id', actionID); 76 | $('#' + actionID).addClass('context-event'); 77 | $(document).on('click', '#' + actionID, eventAction); 78 | } 79 | $menu.append($sub); 80 | if (typeof data[i].subMenu != 'undefined') { 81 | var subMenuData = buildMenu(data[i].subMenu, id, true); 82 | $menu.find('li:last').append(subMenuData); 83 | } 84 | } 85 | if (typeof options.filter == 'function') { 86 | options.filter($menu.find('li:last')); 87 | } 88 | } 89 | return $menu; 90 | } 91 | 92 | function addContext(selector, data) { 93 | 94 | var d = new Date(), 95 | id = d.getTime(), 96 | $menu = buildMenu(data, id); 97 | 98 | $('body').append($menu); 99 | 100 | 101 | $(document).on('contextmenu', selector, function (e) { 102 | e.preventDefault(); 103 | e.stopPropagation(); 104 | 105 | $('.dropdown-context:not(.dropdown-context-sub)').hide(); 106 | 107 | $dd = $('#dropdown-' + id); 108 | if (typeof options.above == 'boolean' && options.above) { 109 | $dd.addClass('dropdown-context-up').css({ 110 | top: e.pageY - 20 - $('#dropdown-' + id).height(), 111 | left: e.pageX - 13 112 | }).fadeIn(options.fadeSpeed); 113 | } else if (typeof options.above == 'string' && options.above == 'auto') { 114 | $dd.removeClass('dropdown-context-up'); 115 | var autoH = $dd.height() + 12; 116 | if ((e.pageY + autoH) > $('html').height()) { 117 | $dd.addClass('dropdown-context-up').css({ 118 | top: e.pageY - 20 - autoH, 119 | left: e.pageX - 13 120 | }).fadeIn(options.fadeSpeed); 121 | } else { 122 | $dd.css({ 123 | top: e.pageY + 10, 124 | left: e.pageX - 13 125 | }).fadeIn(options.fadeSpeed); 126 | } 127 | } 128 | }); 129 | } 130 | 131 | function destroyContext(selector) { 132 | $(document).off('contextmenu', selector).off('click', '.context-event'); 133 | } 134 | 135 | return { 136 | init: initialize, 137 | settings: updateOptions, 138 | attach: addContext, 139 | destroy: destroyContext 140 | }; 141 | })(); -------------------------------------------------------------------------------- /js/filemanager.js: -------------------------------------------------------------------------------- 1 | (function (filemanager, $, undefined) { 2 | "use strict"; 3 | 4 | var _settings; 5 | // public method 6 | filemanager.init = function (settings) { 7 | _settings = $.extend({}, settings); 8 | //this.contextSetup(); 9 | } 10 | 11 | /** 12 | * Setup context 13 | */ 14 | filemanager.contextSetup = function () { 15 | 16 | context.init({ 17 | fadespeed: 100, 18 | above: 'auto', 19 | preventDoubleContext: true, 20 | compress: false, 21 | }); 22 | 23 | context.attach('.image-thumbnail .thumbnail', [{ 24 | text: 'View', 25 | action: function (e) { 26 | var id = $(this).attr('href'); 27 | alert(id); 28 | window.open($(this).attr('href'), 'imageWindow'); 29 | }, 30 | }, 31 | { 32 | text: 'Download', 33 | }, 34 | { 35 | text: 'Properties', 36 | action: function (e) { 37 | e.preventDefault(); 38 | $('#editProperties').modal({ 39 | remote: '/index.php?r=filemanager/files/properties', 40 | }); 41 | }, 42 | }, 43 | { 44 | divider: true, 45 | }, 46 | { 47 | text: 'Delete', 48 | action: function (e) { 49 | e.preventDefault(); 50 | var id = $(this).attr('data-id'); 51 | console.log(id); 52 | filemanager.deleteFile(id); 53 | }, 54 | }, 55 | ]); 56 | 57 | } 58 | 59 | filemanager.getSettings = function () { 60 | return _settings; 61 | } 62 | 63 | filemanager.deleteFile = function (id) { 64 | if (typeof id !== "undefined" && id !== null) { 65 | console.log(id); 66 | } 67 | } 68 | 69 | }(window.filemanager = window.filemanager || {}, jQuery)); 70 | 71 | 72 | function createTag(form) { 73 | 74 | if ($(form).find('.has-error').length) { 75 | return false; 76 | } 77 | 78 | $.ajax({ 79 | url: form.attr('action'), 80 | type: 'post', 81 | data: form.serialize(), 82 | success: function (data) { 83 | if (data.error) { 84 | $('.field-filetag-name').addClass('has-error'); 85 | $('.field-filetag-name .help-block').text(data.error.name); 86 | } 87 | if (data.success) { 88 | $('#myModal').modal('hide'); 89 | $('#filetag-name').val(''); 90 | $('#tag-con').append('
    '); 91 | } 92 | } 93 | }); 94 | 95 | return false; 96 | } 97 | 98 | 99 | $(function () { 100 | 101 | $(document).on('submit', '#create_tag', function () { 102 | event.preventDefault(); 103 | createTag($(this)); 104 | return false; 105 | }); 106 | 107 | $('#fileUploadBtn').click(function (e) { 108 | e.preventDefault(); 109 | $(this).addClass('disabled'); 110 | $('#fileGridBtn').removeClass('disabled'); 111 | $('#fileGridManager,#fileGridFooter').hide(); 112 | $('#filemanagerUpload').show(); 113 | }); 114 | 115 | $('#fileGridBtn').click(function (e) { 116 | e.preventDefault(); 117 | $(this).addClass('disabled'); 118 | $('#fileUploadBtn').removeClass('disabled'); 119 | $('#filemanagerUpload').hide(); 120 | $('#fileGridManager,#fileGridFooter').show(); 121 | }); 122 | 123 | $('.image-thumbnail').click(function (e) { 124 | if ($(this).hasClass('selected')) { 125 | $(this).removeClass('selected'); 126 | } else { 127 | $(this).addClass('selected'); 128 | if (typeof window.parent.filemanagertiny.setImage !== 'undefined' && $.isFunction(window.parent.filemanagertiny.setImage)) { 129 | e.preventDefault(); 130 | window.parent.filemanagertiny.setImage($(this).find('.thumbnail').attr('data-id')); 131 | } else if (typeof window.parent.filePicker !== 'undefined' && $.isFunction(window.parent.filePicker)) { 132 | window.parent.filePicker($(this).attr('data-id')); 133 | } 134 | } 135 | }); 136 | }); 137 | 138 | 139 | ccm_editorSetupImagePicker = function () { 140 | tinyMCE.activeEditor.focus(); 141 | var bm = tinyMCE.activeEditor.selection.getBookmark(); 142 | ccm_chooseAsset = function (obj) { 143 | var mceEd = tinyMCE.activeEditor; 144 | mceEd.selection.moveToBookmark(bm); 145 | var args = {}; 146 | tinymce.extend(args, { 147 | src: obj.filePathInline, 148 | alt: obj.title, 149 | width: obj.width, 150 | height: obj.height 151 | }); 152 | mceEd.execCommand("mceInsertContent", false, '', { 153 | skip_undo: 1 154 | }); 155 | mceEd.dom.setAttribs("__mce_tmp", args); 156 | mceEd.dom.setAttrib("__mce_tmp", "id", ""); 157 | mceEd.undoManager.f() 158 | }; 159 | return false 160 | }; 161 | -------------------------------------------------------------------------------- /js/filemanager_modal.js: -------------------------------------------------------------------------------- 1 | (function (filemanager, $, undefined) { 2 | "use strict"; 3 | var _settings; 4 | 5 | // public method 6 | filemanager.init = function (settings) { 7 | _settings = $.extend({}, settings); 8 | } 9 | 10 | filemanager.getSettings = function () { 11 | return _settings; 12 | } 13 | 14 | }(window.filemanager = window.filemanager || {}, jQuery)); 15 | 16 | $(function () { 17 | context.init({ 18 | fadespeed: 100, 19 | above: 'auto', 20 | preventDoubleContext: true, 21 | compress: false, 22 | }); 23 | 24 | context.attach('.image-thumbnail .thumbnail', [{ 25 | text: 'View', 26 | action: function (e) { 27 | alert(this.href); 28 | window.open($(this).attr('href'), 'imageWindow'); 29 | }, 30 | }, { 31 | text: 'Download', 32 | }, { 33 | text: 'Properties', 34 | action: function (e) { 35 | e.preventDefault(); 36 | $('#editProperties').modal({ 37 | remote: '/index.php?r=filemanager/files/properties', 38 | }); 39 | }, 40 | }, { 41 | divider: true, 42 | }, { 43 | text: 'Delete', 44 | }, 45 | ]); 46 | 47 | $('#fileUploadBtn').click(function (e) { 48 | e.preventDefault(); 49 | $(this).addClass('disabled'); 50 | 51 | $('#fileGridBtn').removeClass('disabled'); 52 | $('#fileGridManager,#fileGridFooter').hide(); 53 | $('#filemanagerUpload').show(); 54 | }); 55 | 56 | $('#fileGridBtn').click(function (e) { 57 | e.preventDefault(); 58 | 59 | $(this).addClass('disabled'); 60 | $('#fileUploadBtn').removeClass('disabled'); 61 | $('#filemanagerUpload').hide(); 62 | $('#fileGridManager,#fileGridFooter').show(); 63 | }); 64 | 65 | $('.image-thumbnail').click(function (e) { 66 | if ($(this).hasClass('selected')) { 67 | $(this).removeClass('selected'); 68 | } else { 69 | $(this).addClass('selected'); 70 | if (typeof window.parent.filemanagertiny.setImage !== 'undefined' && $.isFunction(window.parent.filemanagertiny.setImage)) { 71 | window.parent.filemanagertiny.setImage($(this).attr('data-id')); 72 | } else if (typeof window.parent.filePicker !== 'undefined' && $.isFunction(window.parent.filePicker)) { 73 | window.parent.filePicker($(this).attr('data-id')); 74 | } 75 | } 76 | }); 77 | 78 | $('.image-thumbnail a').click(function (e) { 79 | e.preventDefault(); 80 | }); 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /js/filemanager_plugin.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tinymce.PluginManager.add('filemanager', function(editor, url) { 7 | 8 | function fileman() { 9 | 10 | editor.windowManager.open({ 11 | title: 'Select an image', 12 | file : filemanagertiny.getSettings().tinymce, 13 | width : 960, 14 | height: 600, 15 | resizable : true, 16 | /*buttons: [{ 17 | text: 'insert', 18 | classes:'widget btn primary first abs-layout-item', 19 | disabled : true, 20 | onclick: 'close', 21 | }, 22 | { 23 | text: 'Close', 24 | onclick: 'close' 25 | }],*/ 26 | }); 27 | } 28 | 29 | // Add a button that opens a window 30 | editor.addButton('filemanager', { 31 | tooltip: 'File Manager', 32 | icon : 'image', 33 | text: 'Insert', 34 | onclick: fileman 35 | }); 36 | 37 | // Adds a menu item to the tools menu 38 | editor.addMenuItem('filemanager', { 39 | text: 'File Manager', 40 | icon : 'image', 41 | context: 'Insert', 42 | onclick: fileman 43 | }); 44 | }); -------------------------------------------------------------------------------- /js/filemanagertiny.js: -------------------------------------------------------------------------------- 1 | (function( filemanagertiny, $, undefined ) { 2 | "use strict"; 3 | 4 | var _settings; 5 | 6 | // public method 7 | filemanagertiny.init = function(settings) { 8 | _settings = $.extend({}, settings); 9 | } 10 | 11 | 12 | 13 | filemanagertiny.getSettings = function() { 14 | 15 | return _settings; 16 | 17 | } 18 | 19 | 20 | 21 | 22 | filemanagertiny.setImage = function( imageId ) { 23 | 24 | var ed = top.tinymce; 25 | var html = ''; 26 | 27 | if( typeof ed != 'undefined' && typeof imageId != 'undefined' ){ 28 | _csrf:yii.getCsrfToken() 29 | 30 | var formData = {id:imageId}; 31 | 32 | $.ajax({ 33 | url: _settings.getimage, 34 | type: "GET", 35 | data: formData, 36 | success: function (data) { 37 | console.log(data); 38 | 39 | html = ''+data.title+''; 40 | 41 | ed.activeEditor.insertContent(html); 42 | ed.activeEditor.windowManager.close(); 43 | } 44 | }); 45 | } 46 | 47 | } 48 | 49 | 50 | 51 | }( window.filemanagertiny = window.filemanagertiny || {}, jQuery )); -------------------------------------------------------------------------------- /js/fileupload.js: -------------------------------------------------------------------------------- 1 | (function( filemanager, $, undefined ) { 2 | "use strict"; 3 | var _settings = { 4 | domWrapper: '' 5 | }; 6 | var _selected; 7 | var _multiple = false; 8 | // public method 9 | filemanager.init = function(settings) { 10 | _settings = $.extend({}, settings); 11 | } 12 | filemanager.log = function(obj){ 13 | // if(_settings.debug == true){ 14 | console.log(obj); 15 | // } 16 | } 17 | /* Delete Building 18 | * 19 | * 20 | */ 21 | filemanager.setup = function(){ 22 | 23 | filemanager.log('Function Setup run'); 24 | 25 | $('.thumbnail').click( function(e){ 26 | e.preventDefault(); 27 | }); 28 | 29 | $('#fileupload').fileupload({ 30 | url : _settings.fileUploadURL, 31 | autoUpload: true, 32 | done : function(e,data){ 33 | console.log(data); 34 | filemanager.addToList(data.result.files[0]); 35 | }, 36 | }); 37 | 38 | $('#tabMedialibrary a').click(function (e) { 39 | e.preventDefault(); 40 | $(this).tab('show'); 41 | }); 42 | 43 | $('#tabUploadFiles a').click(function (e) { 44 | e.preventDefault(); 45 | $(this).tab('show'); 46 | }); 47 | 48 | filemanager.markSelected = function(){ 49 | 50 | filemanager.log('Mark Selected'); 51 | 52 | filemanager.selectFiles = function(){ 53 | 54 | filemanager.log('Select Files'); 55 | 56 | } 57 | /* Add to List Building 58 | * 59 | * 60 | */ 61 | filemanager.addToList = function(data){ 62 | 63 | var newImage = '
    '+data.name+'
    '; 64 | $('table#mediaTable > tbody > tr:first').before(newImage); 65 | 66 | $('#tabMedialibrary a').tab('show'); 67 | 68 | return true; 69 | 70 | } 71 | /* Delete Photo 72 | * 73 | * 74 | */ 75 | filemanager.deletePhoto = function(id){ 76 | 77 | $.ajax({ 78 | type : 'POST', 79 | url : _settings.deleteURL, 80 | data : { 81 | id : id, 82 | }, 83 | success : function(data){ 84 | $('#mediaImage_'+id).hide(); 85 | }, 86 | error : function(request, status, error){ 87 | console.log(request.responseText); 88 | } 89 | }); 90 | 91 | } 92 | 93 | }( window.filemanager = window.filemanager || {}, jQuery )) 94 | -------------------------------------------------------------------------------- /js/jquery.contextMenu.js: -------------------------------------------------------------------------------- 1 | // jQuery Context Menu Plugin 2 | // 3 | // Version 1.01 4 | // 5 | // Cory S.N. LaViska 6 | // A Beautiful Site (http://abeautifulsite.net/) 7 | // 8 | // More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ 9 | // 10 | // Terms of Use 11 | // 12 | // This plugin is dual-licensed under the GNU General Public License 13 | // and the MIT License and is copyright A Beautiful Site, LLC. 14 | // 15 | if(jQuery)( function() { 16 | $.extend($.fn, { 17 | 18 | contextMenu: function(o, callback) { 19 | // Defaults 20 | if( o.menu == undefined ) return false; 21 | if( o.inSpeed == undefined ) o.inSpeed = 150; 22 | if( o.outSpeed == undefined ) o.outSpeed = 75; 23 | // 0 needs to be -1 for expected results (no fade) 24 | if( o.inSpeed == 0 ) o.inSpeed = -1; 25 | if( o.outSpeed == 0 ) o.outSpeed = -1; 26 | // Loop each context menu 27 | $(this).each( function() { 28 | var el = $(this); 29 | var offset = $(el).offset(); 30 | // Add contextMenu class 31 | $('#' + o.menu).addClass('contextMenu'); 32 | // Simulate a true right click 33 | $(this).mousedown( function(e) { 34 | var evt = e; 35 | evt.stopPropagation(); 36 | $(this).mouseup( function(e) { 37 | e.stopPropagation(); 38 | var srcElement = $(this); 39 | $(this).unbind('mouseup'); 40 | if( evt.button == 2 ) { 41 | // Hide context menus that may be showing 42 | $(".contextMenu").hide(); 43 | // Get this context menu 44 | var menu = $('#' + o.menu); 45 | 46 | if( $(el).hasClass('disabled') ) return false; 47 | 48 | // Detect mouse position 49 | var d = {}, x, y; 50 | if( self.innerHeight ) { 51 | d.pageYOffset = self.pageYOffset; 52 | d.pageXOffset = self.pageXOffset; 53 | d.innerHeight = self.innerHeight; 54 | d.innerWidth = self.innerWidth; 55 | } else if( document.documentElement && 56 | document.documentElement.clientHeight ) { 57 | d.pageYOffset = document.documentElement.scrollTop; 58 | d.pageXOffset = document.documentElement.scrollLeft; 59 | d.innerHeight = document.documentElement.clientHeight; 60 | d.innerWidth = document.documentElement.clientWidth; 61 | } else if( document.body ) { 62 | d.pageYOffset = document.body.scrollTop; 63 | d.pageXOffset = document.body.scrollLeft; 64 | d.innerHeight = document.body.clientHeight; 65 | d.innerWidth = document.body.clientWidth; 66 | } 67 | (e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft; 68 | (e.pageY) ? y = e.pageY : y = e.clientY + d.scrollTop; 69 | 70 | // Show the menu 71 | $(document).unbind('click'); 72 | $(menu).css({ top: y, left: x }).fadeIn(o.inSpeed); 73 | // Hover events 74 | $(menu).find('A').mouseover( function() { 75 | $(menu).find('LI.hover').removeClass('hover'); 76 | $(this).parent().addClass('hover'); 77 | }).mouseout( function() { 78 | $(menu).find('LI.hover').removeClass('hover'); 79 | }); 80 | 81 | // Keyboard 82 | $(document).keypress( function(e) { 83 | switch( e.keyCode ) { 84 | case 38: // up 85 | if( $(menu).find('LI.hover').size() == 0 ) { 86 | $(menu).find('LI:last').addClass('hover'); 87 | } else { 88 | $(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); 89 | if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover'); 90 | } 91 | break; 92 | case 40: // down 93 | if( $(menu).find('LI.hover').size() == 0 ) { 94 | $(menu).find('LI:first').addClass('hover'); 95 | } else { 96 | $(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); 97 | if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover'); 98 | } 99 | break; 100 | case 13: // enter 101 | $(menu).find('LI.hover A').trigger('click'); 102 | break; 103 | case 27: // esc 104 | $(document).trigger('click'); 105 | break 106 | } 107 | }); 108 | 109 | // When items are selected 110 | $('#' + o.menu).find('A').unbind('click'); 111 | $('#' + o.menu).find('LI:not(.disabled) A').click( function() { 112 | $(document).unbind('click').unbind('keypress'); 113 | $(".contextMenu").hide(); 114 | // Callback 115 | if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); 116 | return false; 117 | }); 118 | 119 | // Hide bindings 120 | setTimeout( function() { // Delay for Mozilla 121 | $(document).click( function() { 122 | $(document).unbind('click').unbind('keypress'); 123 | $(menu).fadeOut(o.outSpeed); 124 | return false; 125 | }); 126 | }, 0); 127 | } 128 | }); 129 | }); 130 | 131 | // Disable text selection 132 | if( $.browser.mozilla ) { 133 | $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); 134 | } else if( $.browser.msie ) { 135 | $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); 136 | } else { 137 | $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); 138 | } 139 | // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) 140 | $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); 141 | 142 | }); 143 | return $(this); 144 | }, 145 | 146 | // Disable context menu items on the fly 147 | disableContextMenuItems: function(o) { 148 | if( o == undefined ) { 149 | // Disable all 150 | $(this).find('LI').addClass('disabled'); 151 | return( $(this) ); 152 | } 153 | $(this).each( function() { 154 | if( o != undefined ) { 155 | var d = o.split(','); 156 | for( var i = 0; i < d.length; i++ ) { 157 | $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); 158 | 159 | } 160 | } 161 | }); 162 | return( $(this) ); 163 | }, 164 | 165 | // Enable context menu items on the fly 166 | enableContextMenuItems: function(o) { 167 | if( o == undefined ) { 168 | // Enable all 169 | $(this).find('LI.disabled').removeClass('disabled'); 170 | return( $(this) ); 171 | } 172 | $(this).each( function() { 173 | if( o != undefined ) { 174 | var d = o.split(','); 175 | for( var i = 0; i < d.length; i++ ) { 176 | $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); 177 | 178 | } 179 | } 180 | }); 181 | return( $(this) ); 182 | }, 183 | 184 | // Disable context menu(s) 185 | disableContextMenu: function() { 186 | $(this).each( function() { 187 | $(this).addClass('disabled'); 188 | }); 189 | return( $(this) ); 190 | }, 191 | 192 | // Enable context menu(s) 193 | enableContextMenu: function() { 194 | $(this).each( function() { 195 | $(this).removeClass('disabled'); 196 | }); 197 | return( $(this) ); 198 | }, 199 | 200 | // Destroy context menu(s) 201 | destroyContextMenu: function() { 202 | // Destroy specified context menus 203 | $(this).each( function() { 204 | // Disable action 205 | $(this).unbind('mousedown').unbind('mouseup'); 206 | }); 207 | return( $(this) ); 208 | } 209 | 210 | }); 211 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.filemanager.js: -------------------------------------------------------------------------------- 1 | (function( filemanager, $, undefined ) { 2 | "use strict"; 3 | 4 | var _settings; 5 | var _selected; 6 | var _multiple = false; 7 | 8 | // public method 9 | filemanager.init = function(settings) { 10 | _settings = $.extend({}, settings); 11 | } 12 | 13 | filemanager.log = function(obj){ 14 | if(_settings.debug == true){ 15 | console.log(obj); 16 | } 17 | } 18 | 19 | /* Delete Building 20 | * 21 | * 22 | */ 23 | filemanager.setup = function(){ 24 | 25 | filemanager.log('Function Setup run'); 26 | 27 | $('#fileupload').fileupload({ 28 | url : _settings.fileUploadURL, 29 | autoUpload: true, 30 | done : function(e,data){ 31 | console.log(data); 32 | filemanager.addToList(data.result.files[0]); 33 | }, 34 | }); 35 | 36 | $('#tabMedialibrary a').click(function (e) { 37 | e.preventDefault(); 38 | $(this).tab('show'); 39 | }); 40 | 41 | $('#tabUploadFiles a').click(function (e) { 42 | e.preventDefault(); 43 | $(this).tab('show'); 44 | }); 45 | 46 | } 47 | 48 | 49 | filemanager.markSelected = function(){ 50 | 51 | filemanager.log('Mark Selected'); 52 | 53 | 54 | } 55 | 56 | 57 | filemanager.selectFiles = function(){ 58 | 59 | filemanager.log('Select Files'); 60 | 61 | 62 | 63 | } 64 | 65 | /* Add to List Building 66 | * 67 | * 68 | */ 69 | filemanager.addToList = function(data){ 70 | 71 | var newImage = '
    '+data.name+'
    '; 72 | $('table#mediaTable > tbody > tr:first').before(newImage); 73 | 74 | $('#tabMedialibrary a').tab('show'); 75 | 76 | return true; 77 | 78 | } 79 | 80 | /* Delete Photo 81 | * 82 | * 83 | */ 84 | filemanager.deletePhoto = function(id){ 85 | 86 | $.ajax({ 87 | type : 'POST', 88 | url : _settings.deleteURL, 89 | data : { 90 | id : id, 91 | }, 92 | success : function(data){ 93 | $('#mediaImage_'+id).hide(); 94 | }, 95 | error : function(request, status, error){ 96 | console.log(request.responseText); 97 | } 98 | }); 99 | 100 | } 101 | 102 | }( window.filemanager = window.filemanager || {}, jQuery )); 103 | -------------------------------------------------------------------------------- /migrations/m140723_010511_filemanager_init.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 13 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; 14 | } 15 | 16 | $this->createTable('{{%files}}', [ 17 | 'id' => Schema::TYPE_PK, 18 | 'user_id' => Schema::TYPE_INTEGER . ' DEFAULT 0', 19 | 'url' => Schema::TYPE_STRING . '(555) NULL', 20 | 'thumbnail_url' => Schema::TYPE_STRING . '(555) NULL', 21 | 'file_name' => Schema::TYPE_STRING . '(555) NULL', 22 | 'type' => Schema::TYPE_STRING . '(45) NULL', 23 | 'title' => Schema::TYPE_STRING . '(45) NULL', 24 | 'size' => Schema::TYPE_INTEGER . ' NULL', 25 | 'width' => Schema::TYPE_INTEGER . ' NULL', 26 | 'height' => Schema::TYPE_INTEGER . ' NULL', 27 | 'date' => Schema::TYPE_DATETIME . ' NULL', 28 | 'date_gmt' => Schema::TYPE_DATETIME . ' NULL', 29 | 'update' => Schema::TYPE_DATETIME . ' NULL', 30 | 'update_gmt' => Schema::TYPE_DATETIME . ' NULL', 31 | ], $tableOptions); 32 | 33 | $this->createTable('{{%file_terms}}', [ 34 | 'id' => Schema::TYPE_PK, 35 | 'file_id' => Schema::TYPE_INTEGER . ' NULL', 36 | 'type' => Schema::TYPE_STRING . '(45) NULL', 37 | 'value' => Schema::TYPE_TEXT . ' NULL', 38 | ], $tableOptions); 39 | 40 | $this->addForeignKey('FK_files_terms','{{%file_terms}}','file_id','{{%files}}','id'); 41 | 42 | } 43 | 44 | public function down() 45 | { 46 | $this->dropForeignKey('FK_files_terms','{{%file_terms}}'); 47 | $this->dropForeignKey('FK_files_users','{{%files}}'); 48 | $this->dropTable('{{%files}}'); 49 | $this->dropTable('{{%file_terms}}'); 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /migrations/m141107_062947_update_titles.php: -------------------------------------------------------------------------------- 1 | alterColumn( '{{%files}}', 'title', Schema::TYPE_STRING . '(555) NULL' ); 11 | } 12 | 13 | public function down() 14 | { 15 | $this->alterColumn( '{{%files}}', 'title', Schema::TYPE_STRING . '(45) NULL' ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /migrations/m150327_233853_create_file_tag.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 14 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; 15 | } 16 | 17 | $this->createTable('{{%file_tag}}', [ 18 | 'id' => Schema::TYPE_PK, 19 | 'name' => Schema::TYPE_STRING . '(255) NULL', 20 | 'slug' => Schema::TYPE_STRING . '(255) NULL', 21 | ], $tableOptions); 22 | 23 | } 24 | 25 | public function down() 26 | { 27 | 28 | $this->dropTable('{{%file_tag}}'); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /migrations/m150327_233907_create_file_tag_relationships.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 14 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; 15 | } 16 | 17 | $this->createTable('{{%file_tag_relationships}}', [ 18 | 'id' => Schema::TYPE_PK, 19 | 'file_id' => Schema::TYPE_INTEGER . ' NOT NULL', 20 | 'tag_id' => Schema::TYPE_INTEGER . ' NOT NULL', 21 | 'sort' => Schema::TYPE_INTEGER . ' DEFAULT 0', 22 | ], $tableOptions); 23 | 24 | } 25 | 26 | public function down() 27 | { 28 | 29 | $this->dropTable('{{%file_tag_relationships}}'); 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /models/FileTag.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'class' => AttributeBehavior::className(), 30 | 'attributes' => [ 31 | ActiveRecord::EVENT_BEFORE_INSERT => 'slug', 32 | ActiveRecord::EVENT_BEFORE_UPDATE => 'slug', 33 | ], 34 | 'value' => function() { 35 | return (empty($this->slug) ? StringHelper::genSlug($this->name) : StringHelper::genSlug($this->slug)); 36 | }, 37 | ], 38 | ]; 39 | } 40 | 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public static function tableName() 46 | { 47 | return '{{%file_tag}}'; 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | */ 53 | public function rules() 54 | { 55 | return [ 56 | [['name', 'slug'], 'string', 'max' => 255] 57 | ]; 58 | } 59 | 60 | /** 61 | * @inheritdoc 62 | */ 63 | public function attributeLabels() 64 | { 65 | return [ 66 | 'id' => Yii::t('app', 'ID'), 67 | 'name' => Yii::t('app', 'Name'), 68 | 'slug' => Yii::t('app', 'URL Slug'), 69 | ]; 70 | } 71 | 72 | 73 | /** 74 | * [getFiles description] 75 | */ 76 | public function getFiles() 77 | { 78 | return $this->hasMany( Files::className(), ['id' => 'file_id']) 79 | ->viaTable( '{{%file_tag_relationships}}', ['tag_id' => 'id'], function($query){ 80 | return $query->orderBy( 'sort' ); 81 | }); 82 | } 83 | 84 | 85 | 86 | public function getFirstfile() 87 | { 88 | return $this->hasMany( Files::className(), ['id' => 'file_id']) 89 | ->viaTable( '{{%file_tag_relationships}}', ['tag_id' => 'id'], function($query){ 90 | return $query->orderBy( 'sort' ); 91 | }) 92 | ->limit(1); 93 | } 94 | 95 | 96 | } 97 | -------------------------------------------------------------------------------- /models/FileTagRelationships.php: -------------------------------------------------------------------------------- 1 | Yii::t('app', 'ID'), 42 | 'file_id' => Yii::t('app', 'File ID'), 43 | 'tag_id' => Yii::t('app', 'Tag ID'), 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /models/FileTagSearch.php: -------------------------------------------------------------------------------- 1 | $query, 48 | ]); 49 | 50 | $this->load($params); 51 | 52 | if (!$this->validate()) { 53 | // uncomment the following line if you do not want to any records when validation fails 54 | // $query->where('0=1'); 55 | return $dataProvider; 56 | } 57 | 58 | $query->andFilterWhere([ 59 | 'id' => $this->id, 60 | ]); 61 | 62 | $query->andFilterWhere(['like', 'name', $this->name]) 63 | ->andFilterWhere(['like', 'slug', $this->slug]); 64 | 65 | return $dataProvider; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /models/FileTerms.php: -------------------------------------------------------------------------------- 1 | 45] 36 | ]; 37 | } 38 | 39 | /** 40 | * @inheritdoc 41 | */ 42 | public function attributeLabels() 43 | { 44 | return [ 45 | 'id' => 'ID', 46 | 'file_id' => 'File ID', 47 | 'type' => 'Type', 48 | 'value' => 'Value', 49 | ]; 50 | } 51 | 52 | /** 53 | * @return \yii\db\ActiveQuery 54 | */ 55 | public function getFile() 56 | { 57 | return $this->hasOne(Files::className(), ['id' => 'file_id']); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /models/Files.php: -------------------------------------------------------------------------------- 1 | [ 42 | 'class' => TimestampBehavior::className(), 43 | 'attributes' => [ 44 | ActiveRecord::EVENT_BEFORE_INSERT => 'update', 45 | ActiveRecord::EVENT_BEFORE_UPDATE => 'update', 46 | ], 47 | 'value' => function() { 48 | return date('Y-m-d H:i:s'); 49 | }, 50 | ], 51 | 'modifiedGMT' => [ 52 | 'class' => TimestampBehavior::className(), 53 | 'attributes' => [ 54 | ActiveRecord::EVENT_BEFORE_INSERT => 'update_gmt', 55 | ActiveRecord::EVENT_BEFORE_UPDATE => 'update_gmt', 56 | ], 57 | 'value' => function() { 58 | return gmdate('Y-m-d H:i:s'); 59 | }, 60 | ], 61 | 'date' => [ 62 | 'class' => TimestampBehavior::className(), 63 | 'attributes' => [ 64 | ActiveRecord::EVENT_BEFORE_INSERT => 'date', 65 | ActiveRecord::EVENT_BEFORE_UPDATE => 'date', 66 | ], 67 | 'value' => function() { 68 | return (empty($this->date) ? date('Y-m-d H:i:s') : date('Y-m-d H:i:s',strtotime($this->date))); 69 | }, 70 | ], 71 | 'dateGMT' => [ 72 | 'class' => TimestampBehavior::className(), 73 | 'attributes' => [ 74 | ActiveRecord::EVENT_BEFORE_INSERT => 'date_gmt', 75 | ActiveRecord::EVENT_BEFORE_UPDATE => 'date_gmt', 76 | ], 77 | 'value' => function() { 78 | return (empty($this->date) ? gmdate('Y-m-d H:i:s') : gmdate('Y-m-d H:i:s',strtotime($this->date))); 79 | }, 80 | ], 81 | ]; 82 | } 83 | 84 | 85 | 86 | /** 87 | * @inheritdoc 88 | */ 89 | public static function tableName() 90 | { 91 | return 'files'; 92 | } 93 | 94 | 95 | /** 96 | * @inheritdoc 97 | */ 98 | public function rules() 99 | { 100 | return [ 101 | [['user_id', 'size', 'width', 'height'], 'integer'], 102 | [['date', 'date_gmt', 'update', 'update_gmt'], 'safe'], 103 | [['url', 'thumbnail_url', 'file_name', 'title'], 'string', 'max' => 555], 104 | [['type'], 'string', 'max' => 45] 105 | ]; 106 | } 107 | 108 | /** 109 | * @inheritdoc 110 | */ 111 | public function attributeLabels() 112 | { 113 | return [ 114 | 'id' => 'ID', 115 | 'user_id' => 'User ID', 116 | 'url' => 'Url', 117 | 'thumbnail_url' => 'Thumbnail Url', 118 | 'file_name' => 'File Name', 119 | 'type' => 'Type', 120 | 'title' => 'Title', 121 | 'size' => 'Size', 122 | 'width' => 'Width', 123 | 'height' => 'Height', 124 | 'date' => 'Date', 125 | 'date_gmt' => 'Date Gmt', 126 | 'update' => 'Update', 127 | 'update_gmt' => 'Update Gmt', 128 | ]; 129 | } 130 | 131 | /** 132 | * @return \yii\db\ActiveQuery 133 | */ 134 | public function getFileTerms() 135 | { 136 | return $this->hasMany(FileTerms::className(), ['file_id' => 'id']); 137 | } 138 | 139 | /** 140 | * @return \yii\db\ActiveQuery 141 | */ 142 | public function getUser() 143 | { 144 | return $this->hasOne(User::className(), ['id' => 'user_id']); 145 | } 146 | 147 | 148 | /** 149 | * [getFiles description] 150 | */ 151 | public function getTags() 152 | { 153 | return $this->hasMany( FileTag::className(), ['id' => 'tag_id'])->viaTable( '{{%file_tag_relationships}}', ['file_id' => 'id']); 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /models/FilesSearch.php: -------------------------------------------------------------------------------- 1 | $query, 48 | 'sort'=> ['defaultOrder' => ['date' => SORT_DESC]], 49 | ]); 50 | 51 | $this->load($params); 52 | 53 | if (!$this->validate()) { 54 | // uncomment the following line if you do not want to any records when validation fails 55 | // $query->where('0=1'); 56 | return $dataProvider; 57 | } 58 | 59 | $query->andFilterWhere([ 60 | 'id' => $this->id, 61 | 'user_id' => $this->user_id, 62 | 'size' => $this->size, 63 | 'width' => $this->width, 64 | 'height' => $this->height, 65 | 'date' => $this->date, 66 | 'date_gmt' => $this->date_gmt, 67 | 'update' => $this->update, 68 | 'update_gmt' => $this->update_gmt, 69 | ]); 70 | 71 | $query->andFilterWhere(['like', 'url', $this->url]) 72 | ->andFilterWhere(['like', 'thumbnail_url', $this->thumbnail_url]) 73 | ->andFilterWhere(['like', 'file_name', $this->file_name]) 74 | ->andFilterWhere(['like', 'type', $this->type]) 75 | ->andFilterWhere(['like', 'title', $this->title]); 76 | 77 | return $dataProvider; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yii2-filemanager", 3 | "version": "1.0.0", 4 | "description": "Yii2 File Manager ================= A file manager for Yii2. Allow you to dynamically manager images and files from any location. Also TinyMCE plugin included.", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.18.0", 11 | "linkstate": "^1.1.1", 12 | "preact": "^8.4.2", 13 | "preact-compat": "^3.18.4", 14 | "react-beautiful-dnd": "^10.0.3", 15 | "react-dragula": "^1.1.17", 16 | "react-dropzone": "^8.0.1", 17 | "unistore": "^3.1.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7", 21 | "@babel/plugin-proposal-class-properties": "^7.2.1", 22 | "@babel/plugin-transform-react-jsx": "^7.2.0", 23 | "@babel/preset-env": "^7.2.0", 24 | "babel": "^6.23.0", 25 | "babel-loader": "^8.0.4", 26 | "babel-preset-env": "^1.7.0", 27 | "cross-env": "^5.2.0", 28 | "css-loader": "^2.1.0", 29 | "style-loader": "^0.23.1", 30 | "webpack": "^4.27.1", 31 | "webpack-cli": "^3.1.2" 32 | }, 33 | "scripts": { 34 | "test": "echo \"Error: no test specified\" && exit 1", 35 | "dev": "cross-env NODE_ENV=development ./node_modules/.bin/webpack --watch" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git+https://github.com/linchpinstudios/yii2-filemanager.git" 40 | }, 41 | "author": "Josh Hagel ", 42 | "license": "ISC", 43 | "bugs": { 44 | "url": "https://github.com/linchpinstudios/yii2-filemanager/issues" 45 | }, 46 | "homepage": "https://github.com/linchpinstudios/yii2-filemanager#readme" 47 | } 48 | -------------------------------------------------------------------------------- /src/js/components/Button.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | 3 | export default class Button extends Component { 4 | render() { 5 | return 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/js/components/Close.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import Thumbnail from '../components/Thumbnail' 3 | import Dragula from 'react-dragula' 4 | 5 | export default class Selected extends Component { 6 | 7 | constructor() { 8 | super() 9 | this.state.images = [] 10 | this.state.clickHandler = () => {} 11 | } 12 | 13 | render(props = { images: [] }, state) { 14 | if (props.clickHandler) state.clickHandler = props.clickHandler 15 | return
    state.clickHandler(props.image)}> 16 | X 17 |
    18 | } 19 | } 20 | 21 | const styles = { 22 | close: { 23 | position: 'absolute', 24 | top: '5px', 25 | right: '5px', 26 | color: '#ff0000', 27 | cursor: 'pointer', 28 | opacity: 0, 29 | 'font-weight': 'bold', 30 | 'text-decoration': 'none', 31 | transition: '500ms opacity' 32 | }, 33 | hover: { 34 | opacity: 1 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/js/components/Pagination.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | 3 | export default class Pagination extends Component { 4 | 5 | constructor() { 6 | super() 7 | this.clickHandler = e => false 8 | } 9 | 10 | getFirstButton(page = 1) { 11 | if (page <= 1) { 12 | return
  • «
  • 13 | } 14 | return
  • this.clickHandler(page-1)}>«
  • 15 | } 16 | 17 | getLastButton(count, page = 1) { 18 | if (page + 1 >= count) { 19 | return
  • »
  • 20 | } 21 | return
  • this.clickHandler(page+1)}>»
  • 22 | } 23 | 24 | getOffset(page, count, limit) { 25 | let offset = page - Math.floor((limit-1) / 2) 26 | return offset >= 1 ? offset : 1 27 | } 28 | 29 | getNumbers(count, page = 1, limit = 11) { 30 | let nums = [] 31 | let offset = this.getOffset(page, count, limit) 32 | let top = (offset + limit) > count ? count : offset + limit 33 | for (let i = offset; i <= top; i++) { 34 | nums.push(
  • this.clickHandler(i)}>{i}
  • ) 35 | } 36 | return nums 37 | } 38 | 39 | render(props) { 40 | if (props.clickHandler) this.clickHandler = props.clickHandler 41 | return
    42 |
      43 | {this.getFirstButton(props.page)} 44 | {this.getNumbers(props.pageCount, props.page)} 45 | {this.getLastButton(props.pageCount, props.page)} 46 |
    47 |
    48 | } 49 | } 50 | 51 | const styles = { 52 | button: { 53 | textAlign: 'center', 54 | minWidth: '40px', 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/js/components/Search.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | 3 | export default class Search extends Component { 4 | 5 | constructor() { 6 | super() 7 | this.clickHandler = e => { 8 | return false 9 | } 10 | this.state.term = '' 11 | } 12 | 13 | handleChange(e) { 14 | this.state.term = e.target.value 15 | console.log('update state', this.state.term) 16 | } 17 | 18 | handleKeyInput(e) { 19 | if (e.charCode == 13 || e.keyCode == 13) { 20 | e.preventDefault(); 21 | this.state.term = e.target.value 22 | this.state.clickHandler(this.state.term) 23 | return false 24 | } 25 | } 26 | 27 | render(props = {term:''}, state) { 28 | state.term = props.term 29 | 30 | if (props.clickHandler) state.clickHandler = props.clickHandler 31 | 32 | return
    33 | 41 |
    42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/js/components/Selected.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import Thumbnail from '../components/Thumbnail' 3 | import Dragula from 'react-dragula' 4 | 5 | export default class Selected extends Component { 6 | 7 | constructor() { 8 | super() 9 | this.state.images = [] 10 | this.state.clickHandler = false 11 | this.state.orderHandler = () => {} 12 | this.state.removeHandle = false 13 | this.dragulaDecorator = this.dragulaDecorator.bind(this); 14 | this.thumbnails = this.thumbnails.bind(this) 15 | } 16 | 17 | dragulaDecorator(componentBackingInstance) { 18 | if (componentBackingInstance) { 19 | let options = { 20 | drop: (el) => { 21 | console.log('dropped', el) 22 | } 23 | } 24 | let drake = Dragula([componentBackingInstance], options); 25 | drake.on('drop', (el, target, source, sibling) => { 26 | let order = [] 27 | 28 | for (let i = 0; i < source.children.length; i++) { 29 | order.push(source.children[i].dataset.id) 30 | } 31 | 32 | this.state.orderHandler(order) 33 | }) 34 | } 35 | } 36 | 37 | thumbnails(images) { 38 | let components = [] 39 | images.forEach((image, key) => { 40 | components.push() 41 | }) 42 | return components 43 | } 44 | 45 | render(props = { images: [] }, state) { 46 | if (props.clickHandler) state.clickHandler = props.clickHandler 47 | if (props.removeHandle) state.removeHandle = props.removeHandle 48 | if (props.orderHandler) state.orderHandler = props.orderHandler 49 | state.images = props.images 50 | return
    51 | {this.thumbnails(state.images)} 52 |
    53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/js/components/Thumbnail.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import Close from '../components/Close' 3 | 4 | export default class Thumbnail extends Component { 5 | constructor() { 6 | super() 7 | this.state.clickHandler = () => {} 8 | this.state.removeHandle = false 9 | this.state.hover = false 10 | this.state.image 11 | } 12 | 13 | hoverOn() { 14 | this.setState({ 15 | hover: true, 16 | }) 17 | } 18 | 19 | hoverOff() { 20 | this.setState({ 21 | hover: false, 22 | }) 23 | } 24 | 25 | closeButton() { 26 | return this.state.removeHandle ? :
    27 | } 28 | 29 | render(props, state) { 30 | if (props.clickHandler) state.clickHandler = props.clickHandler 31 | if (props.removeHandle) state.removeHandle = props.removeHandle 32 | 33 | state.image = props.image 34 | 35 | return 41 | } 42 | } 43 | 44 | const styles = { 45 | wrapper: { 46 | position: 'relative', 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/js/components/Uploader.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import Axios from 'axios'; 3 | 4 | export default class Uploader extends Component { 5 | constructor() { 6 | super() 7 | this.state.uploadCallback = () => { } 8 | this.state.csrfToken = document.querySelector('[name="csrf-token"]').content 9 | this.refs = {} 10 | } 11 | 12 | handleFiles(e) { 13 | let files = e.target.files 14 | console.log(files) 15 | Array.from(files) 16 | .forEach(file => this.upload(file) 17 | .then(response => response.data) 18 | .then(data => { 19 | this.state.uploadCallback(data) 20 | this.refs.fileInput.value = null 21 | }) 22 | .catch(error => console.log(error))) 23 | } 24 | 25 | upload(file) { 26 | let formData = new FormData; 27 | formData.append('Files[file_name]', file) 28 | return Axios.post('/filemanager/files/uploadpicker', formData, { 29 | headers: { 30 | 'Content-Type': 'multipart/form-data', 31 | 'X-CSRF-Token': this.state.csrfToken, 32 | Accept: 'application/json', 33 | } 34 | }) 35 | } 36 | 37 | render(props, state) { 38 | if (props.uploadCallback) state.uploadCallback = props.uploadCallback 39 | return (
    40 | this.refs.fileInput = el} onChange={this.handleFiles.bind(this)} multiple="multiple" style={styles.input} /> 41 | this.refs.fileInput.click()}>Upload 42 |
    ) 43 | } 44 | } 45 | 46 | 47 | const styles = { 48 | input: { 49 | display: 'none' 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact' 2 | import FilePicker from './views/FilePicker' 3 | import { Store, Actions} from './store/FilePickerStore' 4 | import { Provider, connect } from 'unistore/preact' 5 | import 'react-dragula/dist/dragula.min.css'; 6 | 7 | var elements = document.querySelectorAll('*[data-filemanager]') 8 | 9 | if (elements) { 10 | elements.forEach(function(element) { 11 | var view = element.getAttribute('data-filemanager') 12 | var target = element.getAttribute('data-target') 13 | var selected = element.getAttribute('data-selected') 14 | var limit = element.getAttribute('data-limit') 15 | switch (view) { 16 | case 'FilePicker': 17 | render( 18 | 19 | , element); 20 | break; 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /src/js/store/FilePickerStore.js: -------------------------------------------------------------------------------- 1 | import createStore from 'unistore' 2 | import Axios from 'axios' 3 | 4 | export const Store = createStore({ 5 | images: [], 6 | selected: [], 7 | selectedIds: [], 8 | page: 1, 9 | term: '', 10 | pageCount: 10, 11 | showSelector: false, 12 | }) 13 | 14 | export const Actions = store => ({ 15 | 16 | /** 17 | * @param {State} state 18 | * @param {Page} page 19 | */ 20 | async getPage(state, page = 1) { 21 | let params = { page } 22 | if (state.term !== '') params["FilesSearch[title]"] = state.term 23 | 24 | let response = await Axios.get('/filemanager/files/index', { 25 | params, 26 | headers: { 27 | Accept: 'application/json' 28 | } 29 | }) 30 | let data = await response.data 31 | return { 32 | images: state.images.push(data.images), 33 | page: page, 34 | pageCount: data.pageCount 35 | } 36 | } 37 | 38 | 39 | }) 40 | -------------------------------------------------------------------------------- /src/js/views/FilePicker.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import Search from '../components/Search' 3 | import Thumbnail from '../components/Thumbnail' 4 | import Pagination from '../components/Pagination'; 5 | import Selected from '../components/Selected'; 6 | import Axios from 'axios'; 7 | import Uploader from '../components/Uploader'; 8 | 9 | export default class FilePicker extends Component { 10 | constructor(props) { 11 | super(props); 12 | // set initial time: 13 | this.props = props 14 | this.state = this.setDefaultState(props) 15 | 16 | this.thumbnails = this.thumbnails.bind(this) 17 | this.addToSelected = this.addToSelected.bind(this) 18 | } 19 | 20 | setDefaultState(props) { 21 | return { 22 | images: [], 23 | selected: [], 24 | selectedIds: props.selected ? JSON.parse(props.selected) : [], 25 | limit: parseInt(props.limit), 26 | page: 1, 27 | term: '', 28 | pageCount: 10, 29 | showSelector: false, 30 | } 31 | } 32 | 33 | componentDidMount() { 34 | this.getSelected() 35 | this.getPage() 36 | } 37 | 38 | getSelected() { 39 | this.state.selectedIds.forEach(id => this.getById(id).then(image => this.state.selected.push(image)).then(() => {this.orderSelected(this.state.selectedIds)}).catch(error => console.log(error))) 40 | } 41 | 42 | orderSelected(order) { 43 | let selected = order.map((index) => { 44 | return this.state.selected.find(image => index == image.id) 45 | }).filter((item) => item) 46 | this.setState({ 47 | selected: selected, 48 | selectedIds: order, 49 | }) 50 | } 51 | 52 | getById(id) { 53 | return new Promise((resolve, reject) => { 54 | Axios.get('/filemanager/files/view', { 55 | params: { id: id }, 56 | headers: { 57 | Accept: 'application/json' 58 | } 59 | }).then(response => response.data).then(data => { 60 | resolve(data) 61 | }).catch(error => console.log('getById', reject(error))) 62 | }) 63 | } 64 | 65 | handleUploaded(image) { 66 | this.addToSelected(image) 67 | this.getPage() 68 | } 69 | 70 | addToSelected(image) { 71 | let match = this.state.selected.find(img => image === img) 72 | if (match) return 73 | if (this.state.limit > 0 && this.state.selected.length >= this.state.limit) { 74 | this.state.selected.pop() 75 | this.state.selectedIds.pop() 76 | } 77 | this.state.selected.push(image) 78 | this.state.selectedIds.push(image.id) 79 | this.setState({ selected: this.state.selected }) 80 | } 81 | 82 | removeFromSelected(image) { 83 | let selected = this.state.selected.filter(img => image !== img) 84 | let selectedIds = this.state.selectedIds.filter(img => image.id !== img) 85 | this.setState({ 86 | selected: selected, 87 | selectedIds: selectedIds, 88 | }) 89 | } 90 | 91 | clickHandler(page) { 92 | this.getPage(page <= 0 ? 1 : page) 93 | return false 94 | } 95 | 96 | searchHandler(term = '') { 97 | this.setState({term: term}) 98 | this.getPage() 99 | return false 100 | } 101 | 102 | getPage(page = 1) { 103 | let params = { page } 104 | 105 | if (this.state.term !== '') params["FilesSearch[title]"] = this.state.term 106 | 107 | this.clearThumbnails() 108 | 109 | Axios.get('/filemanager/files/index', { 110 | params, 111 | headers: { 112 | Accept: 'application/json' 113 | } 114 | }).then(response => response.data).then(data => { 115 | this.setState({ 116 | page: page, 117 | images: data.images, 118 | pageCount: data.pageCount, 119 | }) 120 | }).catch(error => console.log('getPage', error)) 121 | } 122 | 123 | clearThumbnails () { 124 | this.setState({images: []}) 125 | } 126 | 127 | thumbnails(images) { 128 | let components = [] 129 | images.forEach((image) => { 130 | components.push() 131 | }) 132 | return components 133 | } 134 | 135 | toggleSelector() { 136 | let show = !this.state.showSelector 137 | this.setState({showSelector: show}) 138 | } 139 | 140 | selector() { 141 | if (!this.state.showSelector) { 142 | return '' 143 | } 144 | return (
    145 |
    146 |
    147 |
    148 | 149 |
    150 |
    151 | this.handleUploaded(image)}> 152 |
    153 |
    154 |
    155 |
    156 |
    157 | { this.thumbnails(this.state.images) } 158 |
    159 |
    160 | 163 |
    ) 164 | } 165 | 166 | inputs() { 167 | let inputs = [] 168 | if (this.state.limit == 1) { 169 | this.state.selectedIds.forEach((id, key) => inputs.push()) 170 | } else { 171 | this.state.selectedIds.forEach((id, key) => inputs.push()) 172 | } 173 | return inputs 174 | } 175 | 176 | render(props, state) { 177 | return (
    178 | {this.inputs()} 179 |
    180 |
    181 |
    182 | 183 |
    184 | 189 |
    190 |
    191 | { this.selector() } 192 |
    ) 193 | } 194 | } 195 | 196 | const styles = { 197 | selected: { 198 | backgroundColor: '#eeeff2', 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /tests/functional/TestCase.php: -------------------------------------------------------------------------------- 1 | mockWebApplication( 18 | [ 19 | 'components' => [ 20 | 'request' => [ 21 | 'class' => 'yii\web\Request', 22 | 'url' => '/test', 23 | 'enableCsrfValidation' => false, 24 | ], 25 | 'response' => [ 26 | 'class' => 'yii\web\Response', 27 | ], 28 | ], 29 | ] 30 | ); 31 | } 32 | /** 33 | * Clean up after test. 34 | * By default the application created with [[mockApplication]] will be destroyed. 35 | */ 36 | protected function tearDown() 37 | { 38 | parent::tearDown(); 39 | $this->destroyApplication(); 40 | } 41 | protected function mockApplication($config = [], $appClass = '\yii\console\Application') 42 | { 43 | new $appClass( 44 | ArrayHelper::merge( 45 | [ 46 | 'id' => 'testapp', 47 | 'basePath' => __DIR__, 48 | 'vendorPath' => $this->getVendorPath(), 49 | ], 50 | $config 51 | ) 52 | ); 53 | } 54 | protected function mockWebApplication($config = [], $appClass = '\yii\web\Application') 55 | { 56 | new $appClass( 57 | ArrayHelper::merge( 58 | [ 59 | 'id' => 'testapp', 60 | 'basePath' => __DIR__, 61 | 'vendorPath' => $this->getVendorPath(), 62 | 'components' => [ 63 | 'request' => [ 64 | 'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq', 65 | 'scriptFile' => __DIR__ . '/index.php', 66 | 'scriptUrl' => '/index.php', 67 | ], 68 | 'assetManager' => [ 69 | 'basePath' => '@tests/data/assets', 70 | 'baseUrl' => '/', 71 | ] 72 | ] 73 | ], 74 | $config 75 | ) 76 | ); 77 | } 78 | protected function getVendorPath() 79 | { 80 | return dirname(dirname(__DIR__)) . '/vendor'; 81 | } 82 | /** 83 | * Destroys application in Yii::$app by setting it to null. 84 | */ 85 | protected function destroyApplication() 86 | { 87 | \Yii::$app = null; 88 | } 89 | /** 90 | * Creates a view for testing purposes 91 | * 92 | * @return View 93 | */ 94 | protected function getView() 95 | { 96 | $view = new View(); 97 | $view->setAssetManager( 98 | new AssetManager( 99 | [ 100 | 'basePath' => '@tests/data/assets', 101 | 'baseUrl' => '/', 102 | ] 103 | ) 104 | ); 105 | return $view; 106 | } 107 | /** 108 | * Asserting two strings equality ignoring line endings 109 | * 110 | * @param string $expected 111 | * @param string $actual 112 | */ 113 | public function assertEqualsWithoutLE($expected, $actual) 114 | { 115 | $expected = str_replace("\r\n", "\n", $expected); 116 | $actual = str_replace("\r\n", "\n", $actual); 117 | $this->assertEquals($expected, $actual); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/functional/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * @link http://linchpinstudios.com/ 8 | */ 9 | error_reporting(-1); 10 | define('YII_ENABLE_ERROR_HANDLER', false); 11 | define('YII_DEBUG', true); 12 | $_SERVER['SCRIPT_NAME'] = '/' . __DIR__; 13 | $_SERVER['SCRIPT_FILENAME'] = __FILE__; 14 | require_once(__DIR__ . '/../../vendor/autoload.php'); 15 | require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); 16 | Yii::setAlias('@tests', __DIR__); 17 | require_once(__DIR__ . '/TestCase.php'); 18 | -------------------------------------------------------------------------------- /views/default/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 |
    7 | 8 |
    9 |
    10 |
    11 | 'glyphicon glyphicon-cloud-upload']),['filemanager/files/filemodal'],['class' => 'btn btn-default navbar-btn', 'data-toggle' => 'modal', 'data-target' => '#filemanagerUpload']); ?> 12 |
    13 | 19 |
    20 |
    21 |
    22 |
    23 |
    24 | 25 | ... 26 | 27 |
    28 |
    29 | 30 | ... 31 | 32 |
    33 |
    34 | 35 | ... 36 | 37 |
    38 |
    39 | 40 | ... 41 | 42 |
    43 |
    44 | 45 | ... 46 | 47 |
    48 |
    49 | 50 | ... 51 | 52 |
    53 |
    54 | 55 | ... 56 | 57 |
    58 |
    59 | 60 | ... 61 | 62 |
    63 |
    64 | 65 | ... 66 | 67 |
    68 |
    69 | 70 | ... 71 | 72 |
    73 |
    74 | 75 | ... 76 | 77 |
    78 |
    79 | 80 | ... 81 | 82 |
    83 |
    84 |
    85 | 96 |
    97 | 98 |
    99 | 100 | 101 | 102 | 115 | -------------------------------------------------------------------------------- /views/file-tag/_form.php: -------------------------------------------------------------------------------- 1 | 10 | 11 |
    12 | 13 | 14 | 15 | field($model, 'name')->textInput(['maxlength' => true]) ?> 16 | 17 | field($model, 'slug')->textInput(['maxlength' => true]) ?> 18 | 19 |
    20 | isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 21 |
    22 | 23 | 24 | 25 |
    26 | -------------------------------------------------------------------------------- /views/file-tag/_search.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 32 | -------------------------------------------------------------------------------- /views/file-tag/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('app', 'Create File Tag'); 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | 17 | render('_form', [ 18 | 'model' => $model, 19 | ]) ?> 20 | 21 |
    22 | -------------------------------------------------------------------------------- /views/file-tag/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('app', 'File Tags'); 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | render('_search', ['model' => $searchModel]); ?> 17 | 18 |

    19 | 'btn btn-success']) ?> 20 |

    21 | 22 | $dataProvider, 24 | 'filterModel' => $searchModel, 25 | 'columns' => [ 26 | ['class' => 'yii\grid\SerialColumn'], 27 | 28 | 'id', 29 | 'name', 30 | 'slug', 31 | 32 | ['class' => 'yii\grid\ActionColumn'], 33 | ], 34 | ]); ?> 35 | 36 |
    37 | -------------------------------------------------------------------------------- /views/file-tag/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('app', 'Update {modelClass}: ', [ 9 | 'modelClass' => 'File Tag', 10 | ]) . ' ' . $model->name; 11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']]; 12 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; 13 | $this->params['breadcrumbs'][] = Yii::t('app', 'Update'); 14 | ?> 15 |
    16 | 17 |

    title) ?>

    18 | 19 | render('_form', [ 20 | 'model' => $model, 21 | ]) ?> 22 | 23 |
    24 | -------------------------------------------------------------------------------- /views/file-tag/view.php: -------------------------------------------------------------------------------- 1 | title = $model->name; 10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | 17 |

    18 | $model->id], ['class' => 'btn btn-primary']) ?> 19 | $model->id], [ 20 | 'class' => 'btn btn-danger', 21 | 'data' => [ 22 | 'confirm' => Yii::t('app', 'Are you sure you want to delete this item?'), 23 | 'method' => 'post', 24 | ], 25 | ]) ?> 26 |

    27 | 28 | $model, 30 | 'attributes' => [ 31 | 'id', 32 | 'name', 33 | 'slug', 34 | ], 35 | ]) ?> 36 | 37 |
    38 | -------------------------------------------------------------------------------- /views/files/_form.php: -------------------------------------------------------------------------------- 1 | 11 | 12 |
    13 | 14 | 15 | 16 |
    17 |
    18 | 19 | 20 | 21 |
    22 |
    23 |
    24 |
    25 | Details 26 |
    27 |
    28 | 29 |
    30 |
    31 | field($model, 'title')->textInput(['maxlength' => true]) ?> 32 |
    33 |
    34 | field($model, 'file_name')->textInput(['maxlength' => true]) ?> 35 |
    36 |
    37 | field($model, 'width')->textInput() ?> 38 |
    39 |
    40 | field($model, 'height')->textInput() ?> 41 |
    42 |
    43 | 44 |
    45 |
    46 | field($model, 'url')->textInput(['maxlength' => true]) ?> 47 |
    48 |
    49 | field($model, 'thumbnail_url')->textInput(['maxlength' => true]) ?> 50 |
    51 |
    52 | 53 |
    54 |
    55 |
    56 |
    57 | 58 |
    59 |
    60 | 61 |
    62 |
    63 | Tags 64 | Add', ['#'], ['class' => 'pull-right', 'data-toggle' => 'modal', 'data-target' => '#myModal']) ?> 65 |
    66 |
    67 | 68 |
    69 | tags), 'name', 'id' ); 72 | ?> 73 | 'tag-con', 'separator'=>'', 'item' => function ($index, $label, $name, $checked, $value){ 74 | return '
    ' . Html::checkbox($name, $checked, ['value' => $value, 'label' => $label, ]) . '
    '; 75 | }]) ?> 76 |
    77 | 78 |
    79 |
    80 | 81 |
    82 |
    83 | 84 | 85 |
    86 |
    87 | 88 |
    89 | isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> 90 |
    91 | 92 |
    93 |
    94 | Tags 95 |
    96 |
    97 | 98 | field($model, 'user_id')->textInput() ?> 99 | 100 | field($model, 'type')->textInput(['maxlength' => true]) ?> 101 | 102 | field($model, 'size')->textInput() ?> 103 | 104 |
    105 |
    106 | 107 |
    108 |
    109 | 110 | 111 | 112 |
    113 | 114 | 115 | 116 | 142 | -------------------------------------------------------------------------------- /views/files/_properties.php: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /views/files/_search.php: -------------------------------------------------------------------------------- 1 | 10 | 11 | 54 | -------------------------------------------------------------------------------- /views/files/create.php: -------------------------------------------------------------------------------- 1 | title = 'Create Files'; 10 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | 17 | render('_form', [ 18 | 'model' => $model, 19 | 'tags' => $tags, 20 | 'newTag' => $newTag, 21 | ]) ?> 22 | 23 |
    24 | -------------------------------------------------------------------------------- /views/files/fileModal.php: -------------------------------------------------------------------------------- 1 | title = 'File Upload'; 7 | ?> 8 | 9 | 10 | $model, 12 | 'attribute' => 'file_name', 13 | 'url' => ['files/upload'], // your url, this is just for demo purposes, 14 | 'options' => ['accept' => 'image/*'], 15 | 'clientOptions' => [ 16 | 'maxFileSize' => 2000000 17 | ] 18 | ]);?> 19 | -------------------------------------------------------------------------------- /views/files/index.php: -------------------------------------------------------------------------------- 1 | title = 'Files'; 16 | $this->params['breadcrumbs'][] = $this->title; 17 | 18 | $awsConfig = $this->context->module->aws; 19 | 20 | if($awsConfig['enable']){ 21 | $path = $this->context->module->url; 22 | }else{ 23 | $path = '/'; 24 | } 25 | 26 | ?> 27 | 28 |
    29 | 30 |
    31 |
    32 | 33 |
    34 |
    35 |
    36 | 'glyphicon glyphicon-th-large']), '#', ['class' => 'btn btn-primary navbar-btn disabled', 'id' => 'fileGridBtn']); ?> 37 | 'glyphicon glyphicon-cloud-upload']), '#', ['class' => 'btn btn-success navbar-btn', 'id' => 'fileUploadBtn']); ?> 38 |
    39 | 40 | 'file-search-form', 43 | 'method' => 'get', 44 | 'options' => ['class' => 'navbar-form navbar-right'], 45 | ]); 46 | 47 | echo Html::beginTag('div',['class' => 'form-group']); 48 | echo $form->field($searchModel, 'title')->textInput(['class' => 'form-control', 'placeholder' => 'Search']); 49 | echo Html::endTag('div'); 50 | echo Html::submitButton('', ['class' => 'btn btn-primary']); 51 | ActiveForm::end(); 52 | ?> 53 | 54 |
    55 |
    56 | 57 |
    58 |
    59 |
    60 | getModels(); 63 | 64 | foreach($models as $m){ 65 | 66 | echo '
    '; 67 | echo Html::a( '', ['view', 'id' => $m->id],['class'=>'thumbnail', 'data-id' => $m->id]); 68 | echo '
    '; 69 | 70 | } 71 | ?> 72 |
    73 |
    74 |
    75 | $model, 77 | 'attribute' => 'file_name', 78 | 'url' => ['files/upload'], // your url, this is just for demo purposes, 79 | 'options' => [ 80 | 'accept' => 'image/*', 81 | 'done' => 'filemanager', 82 | ], 83 | 'clientOptions' => [ 84 | 'maxFileSize' => 2000000, 85 | 'debug' => true, 86 | ], 87 | 'clientEvents' => [ 88 | 'fileuploaddone' => 'function(e, data) { 89 | console.log(data); 90 | $.each(data.result.files, function( index, value ){ 91 | console.log(value); 92 | $("#fileGridManager .row").prepend(\'
    \'); 93 | $(\'#filemanagerUpload\').hide(); 94 | $(\'#fileGridManager,#fileGridFooter\').show(); 95 | }); 96 | }', 97 | 'fileuploadfail' => 'function(e, data) { 98 | console.log(e); 99 | console.log(data); 100 | }', 101 | ], 102 | ]);?> 103 |
    104 |
    105 | 106 | 115 | 116 |
    117 |
    118 | 119 |
    120 | 121 |
    122 | -------------------------------------------------------------------------------- /views/files/update.php: -------------------------------------------------------------------------------- 1 | title = 'Update Files: ' . ' ' . $model->title; 9 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']]; 10 | $this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]]; 11 | $this->params['breadcrumbs'][] = 'Update'; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | 17 | render('_form', [ 18 | 'model' => $model, 19 | 'tags' => $tags, 20 | 'newTag' => $newTag, 21 | ]) ?> 22 | 23 |
    24 | -------------------------------------------------------------------------------- /views/files/view.php: -------------------------------------------------------------------------------- 1 | title = $model->title; 10 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']]; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
    14 | 15 |

    title) ?>

    16 | 17 |

    18 | $model->id], ['class' => 'btn btn-primary']) ?> 19 | $model->id], [ 20 | 'class' => 'btn btn-danger', 21 | 'data' => [ 22 | 'confirm' => 'Are you sure you want to delete this item?', 23 | 'method' => 'post', 24 | ], 25 | ]) ?> 26 |

    27 | 28 | $model, 30 | 'attributes' => [ 31 | 'id', 32 | 'user_id', 33 | 'url:url', 34 | 'thumbnail_url:url', 35 | 'file_name', 36 | 'type', 37 | 'title', 38 | 'size', 39 | 'width', 40 | 'height', 41 | 'date', 42 | 'date_gmt', 43 | 'update', 44 | 'update_gmt', 45 | ], 46 | ]) ?> 47 | 48 |
    49 | -------------------------------------------------------------------------------- /views/layouts/modal.php: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | -------------------------------------------------------------------------------- /views/layouts/tinymce.php: -------------------------------------------------------------------------------- 1 | 14 | beginPage() ?> 15 | 16 | 17 | 18 | 19 | 20 | <?= Html::encode($this->title) ?> 21 | head() ?> 22 | 23 | 24 | 25 | beginBody() ?> 26 | 27 | endBody() ?> 28 | 29 | 30 | endPage() ?> 31 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: ['./src/js/index.js'], 6 | output: { 7 | path: path.resolve(__dirname, 'js'), 8 | filename: 'bundle.js' 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.js$/, 13 | exclude: /node_modules/, 14 | use: { 15 | loader: "babel-loader" 16 | } 17 | }, 18 | { 19 | test: /\.css$/, 20 | use: ['style-loader', 'css-loader'], 21 | }] 22 | }, 23 | resolve: { 24 | alias: { 25 | react: "preact-compat", 26 | "react-dom": "preact-compat" 27 | } 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /widgets/FilePicker.php: -------------------------------------------------------------------------------- 1 | 20 | * @since 0.1 21 | */ 22 | 23 | class FilePicker extends InputWidget 24 | { 25 | /** 26 | * @var array the options for the DateTime JS plugin. 27 | * Please refer to the DateTime JS plugin Web page for possible options. 28 | * @see http://xdsoft.net/jqplugins/datetimepicker/ 29 | */ 30 | public $clientOptions = [ 31 | 'limit' 32 | ]; 33 | 34 | 35 | /** 36 | * run function. 37 | * 38 | * @access public 39 | * @return void 40 | */ 41 | public function run() 42 | { 43 | \Yii::$app->assetManager->forceCopy = true; 44 | $view = $this->getView(); 45 | FilemanagerPreactAssets::register( $view ); 46 | 47 | if ( isset($this->clientOptions['fileTypes']) && !in_array('*', $this->clientOptions['fileTypes']) ) { 48 | $where = ['type'=>$this->clientOptions['fileTypes']]; 49 | } else { 50 | $where = []; 51 | } 52 | 53 | if ($this->hasModel()) { 54 | $selected = []; 55 | if (is_array($this->model[$this->attribute])) { 56 | foreach ($this->model[$this->attribute] as $file) { 57 | $selected[] = $file->id; 58 | } 59 | } else if (!empty($this->model[$this->attribute])) { 60 | $selected[] = $this->model[$this->attribute]; 61 | } 62 | } else { 63 | $selected = $this->value; 64 | } 65 | 66 | if ($this->model) { 67 | $this->name = $this->model->formName() . '[' . $this->attribute .']'; 68 | } 69 | 70 | echo Html::beginTag('div', [ 71 | 'data-filemanager' => 'FilePicker', 72 | 'data-target' => $this->name, 73 | 'data-selected' => $selected, 74 | 'data-limit' => isset($this->options['limit']) ? $this->options['limit'] : 0, 75 | ]); 76 | echo Html::endTag('div'); 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /widgets/FileSelect.php: -------------------------------------------------------------------------------- 1 | 19 | * @since 0.1 20 | */ 21 | 22 | class FileSelect extends InputWidget 23 | { 24 | /** 25 | * @var array the options for the DateTime JS plugin. 26 | * Please refer to the DateTime JS plugin Web page for possible options. 27 | * @see http://xdsoft.net/jqplugins/datetimepicker/ 28 | */ 29 | public $clientOptions = []; 30 | 31 | 32 | 33 | 34 | /** 35 | * run function. 36 | * 37 | * @access public 38 | * @return void 39 | */ 40 | public function run() 41 | { 42 | 43 | $randomId = uniqid(); 44 | 45 | if ( isset($this->clientOptions['fileTypes']) && !in_array('*', $this->clientOptions['fileTypes']) ) { 46 | $where = ['type'=>$this->clientOptions['fileTypes']]; 47 | } else { 48 | $where = []; 49 | } 50 | 51 | $imageArray = ArrayHelper::map(Files::find()->select(['id', 'title'])->where( $where )->orderBy('title')->all(), 'id', 'title'); 52 | 53 | $selectOptions = ArrayHelper::merge(['' => 'Select a Thumbnail'], $imageArray); 54 | 55 | if ($this->hasModel()) { 56 | echo Html::activeDropDownList($this->model, $this->attribute, $selectOptions, $this->options); 57 | } else { 58 | echo Html::dropDownList($this->name, $this->value, $selectOptions, $this->options); 59 | } 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /widgets/FileTagSelect.php: -------------------------------------------------------------------------------- 1 | 21 | * @since 0.1 22 | */ 23 | 24 | class FileTagSelect extends InputWidget 25 | { 26 | /** 27 | * @var array the options for the DateTime JS plugin. 28 | * Please refer to the DateTime JS plugin Web page for possible options. 29 | * @see http://xdsoft.net/jqplugins/datetimepicker/ 30 | */ 31 | public $clientOptions = []; 32 | 33 | 34 | 35 | 36 | /** 37 | * run function. 38 | * 39 | * @access public 40 | * @return void 41 | */ 42 | public function run() 43 | { 44 | 45 | $randomId = uniqid(); 46 | 47 | $tagsArray = ArrayHelper::map( FileTag::find()->select(['id', 'name'])->orderBy('name')->all(), 'id', 'name' ); 48 | 49 | $selectOptions = ArrayHelper::merge(['' => 'Select a File Tag'], $tagsArray); 50 | 51 | if ($this->hasModel()) { 52 | echo Html::activeDropDownList($this->model, $this->attribute, $selectOptions, $this->options); 53 | } else { 54 | echo Html::dropDownList($this->name, $this->value, $selectOptions, $this->options); 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /widgets/Fileupload.php: -------------------------------------------------------------------------------- 1 | field($model, 'body')->widget(DateTime::className(), [ 24 | * 'options' => ['rows' => 10], 25 | * 'clientOptions' => [ 26 | * 'datepicker' => false, 27 | * 'format' => 'H:i', 28 | * ] 29 | * ]); 30 | * ``` 31 | * @see http://xdsoft.net/jqplugins/datetimepicker/ 32 | * @author Josh Hagel 33 | * @since 0.1 34 | */ 35 | 36 | class Fileupload extends InputWidget 37 | { 38 | /** 39 | * @var array the options for the DateTime JS plugin. 40 | * Please refer to the DateTime JS plugin Web page for possible options. 41 | * @see http://xdsoft.net/jqplugins/datetimepicker/ 42 | */ 43 | public $clientOptions = []; 44 | 45 | 46 | 47 | 48 | /** 49 | * run function. 50 | * 51 | * @access public 52 | * @return void 53 | */ 54 | public function run() 55 | { 56 | 57 | $randomId = uniqid(); 58 | 59 | if ($this->hasModel()) { 60 | echo Html::activeHiddenInput($this->model, $this->attribute, $this->options); 61 | } else { 62 | echo Html::hiddenInput($this->name, $this->value, $this->options); 63 | } 64 | echo Html::tag('div', Html::a('Select Image',['/filemanager/files/filemodal'],['class' => 'btn btn-success','data-toggle' => 'modal','data-target' => '#filePickModal_'.$randomId])); 65 | 66 | echo $this->generateModal($randomId); 67 | 68 | $this->registerClientScript(); 69 | } 70 | 71 | 72 | /** 73 | * Registers CSS and Scripts 74 | */ 75 | protected function registerClientScript() 76 | { 77 | 78 | $view = $this->getView(); 79 | 80 | FileUploadAssets::register( $view ); 81 | 82 | /*$view = $this->getView(); 83 | 84 | DateTimePickerAssets::register($view); 85 | 86 | $id = $this->options['id']; 87 | 88 | $options = Json::encode($this->clientOptions); 89 | 90 | $view->registerJs("jQuery('#$id').datetimepicker($options);");*/ 91 | } 92 | 93 | 94 | 95 | /** 96 | * [generateModal description] 97 | * @param [type] $id [description] 98 | */ 99 | protected function generateModal($id) 100 | { 101 | $html = ''; 108 | 109 | return $html; 110 | } 111 | 112 | } 113 | --------------------------------------------------------------------------------