├── .sensiolabs.yml ├── Resources ├── config │ ├── routing.yml │ └── services.yml ├── doc │ ├── book │ │ ├── filemanager-promo.png │ │ ├── 4-security.md │ │ ├── 0-installation.md │ │ ├── 3-access-file-manager.md │ │ └── 2-service-configuration.md │ ├── images │ │ ├── filemanager-promo.png │ │ ├── filemanager-promo-no-tree.png │ │ └── filemanager-promo-thumbnail.png │ └── tutorials │ │ ├── integrate-fos-ckeditor.md │ │ ├── input-button.md │ │ └── integrate-tinymce.md ├── public │ ├── libs │ │ ├── blueimp-file-upload │ │ │ ├── img │ │ │ │ ├── loading.gif │ │ │ │ └── progressbar.gif │ │ │ ├── css │ │ │ │ ├── jquery.fileupload-ui-noscript.css │ │ │ │ ├── jquery.fileupload-noscript.css │ │ │ │ ├── jquery.fileupload.css │ │ │ │ └── jquery.fileupload-ui.css │ │ │ └── js │ │ │ │ ├── cors │ │ │ │ ├── jquery.xdr-transport.js │ │ │ │ └── jquery.postmessage-transport.js │ │ │ │ ├── jquery.fileupload-audio.js │ │ │ │ ├── jquery.fileupload-video.js │ │ │ │ ├── jquery.fileupload-validate.js │ │ │ │ ├── jquery.fileupload-jquery-ui.js │ │ │ │ └── jquery.fileupload-process.js │ │ ├── jstree │ │ │ └── dist │ │ │ │ └── themes │ │ │ │ ├── default │ │ │ │ ├── 32px.png │ │ │ │ ├── 40px.png │ │ │ │ └── throbber.gif │ │ │ │ └── default-dark │ │ │ │ ├── 32px.png │ │ │ │ ├── 40px.png │ │ │ │ └── throbber.gif │ │ ├── blueimp-load-image │ │ │ ├── css │ │ │ │ ├── vendor │ │ │ │ │ ├── Jcrop.gif │ │ │ │ │ └── jquery.Jcrop.css │ │ │ │ └── demo.css │ │ │ └── js │ │ │ │ ├── index.js │ │ │ │ ├── load-image-fetch.js │ │ │ │ ├── load-image.js │ │ │ │ ├── demo │ │ │ │ └── demo.js │ │ │ │ ├── load-image-orientation.js │ │ │ │ └── load-image-meta.js │ │ ├── jQuery-contextMenu │ │ │ └── dist │ │ │ │ ├── font │ │ │ │ ├── context-menu-icons.eot │ │ │ │ ├── context-menu-icons.ttf │ │ │ │ ├── context-menu-icons.woff │ │ │ │ └── context-menu-icons.woff2 │ │ │ │ ├── jquery.ui.position.min.js │ │ │ │ └── jquery.contextMenu.min.css │ │ ├── bootstrap │ │ │ └── dist │ │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ └── js │ │ │ │ └── npm.js │ │ ├── .gitignore │ │ ├── blueimp-tmpl │ │ │ ├── js │ │ │ │ ├── tmpl.min.js │ │ │ │ ├── runtime.js │ │ │ │ ├── tmpl.min.js.map │ │ │ │ ├── demo │ │ │ │ │ └── demo.js │ │ │ │ ├── tmpl.js │ │ │ │ └── compile.js │ │ │ └── css │ │ │ │ └── demo.css │ │ ├── blueimp-canvas-to-blob │ │ │ └── js │ │ │ │ ├── canvas-to-blob.min.js │ │ │ │ ├── canvas-to-blob.min.js.map │ │ │ │ └── canvas-to-blob.js │ │ ├── sticky-kit │ │ │ └── jquery.sticky-kit.min.js │ │ └── jquery-lazy │ │ │ └── jquery.lazy.min.js │ ├── css │ │ └── manager.css │ └── js │ │ └── betamax │ │ ├── jquery.getimagedata.min.js │ │ └── jquery.getimagedata.js ├── views │ ├── views │ │ ├── _manager_view.html.twig │ │ ├── preview.html.twig │ │ ├── _modals.html.twig │ │ ├── _thumbnail.html.twig │ │ └── _list.html.twig │ └── extension │ │ └── _order.html.twig └── translations │ ├── messages.tr.yml │ ├── messages.en.yml │ ├── messages.ru.yml │ ├── messages.pl.yml │ ├── messages.pt_BR.yml │ ├── messages.ro.yml │ ├── messages.it.yml │ ├── messages.es.yml │ ├── messages.nl.yml │ ├── messages.ca.yml │ ├── messages.fr.yml │ └── messages.de.yml ├── Service ├── CustomConfServiceInterface.php ├── FilemanagerService.php └── FileTypeService.php ├── ArtgrisFileManagerBundle.php ├── .php-cs-fixer.php ├── LICENSE.md ├── Twig ├── FileTypeExtension.php └── OrderExtension.php ├── DependencyInjection ├── ArtgrisFileManagerExtension.php └── Configuration.php ├── .github └── workflows │ ├── tests-windows.yaml │ └── tests-linux.yaml ├── Event └── FileManagerEvents.php ├── composer.json ├── Helpers ├── File.php └── FileManagerUploadHandler.php └── README.md /.sensiolabs.yml: -------------------------------------------------------------------------------- 1 | exclude_patterns: 2 | - Helpers/UploadHandler.php 3 | - Resources/public/lib 4 | -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | interactive: 2 | resource: "@ArtgrisFileManagerBundle/Controller" 3 | type: attribute 4 | -------------------------------------------------------------------------------- /Resources/doc/book/filemanager-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/doc/book/filemanager-promo.png -------------------------------------------------------------------------------- /Resources/doc/images/filemanager-promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/doc/images/filemanager-promo.png -------------------------------------------------------------------------------- /Resources/doc/images/filemanager-promo-no-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/doc/images/filemanager-promo-no-tree.png -------------------------------------------------------------------------------- /Resources/doc/images/filemanager-promo-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/doc/images/filemanager-promo-thumbnail.png -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/blueimp-file-upload/img/loading.gif -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default/32px.png -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default/40px.png -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/img/progressbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/blueimp-file-upload/img/progressbar.gif -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/css/vendor/Jcrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/blueimp-load-image/css/vendor/Jcrop.gif -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default/throbber.gif -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default-dark/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default-dark/32px.png -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default-dark/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default-dark/40px.png -------------------------------------------------------------------------------- /Resources/public/libs/jstree/dist/themes/default-dark/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jstree/dist/themes/default-dark/throbber.gif -------------------------------------------------------------------------------- /Resources/public/libs/jQuery-contextMenu/dist/font/context-menu-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jQuery-contextMenu/dist/font/context-menu-icons.eot -------------------------------------------------------------------------------- /Resources/public/libs/jQuery-contextMenu/dist/font/context-menu-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artgris/FileManagerBundle/HEAD/Resources/public/libs/jQuery-contextMenu/dist/font/context-menu-icons.ttf -------------------------------------------------------------------------------- /Service/CustomConfServiceInterface.php: -------------------------------------------------------------------------------- 1 | 2 | {{ ('table.'~type)|trans }} 3 | 4 | 5 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/js/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./load-image') 2 | 3 | require('./load-image-scale') 4 | require('./load-image-meta') 5 | require('./load-image-fetch') 6 | require('./load-image-exif') 7 | require('./load-image-exif-map') 8 | require('./load-image-orientation') 9 | -------------------------------------------------------------------------------- /Resources/views/views/preview.html.twig: -------------------------------------------------------------------------------- 1 | {% if lazy %} 2 | {% if twig_extension %} 3 | {% set filename = include(template_from_string("{{"~image_template~"}}")) %} 4 | {% endif %} 5 | 6 | {% else %} 7 | 8 | {% endif %} 9 | -------------------------------------------------------------------------------- /Resources/public/libs/.gitignore: -------------------------------------------------------------------------------- 1 | blueimp*/* 2 | !blueimp*/js 3 | !blueimp*/img 4 | !blueimp*/css 5 | bootstrap*/* 6 | !bootstrap*/dist 7 | components-font-awesome/* 8 | !components-font-awesome/css 9 | !components-font-awesome/fonts 10 | jquery/* 11 | !jquery/dist 12 | remarkable-bootstrap-notify/* 13 | !remarkable-bootstrap-notify/dist 14 | sticky-kit/* 15 | !sticky-kit/jquery.sticky-kit.min.js 16 | jstree/* 17 | !jstree/dist 18 | jQuery-contextMenu/* 19 | !jQuery-contextMenu/dist 20 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/css/jquery.fileupload-ui-noscript.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload UI Plugin NoScript CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2012, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button i, 14 | .fileupload-buttonbar .delete, 15 | .fileupload-buttonbar .toggle { 16 | display: none; 17 | } 18 | -------------------------------------------------------------------------------- /Resources/public/libs/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/css/jquery.fileupload-noscript.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin NoScript CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button input { 14 | position: static; 15 | opacity: 1; 16 | filter: none; 17 | font-size: inherit !important; 18 | direction: inherit; 19 | } 20 | .fileinput-button span { 21 | display: none; 22 | } 23 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/css/jquery.fileupload.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload Plugin CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2013, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileinput-button { 14 | position: relative; 15 | overflow: hidden; 16 | display: inline-block; 17 | } 18 | .fileinput-button input { 19 | position: absolute; 20 | top: 0; 21 | right: 0; 22 | margin: 0; 23 | opacity: 0; 24 | -ms-filter: 'alpha(opacity=0)'; 25 | font-size: 200px !important; 26 | direction: ltr; 27 | cursor: pointer; 28 | } 29 | 30 | /* Fixes for IE < 8 */ 31 | @media screen\9 { 32 | .fileinput-button input { 33 | filter: alpha(opacity=0); 34 | font-size: 100%; 35 | height: 100%; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 5 | ->ignoreDotFiles(true) 6 | ->ignoreVCS(true) 7 | ->exclude(array('build', 'vendor')) 8 | ->files() 9 | ->name('*.php') 10 | ; 11 | return (new PhpCsFixer\Config()) 12 | ->setUsingCache(true) 13 | ->setRiskyAllowed(true) 14 | ->setFinder($finder) 15 | ->setRules(array( 16 | '@Symfony' => true, 17 | '@Symfony:risky' => true, 18 | 'array_syntax' => array('syntax' => 'short'), 19 | 'binary_operator_spaces' => [ 20 | 'operators' => [ 21 | '=>' => 'align', 22 | ] 23 | ], 24 | 'combine_consecutive_unsets' => true, 25 | 'no_useless_else' => true, 26 | 'no_useless_return' => true, 27 | 'ordered_imports' => true, 28 | 'php_unit_strict' => true, 29 | 'phpdoc_summary' => false, 30 | 'strict_comparison' => true, 31 | )) 32 | ; -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | _defaults: 4 | autowire: true # Automatically injects dependencies in your services. 5 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 6 | 7 | Artgris\Bundle\FileManagerBundle\Controller\: 8 | resource: '../../Controller/*' 9 | 10 | Artgris\Bundle\FileManagerBundle\Twig\FileTypeExtension: 11 | tags: 12 | - { name: twig.extension } 13 | arguments: ['@Artgris\Bundle\FileManagerBundle\Service\FileTypeService'] 14 | 15 | Artgris\Bundle\FileManagerBundle\Service\FileTypeService: 16 | arguments: ['@router'] 17 | 18 | Artgris\Bundle\FileManagerBundle\Twig\OrderExtension: 19 | tags: 20 | - { name: twig.extension } 21 | arguments: ['@router'] 22 | 23 | Artgris\Bundle\FileManagerBundle\Service\FilemanagerService: 24 | arguments: ['%artgris_file_manager%', '@service_container'] 25 | 26 | 27 | Twig\Extension\StringLoaderExtension: ~ -------------------------------------------------------------------------------- /Service/FilemanagerService.php: -------------------------------------------------------------------------------- 1 | artgrisFileManagerConfig['conf']; 15 | if (isset($managerConf[$conf]['dir'])) { 16 | return $managerConf[$conf]; 17 | } 18 | 19 | if (isset($managerConf[$conf]['service'])) { 20 | $extra = $queryParameters['extra'] ?? []; 21 | $confService = $this->container->get($managerConf[$conf]['service'])->getConf($extra); 22 | 23 | return array_merge($managerConf[$conf], $confService); 24 | } 25 | 26 | throw new \RuntimeException('Please define a "dir" or a "service" parameter in your config.yml'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/tmpl.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"use strict";var n=function(e,t){var r=/[^\w\-\.:]/.test(e)?new Function(n.arg+",tmpl","var _e=tmpl.encode"+n.helper+",_s='"+e.replace(n.regexp,n.func)+"';return _s;"):n.cache[e]=n.cache[e]||n(n.load(e));return t?r(t,n):function(e){return r(e,n)}};n.cache={},n.load=function(e){return document.getElementById(e).innerHTML},n.regexp=/([\s'\\])(?!(?:[^{]|\{(?!%))*%\})|(?:\{%(=|#)([\s\S]+?)%\})|(\{%)|(%\})/g,n.func=function(e,n,t,r,c,u){return n?{"\n":"\\n","\r":"\\r","\t":"\\t"," ":" "}[n]||"\\"+n:t?"="===t?"'+_e("+r+")+'":"'+("+r+"==null?'':"+r+")+'":c?"';":u?"_s+='":void 0},n.encReg=/[<>&"'\x00]/g,n.encMap={"<":"<",">":">","&":"&",'"':""","'":"'"},n.encode=function(e){return(null==e?"":""+e).replace(n.encReg,function(e){return n.encMap[e]||""})},n.arg="o",n.helper=",print=function(s,e){_s+=e?(s==null?'':s):_e(s);},include=function(s,d){_s+=tmpl(s,d);}","function"==typeof define&&define.amd?define(function(){return n}):"object"==typeof module&&module.exports?module.exports=n:e.tmpl=n}(this); 2 | //# sourceMappingURL=tmpl.min.js.map -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Twig/FileTypeExtension.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class FileTypeExtension extends AbstractExtension { 13 | public function __construct(private FileTypeService $fileTypeService) { 14 | } 15 | 16 | public function accept($type): bool|string { 17 | return $this->fileTypeService->accept($type); 18 | } 19 | 20 | public function fileIcon(string $filePath, ?string $extension = null, ?int $size = 75): array { 21 | return $this->fileTypeService->fileIcon($filePath, $extension, $size); 22 | } 23 | 24 | public function getFunctions(): array { 25 | return [ 26 | 'accept' => new TwigFunction('accept', [$this, 'accept'], ['needs_environment' => false, 'is_safe' => ['html']]), 27 | 'fileIcon' => new TwigFunction('fileIcon', [$this, 'fileIcon'], ['needs_environment' => false, 'is_safe' => ['html']]), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Resources/doc/book/4-security.md: -------------------------------------------------------------------------------- 1 | Chapter 4 - Security 2 | ====================================== 3 | 4 | To prevent attackers from uploading and executing PHP scripts, you should add a **.htaccess** to enforce security restrictions. 5 | 6 | Example: 7 | 8 | // .htaccess 9 | 10 | ForceType application/octet-stream 11 | Header set Content-Disposition attachment 12 | 13 | ForceType none 14 | Header unset Content-Disposition 15 | 16 | Header set X-Content-Type-Options nosniff 17 | 18 | *Source:* https://github.com/blueimp/jQuery-File-Upload/wiki/Security 19 | 20 | Note: 21 | Since Apache version 2.3.9, .htaccess support is disabled by default and must be explicitly enabled with the AllowOverride directive. 22 | Without the configuration in the .htaccess file, allowing uploads of all file types makes your site vulnerable to remote code execution attacks. 23 | 24 | 25 | ### Hide and/or block access to specific files or folders 26 | 27 | Example: Block and hide all files/folders with regex: "/privates|.privates/": https://github.com/artgris/FileManagerBundleDemo/blob/symfony-5/src/EventSubscriber/FileManagerConfiguration.php -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-canvas-to-blob/js/canvas-to-blob.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,b,c,d,B,f;if(e=t.match(a),!e)throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),b=l?atob(u):decodeURIComponent(u),c=new ArrayBuffer(b.length),d=new Uint8Array(c),B=0;B 12 | */ 13 | class ArtgrisFileManagerExtension extends Extension 14 | { 15 | public function getConfiguration(array $config, ContainerBuilder $container): Configuration 16 | { 17 | return new Configuration($container->getParameter('kernel.project_dir')); 18 | } 19 | 20 | /** 21 | * {@inheritdoc} 22 | */ 23 | public function load(array $configs, ContainerBuilder $container): void 24 | { 25 | $configuration = $this->getConfiguration($configs, $container); 26 | $config = $this->processConfiguration($configuration, $configs); 27 | 28 | $container->setParameter('artgris_file_manager', $config); 29 | 30 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 31 | $loader->load('services.yml'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/runtime.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Templates Runtime 3 | * https://github.com/blueimp/JavaScript-Templates 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define */ 13 | 14 | ;(function ($) { 15 | 'use strict' 16 | var tmpl = function (id, data) { 17 | var f = tmpl.cache[id] 18 | return data ? f(data, tmpl) : function (data) { 19 | return f(data, tmpl) 20 | } 21 | } 22 | tmpl.cache = {} 23 | tmpl.encReg = /[<>&"'\x00]/g // eslint-disable-line no-control-regex 24 | tmpl.encMap = { 25 | '<': '<', 26 | '>': '>', 27 | '&': '&', 28 | '"': '"', 29 | "'": ''' 30 | } 31 | tmpl.encode = function (s) { 32 | return (s == null ? '' : '' + s).replace( 33 | tmpl.encReg, 34 | function (c) { 35 | return tmpl.encMap[c] || '' 36 | } 37 | ) 38 | } 39 | if (typeof define === 'function' && define.amd) { 40 | define(function () { 41 | return tmpl 42 | }) 43 | } else if (typeof module === 'object' && module.exports) { 44 | module.exports = tmpl 45 | } else { 46 | $.tmpl = tmpl 47 | } 48 | }(this)) 49 | -------------------------------------------------------------------------------- /.github/workflows/tests-windows.yaml: -------------------------------------------------------------------------------- 1 | # OS: Windows; Symfony: latest stable; PHP: latest stable 2 | name: "Tests - Windows" 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - 'master' 9 | 10 | env: 11 | fail-fast: true 12 | 13 | jobs: 14 | tests: 15 | runs-on: 'windows-latest' 16 | continue-on-error: false 17 | steps: 18 | - name: 'Checkout code' 19 | uses: actions/checkout@v2.3.3 20 | 21 | - name: 'Install PHP with extensions' 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | coverage: none 25 | php-version: '8.1' 26 | tools: composer:v2 27 | extensions: mbstring, intl 28 | ini-values: date.timezone=UTC 29 | 30 | - name: 'Install project dependencies' 31 | env: 32 | SYMFONY_REQUIRE: 6.2 33 | run: | 34 | composer update --no-interaction --prefer-dist --optimize-autoloader --prefer-stable 35 | vendor/bin/simple-phpunit install 36 | - name: 'Run tests' 37 | env: 38 | SYMFONY_DEPRECATIONS_HELPER: 'max[indirect]=10&max[total]=27' 39 | run: vendor/bin/simple-phpunit -v -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/tmpl.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["tmpl.js"],"names":["$","tmpl","str","data","f","test","Function","arg","helper","replace","regexp","func","cache","load","id","document","getElementById","innerHTML","s","p1","p2","p3","p4","p5","\n","\r","\t"," ","encReg","encMap","<",">","&","\"","'","encode","c","define","amd","module","exports","this"],"mappings":"CAgBE,SAAUA,GACV,YACA,IAAIC,GAAO,SAAUC,EAAKC,GACxB,GAAIC,GAAK,aAAaC,KAAKH,GAEvB,GAAII,UACJL,EAAKM,IAAM,QACX,qBAAuBN,EAAKO,OAAS,QACnCN,EAAIO,QAAQR,EAAKS,OAAQT,EAAKU,MAAQ,gBAJxCV,EAAKW,MAAMV,GAAOD,EAAKW,MAAMV,IAAQD,EAAKA,EAAKY,KAAKX,GAMxD,OAAOC,GAAOC,EAAED,EAAMF,GAAQ,SAAUE,GACtC,MAAOC,GAAED,EAAMF,IAGnBA,GAAKW,SACLX,EAAKY,KAAO,SAAUC,GACpB,MAAOC,UAASC,eAAeF,GAAIG,WAErChB,EAAKS,OAAS,2EACdT,EAAKU,KAAO,SAAUO,EAAGC,EAAIC,EAAIC,EAAIC,EAAIC,GACvC,MAAIJ,IAEAK,KAAM,MACNC,KAAM,MACNC,KAAM,MACNC,IAAK,KACLR,IAAO,KAAOA,EAEdC,EACS,MAAPA,EACK,QAAUC,EAAK,MAEjB,MAAQA,EAAK,aAAeA,EAAK,MAEtCC,EACK,KAELC,EACK,QADT,QAIFtB,EAAK2B,OAAS,eACd3B,EAAK4B,QACHC,IAAK,OACLC,IAAK,OACLC,IAAK,QACLC,IAAK,SACLC,IAAK,SAEPjC,EAAKkC,OAAS,SAAUjB,GACtB,OAAa,MAALA,EAAY,GAAK,GAAKA,GAAGT,QAC/BR,EAAK2B,OACL,SAAUQ,GACR,MAAOnC,GAAK4B,OAAOO,IAAM,MAI/BnC,EAAKM,IAAM,IACXN,EAAKO,OAAS,0FAEQ,kBAAX6B,SAAyBA,OAAOC,IACzCD,OAAO,WACL,MAAOpC,KAEkB,gBAAXsC,SAAuBA,OAAOC,QAC9CD,OAAOC,QAAUvC,EAEjBD,EAAEC,KAAOA,GAEXwC","file":"tmpl.min.js"} -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/js/load-image-fetch.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Load Image Fetch 3 | * https://github.com/blueimp/JavaScript-Load-Image 4 | * 5 | * Copyright 2017, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, fetch, Request */ 13 | 14 | ;(function (factory) { 15 | 'use strict' 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['./load-image', './load-image-meta'], factory) 19 | } else if (typeof module === 'object' && module.exports) { 20 | factory(require('./load-image'), require('./load-image-meta')) 21 | } else { 22 | // Browser globals: 23 | factory(window.loadImage) 24 | } 25 | }(function (loadImage) { 26 | 'use strict' 27 | 28 | if ('fetch' in window && 'Request' in window) { 29 | loadImage.fetchBlob = function (url, callback, options) { 30 | if (loadImage.hasMetaOption(options)) { 31 | return fetch(new Request(url, options)).then(function (response) { 32 | return response.blob() 33 | }).then(callback).catch(function (err) { 34 | console.log(err) 35 | callback() 36 | }) 37 | } else { 38 | callback() 39 | } 40 | } 41 | } 42 | })) 43 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/css/jquery.fileupload-ui.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* 3 | * jQuery File Upload UI Plugin CSS 4 | * https://github.com/blueimp/jQuery-File-Upload 5 | * 6 | * Copyright 2010, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | .fileupload-buttonbar .btn, 14 | .fileupload-buttonbar .toggle { 15 | margin-bottom: 5px; 16 | } 17 | .progress-animated .progress-bar, 18 | .progress-animated .bar { 19 | background: url("../img/progressbar.gif") !important; 20 | filter: none; 21 | } 22 | .fileupload-process { 23 | float: right; 24 | display: none; 25 | } 26 | .fileupload-processing .fileupload-process, 27 | .files .processing .preview { 28 | display: block; 29 | width: 32px; 30 | height: 32px; 31 | background: url("../img/loading.gif") center no-repeat; 32 | background-size: contain; 33 | } 34 | .files audio, 35 | .files video { 36 | max-width: 300px; 37 | } 38 | 39 | @media (max-width: 767px) { 40 | .fileupload-buttonbar .toggle, 41 | .files .toggle, 42 | .files .btn span { 43 | display: none; 44 | } 45 | .files .name { 46 | width: 80px; 47 | word-wrap: break-word; 48 | } 49 | .files audio, 50 | .files video { 51 | max-width: 80px; 52 | } 53 | .files img, 54 | .files canvas { 55 | max-width: 100%; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Resources/doc/tutorials/integrate-fos-ckeditor.md: -------------------------------------------------------------------------------- 1 | How to integrate FileManagerBundle into FOSCKEditorBundle 2 | ========================================================== 3 | 4 | [FOSCKEditorBundle Installation](https://symfony.com/doc/master/bundles/FOSCKEditorBundle/installation.html) 5 | 6 | ### Step 1 - Create your artgris_file_manager conf: 7 | 8 | ```yml 9 | artgris_file_manager: 10 | conf: 11 | files: 12 | dir: "%kernel.project_dir%/public/uploads" 13 | type: 'file' 14 | images: 15 | dir: "%kernel.project_dir%/public/uploads" 16 | type: 'image' 17 | ``` 18 | 19 | ### Step 2 - Add fos_ck_editor conf: 20 | ```yaml 21 | fos_ck_editor: 22 | default_config: basic_config 23 | configs: 24 | basic_config: 25 | toolbar: full 26 | filebrowserBrowseRoute: file_manager 27 | filebrowserBrowseRouteParameters: 28 | conf: files 29 | module: ckeditor 30 | filebrowserImageBrowseRoute: file_manager 31 | filebrowserImageBrowseRouteParameters: 32 | conf: images 33 | module: ckeditor 34 | ``` 35 | 36 | ### Step 3 - Add a new field 37 | 38 | ```php 39 | use FOS\CKEditorBundle\Form\Type\CKEditorType; 40 | 41 | $builder->add('ckeditor', CKEditorType::class, array( 42 | 'config_name' => 'basic_config', 43 | )); 44 | ``` -------------------------------------------------------------------------------- /.github/workflows/tests-linux.yaml: -------------------------------------------------------------------------------- 1 | # OS: Linux; Symfony: latest stable; PHP: all the commonly used versions supported by this bundle 2 | name: "Tests - Linux" 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - 'master' 9 | 10 | env: 11 | fail-fast: true 12 | 13 | jobs: 14 | tests: 15 | name: "PHP ${{ matrix.php-version }}" 16 | runs-on: 'ubuntu-latest' 17 | continue-on-error: false 18 | strategy: 19 | matrix: 20 | php-version: ['8.1', '8.2'] 21 | steps: 22 | - name: 'Checkout code' 23 | uses: actions/checkout@v2.3.3 24 | 25 | - name: 'Install PHP with extensions' 26 | uses: shivammathur/setup-php@v2 27 | with: 28 | coverage: none 29 | php-version: ${{ matrix.php-version }} 30 | tools: composer:v2 31 | extensions: mbstring, intl 32 | ini-values: date.timezone=UTC 33 | 34 | - name: 'Install project dependencies' 35 | run: | 36 | composer update --no-interaction --prefer-dist --optimize-autoloader --prefer-stable 37 | vendor/bin/simple-phpunit install 38 | - name: 'Run tests' 39 | env: 40 | SYMFONY_DEPRECATIONS_HELPER: 'max[indirect]=10&max[total]=27' 41 | run: vendor/bin/simple-phpunit -v -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/css/demo.css: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Load Image Demo CSS 3 | * https://github.com/blueimp/JavaScript-Load-Image 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | body { 13 | max-width: 750px; 14 | margin: 0 auto; 15 | padding: 1em; 16 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, sans-serif; 17 | font-size: 1em; 18 | line-height: 1.4em; 19 | background: #222; 20 | color: #fff; 21 | -webkit-text-size-adjust: 100%; 22 | -ms-text-size-adjust: 100%; 23 | } 24 | a { 25 | color: orange; 26 | text-decoration: none; 27 | } 28 | img { 29 | border: 0; 30 | vertical-align: middle; 31 | } 32 | h1 { 33 | line-height: 1em; 34 | } 35 | table { 36 | width: 100%; 37 | word-wrap: break-word; 38 | table-layout: fixed; 39 | border-collapse: collapse; 40 | } 41 | tr { 42 | background: #fff; 43 | color: #222; 44 | } 45 | tr:nth-child(odd) { 46 | background: #eee; 47 | color: #222; 48 | } 49 | td { 50 | padding: 10px; 51 | } 52 | .result, 53 | .thumbnail { 54 | padding: 20px; 55 | background: #fff; 56 | color: #222; 57 | text-align: center; 58 | } 59 | .jcrop-holder { 60 | margin: 0 auto; 61 | } 62 | 63 | @media (min-width: 481px) { 64 | .navigation { 65 | list-style: none; 66 | padding: 0; 67 | } 68 | .navigation li { 69 | display: inline-block; 70 | } 71 | .navigation li:not(:first-child):before { 72 | content: '| '; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Resources/doc/book/0-installation.md: -------------------------------------------------------------------------------- 1 | Chapter 0. Installation and your first File Manager 2 | =================================================== 3 | 4 | FileManager Project is a simple Multilingual File Manager Bundle for symfony 5 | 6 | Installation 7 | ------------ 8 | 9 | ### Step 1: Download the Bundle 10 | 11 | ```bash 12 | $ composer require artgris/filemanager-bundle 13 | ``` 14 | 15 | ### Step 2: Load the Routes 16 | 17 | 18 | ```yaml 19 | # app/config/routing.yml 20 | artgris_bundle_file_manager: 21 | resource: "@ArtgrisFileManagerBundle/Controller" 22 | type: attribute 23 | prefix: /manager 24 | ``` 25 | 26 | ### Step 3: Enable the translator service 27 | 28 | ```yml 29 | # app/config/config.yml 30 | framework: 31 | translator: { fallbacks: [ "en" ] } 32 | ``` 33 | 34 | Creating Your First File Manager 35 | --------------------------------- 36 | 37 | Create a folder **uploads** in **public**. 38 | 39 | #### Add following minimal configuration : 40 | 41 | ```yaml 42 | # app/config/config.yml 43 | artgris_file_manager: 44 | conf: 45 | default: 46 | dir: "%kernel.project_dir%/public/uploads" 47 | ``` 48 | 49 | Browse the `/manager/?conf=default` URL and you'll get access to your file manager 50 | 51 | 52 | Symfony Filemanager created with FileManagerBundle 53 | 54 | 55 | ------------------------------------------------------------------------------- 56 | 57 | [Chapter 1. Basic Configuration](1-basic-configuration.md) → 58 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/css/demo.css: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Templates Demo CSS 3 | * https://github.com/blueimp/JavaScript-Templates 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | body { 13 | max-width: 750px; 14 | margin: 0 auto; 15 | padding: 1em; 16 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, sans-serif; 17 | font-size: 1em; 18 | line-height: 1.4em; 19 | background: #222; 20 | color: #fff; 21 | -webkit-text-size-adjust: 100%; 22 | -ms-text-size-adjust: 100%; 23 | } 24 | a { 25 | color: orange; 26 | text-decoration: none; 27 | } 28 | img { 29 | border: 0; 30 | vertical-align: middle; 31 | } 32 | h1 { 33 | line-height: 1em; 34 | } 35 | textarea, 36 | input { 37 | display: inline-block; 38 | width: 100%; 39 | -webkit-box-sizing: border-box; 40 | -moz-box-sizing: border-box; 41 | box-sizing: border-box; 42 | padding: 10px; 43 | margin: 0 0 10px; 44 | font-family: "Lucida Console", Monaco, monospace; 45 | } 46 | .result { 47 | padding: 20px 40px; 48 | background: #fff; 49 | color: #222; 50 | } 51 | .error { 52 | color: red; 53 | } 54 | 55 | @media (min-width: 481px) { 56 | .navigation { 57 | list-style: none; 58 | padding: 0; 59 | } 60 | .navigation li { 61 | display: inline-block; 62 | } 63 | .navigation li:not(:first-child):before { 64 | content: '| '; 65 | } 66 | } 67 | 68 | /* IE7 fixes */ 69 | *+html textarea, 70 | *+html input { 71 | width: 460px; 72 | } 73 | *+html .result { 74 | width: 400px; 75 | } 76 | -------------------------------------------------------------------------------- /Resources/translations/messages.tr.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: başarıyla yüklendi 4 | renamed: 5 | success: Dosya başarıyla yeniden adlandırıldı. 6 | danger: Dosya adı mevcut veya bu işlem için yetkiniz yok 7 | unauthorized: Dosya mevcut değil veya bu işlem için yetkiniz yok 8 | nochanged: Herhangi birşey değiştirilmedi 9 | deleted: 10 | success: Dosyalar başarıyla silindi 11 | danger: Dosyalar mevcut değil veya bu işlem için yetkiniz yok 12 | unauthorized: Dosyalar mevcut değil veya bu işlem için yetkiniz yok 13 | folder: 14 | add: 15 | danger: "Klasör oluşturulurken Hata Oluştu: %message%" 16 | success: Klasör başarıyla oluşturuldu 17 | deleted: 18 | success: Klasör başarıyla silindi 19 | unauthorized: Klasör mevcut değil veya bu işlem için yetkiniz yok 20 | button: 21 | cancel: İPTAL 22 | refresh: Yenile 23 | parent: Parent 24 | save: KAYDET 25 | add: 26 | files: Dosya Yükle... 27 | folder: Yeni Klasör... 28 | delete: 29 | current: Mevcut Klasörü Sil 30 | selected: Seçili Dosyaları Sil 31 | action: SİL 32 | rename: 33 | action: YENİDEN ADLANDIR 34 | tree: Dizinler 35 | title: 36 | add: 37 | folder: Yeni Klasör 38 | rename: 39 | file: Yeniden adlandır 40 | delete: Sil 41 | download: İndir 42 | preview: 43 | file: Aç 44 | input: 45 | default: İsimsiz Klasör 46 | table: 47 | name: Ad 48 | date: Tarih 49 | size: Boyut 50 | dimension: Ebatlar 51 | actions: İşlemler 52 | confirm: 53 | delete: Silmek için onay veriyor musunuz? 54 | size: 55 | mb: MB 56 | kb: KB 57 | select-all: Hepsini Seç 58 | upload: 59 | exception_move_uploaded_file: Yetkiniz yok 60 | search: 61 | placeholder: Arama -------------------------------------------------------------------------------- /Resources/translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: was uploaded successfully 4 | renamed: 5 | success: File has been renamed successfully 6 | danger: File already exists or you are not authorized to rename this file 7 | unauthorized: The files no longer exist or you are not authorized to access this page 8 | nochanged: No changed detected 9 | deleted: 10 | success: The files have been deleted successfully 11 | danger: The files no longer exist or you are not authorized to access this page 12 | unauthorized: The files no longer exist or you are not authorized to access this page 13 | folder: 14 | add: 15 | danger: "An error occurred while creating the directory: %message%" 16 | success: Folder has been created successfully 17 | deleted: 18 | success: Folder has been deleted successfully 19 | unauthorized: Folder no longer exist or you are not authorized to access this page 20 | button: 21 | cancel: CANCEL 22 | refresh: Refresh 23 | parent: Parent 24 | save: SAVE 25 | add: 26 | files: Add files... 27 | folder: New folder... 28 | delete: 29 | current: Delete current folder 30 | selected: Delete selected files 31 | action: DELETE 32 | rename: 33 | action: RENAME 34 | tree: Tree 35 | title: 36 | add: 37 | folder: New folder 38 | rename: 39 | file: Rename 40 | delete: Delete 41 | download: Download 42 | preview: 43 | file: Open 44 | input: 45 | default: Untitled folder 46 | table: 47 | name: Name 48 | date: Date 49 | size: Size 50 | dimension: Dimension 51 | actions: Actions 52 | confirm: 53 | delete: Are you sure that you want to delete? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Select all 58 | upload: 59 | exception_move_uploaded_file: Permission denied 60 | search: 61 | placeholder: Search -------------------------------------------------------------------------------- /Event/FileManagerEvents.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | final class FileManagerEvents { 9 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 10 | public const PRE_UPDATE = 'file_manager.pre_update'; 11 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 12 | public const POST_UPDATE = 'file_manager.post_update'; 13 | 14 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 15 | public const RENAME_FILE = 'file_manager.post_rename_file'; 16 | 17 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 18 | public const PRE_DELETE_FILE = 'file_manager.pre_delete_file'; 19 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 20 | public const POST_DELETE_FILE = 'file_manager.post_delete_file'; 21 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 22 | public const PRE_DELETE_FOLDER = ' file_manager.pre_delete_folder'; 23 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 24 | public const POST_DELETE_FOLDER = 'file_manager.post_delete_folder'; 25 | 26 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 27 | public const POST_DIRECTORY_FILTER_CONFIGURATION = 'file_manager.post_directory_filter_configuration'; 28 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 29 | public const POST_FILE_FILTER_CONFIGURATION = 'file_manager.post_file_filter_configuration'; 30 | 31 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 32 | public const POST_CHECK_SECURITY = 'file_manager.post_check_security'; 33 | /** @Event("Symfony\Component\EventDispatcher\GenericEvent") */ 34 | public const FILE_ACCESS = 'file_manager.file_access'; 35 | } 36 | -------------------------------------------------------------------------------- /Resources/translations/messages.ru.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: успешно загружен 4 | renamed: 5 | success: Файл успешно переименован 6 | danger: Файл уже существует или у вас недостаточно прав чтобы его переименовать 7 | unauthorized: Файлы больше не существуют или у вас недостаточно прав для доступа к этой странице 8 | nochanged: Изменений не найдено 9 | deleted: 10 | success: Файлы успешно удалены 11 | danger: Файлы больше не существуют или у вас недостаточно прав для доступа к этой странице 12 | unauthorized: Файлы больше не существуют или у вас недостаточно прав для доступа к этой странице 13 | folder: 14 | add: 15 | danger: "Ошибка при создании директории: %message%" 16 | success: Папка успешно создана 17 | deleted: 18 | success: Папка успешно удалена 19 | unauthorized: Папка больше не существует или у вас недостаточно прав для доступа к этой странице 20 | button: 21 | cancel: ОТМЕНА 22 | refresh: Обновить 23 | parent: К родительской директории 24 | save: СОХРАНИТЬ 25 | add: 26 | files: Добавить файлы... 27 | folder: Новая папка... 28 | delete: 29 | current: Удалить текущую папку 30 | selected: Удалить выбранные файлы 31 | action: УДАЛИТЬ 32 | rename: 33 | action: ПЕРЕИМЕНОВАТЬ 34 | tree: Дерево 35 | title: 36 | add: 37 | folder: Новая папка 38 | rename: 39 | file: Переименовать 40 | delete: Удалить 41 | download: Скачать 42 | preview: 43 | file: открыть 44 | input: 45 | default: Новая папка 46 | table: 47 | name: Название 48 | date: Дата 49 | size: Размер 50 | dimension: Параметры 51 | actions: Действия 52 | confirm: 53 | delete: Вы уверены что хотите удалить? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Выбрать все 58 | upload: 59 | exception_move_uploaded_file: Доступ запрещен 60 | search: 61 | placeholder: Поиск -------------------------------------------------------------------------------- /Resources/translations/messages.pl.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: został pomyślnie wgrany 4 | renamed: 5 | success: Nazwa pliku została pomyślnie zmieniona 6 | danger: Plik już istnieje lub nie jesteś uprawniony do zmiany nazwy tego pliku 7 | unauthorized: Pliki już nie istnieją lub nie jesteś uprawniony do dostępu do tej strony 8 | nochanged: Nie wykryto zmian 9 | deleted: 10 | success: Pliki zostały pomyślnie usunięte 11 | danger: Pliki już nie istnieją lub nie masz uprawnień dostępu do tej strony. 12 | unauthorized: Pliki już nie istnieją lub nie masz uprawnień dostępu do tej strony. 13 | folder: 14 | add: 15 | danger: "Wystąpił błąd podczas tworzenia folderu: %message%" 16 | success: Folder został utworzony 17 | deleted: 18 | success: Folder został pomyślnie usunięty 19 | unauthorized: Folder już nie istnieje lub nie masz uprawnień dostępu do tej strony. 20 | button: 21 | cancel: Anuluj 22 | refresh: Odśwież 23 | parent: Rodzic 24 | save: ZAPISZ 25 | add: 26 | files: Dodaj pliki... 27 | folder: Nowy folder... 28 | delete: 29 | current: Usuń bieżący folder 30 | selected: Usuń zaznaczone pliki 31 | action: USUŃ 32 | rename: 33 | action: ZMIEŃ NAZWĘ 34 | tree: Drzewo 35 | title: 36 | add: 37 | folder: Nowy folder 38 | rename: 39 | file: Zmień nazwę 40 | delete: Usuń 41 | download: Pobierz 42 | preview: 43 | file: Otwórz 44 | input: 45 | default: Folder bez nazwy 46 | table: 47 | name: Nazwa 48 | date: Data 49 | size: Rozmiar 50 | dimension: Wymiary 51 | actions: Akcje 52 | confirm: 53 | delete: Czy na pewno chcesz usunąć? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Zaznacz wszystkie 58 | upload: 59 | exception_move_uploaded_file: Brak uprawnień 60 | search: 61 | placeholder: Szukaj -------------------------------------------------------------------------------- /Resources/translations/messages.pt_BR.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: enviado com sucesso 4 | renamed: 5 | success: O arquivo foi renomeado com sucesso 6 | danger: Arquivo já existe ou você não está autorizado a renomear este arquivo 7 | unauthorized: Os arquivos não existem mais ou você não tem autorização para acessar esta página 8 | nochanged: Nenhuma alteração detectada 9 | deleted: 10 | success: Os arquivos foram apagados com sucesso 11 | danger: Os arquivos não existem mais ou você não tem autorização para acessar esta página 12 | unauthorized: Os arquivos não existem mais ou você não tem autorização para acessar esta página 13 | folder: 14 | add: 15 | danger: "Ocorreu um erro ao criar o diretório: %message%" 16 | success: Pasta criada com sucesso 17 | deleted: 18 | success: A pasta excluída com sucesso 19 | unauthorized: A pasta não existe mais ou você não tem autorização para acessar esta página 20 | button: 21 | cancel: CANCELAR 22 | refresh: Atualizar 23 | parent: Subir 24 | save: SALVAR 25 | add: 26 | files: Adicionar arquivos... 27 | folder: Nova pasta... 28 | delete: 29 | current: Excluir pasta atual 30 | selected: Excluir arquivos selecionados 31 | action: EXCLUIR 32 | rename: 33 | action: RENOMEAR 34 | tree: Pastas 35 | title: 36 | add: 37 | folder: Nova pasta 38 | rename: 39 | file: Renomear 40 | delete: Excluir 41 | download: Download 42 | preview: 43 | file: Abrir 44 | input: 45 | default: Nova pasta 46 | table: 47 | name: Nome 48 | date: Data 49 | size: Tamanho 50 | dimension: Dimensão 51 | actions: Ações 52 | confirm: 53 | delete: Tem certeza de que deseja excluir? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Selecionar tudo 58 | upload: 59 | exception_move_uploaded_file: Permissão negada 60 | search: 61 | placeholder: Pesquisa -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/demo/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Templates Demo 3 | * https://github.com/blueimp/JavaScript-Templates 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global tmpl */ 13 | 14 | ;(function () { 15 | 'use strict' 16 | 17 | var templateInput = document.getElementById('template') 18 | var dataInput = document.getElementById('data') 19 | var resultNode = document.getElementById('result') 20 | var templateDemoNode = document.getElementById('tmpl-demo') 21 | var templateDataNode = document.getElementById('tmpl-data') 22 | 23 | function renderError (title, error) { 24 | resultNode.innerHTML = tmpl( 25 | 'tmpl-error', 26 | {title: title, error: error} 27 | ) 28 | } 29 | 30 | function render (event) { 31 | event.preventDefault() 32 | var data 33 | try { 34 | data = JSON.parse(dataInput.value) 35 | } catch (e) { 36 | renderError('JSON parsing failed', e) 37 | return 38 | } 39 | try { 40 | resultNode.innerHTML = tmpl( 41 | templateInput.value, 42 | data 43 | ) 44 | } catch (e) { 45 | renderError('Template rendering failed', e) 46 | } 47 | } 48 | 49 | function empty (node) { 50 | while (node.lastChild) { 51 | node.removeChild(node.lastChild) 52 | } 53 | } 54 | 55 | function init (event) { 56 | if (event) { 57 | event.preventDefault() 58 | } 59 | templateInput.value = templateDemoNode.innerHTML.trim() 60 | dataInput.value = templateDataNode.innerHTML.trim() 61 | empty(resultNode) 62 | } 63 | 64 | document.getElementById('render').addEventListener('click', render) 65 | document.getElementById('reset').addEventListener('click', init) 66 | 67 | init() 68 | }()) 69 | -------------------------------------------------------------------------------- /Resources/translations/messages.ro.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: a fost adaugata cu succes 4 | renamed: 5 | success: Fisierul a fost redenumit cu succes 6 | danger: Fisierul deja exista sau nu esti autorizat sa redenumesti acest fisier 7 | unauthorized: Fisierul nu mai exista sau nu esti autorizat sa accesezi aceasta pagina 8 | nochanged: Nu a fost detectata nici o schimbare 9 | deleted: 10 | success: Fisierul a fost sters cu succes 11 | danger: Fisierul nu mai exista sau nu esti autorizat sa accesezi aceasta pagina 12 | unauthorized: Fisierul nu mai exista sau nu esti autorizat sa accesezi aceasta pagina 13 | folder: 14 | add: 15 | danger: "A aparut o eroare in timpul crearii directorului: %message%" 16 | success: Folderul a fost creat cu succes 17 | deleted: 18 | success: Directorul a fost sters cu succes 19 | unauthorized: Directorul nu mai exista sau nu esti autorizat sa accesezi aceasta pagina 20 | button: 21 | cancel: ANULEAZA 22 | refresh: Reimprospateaza 23 | parent: Parinte 24 | save: SALVEAZA 25 | add: 26 | files: Adauga fisiere... 27 | folder: Director nou... 28 | delete: 29 | current: Sterge directorul curent 30 | selected: Sterge fisierele selectate 31 | action: STERGE 32 | rename: 33 | action: REDENUMESTE 34 | tree: Tree 35 | title: 36 | add: 37 | folder: Director nou 38 | rename: 39 | file: Redenumeste 40 | delete: Sterge 41 | download: Download 42 | preview: 43 | file: Deschide 44 | input: 45 | default: Director nedenumit 46 | table: 47 | name: Nume 48 | date: Data 49 | size: Marime 50 | dimension: Dimensiuni 51 | actions: Actiuni 52 | confirm: 53 | delete: Esti sigur ca vrei sa stergi? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Selecteaza tot 58 | upload: 59 | exception_move_uploaded_file: Permisiune anulata 60 | search: 61 | placeholder: Căutare -------------------------------------------------------------------------------- /Resources/translations/messages.it.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: è stato caricato correttamente 4 | renamed: 5 | success: Il file è stato rinominato correttamente 6 | danger: Il file esiste già o non sei autorizzato a rinominarlo 7 | unauthorized: I file non esistono più o non sei autorizzato ad accedere a questa pagina 8 | nochanged: Nessuna modifica rilevata 9 | deleted: 10 | success: I file sono stati eliminati correttamente 11 | danger: I file non esistono più o non sei autorizzato ad accedere a questa pagina 12 | unauthorized: I file non esistono più o non sei autorizzato ad accedere a questa pagina 13 | folder: 14 | add: 15 | danger: "Si è verificato un errore durante la creazione della cartella: %message%" 16 | success: La cartella è stata creata correttamente 17 | deleted: 18 | success: La cartella è stata eliminata correttamente 19 | unauthorized: La cartella non esiste più o non sei autorizzato ad accedere a questa pagina 20 | button: 21 | cancel: ANNULLA 22 | refresh: Aggiorna 23 | parent: Genitore 24 | save: SALVA 25 | add: 26 | files: Aggiungi file... 27 | folder: Nuova cartella... 28 | delete: 29 | current: Elimina cartella corrente 30 | selected: Elimina file selezionati 31 | action: ELIMINA 32 | rename: 33 | action: RINOMINA 34 | tree: Albero 35 | title: 36 | add: 37 | folder: Nuova cartella 38 | rename: 39 | file: Rinomina 40 | delete: Elimina 41 | download: Scarica 42 | preview: 43 | file: Apri 44 | input: 45 | default: Cartella senza titolo 46 | table: 47 | name: Nome 48 | date: Data 49 | size: Peso 50 | dimension: Dimensione 51 | actions: Azioni 52 | confirm: 53 | delete: Sei sicuro di voler eliminare? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Seleziona tutto 58 | upload: 59 | exception_move_uploaded_file: Permesso negato 60 | search: 61 | placeholder: Cerca 62 | -------------------------------------------------------------------------------- /Resources/translations/messages.es.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: Se cargó correctamente 4 | renamed: 5 | success: El archivo ha cambiado de nombre correctamente 6 | danger: El archivo ya existe o no está autorizado para cambiar el nombre de este archivo 7 | unauthorized: Los archivos ya no existen o no está autorizado para acceder a esta página 8 | nochanged: No se detectó ningún cambio 9 | deleted: 10 | success: Los archivos se han eliminado correctamente 11 | danger: Los archivos ya no existen o no está autorizado para acceder a esta página 12 | unauthorized: Los archivos ya no existen o no está autorizado para acceder a esta página 13 | folder: 14 | add: 15 | danger: "Se produjo un error al crear el directorio: %message%" 16 | success: La carpeta se ha creado correctamente 17 | deleted: 18 | success: La carpeta se ha eliminado correctamente 19 | unauthorized: La carpeta ya no existe o no está autorizado para acceder a esta página 20 | button: 21 | cancel: CANCELAR 22 | refresh: Actualizar 23 | parent: Padre 24 | save: GUARDAR 25 | add: 26 | files: Agregar archivos... 27 | folder: Nueva carpeta... 28 | delete: 29 | current: Eliminar la carpeta actual 30 | selected: Eliminar archivos seleccionados 31 | action: BORRAR 32 | rename: 33 | action: RENOMBRAR 34 | tree: Árbol 35 | title: 36 | add: 37 | folder: Nueva carpeta 38 | rename: 39 | file: Renombrar 40 | delete: Eliminar 41 | download: Descargar 42 | preview: 43 | file: Abrir 44 | input: 45 | default: Carpeta sin título 46 | table: 47 | name: Nombre 48 | date: Fecha 49 | size: Tamaño 50 | dimension: Dimensión 51 | actions: Acciones 52 | confirm: 53 | delete: ¿Está seguro de que desea eliminar? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Seleccionar todo 58 | upload: 59 | exception_move_uploaded_file: Permiso denegado 60 | search: 61 | placeholder: Buscar -------------------------------------------------------------------------------- /Resources/translations/messages.nl.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: is succesvol geuploaded 4 | renamed: 5 | success: Bestand is succesvol hernoemd naar een ander bestand 6 | danger: Bestand bestaat al of u bent niet bevoegd om dit bestand een andere naam te geven. 7 | unauthorized: De bestanden bestaan niet meer of u bent niet bevoegd om deze pagina te openen. 8 | nochanged: Geen wijziging gedetecteerd 9 | deleted: 10 | success: De bestanden zijn met succes verwijderd 11 | danger: De bestanden bestaan niet meer of u bent niet bevoegd om deze pagina te openen. 12 | unauthorized: De bestanden bestaan niet meer of u bent niet bevoegd om deze pagina te openen. 13 | folder: 14 | add: 15 | danger: "Er is een fout opgetreden tijdens het aanmaken van de directory: %message%" 16 | success: Map is met succes aangemaakt 17 | deleted: 18 | success: Map is met succes verwijderd. 19 | unauthorized: Map bestaat niet meer of u bent niet bevoegd om deze pagina te openen. 20 | button: 21 | cancel: ANULEREN 22 | refresh: Verversen 23 | parent: Parent 24 | save: OPSLAAN 25 | add: 26 | files: Voeg bestanden toe... 27 | folder: Nieuwe map... 28 | delete: 29 | current: Verwijder huidige map 30 | selected: Geselecteerde bestanden verwijderen 31 | action: VERWIJDER 32 | rename: 33 | action: HERNOEMEN 34 | tree: Boom 35 | title: 36 | add: 37 | folder: Nieuwe map 38 | rename: 39 | file: Hernoemen 40 | delete: Verwijderen 41 | download: Downloaden 42 | preview: 43 | file: Openen 44 | input: 45 | default: Naamloze map 46 | table: 47 | name: Naam 48 | date: Datum 49 | size: Grootte 50 | dimension: Dimensie 51 | actions: Acties 52 | confirm: 53 | delete: Weet u zeker dat u wilt verwijderen? 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: Selecter alle 58 | upload: 59 | exception_move_uploaded_file: Toestemming geweigerd 60 | search: 61 | placeholder: Zoeken 62 | -------------------------------------------------------------------------------- /Twig/OrderExtension.php: -------------------------------------------------------------------------------- 1 | 'up', self::DESC => 'down']; 16 | 17 | /** 18 | * OrderExtension constructor. 19 | */ 20 | public function __construct(private RouterInterface $router) 21 | { 22 | } 23 | 24 | public function order(Environment $environment, FileManager $fileManager, $type): string { 25 | $order = self::ASC === $fileManager->getQueryParameter('order'); 26 | $active = $fileManager->getQueryParameter('orderby') === $type ? 'actived' : null; 27 | $orderBy = []; 28 | $orderBy['orderby'] = $type; 29 | $orderBy['order'] = $active ? ($order ? self::DESC : self::ASC) : self::ASC; 30 | $parameters = array_merge($fileManager->getQueryParameters(), $orderBy); 31 | 32 | $icon = $active ? '-'.($order ? self::ICON[self::ASC] : self::ICON[self::DESC]) : ''; 33 | 34 | $href = $this->router->generate('file_manager', $parameters); 35 | 36 | return $environment->render('@ArtgrisFileManager/extension/_order.html.twig', [ 37 | 'active' => $active, 38 | 'href' => $href, 39 | 'icon' => $icon, 40 | 'type' => $type, 41 | 'islist' => 'list' === $fileManager->getView(), 42 | ]); 43 | } 44 | 45 | /** 46 | * @return array 47 | */ 48 | public function getFunctions(): array { 49 | return [ 50 | 'order' => new TwigFunction('order', [$this, 'order'], 51 | ['needs_environment' => true, 'is_safe' => ['html']]), 52 | ]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-canvas-to-blob/js/canvas-to-blob.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["canvas-to-blob.js"],"names":["window","CanvasPrototype","HTMLCanvasElement","prototype","hasBlobConstructor","Blob","Boolean","e","hasArrayBufferViewSupport","Uint8Array","size","BlobBuilder","WebKitBlobBuilder","MozBlobBuilder","MSBlobBuilder","dataURIPattern","dataURLtoBlob","atob","ArrayBuffer","dataURI","matches","mediaType","isBase64","dataString","byteString","arrayBuffer","intArray","i","bb","match","Error","slice","length","decodeURIComponent","charCodeAt","type","append","getBlob","toBlob","mozGetAsFile","callback","quality","toDataURL","this","define","amd","module","exports"],"mappings":"CAgBE,SAAUA,GACV,YAEA,IAAIC,GAAkBD,EAAOE,mBACLF,EAAOE,kBAAkBC,UAC7CC,EAAqBJ,EAAOK,MAAS,WACvC,IACE,MAAOC,SAAQ,GAAID,OACnB,MAAOE,GACP,OAAO,MAGPC,EAA4BJ,GAAsBJ,EAAOS,YAC1D,WACC,IACE,MAAgD,OAAzC,GAAIJ,OAAM,GAAII,YAAW,OAAOC,KACvC,MAAOH,GACP,OAAO,MAGTI,EAAcX,EAAOW,aAAeX,EAAOY,mBAC3BZ,EAAOa,gBAAkBb,EAAOc,cAChDC,EAAiB,0CACjBC,GAAiBZ,GAAsBO,IAAgBX,EAAOiB,MAChEjB,EAAOkB,aAAelB,EAAOS,YAC7B,SAAUU,GACR,GAAIC,GACFC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,CAGF,IADAR,EAAUD,EAAQU,MAAMd,IACnBK,EACH,KAAM,IAAIU,OAAM,mBAkBlB,KAfAT,EAAYD,EAAQ,GAChBA,EAAQ,GACR,cAAgBA,EAAQ,IAAM,qBAClCE,IAAaF,EAAQ,GACrBG,EAAaJ,EAAQY,MAAMX,EAAQ,GAAGY,QAGpCR,EAFEF,EAEWL,KAAKM,GAGLU,mBAAmBV,GAGlCE,EAAc,GAAIP,aAAYM,EAAWQ,QACzCN,EAAW,GAAIjB,YAAWgB,GACrBE,EAAI,EAAGA,EAAIH,EAAWQ,OAAQL,GAAK,EACtCD,EAASC,GAAKH,EAAWU,WAAWP,EAGtC,OAAIvB,GACK,GAAIC,OACRG,EAA4BkB,EAAWD,IACvCU,KAAMd,KAGXO,EAAK,GAAIjB,GACTiB,EAAGQ,OAAOX,GACHG,EAAGS,QAAQhB,IAElBrB,GAAOE,oBAAsBD,EAAgBqC,SAC3CrC,EAAgBsC,aAClBtC,EAAgBqC,OAAS,SAAUE,EAAUL,EAAMM,GAE/CD,EADEC,GAAWxC,EAAgByC,WAAa1B,EACjCA,EAAc2B,KAAKD,UAAUP,EAAMM,IAEnCE,KAAKJ,aAAa,OAAQJ,KAG9BlC,EAAgByC,WAAa1B,IACtCf,EAAgBqC,OAAS,SAAUE,EAAUL,EAAMM,GACjDD,EAASxB,EAAc2B,KAAKD,UAAUP,EAAMM,QAI5B,kBAAXG,SAAyBA,OAAOC,IACzCD,OAAO,WACL,MAAO5B,KAEkB,gBAAX8B,SAAuBA,OAAOC,QAC9CD,OAAOC,QAAU/B,EAEjBhB,EAAOgB,cAAgBA,GAEzBhB","file":"canvas-to-blob.min.js"} -------------------------------------------------------------------------------- /Resources/translations/messages.ca.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: "S'ha carregat correctament" 4 | renamed: 5 | success: "L'arxiu ha canviat de nom correctament" 6 | danger: "L'arxiu ja existeix o no està autoritzat per canviar el nom d'aquest arxiu" 7 | unauthorized: "Els arxius ja no existeixen o no està autoritzat per accedir a aquesta pàgina" 8 | nochanged: "No s'ha detectat cap canvi" 9 | deleted: 10 | success: "Els arxius s'han eliminat correctament" 11 | danger: "Els arxius ja no existeixen o no està autoritzat per accedir a aquesta pàgina" 12 | unauthorized: "Els arxius ja no existeixen o no està autoritzat per accedir a aquesta pàgina" 13 | folder: 14 | add: 15 | danger: "S'ha produït un error al crear el directori: %message%" 16 | success: "La carpeta s'ha creat correctament" 17 | deleted: 18 | success: "La carpeta s'ha eliminat correctament" 19 | unauthorized: "La carpeta ja no existeix o no està autoritzat per accedir a aquesta pàgina" 20 | button: 21 | cancel: "CANCEL·LAR" 22 | refresh: "Actualitzar" 23 | parent: "Pare" 24 | save: "GUARDAR" 25 | add: 26 | files: "Afegir arxius..." 27 | folder: "Nova carpeta..." 28 | delete: 29 | current: "Eliminar la carpeta actual" 30 | selected: "Eliminar arxius seleccionats" 31 | action: "ESBORRAR" 32 | rename: 33 | action: "REANOMENAR" 34 | tree: "Arbre" 35 | title: 36 | add: 37 | folder: "Nova carpeta" 38 | rename: 39 | file: "Reannomenar" 40 | delete: "Eliminar" 41 | download: "Descarregar" 42 | preview: 43 | file: "Obrir" 44 | input: 45 | default: "Carpeta sense títol" 46 | table: 47 | name: "Nom" 48 | date: "Data" 49 | size: "Mida" 50 | dimension: "Dimensió" 51 | actions: "Accions" 52 | confirm: 53 | delete: "Esteu segur que voleu suprimir?" 54 | size: 55 | mb: MB 56 | kb: kB 57 | select-all: "Selecciona-ho tot" 58 | upload: 59 | exception_move_uploaded_file: "Permís denegat" 60 | search: 61 | placeholder: Cerca -------------------------------------------------------------------------------- /Resources/doc/book/3-access-file-manager.md: -------------------------------------------------------------------------------- 1 | Chapter 3 - Access to the File Manager 2 | ====================================== 3 | 4 | ```yaml 5 | # app/config/config.yml 6 | artgris_file_manager: 7 | conf: 8 | public: # Access URL: /manager/?conf=public 9 | dir: "%kernel.project_dir%/public/uploads" 10 | ... 11 | myprivatefolder: ... # Access URL: /manager/?conf=myprivatefolder 12 | onlypdf: ... # Access URL: /manager/?conf=onlypdf 13 | anystring: ... # Access URL: /manager/?conf=anystring 14 | ``` 15 | 16 | Here is a list of URL parameters: 17 | 18 | | Param | Type | Required | Possible values | Default value | Description | Priority (yml / url) | 19 | | :------- |:--------:|:---------:|:------------------------:|:-------------:|:------------------|:------------------:| 20 | | `conf` | `String` | **True** | | | name of the conf | 21 | | `type` | `String` | False | `file`, `image`, `media` | `file` | type (used by tinymce) | yml > url 22 | | `module` | `String` | False | `tiny`, `ckeditor` | `null` | module (used by tinymce) | 23 | | `tree` in url | `Integer` | False | `0`, `1` | `1` | Display Folder Tree (1:Yes, 2:No) | url > yml 24 | | `tree` in yml | `Boolean` | False | `false`, `true` | `true` | Display Folder Tree (1:Yes, 2:No) | url > yml 25 | | `view` | `String` | False | `thumbnail`, `list` | `list` | Display Mode Type | url > yml 26 | | `orderby` | `String` | False | `name`, `date`, `size`, `dimension` | | Sort files | 27 | | `order` | `String` | False | `asc`, `desc` | | Order by asc or desc | 28 | | `extra` | `Array` | False | | `null` | extra parameters (used by service configuration) 29 | | `route` | `String` | False | | | a folder path under the 'dir' folder ex: /subfolder 30 | 31 | Example: 32 | 33 | path('file_manager', {module:'tiny', type:'image', conf:'perso', extra: {'user':'miamolex', 'allow': true}, route: '/subfolder'}) 34 | 35 | # Access URL: /manager/?module=tiny&type=image&conf=perso&extra[user]=miamolex&extra[allow]=1&route=/subfolder 36 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "artgris/filemanager-bundle", 3 | "type": "symfony-bundle", 4 | "description": "FileManager is a simple Multilingual File Manager Bundle for Symfony", 5 | "keywords": [ 6 | "symfony", 7 | "bundle", 8 | "file manager" 9 | ], 10 | "homepage": "https://github.com/artgris/FileManagerBundle", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Arthur Gribet", 15 | "email": "a.gribet@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=8.1", 20 | "oomphinc/composer-installers-extender": "^2.0", 21 | "symfony/asset": "^6.0||^7.0", 22 | "symfony/event-dispatcher": "^6.0||^7.0", 23 | "symfony/expression-language": "^6.0||^7.0", 24 | "symfony/flex": "^2.3", 25 | "symfony/form": "^6.0||^7.0", 26 | "symfony/framework-bundle": "^6.0||^7.0", 27 | "symfony/mime": "^6.0||^7.0", 28 | "symfony/string": "^6.0||^7.0", 29 | "symfony/translation": "^6.0||^7.0", 30 | "symfony/twig-bridge": "^6.0||^7.0", 31 | "symfony/twig-bundle": "^6.0||^7.0", 32 | "symfony/validator": "^6.0||^7.0" 33 | }, 34 | "require-dev": { 35 | "phpunit/phpunit": "^9.5", 36 | "symfony/browser-kit": "^6.0||^7.0", 37 | "symfony/css-selector": "^6.0||^7.0", 38 | "symfony/phpunit-bridge": "^6.0||^7.0", 39 | "symfony/templating": "^6.0||^7.0", 40 | "symfony/var-dumper": "^6.0||^7.0", 41 | "symfony/yaml": "^6.0||^7.0" 42 | }, 43 | "config": { 44 | "sort-packages": true, 45 | "preferred-install": { 46 | "symfony/doctrine-bridge": "source", 47 | "*": "dist" 48 | }, 49 | "allow-plugins": { 50 | "composer/installers": true, 51 | "symfony/flex": true, 52 | "symfony/runtime": true, 53 | "composer/package-versions-deprecated": true, 54 | "oomphinc/composer-installers-extender": true 55 | } 56 | }, 57 | "autoload": { 58 | "psr-4": { 59 | "Artgris\\Bundle\\FileManagerBundle\\": "" 60 | }, 61 | "exclude-from-classmap": [ 62 | "/Tests/" 63 | ] 64 | }, 65 | "autoload-dev": { 66 | "psr-4": { 67 | "Artgris\\Bundle\\FileManagerBundle\\Tests\\": "/Tests/" 68 | } 69 | }, 70 | "scripts": { 71 | "auto-scripts": { 72 | "cache:clear": "symfony-cmd", 73 | "assets:install %PUBLIC_DIR%": "symfony-cmd" 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/tmpl.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Templates 3 | * https://github.com/blueimp/JavaScript-Templates 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | * 11 | * Inspired by John Resig's JavaScript Micro-Templating: 12 | * http://ejohn.org/blog/javascript-micro-templating/ 13 | */ 14 | 15 | /* global define */ 16 | 17 | ;(function ($) { 18 | 'use strict' 19 | var tmpl = function (str, data) { 20 | var f = !/[^\w\-\.:]/.test(str) 21 | ? tmpl.cache[str] = tmpl.cache[str] || tmpl(tmpl.load(str)) 22 | : new Function(// eslint-disable-line no-new-func 23 | tmpl.arg + ',tmpl', 24 | 'var _e=tmpl.encode' + tmpl.helper + ",_s='" + 25 | str.replace(tmpl.regexp, tmpl.func) + "';return _s;" 26 | ) 27 | return data ? f(data, tmpl) : function (data) { 28 | return f(data, tmpl) 29 | } 30 | } 31 | tmpl.cache = {} 32 | tmpl.load = function (id) { 33 | return document.getElementById(id).innerHTML 34 | } 35 | tmpl.regexp = /([\s'\\])(?!(?:[^{]|\{(?!%))*%\})|(?:\{%(=|#)([\s\S]+?)%\})|(\{%)|(%\})/g 36 | tmpl.func = function (s, p1, p2, p3, p4, p5) { 37 | if (p1) { // whitespace, quote and backspace in HTML context 38 | return { 39 | '\n': '\\n', 40 | '\r': '\\r', 41 | '\t': '\\t', 42 | ' ': ' ' 43 | }[p1] || '\\' + p1 44 | } 45 | if (p2) { // interpolation: {%=prop%}, or unescaped: {%#prop%} 46 | if (p2 === '=') { 47 | return "'+_e(" + p3 + ")+'" 48 | } 49 | return "'+(" + p3 + "==null?'':" + p3 + ")+'" 50 | } 51 | if (p4) { // evaluation start tag: {% 52 | return "';" 53 | } 54 | if (p5) { // evaluation end tag: %} 55 | return "_s+='" 56 | } 57 | } 58 | tmpl.encReg = /[<>&"'\x00]/g // eslint-disable-line no-control-regex 59 | tmpl.encMap = { 60 | '<': '<', 61 | '>': '>', 62 | '&': '&', 63 | '"': '"', 64 | "'": ''' 65 | } 66 | tmpl.encode = function (s) { 67 | return (s == null ? '' : '' + s).replace( 68 | tmpl.encReg, 69 | function (c) { 70 | return tmpl.encMap[c] || '' 71 | } 72 | ) 73 | } 74 | tmpl.arg = 'o' 75 | tmpl.helper = ",print=function(s,e){_s+=e?(s==null?'':s):_e(s);}" + 76 | ',include=function(s,d){_s+=tmpl(s,d);}' 77 | if (typeof define === 'function' && define.amd) { 78 | define(function () { 79 | return tmpl 80 | }) 81 | } else if (typeof module === 'object' && module.exports) { 82 | module.exports = tmpl 83 | } else { 84 | $.tmpl = tmpl 85 | } 86 | }(this)) 87 | -------------------------------------------------------------------------------- /Resources/doc/tutorials/input-button.md: -------------------------------------------------------------------------------- 1 | How to add a button that open the File manager to fill out an input field with the file URL 2 | ========================================================================================== 3 | 4 | 5 | > Required: bootstrap and jquery 6 | 7 | ### Step 1 - Create a `button` conf 8 | 9 | ```yml 10 | artgris_file_manager: 11 | conf: 12 | button: 13 | dir: "%kernel.project_dir%/public/uploads" 14 | ``` 15 | 16 | ### Step 2 - Create input and button 17 | 18 | ```html 19 |
20 |
21 |
22 | 23 |
24 |
25 | 28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 | ``` 37 | 38 | ### Step 3 - Add modal with an iframe of your file manager; use `module:1` 39 | 40 | ```html 41 | 42 | 60 | ``` 61 | 62 | ### Step 4 - Add following js 63 | 64 | ```js 65 | 75 | ``` 76 | -------------------------------------------------------------------------------- /Resources/public/libs/sticky-kit/jquery.sticky-kit.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 3 | */ 4 | (function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); 5 | if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, 6 | u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), 8 | a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", 9 | y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;npreview = $this->fileTypeService->preview($this->fileManager, $this->file); 19 | } 20 | 21 | /** 22 | * @return array|false|string 23 | */ 24 | public function getDimension(): bool|array|string { 25 | return preg_match('/(gif|png|jpe?g|svg|webp)$/i', $this->file->getExtension()) ? 26 | @getimagesize($this->file->getPathname()) : ''; 27 | } 28 | 29 | public function getHTMLDimension(): ?string { 30 | $dimension = $this->getDimension(); 31 | if ($dimension) { 32 | return "{$dimension[0]} × {$dimension[1]}"; 33 | } 34 | 35 | return null; 36 | } 37 | 38 | public function getHTMLSize(): ?string { 39 | if ('file' === $this->getFile()->getType()) { 40 | $size = $this->file->getSize() / 1000; 41 | $kb = $this->translator->trans('size.kb'); 42 | $mb = $this->translator->trans('size.mb'); 43 | 44 | return $size > 1000 ? number_format(($size / 1000), 1, '.', '').' '.$mb : number_format($size, 1, '.', '').' '.$kb; 45 | } 46 | return null; 47 | } 48 | 49 | public function getAttribut(): ?string { 50 | if ($this->fileManager->getModule()) { 51 | $attr = ''; 52 | $dimension = $this->getDimension(); 53 | if ($dimension) { 54 | $width = $dimension[0]; 55 | $height = $dimension[1]; 56 | $attr .= "data-width=\"{$width}\" data-height=\"{$height}\" "; 57 | } 58 | 59 | if ('file' === $this->file->getType()) { 60 | $attr .= "data-path=\"{$this->getPreview()['path']}\""; 61 | $attr .= ' class="select"'; 62 | } 63 | 64 | return $attr; 65 | } 66 | 67 | return null; 68 | } 69 | 70 | public function isImage(): bool { 71 | return \array_key_exists('image', $this->preview); 72 | } 73 | 74 | public function getFile(): SplFileInfo { 75 | return $this->file; 76 | } 77 | 78 | public function setFile(SplFileInfo $file) :void 79 | { 80 | $this->file = $file; 81 | } 82 | 83 | public function getPreview(): array { 84 | return $this->preview; 85 | } 86 | 87 | public function setPreview(array $preview) :void 88 | { 89 | $this->preview = $preview; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Resources/public/css/manager.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-bottom: 20px; 3 | } 4 | 5 | .select { 6 | cursor: pointer 7 | } 8 | 9 | .thead-default th { 10 | color: #464a4c; 11 | background-color: #eceeef; 12 | } 13 | 14 | .bar { 15 | height: 18px; 16 | background: green; 17 | } 18 | 19 | .alert-file-manager { 20 | padding: 2px 32px 0 11px; 21 | margin: 1px 5px; 22 | display: inline-block; 23 | } 24 | 25 | .top-bar { 26 | padding: 10px 0; 27 | margin: 3px 0; 28 | } 29 | 30 | .select:hover { 31 | background-color: #d8d8d8; 32 | } 33 | 34 | .context-menu-active, .select:focus, .select:active { 35 | background-color: #beebff; 36 | } 37 | 38 | /*i.fa,i.far,i.fas {*/ 39 | /*font-size: 1.4em;*/ 40 | /*}*/ 41 | 42 | .alert > [data-notify="message"] { 43 | font-size: 80%; 44 | } 45 | 46 | .nopadding { 47 | margin: 0 !important; 48 | } 49 | 50 | .margin-bottom { 51 | margin-bottom: 20px; 52 | } 53 | 54 | .label { 55 | font-size: 70% !important; 56 | line-height: 24px !important; 57 | vertical-align: middle; 58 | } 59 | 60 | .jstree { 61 | background-color: #f9f9f9; 62 | padding: 10px 5px; 63 | } 64 | 65 | .thumbnail { 66 | padding: 20px 14px; 67 | margin-bottom: 0; 68 | border-left: none; 69 | border-radius: inherit; 70 | border-top: none; 71 | border-bottom: 1px #dcdcdc solid; 72 | border-right: 1px #dcdcdc solid; 73 | } 74 | 75 | .thumbnail p { 76 | height: 85px; 77 | } 78 | 79 | .thumbnail-img { 80 | height: 115px; 81 | padding: 5px; 82 | } 83 | 84 | .thumbnail-img img { 85 | max-width: 100%; 86 | } 87 | 88 | .thumbnail-img .fa, .thumbnail-img .fas, .thumbnail-img .far { 89 | font-size: 6em; 90 | } 91 | 92 | .thumbnail-blk .select { 93 | padding: 5px 0; 94 | } 95 | 96 | .thumbnail-blk div.thumbnail { 97 | overflow: hidden; 98 | } 99 | 100 | .no-tree-blk .thumbnail-blk .select-all { 101 | padding-left: 5px; 102 | } 103 | 104 | .thead-default a { 105 | color: #464a4c; 106 | } 107 | 108 | .thead-default span { 109 | color: #adadad; 110 | } 111 | 112 | .thead-default span.actived { 113 | color: #337ab7; 114 | } 115 | 116 | button i { 117 | padding-right: 4px; 118 | } 119 | 120 | .progress { 121 | height: 5px; 122 | margin-bottom: 0; 123 | border-radius: 0; 124 | background-color: transparent; 125 | } 126 | 127 | .notransition { 128 | -webkit-transition: none !important; 129 | -moz-transition: none !important; 130 | -o-transition: none !important; 131 | -ms-transition: none !important; 132 | transition: none !important; 133 | } 134 | 135 | .search { 136 | width: auto; 137 | display: inline-block; 138 | float: left; 139 | height: 30px; 140 | margin-right: 5px; 141 | } 142 | 143 | @media only screen and (max-width: 700px) { 144 | 145 | .top-bar .btn-action > span.bar-action { 146 | display: none; 147 | } 148 | 149 | } 150 | 151 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-tmpl/js/compile.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * JavaScript Templates Compiler 4 | * https://github.com/blueimp/JavaScript-Templates 5 | * 6 | * Copyright 2011, Sebastian Tschan 7 | * https://blueimp.net 8 | * 9 | * Licensed under the MIT license: 10 | * https://opensource.org/licenses/MIT 11 | */ 12 | 13 | ;(function () { 14 | 'use strict' 15 | var path = require('path') 16 | var tmpl = require(path.join(__dirname, 'tmpl.js')) 17 | var fs = require('fs') 18 | // Retrieve the content of the minimal runtime: 19 | var runtime = fs.readFileSync(path.join(__dirname, 'runtime.js'), 'utf8') 20 | // A regular expression to parse templates from script tags in a HTML page: 21 | var regexp = /([\s\S]+?)<\/script>/gi 22 | // A regular expression to match the helper function names: 23 | var helperRegexp = new RegExp( 24 | tmpl.helper.match(/\w+(?=\s*=\s*function\s*\()/g).join('\\s*\\(|') + '\\s*\\(' 25 | ) 26 | // A list to store the function bodies: 27 | var list = [] 28 | var code 29 | // Extend the Templating engine with a print method for the generated functions: 30 | tmpl.print = function (str) { 31 | // Only add helper functions if they are used inside of the template: 32 | var helper = helperRegexp.test(str) ? tmpl.helper : '' 33 | var body = str.replace(tmpl.regexp, tmpl.func) 34 | if (helper || (/_e\s*\(/.test(body))) { 35 | helper = '_e=tmpl.encode' + helper + ',' 36 | } 37 | return 'function(' + tmpl.arg + ',tmpl){' + 38 | ('var ' + helper + "_s='" + body + "';return _s;") 39 | .split("_s+='';").join('') + '}' 40 | } 41 | // Loop through the command line arguments: 42 | process.argv.forEach(function (file, index) { 43 | var listLength = list.length 44 | var stats 45 | var content 46 | var result 47 | var id 48 | // Skip the first two arguments, which are "node" and the script: 49 | if (index > 1) { 50 | stats = fs.statSync(file) 51 | if (!stats.isFile()) { 52 | console.error(file + ' is not a file.') 53 | return 54 | } 55 | content = fs.readFileSync(file, 'utf8') 56 | while (true) { 57 | // Find templates in script tags: 58 | result = regexp.exec(content) 59 | if (!result) { 60 | break 61 | } 62 | id = result[2] || result[4] 63 | list.push("'" + id + "':" + tmpl.print(result[5])) 64 | } 65 | if (listLength === list.length) { 66 | // No template script tags found, use the complete content: 67 | id = path.basename(file, path.extname(file)) 68 | list.push("'" + id + "':" + tmpl.print(content)) 69 | } 70 | } 71 | }) 72 | if (!list.length) { 73 | console.error('Missing input file.') 74 | return 75 | } 76 | // Combine the generated functions as cache of the minimal runtime: 77 | code = runtime.replace('{}', '{' + list.join(',') + '}') 78 | // Print the resulting code to the console output: 79 | console.log(code) 80 | }()) 81 | -------------------------------------------------------------------------------- /Helpers/FileManagerUploadHandler.php: -------------------------------------------------------------------------------- 1 | set_filename_sanitizer($name); 15 | 16 | if ($this->options['override']) { 17 | return $name; 18 | } 19 | 20 | while (is_dir($this->get_upload_path($name))) { 21 | $name = $this->upcount_name($name); 22 | } 23 | // Keep an existing filename if this is part of a chunked upload: 24 | $uploaded_bytes = $this->fix_integer_overflow((int)@$content_range[1]); 25 | while (is_file($this->get_upload_path($name))) { 26 | if ($uploaded_bytes === $this->get_file_size( 27 | $this->get_upload_path($name) 28 | )) { 29 | break; 30 | } 31 | $name = $this->upcount_name($name); 32 | } 33 | 34 | return $name; 35 | } 36 | 37 | protected function set_filename_sanitizer($name): string 38 | { 39 | 40 | if(!isset($this->options['filename_sanitizer']['slugger']) || $this->options['filename_sanitizer']['slugger'] !== true){ 41 | return $name; 42 | } 43 | 44 | $file_extension = pathinfo($name, PATHINFO_EXTENSION); 45 | $new_file_name = str_replace('.' . $file_extension, '', $name); 46 | 47 | $slugger = new AsciiSlugger(); 48 | 49 | if (isset($this->options['filename_sanitizer']['prepend'])) { 50 | $new_file_name = $slugger->slug($new_file_name)->prepend($this->options['filename_sanitizer']['prepend']); 51 | } 52 | 53 | if (isset($this->options['filename_sanitizer']['append'])) { 54 | $new_file_name = $slugger->slug($new_file_name)->append($this->options['filename_sanitizer']['append']); 55 | } 56 | 57 | if (isset($this->options['filename_sanitizer']['transformer'])) { 58 | $new_file_name = match ($this->options['filename_sanitizer']['transformer']) { 59 | 'uppercase' => $slugger->slug($new_file_name)->upper(), 60 | 'lowercase' => $slugger->slug($new_file_name)->lower(), 61 | 'camel' => $slugger->slug($new_file_name)->camel(), 62 | 'snake' => $slugger->slug($new_file_name)->snake(), 63 | 'cameltitle' => $slugger->slug($new_file_name)->camel()->title(), 64 | 'title' => $slugger->slug($new_file_name)->title(), 65 | 'titleall' => $slugger->slug($new_file_name)->title(true), 66 | 'folded' => $slugger->slug($new_file_name)->folded(), 67 | default => $slugger->slug($new_file_name), 68 | }; 69 | } else { 70 | $new_file_name = $slugger->slug($new_file_name); 71 | } 72 | 73 | 74 | return $new_file_name . "." . $file_extension; 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /Resources/public/js/betamax/jquery.getimagedata.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * jQuery $.getImageData Plugin 0.3 4 | * http://www.maxnov.com/getimagedata 5 | * 6 | * Written by Max Novakovic (http://www.maxnov.com/) 7 | * Date: Thu Jan 13 2011 8 | * 9 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 | * 11 | * Includes jQuery JSONP Core Plugin 2.4.0 (2012-08-21) 12 | * https://github.com/jaubourg/jquery-jsonp 13 | * Copyright 2012, Julian Aubourg 14 | * Released under the MIT License. 15 | * 16 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 17 | * 18 | * Copyright 2011, Max Novakovic 19 | * Dual licensed under the MIT or GPL Version 2 licenses. 20 | * http://www.maxnov.com/getimagedata/#license 21 | * 22 | */ 23 | (function(d){function U(){}function V(a){r=[a]}function e(a,d,e){return a&&a.apply(d.context||d,e)}function g(a){function g(b){l++||(m(),n&&(t[c]={s:[b]}),A&&(b=A.apply(a,[b])),e(u,a,[b,B,a]),e(C,a,[a,B]))}function s(b){l++||(m(),n&&b!=D&&(t[c]=b),e(v,a,[a,b]),e(C,a,[a,b]))}a=d.extend({},E,a);var u=a.success,v=a.error,C=a.complete,A=a.dataFilter,p=a.callbackParameter,F=a.callback,W=a.cache,n=a.pageCache,G=a.charset,c=a.url,f=a.data,H=a.timeout,q,l=0,m=U,b,h,w;I&&I(function(a){a.done(u).fail(v);u=a.resolve;v=a.reject}).promise(a);a.abort=function(){!l++&&m()};if(!1===e(a.beforeSend,a,[a])||l)return a;c=c||x;f=f?"string"==typeof f?f:d.param(f,a.traditional):x;c+=f?(/\?/.test(c)?"&":"?")+f:x;p&&(c+=(/\?/.test(c)?"&":"?")+encodeURIComponent(p)+"=?");W||n||(c+=(/\?/.test(c)?"&":"?")+"_"+(new Date).getTime()+"=");c=c.replace(/=\?(&|$)/,"="+F+"$1");n&&(q=t[c])?q.s?g(q.s[0]):s(q):(J[F]=V,b=d(K)[0],b.id=L+X++,G&&(b[Y]=G),M&&11.6>M.version()?(h=d(K)[0]).text="document.getElementById('"+b.id+"')."+y+"()":b[N]=N,Z&&(b.htmlFor=b.id,b.event=z),b[O]=b[y]=b[P]=function(a){if(!b[Q]||!/i/.test(b[Q])){try{b[z]&&b[z]()}catch(c){}a=r;r=0;a?g(a[0]):s(R)}},b.src=c,m=function(a){w&&clearTimeout(w);b[P]=b[O]=b[y]=null;k[S](b);h&&k[S](h)},k[T](b,p=k.firstChild),h&&k[T](h,p),w=0").html("").find("i").length;g.setup=function(a){d.extend(E,a)};d.jsonp=g})(jQuery);(function($){$.getImageData=function(args){var regex_url_test=/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;if(args.url){var is_secure=location.protocol==="https:";var server_url="";if(args.server&®ex_url_test.test(args.server)&&!(is_secure&&args.server.indexOf("http:")==0)){server_url=args.server}else server_url="//img-to-json.appspot.com/";server_url+="?callback=?";$.jsonp({url:server_url,data:{url:escape(args.url)},dataType:"jsonp",timeout:args.timeout||1e4,success:function(data,status){var return_image=new Image;$(return_image).load(function(){this.width=data.width;this.height=data.height;if(typeof args.success==typeof Function){args.success(this)}}).attr("src",data.data)},error:function(xhr,text_status){if(typeof args.error==typeof Function){args.error(xhr,text_status)}}})}else{if(typeof args.error==typeof Function){args.error(null,"no_url")}}}})(jQuery); 24 | -------------------------------------------------------------------------------- /Resources/translations/messages.fr.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: a été téléchagé avec succès 4 | renamed: 5 | success: Le fichier a été renommé avec succès 6 | danger: Le fichier existe déjà ou vous n'êtes pas autorisé à renommer ce fichier 7 | unauthorized: Les fichiers n'existent plus ou vous n'êtes pas autorisé à accéder à cette page 8 | nochanged: Aucun changement détecté 9 | deleted: 10 | success: Les fichiers ont été supprimés avec succès 11 | danger: Les fichiers n'existent plus ou vous n'êtes pas autorisé à accéder à cette page 12 | unauthorized: Les fichiers n'existent plus ou vous n'êtes pas autorisé à accéder à cette page 13 | folder: 14 | add: 15 | danger: "Une erreur s'est produite lors de la création du dossier : %message%" 16 | success: Le dossier a été créé avec succès 17 | deleted: 18 | success: Le dossier a été supprimé avec succès 19 | unauthorized: Le dossier n'existe plus ou vous n'êtes pas autorisé à accéder à cette page 20 | button: 21 | cancel: ANNULER 22 | refresh: Rafraîchir 23 | parent: Parent 24 | save: ENREGISTRER 25 | add: 26 | files: Nouveaux fichiers 27 | folder: Nouveau dossier 28 | delete: 29 | current: Supprimer le dossier courant 30 | selected: Supprimer les fichiers sélectionnés 31 | action: SUPPRIMER 32 | rename: 33 | action: RENOMMER 34 | tree: Arborescence 35 | title: 36 | add: 37 | folder: Nouveau dossier 38 | rename: 39 | file: Renommer 40 | delete: Supprimer 41 | download: Télécharger 42 | preview: 43 | file: Ouvrir 44 | input: 45 | default: Dossier sans titre 46 | table: 47 | name: Nom 48 | date: Date 49 | size: Taille 50 | dimension: Dimensions 51 | actions: Actions 52 | confirm: 53 | delete: Êtes-vous sûr de vouloir supprimer ? 54 | size: 55 | mb: Mo 56 | kb: ko 57 | select-all: Tout selectionner 58 | upload: 59 | exception_move_uploaded_file: Permission refusée 60 | search: 61 | placeholder: Recherche 62 | 63 | 'The uploaded file exceeds the upload_max_filesize directive in php.ini': La taille maximum des fichiers (upload_max_filesize) a été atteinte 64 | 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form': La taille maximum de fichier (MAX_FILE_SIZE) a été atteinte 65 | 'The uploaded file was only partially uploaded': Le fichier n'a été que partiellement uploadé 66 | 'No file was uploaded': Aucun fichier n'a été uploadé 67 | 'Missing a temporary folder': Il manque le dossier temporaire 68 | 'Failed to write file to disk': Impossible d'enregistrer le ficher 69 | 'A PHP extension stopped the file upload': une extension PHP bloque l'upload 70 | 'The uploaded file exceeds the post_max_size directive in php.ini': L'upload de fichier dépasse la taille autorisée par le serveur 71 | 'File is too big': Le fichier est trop gros 72 | 'File is too small': Le fichier est trop petit 73 | 'Filetype not allowed': Ce type de fichier n'est pas autorisé 74 | 'Maximum number of files exceeded': Le nombre maximum de fichier a été atteint 75 | 'Image exceeds maximum width': L'image a une largeur trop grande 76 | 'Image requires a minimum width': L'image a une largeur trop petite 77 | 'Image exceeds maximum height': L'image a une hauteur trop grande 78 | 'Image requires a minimum height': L'image a une hauteur trop petite 79 | 'File upload aborted': L'upload a été annulé 80 | 'Failed to resize image': une erreur est survenue lors du redimensionnement de l'image 81 | -------------------------------------------------------------------------------- /Resources/translations/messages.de.yml: -------------------------------------------------------------------------------- 1 | file: 2 | add: 3 | success: wurde erfolgreich hochgeladen 4 | renamed: 5 | success: Die Datei wurde erfolgreich umbenannt 6 | danger: Die Datei existiert bereits oder Sie haben keine Rechte sie umzubenennen 7 | unauthorized: Die Datei existiert nicht mehr oder Sie haben keine Zugriffsrechte auf diese Seite 8 | nochanged: Kein Änderung festgestellt 9 | deleted: 10 | success: Die Dateien wurden erfolgreich gelöscht 11 | danger: Die Datei existiert nicht mehr oder Sie haben keine Zugriffsrechte auf diese Seite 12 | unauthorized: Die Datei existiert nicht mehr oder Sie haben keine Zugriffsrechte auf diese Seite 13 | folder: 14 | add: 15 | danger: "Beim Erstellen des Verzeichnisses ist ein Fehler aufgetreten : %message%" 16 | success: Das Verzeichnis wurde erfolgreich erstellt 17 | deleted: 18 | success: Das Verzeichnis wurde erfolgreich gelöscht 19 | unauthorized: Die Datei existiert nicht mehr oder Sie haben keine Zugriffsrechte auf diese Seite 20 | button: 21 | cancel: ABBRECHEN 22 | refresh: Neu laden 23 | parent: Nach oben 24 | save: SPEICHERN 25 | add: 26 | files: Datei hinzufügen ... 27 | folder: Verzeichnis erstellen ... 28 | delete: 29 | current: Aktuelles Verzeichnis löschen 30 | selected: Ausgewählte Datei löschen 31 | action: LÖSCHEN 32 | rename: 33 | action: UMBENENNEN 34 | tree: Baumstruktur 35 | title: 36 | add: 37 | folder: Neues Verzeichnis 38 | rename: 39 | file: Umbenennen 40 | delete: Löschen 41 | download: Herunterladen 42 | preview: 43 | file: Öffnen 44 | input: 45 | default: Unbetiteltes Verzeichnis 46 | table: 47 | name: Name 48 | date: Datum 49 | size: Größe 50 | dimension: Auflösung 51 | actions: Aktionen 52 | confirm: 53 | delete: Möchten Sie dies wirklich löschen? 54 | size: 55 | mb: Mb 56 | kb: kb 57 | select-all: Alles auswählen 58 | upload: 59 | exception_move_uploaded_file: Zugriff verweigert 60 | search: 61 | placeholder: Suche 62 | 63 | 'The uploaded file exceeds the upload_max_filesize directive in php.ini': Die Dateigrösse überschreitet die maximal erlaubte Größe (upload_max_filesize in php.ini) 64 | 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form': Die Dateigrösse überschreitet die maximal erlaubte Größe (MAX_FILE_SIZE im HTML-Formular) 65 | 'The uploaded file was only partially uploaded': Datei wurde nur teilweise hochgeladen 66 | 'No file was uploaded': Es wurde keine Datei hochgeladen 67 | 'Missing a temporary folder': Es fehlt das temporäre Verzeichnis 68 | 'Failed to write file to disk': Datei kann nicht gespeichert werden 69 | 'A PHP extension stopped the file upload': Eine PHP-Erweiterung blockiert das Hochladen 70 | 'The uploaded file exceeds the post_max_size directive in php.ini': Die Dateigrösse überschreitet die maximal erlaubte Größe (post_max_size in php.ini) 71 | 'File is too big': Die Datei ist zu groß 72 | 'File is too small': Die Datei ist zu klein 73 | 'Filetype not allowed': Der Dateityp ist nicht erlaubt 74 | 'Maximum number of files exceeded': Die maximale Anzahl Dateien wurde erreicht 75 | 'Image exceeds maximum width': Das Bild ist zu breit 76 | 'Image requires a minimum width': Das Bild ist zu schmal 77 | 'Image exceeds maximum height': Das Bild ist zu hoch 78 | 'Image requires a minimum height': Das Bild ist zu niedrig 79 | 'File upload aborted': Der Upload wurde abgebrochen 80 | 'Failed to resize image': Beim Skalieren des Bildes ist ein Fehler aufgetreten 81 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/cors/jquery.xdr-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery XDomainRequest Transport Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | * 11 | * Based on Julian Aubourg's ajaxHooks xdr.js: 12 | * https://github.com/jaubourg/ajaxHooks/ 13 | */ 14 | 15 | /* global define, require, window, XDomainRequest */ 16 | 17 | ;(function (factory) { 18 | 'use strict'; 19 | if (typeof define === 'function' && define.amd) { 20 | // Register as an anonymous AMD module: 21 | define(['jquery'], factory); 22 | } else if (typeof exports === 'object') { 23 | // Node/CommonJS: 24 | factory(require('jquery')); 25 | } else { 26 | // Browser globals: 27 | factory(window.jQuery); 28 | } 29 | }(function ($) { 30 | 'use strict'; 31 | if (window.XDomainRequest && !$.support.cors) { 32 | $.ajaxTransport(function (s) { 33 | if (s.crossDomain && s.async) { 34 | if (s.timeout) { 35 | s.xdrTimeout = s.timeout; 36 | delete s.timeout; 37 | } 38 | var xdr; 39 | return { 40 | send: function (headers, completeCallback) { 41 | var addParamChar = /\?/.test(s.url) ? '&' : '?'; 42 | function callback(status, statusText, responses, responseHeaders) { 43 | xdr.onload = xdr.onerror = xdr.ontimeout = $.noop; 44 | xdr = null; 45 | completeCallback(status, statusText, responses, responseHeaders); 46 | } 47 | xdr = new XDomainRequest(); 48 | // XDomainRequest only supports GET and POST: 49 | if (s.type === 'DELETE') { 50 | s.url = s.url + addParamChar + '_method=DELETE'; 51 | s.type = 'POST'; 52 | } else if (s.type === 'PUT') { 53 | s.url = s.url + addParamChar + '_method=PUT'; 54 | s.type = 'POST'; 55 | } else if (s.type === 'PATCH') { 56 | s.url = s.url + addParamChar + '_method=PATCH'; 57 | s.type = 'POST'; 58 | } 59 | xdr.open(s.type, s.url); 60 | xdr.onload = function () { 61 | callback( 62 | 200, 63 | 'OK', 64 | {text: xdr.responseText}, 65 | 'Content-Type: ' + xdr.contentType 66 | ); 67 | }; 68 | xdr.onerror = function () { 69 | callback(404, 'Not Found'); 70 | }; 71 | if (s.xdrTimeout) { 72 | xdr.ontimeout = function () { 73 | callback(0, 'timeout'); 74 | }; 75 | xdr.timeout = s.xdrTimeout; 76 | } 77 | xdr.send((s.hasContent && s.data) || null); 78 | }, 79 | abort: function () { 80 | if (xdr) { 81 | xdr.onerror = $.noop(); 82 | xdr.abort(); 83 | } 84 | } 85 | }; 86 | } 87 | }); 88 | } 89 | })); 90 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-canvas-to-blob/js/canvas-to-blob.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Canvas to Blob 3 | * https://github.com/blueimp/JavaScript-Canvas-to-Blob 4 | * 5 | * Copyright 2012, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | * 11 | * Based on stackoverflow user Stoive's code snippet: 12 | * http://stackoverflow.com/q/4998908 13 | */ 14 | 15 | /* global atob, Blob, define */ 16 | 17 | ;(function (window) { 18 | 'use strict' 19 | 20 | var CanvasPrototype = window.HTMLCanvasElement && 21 | window.HTMLCanvasElement.prototype 22 | var hasBlobConstructor = window.Blob && (function () { 23 | try { 24 | return Boolean(new Blob()) 25 | } catch (e) { 26 | return false 27 | } 28 | }()) 29 | var hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array && 30 | (function () { 31 | try { 32 | return new Blob([new Uint8Array(100)]).size === 100 33 | } catch (e) { 34 | return false 35 | } 36 | }()) 37 | var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || 38 | window.MozBlobBuilder || window.MSBlobBuilder 39 | var dataURIPattern = /^data:((.*?)(;charset=.*?)?)(;base64)?,/ 40 | var dataURLtoBlob = (hasBlobConstructor || BlobBuilder) && window.atob && 41 | window.ArrayBuffer && window.Uint8Array && 42 | function (dataURI) { 43 | var matches, 44 | mediaType, 45 | isBase64, 46 | dataString, 47 | byteString, 48 | arrayBuffer, 49 | intArray, 50 | i, 51 | bb 52 | // Parse the dataURI components as per RFC 2397 53 | matches = dataURI.match(dataURIPattern) 54 | if (!matches) { 55 | throw new Error('invalid data URI') 56 | } 57 | // Default to text/plain;charset=US-ASCII 58 | mediaType = matches[2] 59 | ? matches[1] 60 | : 'text/plain' + (matches[3] || ';charset=US-ASCII') 61 | isBase64 = !!matches[4] 62 | dataString = dataURI.slice(matches[0].length) 63 | if (isBase64) { 64 | // Convert base64 to raw binary data held in a string: 65 | byteString = atob(dataString) 66 | } else { 67 | // Convert base64/URLEncoded data component to raw binary: 68 | byteString = decodeURIComponent(dataString) 69 | } 70 | // Write the bytes of the string to an ArrayBuffer: 71 | arrayBuffer = new ArrayBuffer(byteString.length) 72 | intArray = new Uint8Array(arrayBuffer) 73 | for (i = 0; i < byteString.length; i += 1) { 74 | intArray[i] = byteString.charCodeAt(i) 75 | } 76 | // Write the ArrayBuffer (or ArrayBufferView) to a blob: 77 | if (hasBlobConstructor) { 78 | return new Blob( 79 | [hasArrayBufferViewSupport ? intArray : arrayBuffer], 80 | {type: mediaType} 81 | ) 82 | } 83 | bb = new BlobBuilder() 84 | bb.append(arrayBuffer) 85 | return bb.getBlob(mediaType) 86 | } 87 | if (window.HTMLCanvasElement && !CanvasPrototype.toBlob) { 88 | if (CanvasPrototype.mozGetAsFile) { 89 | CanvasPrototype.toBlob = function (callback, type, quality) { 90 | if (quality && CanvasPrototype.toDataURL && dataURLtoBlob) { 91 | callback(dataURLtoBlob(this.toDataURL(type, quality))) 92 | } else { 93 | callback(this.mozGetAsFile('blob', type)) 94 | } 95 | } 96 | } else if (CanvasPrototype.toDataURL && dataURLtoBlob) { 97 | CanvasPrototype.toBlob = function (callback, type, quality) { 98 | callback(dataURLtoBlob(this.toDataURL(type, quality))) 99 | } 100 | } 101 | } 102 | if (typeof define === 'function' && define.amd) { 103 | define(function () { 104 | return dataURLtoBlob 105 | }) 106 | } else if (typeof module === 'object' && module.exports) { 107 | module.exports = dataURLtoBlob 108 | } else { 109 | window.dataURLtoBlob = dataURLtoBlob 110 | } 111 | }(window)) 112 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Configuration implements ConfigurationInterface 12 | { 13 | public function __construct(private string $projectDir) { 14 | } 15 | 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function getConfigTreeBuilder(): TreeBuilder { 20 | 21 | // symfony > 4.2 22 | $treeBuilder = new TreeBuilder('artgris_file_manager'); 23 | $rootNode = $treeBuilder->getRootNode(); 24 | 25 | $rootNode 26 | ->children() 27 | ->scalarNode('web_dir') 28 | ->defaultValue($this->projectDir."/public") 29 | ->end() 30 | ->arrayNode('conf') 31 | ->prototype('array') 32 | ->children() 33 | ->scalarNode('dir')->end() 34 | ->enumNode('type')->values(['file', 'image', 'media'])->end() 35 | ->booleanNode('tree')->end() 36 | ->booleanNode('show_file_count')->defaultValue(true)->end() 37 | ->scalarNode('root_name')->defaultValue(null)->end() 38 | ->scalarNode('twig_extension')->end() 39 | ->booleanNode('cachebreaker')->defaultValue(true)->end() 40 | ->enumNode('view')->values(['thumbnail', 'list'])->defaultValue('list')->end() 41 | ->scalarNode('regex')->end() 42 | ->scalarNode('service')->end() 43 | ->scalarNode('accept')->end() 44 | ->arrayNode('upload') 45 | ->children() 46 | ->integerNode('min_file_size')->end() 47 | ->integerNode('max_file_size')->end() 48 | ->integerNode('max_width')->end() 49 | ->integerNode('max_height')->end() 50 | ->integerNode('min_width')->end() 51 | ->integerNode('min_height')->end() 52 | ->integerNode('image_library')->end() 53 | ->arrayNode('image_versions') 54 | ->prototype('array') 55 | ->children() 56 | ->booleanNode('auto_orient')->end() 57 | ->booleanNode('crop')->end() 58 | ->integerNode('max_width')->end() 59 | ->integerNode('max_height')->end() 60 | ->end() 61 | ->end() 62 | ->end() 63 | ->booleanNode('override')->defaultValue(false)->end() 64 | ->end() 65 | ->children() 66 | ->arrayNode('filename_sanitizer') 67 | ->children() 68 | ->scalarNode('transformer')->end() 69 | ->booleanNode('slugger')->end() 70 | ->scalarNode('prepend')->end() 71 | ->scalarNode('append')->end() 72 | ->end() 73 | ->end() 74 | ->end() 75 | ->end() 76 | ->end() 77 | ->end() 78 | ->end() 79 | ->end(); 80 | 81 | return $treeBuilder; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/css/vendor/jquery.Jcrop.css: -------------------------------------------------------------------------------- 1 | /* jquery.Jcrop.css v0.9.12 - MIT License */ 2 | /* 3 | The outer-most container in a typical Jcrop instance 4 | If you are having difficulty with formatting related to styles 5 | on a parent element, place any fixes here or in a like selector 6 | 7 | You can also style this element if you want to add a border, etc 8 | A better method for styling can be seen below with .jcrop-light 9 | (Add a class to the holder and style elements for that extended class) 10 | */ 11 | .jcrop-holder { 12 | direction: ltr; 13 | text-align: left; 14 | } 15 | /* Selection Border */ 16 | .jcrop-vline, 17 | .jcrop-hline { 18 | background: #ffffff url("Jcrop.gif"); 19 | font-size: 0; 20 | position: absolute; 21 | } 22 | .jcrop-vline { 23 | height: 100%; 24 | width: 1px !important; 25 | } 26 | .jcrop-vline.right { 27 | right: 0; 28 | } 29 | .jcrop-hline { 30 | height: 1px !important; 31 | width: 100%; 32 | } 33 | .jcrop-hline.bottom { 34 | bottom: 0; 35 | } 36 | /* Invisible click targets */ 37 | .jcrop-tracker { 38 | height: 100%; 39 | width: 100%; 40 | /* "turn off" link highlight */ 41 | -webkit-tap-highlight-color: transparent; 42 | /* disable callout, image save panel */ 43 | -webkit-touch-callout: none; 44 | /* disable cut copy paste */ 45 | -webkit-user-select: none; 46 | } 47 | /* Selection Handles */ 48 | .jcrop-handle { 49 | background-color: #333333; 50 | border: 1px #eeeeee solid; 51 | width: 7px; 52 | height: 7px; 53 | font-size: 1px; 54 | } 55 | .jcrop-handle.ord-n { 56 | left: 50%; 57 | margin-left: -4px; 58 | margin-top: -4px; 59 | top: 0; 60 | } 61 | .jcrop-handle.ord-s { 62 | bottom: 0; 63 | left: 50%; 64 | margin-bottom: -4px; 65 | margin-left: -4px; 66 | } 67 | .jcrop-handle.ord-e { 68 | margin-right: -4px; 69 | margin-top: -4px; 70 | right: 0; 71 | top: 50%; 72 | } 73 | .jcrop-handle.ord-w { 74 | left: 0; 75 | margin-left: -4px; 76 | margin-top: -4px; 77 | top: 50%; 78 | } 79 | .jcrop-handle.ord-nw { 80 | left: 0; 81 | margin-left: -4px; 82 | margin-top: -4px; 83 | top: 0; 84 | } 85 | .jcrop-handle.ord-ne { 86 | margin-right: -4px; 87 | margin-top: -4px; 88 | right: 0; 89 | top: 0; 90 | } 91 | .jcrop-handle.ord-se { 92 | bottom: 0; 93 | margin-bottom: -4px; 94 | margin-right: -4px; 95 | right: 0; 96 | } 97 | .jcrop-handle.ord-sw { 98 | bottom: 0; 99 | left: 0; 100 | margin-bottom: -4px; 101 | margin-left: -4px; 102 | } 103 | /* Dragbars */ 104 | .jcrop-dragbar.ord-n, 105 | .jcrop-dragbar.ord-s { 106 | height: 7px; 107 | width: 100%; 108 | } 109 | .jcrop-dragbar.ord-e, 110 | .jcrop-dragbar.ord-w { 111 | height: 100%; 112 | width: 7px; 113 | } 114 | .jcrop-dragbar.ord-n { 115 | margin-top: -4px; 116 | } 117 | .jcrop-dragbar.ord-s { 118 | bottom: 0; 119 | margin-bottom: -4px; 120 | } 121 | .jcrop-dragbar.ord-e { 122 | margin-right: -4px; 123 | right: 0; 124 | } 125 | .jcrop-dragbar.ord-w { 126 | margin-left: -4px; 127 | } 128 | /* The "jcrop-light" class/extension */ 129 | .jcrop-light .jcrop-vline, 130 | .jcrop-light .jcrop-hline { 131 | background: #ffffff; 132 | filter: alpha(opacity=70) !important; 133 | opacity: .70!important; 134 | } 135 | .jcrop-light .jcrop-handle { 136 | -moz-border-radius: 3px; 137 | -webkit-border-radius: 3px; 138 | background-color: #000000; 139 | border-color: #ffffff; 140 | border-radius: 3px; 141 | } 142 | /* The "jcrop-dark" class/extension */ 143 | .jcrop-dark .jcrop-vline, 144 | .jcrop-dark .jcrop-hline { 145 | background: #000000; 146 | filter: alpha(opacity=70) !important; 147 | opacity: 0.7 !important; 148 | } 149 | .jcrop-dark .jcrop-handle { 150 | -moz-border-radius: 3px; 151 | -webkit-border-radius: 3px; 152 | background-color: #ffffff; 153 | border-color: #000000; 154 | border-radius: 3px; 155 | } 156 | /* Simple macro to turn off the antlines */ 157 | .solid-line .jcrop-vline, 158 | .solid-line .jcrop-hline { 159 | background: #ffffff; 160 | } 161 | /* Fix for twitter bootstrap et al. */ 162 | .jcrop-holder img, 163 | img.jcrop-preview { 164 | max-width: none; 165 | } 166 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/jquery.fileupload-audio.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Audio Preview Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window, document */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | 'load-image', 22 | './jquery.fileupload-process' 23 | ], factory); 24 | } else if (typeof exports === 'object') { 25 | // Node/CommonJS: 26 | factory( 27 | require('jquery'), 28 | require('blueimp-load-image/js/load-image'), 29 | require('./jquery.fileupload-process') 30 | ); 31 | } else { 32 | // Browser globals: 33 | factory( 34 | window.jQuery, 35 | window.loadImage 36 | ); 37 | } 38 | }(function ($, loadImage) { 39 | 'use strict'; 40 | 41 | // Prepend to the default processQueue: 42 | $.blueimp.fileupload.prototype.options.processQueue.unshift( 43 | { 44 | action: 'loadAudio', 45 | // Use the action as prefix for the "@" options: 46 | prefix: true, 47 | fileTypes: '@', 48 | maxFileSize: '@', 49 | disabled: '@disableAudioPreview' 50 | }, 51 | { 52 | action: 'setAudio', 53 | name: '@audioPreviewName', 54 | disabled: '@disableAudioPreview' 55 | } 56 | ); 57 | 58 | // The File Upload Audio Preview plugin extends the fileupload widget 59 | // with audio preview functionality: 60 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 61 | 62 | options: { 63 | // The regular expression for the types of audio files to load, 64 | // matched against the file type: 65 | loadAudioFileTypes: /^audio\/.*$/ 66 | }, 67 | 68 | _audioElement: document.createElement('audio'), 69 | 70 | processActions: { 71 | 72 | // Loads the audio file given via data.files and data.index 73 | // as audio element if the browser supports playing it. 74 | // Accepts the options fileTypes (regular expression) 75 | // and maxFileSize (integer) to limit the files to load: 76 | loadAudio: function (data, options) { 77 | if (options.disabled) { 78 | return data; 79 | } 80 | var file = data.files[data.index], 81 | url, 82 | audio; 83 | if (this._audioElement.canPlayType && 84 | this._audioElement.canPlayType(file.type) && 85 | ($.type(options.maxFileSize) !== 'number' || 86 | file.size <= options.maxFileSize) && 87 | (!options.fileTypes || 88 | options.fileTypes.test(file.type))) { 89 | url = loadImage.createObjectURL(file); 90 | if (url) { 91 | audio = this._audioElement.cloneNode(false); 92 | audio.src = url; 93 | audio.controls = true; 94 | data.audio = audio; 95 | return data; 96 | } 97 | } 98 | return data; 99 | }, 100 | 101 | // Sets the audio element as a property of the file object: 102 | setAudio: function (data, options) { 103 | if (data.audio && !options.disabled) { 104 | data.files[data.index][options.name || 'preview'] = data.audio; 105 | } 106 | return data; 107 | } 108 | 109 | } 110 | 111 | }); 112 | 113 | })); 114 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/jquery.fileupload-video.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Video Preview Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window, document */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | 'load-image', 22 | './jquery.fileupload-process' 23 | ], factory); 24 | } else if (typeof exports === 'object') { 25 | // Node/CommonJS: 26 | factory( 27 | require('jquery'), 28 | require('blueimp-load-image/js/load-image'), 29 | require('./jquery.fileupload-process') 30 | ); 31 | } else { 32 | // Browser globals: 33 | factory( 34 | window.jQuery, 35 | window.loadImage 36 | ); 37 | } 38 | }(function ($, loadImage) { 39 | 'use strict'; 40 | 41 | // Prepend to the default processQueue: 42 | $.blueimp.fileupload.prototype.options.processQueue.unshift( 43 | { 44 | action: 'loadVideo', 45 | // Use the action as prefix for the "@" options: 46 | prefix: true, 47 | fileTypes: '@', 48 | maxFileSize: '@', 49 | disabled: '@disableVideoPreview' 50 | }, 51 | { 52 | action: 'setVideo', 53 | name: '@videoPreviewName', 54 | disabled: '@disableVideoPreview' 55 | } 56 | ); 57 | 58 | // The File Upload Video Preview plugin extends the fileupload widget 59 | // with video preview functionality: 60 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 61 | 62 | options: { 63 | // The regular expression for the types of video files to load, 64 | // matched against the file type: 65 | loadVideoFileTypes: /^video\/.*$/ 66 | }, 67 | 68 | _videoElement: document.createElement('video'), 69 | 70 | processActions: { 71 | 72 | // Loads the video file given via data.files and data.index 73 | // as video element if the browser supports playing it. 74 | // Accepts the options fileTypes (regular expression) 75 | // and maxFileSize (integer) to limit the files to load: 76 | loadVideo: function (data, options) { 77 | if (options.disabled) { 78 | return data; 79 | } 80 | var file = data.files[data.index], 81 | url, 82 | video; 83 | if (this._videoElement.canPlayType && 84 | this._videoElement.canPlayType(file.type) && 85 | ($.type(options.maxFileSize) !== 'number' || 86 | file.size <= options.maxFileSize) && 87 | (!options.fileTypes || 88 | options.fileTypes.test(file.type))) { 89 | url = loadImage.createObjectURL(file); 90 | if (url) { 91 | video = this._videoElement.cloneNode(false); 92 | video.src = url; 93 | video.controls = true; 94 | data.video = video; 95 | return data; 96 | } 97 | } 98 | return data; 99 | }, 100 | 101 | // Sets the video element as a property of the file object: 102 | setVideo: function (data, options) { 103 | if (data.video && !options.disabled) { 104 | data.files[data.index][options.name || 'preview'] = data.video; 105 | } 106 | return data; 107 | } 108 | 109 | } 110 | 111 | }); 112 | 113 | })); 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FileManagerBundle 2 | ================= 3 | 4 | [![Symfony 2.x, 3.x, 4.x, 5.x, 6.x, 7.x][7]][8] 5 | 6 | FileManager is a simple Multilingual File Manager Bundle for Symfony 7 | 8 | Symfony Filemanager created with FileManagerBundle 9 | 10 | * [Documentation](#documentation) 11 | * [Installation](#installation) 12 | * [Creating Your First File Manager](#creating-your-first-file-manager) 13 | 14 | 15 | **Features** 16 | * Upload, delete (multiple), rename, download and sort files 17 | * Create, rename and delete folders 18 | * Manage **Public** and **Private** folders 19 | * File Names **Sanitizer** / **Slugger** ([Look Documentation](Resources/doc/book/1-basic-configuration.md)) 20 | * **Multilingual** (English, French, Catalan, German, Spanish, Dutch, Portuguese, Romanian, Russian, Turkish) 21 | * **Fully responsive design** (bootstrap) 22 | * Multilple view modes (list, thumbnail, with tree or not) 23 | * Easy integration with [**Tinymce**](https://www.tinymce.com/) 24 | * **Preview images** (even with a Private folder) 25 | * Create **multilple configurations** 26 | * **Advanced configuration** (ex : ACL, ...) with your own **service** 27 | * **File restriction** based on patterns 28 | * File Upload widget used : [blueimp/jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload) 29 | * **Multiple uploads support** 30 | * **Drag & Drop support** 31 | * **Min/Max file size restriction** 32 | * **Thumbnails generation** 33 | * [Exhaustive options](https://github.com/blueimp/jQuery-File-Upload/blob/master/server/php/UploadHandler.php) 34 | * Compatible with [**FOSCKEditorBundle**](https://github.com/FriendsOfSymfony/FOSCKEditorBundle) 35 | 36 | Documentation 37 | ------------- 38 | 39 | #### The Book 40 | 41 | * [Chapter 0 - Installation and your first File Manager](Resources/doc/book/0-installation.md) 42 | * [Chapter 1 - Basic Configuration](Resources/doc/book/1-basic-configuration.md) 43 | * [Chapter 2 - Service Configuration](Resources/doc/book/2-service-configuration.md) 44 | * [Chapter 3 - Access to the File Manager](Resources/doc/book/3-access-file-manager.md) 45 | * [Chapter 4 - Security | Hide and/or block access to specific files or folders](Resources/doc/book/4-security.md) 46 | 47 | #### Tutorials 48 | 49 | * [How to integrate FileManagerBundle into Tinymce](Resources/doc/tutorials/integrate-tinymce.md) 50 | * [How to integrate FileManagerBundle into FOSCKEditorBundle](Resources/doc/tutorials/integrate-fos-ckeditor.md) 51 | * [How to add a button that open the File manager to fill out an input field with the file URL](Resources/doc/tutorials/input-button.md) 52 | 53 | 54 | Installation 55 | ------------ 56 | 57 | ### Step 1: Download the Bundle 58 | 59 | ```bash 60 | $ composer require artgris/filemanager-bundle 61 | ``` 62 | 63 | ### Step 2: Load the Routes 64 | 65 | 66 | ```yaml 67 | # app/config/routes.yaml 68 | artgris_bundle_file_manager: 69 | resource: "@ArtgrisFileManagerBundle/Controller" 70 | type: attribute 71 | prefix: /manager 72 | ``` 73 | ### Step 3: Enable the translator service 74 | 75 | ```yml 76 | # app/config/packages/translation.yaml 77 | framework: 78 | translator: { fallbacks: [ "en" ] } 79 | ``` 80 | 81 | Creating Your First File Manager 82 | --------------------------------- 83 | 84 | Create a folder **uploads** in **public**. 85 | 86 | #### Add following configuration: 87 | 88 | ```yaml 89 | # app/config/packages/artgris_file_manager.yaml 90 | artgris_file_manager: 91 | conf: 92 | default: 93 | dir: '%kernel.project_dir%/public/uploads' 94 | ``` 95 | 96 | Browse the `/manager/?conf=default` URL and you'll get access to your 97 | file manager 98 | 99 | [7]: https://img.shields.io/badge/symfony-2.x%2C%203.x%2C%204.x%2C%205.x,%206.x%20and%207.x-green.svg 100 | [8]: https://symfony.com/ 101 | 102 | 103 | #### Run tests: 104 | 105 | ./vendor/bin/simple-phpunit 106 | 107 | #### Demo Application 108 | 109 | [FileManagerDemo](https://github.com/artgris/FileManagerBundleDemo) is a complete Symfony application (Symfony 4.4 and 5.0) created to showcase FileManagerBundle features. 110 | -------------------------------------------------------------------------------- /Resources/views/views/_modals.html.twig: -------------------------------------------------------------------------------- 1 | {% block delete_modal %} 2 | 23 | {% endblock %} 24 | {% block rename_modal %} 25 | 47 | {% endblock %} 48 | {% block add_modal %} 49 | 71 | {% endblock %} 72 | {% block preview_modal %} 73 | 91 | {% endblock %} 92 | -------------------------------------------------------------------------------- /Resources/public/js/betamax/jquery.getimagedata.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * jQuery $.getImageData Plugin 0.3 4 | * http://www.maxnov.com/getimagedata 5 | * 6 | * Written by Max Novakovic (http://www.maxnov.com/) 7 | * Date: Thu Jan 13 2011 8 | * 9 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 | * 11 | * Includes jQuery JSONP Core Plugin 2.4.0 (2012-08-21) 12 | * https://github.com/jaubourg/jquery-jsonp 13 | * Copyright 2012, Julian Aubourg 14 | * Released under the MIT License. 15 | * 16 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 17 | * 18 | * Copyright 2011, Max Novakovic 19 | * Dual licensed under the MIT or GPL Version 2 licenses. 20 | * http://www.maxnov.com/getimagedata/#license 21 | * 22 | */ 23 | 24 | // jQuery JSONP 25 | (function(d){function U(){}function V(a){r=[a]}function e(a,d,e){return a&&a.apply(d.context||d,e)}function g(a){function g(b){l++||(m(),n&&(t[c]={s:[b]}),A&&(b=A.apply(a,[b])),e(u,a,[b,B,a]),e(C,a,[a,B]))}function s(b){l++||(m(),n&&b!=D&&(t[c]=b),e(v,a,[a,b]),e(C,a,[a,b]))}a=d.extend({},E,a);var u=a.success,v=a.error,C=a.complete,A=a.dataFilter,p=a.callbackParameter,F=a.callback,W=a.cache,n=a.pageCache,G=a.charset,c=a.url,f=a.data,H=a.timeout,q,l=0,m=U,b,h,w;I&&I(function(a){a.done(u).fail(v);u= 26 | a.resolve;v=a.reject}).promise(a);a.abort=function(){!l++&&m()};if(!1===e(a.beforeSend,a,[a])||l)return a;c=c||x;f=f?"string"==typeof f?f:d.param(f,a.traditional):x;c+=f?(/\?/.test(c)?"&":"?")+f:x;p&&(c+=(/\?/.test(c)?"&":"?")+encodeURIComponent(p)+"=?");W||n||(c+=(/\?/.test(c)?"&":"?")+"_"+(new Date).getTime()+"=");c=c.replace(/=\?(&|$)/,"="+F+"$1");n&&(q=t[c])?q.s?g(q.s[0]):s(q):(J[F]=V,b=d(K)[0],b.id=L+X++,G&&(b[Y]=G),M&&11.6>M.version()?(h=d(K)[0]).text="document.getElementById('"+b.id+"')."+ 27 | y+"()":b[N]=N,Z&&(b.htmlFor=b.id,b.event=z),b[O]=b[y]=b[P]=function(a){if(!b[Q]||!/i/.test(b[Q])){try{b[z]&&b[z]()}catch(c){}a=r;r=0;a?g(a[0]):s(R)}},b.src=c,m=function(a){w&&clearTimeout(w);b[P]=b[O]=b[y]=null;k[S](b);h&&k[S](h)},k[T](b,p=k.firstChild),h&&k[T](h,p),w=0").html("\x3c!--[if IE]> '%kernel.project_dir%/public' 50 | ... 51 | ]; 52 | 53 | } 54 | ``` 55 | 56 | Do not forget to configure your services.yml 57 | 58 | ```yml 59 | services: 60 | custom_service: 61 | class: AppBundle\Service\CustomService 62 | ``` 63 | 64 | >Browse the `/manager/?conf=perso` URL to get access to this File Manager 65 | 66 | #### Extra URL parameters injections 67 | 68 | You can inject `extra` parameters in your service via URL: 69 | 70 | Example: 71 | 72 | path('file_manager', {module:'tiny', type:'image', conf:'perso', extra: {'user':'miamolex', 'allow': true}}) 73 | 74 | 75 | Here, I add 2 extra parameters, which I recover in my Service: 76 | 77 | ```php 78 | public function getConf($extra = []) { 79 | 80 | $user = $extra['user'] # miamolex 81 | $allow = $extra['allow'] # true 82 | 83 | ... 84 | ``` 85 | With this `service` configuration, you can define (for example) a folder for each user 86 | 87 | ```php 88 | tokenStorage = $tokenStorage; 113 | } 114 | 115 | 116 | public function getConf($extra = []) 117 | { 118 | $folder = 'user/' . $this->tokenStorage->getToken()->getUser(); 119 | $fs = new Filesystem(); 120 | if (!$fs->exists($folder)) { 121 | $fs->mkdir($folder); 122 | } 123 | return ['dir' => $folder]; 124 | 125 | } 126 | 127 | } 128 | ``` 129 | 130 | with 131 | 132 | ```yml 133 | custom_service: 134 | public: true 135 | class: AppBundle\Service\CustomService 136 | arguments: ['@security.token_storage'] 137 | ``` 138 | 139 | 140 | ## `upload` Exhaustive options (file upload widget) 141 | 142 | You can include all the options of `jQuery File Upload` in `return` (to make it easier than .yml): 143 | 144 | [Exhaustive options](https://github.com/blueimp/jQuery-File-Upload/blob/master/server/php/UploadHandler.php) 145 | 146 | Example 147 | 148 | ```php 149 | '%kernel.project_dir%/public/perso', 161 | 'upload' => [ 162 | 'image_versions' => [ 163 | 'medium' => [ 164 | 'auto_orient' => true, 165 | 'max_width' => 10 166 | ] 167 | ], 168 | ] 169 | ]; 170 | } 171 | } 172 | ``` 173 | 174 | ------------------------------------------------------------------------------- 175 | 176 | [Chapter 3 - Access to the File Manager](3-access-file-manager.md) → 177 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/js/load-image.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Load Image 3 | * https://github.com/blueimp/JavaScript-Load-Image 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, URL, webkitURL, FileReader */ 13 | 14 | ;(function ($) { 15 | 'use strict' 16 | 17 | // Loads an image for a given File object. 18 | // Invokes the callback with an img or optional canvas 19 | // element (if supported by the browser) as parameter: 20 | function loadImage (file, callback, options) { 21 | var img = document.createElement('img') 22 | var url 23 | img.onerror = function (event) { 24 | return loadImage.onerror(img, event, file, callback, options) 25 | } 26 | img.onload = function (event) { 27 | return loadImage.onload(img, event, file, callback, options) 28 | } 29 | if (typeof file === 'string') { 30 | loadImage.fetchBlob(file, function (blob) { 31 | if (blob) { 32 | file = blob 33 | url = loadImage.createObjectURL(file) 34 | } else { 35 | url = file 36 | if (options && options.crossOrigin) { 37 | img.crossOrigin = options.crossOrigin 38 | } 39 | } 40 | img.src = url 41 | }, options) 42 | return img 43 | } else if (loadImage.isInstanceOf('Blob', file) || 44 | // Files are also Blob instances, but some browsers 45 | // (Firefox 3.6) support the File API but not Blobs: 46 | loadImage.isInstanceOf('File', file)) { 47 | url = img._objectURL = loadImage.createObjectURL(file) 48 | if (url) { 49 | img.src = url 50 | return img 51 | } 52 | return loadImage.readFile(file, function (e) { 53 | var target = e.target 54 | if (target && target.result) { 55 | img.src = target.result 56 | } else if (callback) { 57 | callback(e) 58 | } 59 | }) 60 | } 61 | } 62 | // The check for URL.revokeObjectURL fixes an issue with Opera 12, 63 | // which provides URL.createObjectURL but doesn't properly implement it: 64 | var urlAPI = (window.createObjectURL && window) || 65 | (window.URL && URL.revokeObjectURL && URL) || 66 | (window.webkitURL && webkitURL) 67 | 68 | function revokeHelper (img, options) { 69 | if (img._objectURL && !(options && options.noRevoke)) { 70 | loadImage.revokeObjectURL(img._objectURL) 71 | delete img._objectURL 72 | } 73 | } 74 | 75 | // If the callback given to this function returns a blob, it is used as image 76 | // source instead of the original url and overrides the file argument used in 77 | // the onload and onerror event callbacks: 78 | loadImage.fetchBlob = function (url, callback, options) { 79 | callback() 80 | } 81 | 82 | loadImage.isInstanceOf = function (type, obj) { 83 | // Cross-frame instanceof check 84 | return Object.prototype.toString.call(obj) === '[object ' + type + ']' 85 | } 86 | 87 | loadImage.transform = function (img, options, callback, file, data) { 88 | callback(img, data) 89 | } 90 | 91 | loadImage.onerror = function (img, event, file, callback, options) { 92 | revokeHelper(img, options) 93 | if (callback) { 94 | callback.call(img, event) 95 | } 96 | } 97 | 98 | loadImage.onload = function (img, event, file, callback, options) { 99 | revokeHelper(img, options) 100 | if (callback) { 101 | loadImage.transform(img, options, callback, file, {}) 102 | } 103 | } 104 | 105 | loadImage.createObjectURL = function (file) { 106 | return urlAPI ? urlAPI.createObjectURL(file) : false 107 | } 108 | 109 | loadImage.revokeObjectURL = function (url) { 110 | return urlAPI ? urlAPI.revokeObjectURL(url) : false 111 | } 112 | 113 | // Loads a given File object via FileReader interface, 114 | // invokes the callback with the event object (load or error). 115 | // The result can be read via event.target.result: 116 | loadImage.readFile = function (file, callback, method) { 117 | if (window.FileReader) { 118 | var fileReader = new FileReader() 119 | fileReader.onload = fileReader.onerror = callback 120 | method = method || 'readAsDataURL' 121 | if (fileReader[method]) { 122 | fileReader[method](file) 123 | return fileReader 124 | } 125 | } 126 | return false 127 | } 128 | 129 | if (typeof define === 'function' && define.amd) { 130 | define(function () { 131 | return loadImage 132 | }) 133 | } else if (typeof module === 'object' && module.exports) { 134 | module.exports = loadImage 135 | } else { 136 | $.loadImage = loadImage 137 | } 138 | }(window)) 139 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/jquery.fileupload-validate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Validation Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, require, window */ 13 | 14 | ;(function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define([ 19 | 'jquery', 20 | './jquery.fileupload-process' 21 | ], factory); 22 | } else if (typeof exports === 'object') { 23 | // Node/CommonJS: 24 | factory( 25 | require('jquery'), 26 | require('./jquery.fileupload-process') 27 | ); 28 | } else { 29 | // Browser globals: 30 | factory( 31 | window.jQuery 32 | ); 33 | } 34 | }(function ($) { 35 | 'use strict'; 36 | 37 | // Append to the default processQueue: 38 | $.blueimp.fileupload.prototype.options.processQueue.push( 39 | { 40 | action: 'validate', 41 | // Always trigger this action, 42 | // even if the previous action was rejected: 43 | always: true, 44 | // Options taken from the global options map: 45 | acceptFileTypes: '@', 46 | maxFileSize: '@', 47 | minFileSize: '@', 48 | maxNumberOfFiles: '@', 49 | disabled: '@disableValidation' 50 | } 51 | ); 52 | 53 | // The File Upload Validation plugin extends the fileupload widget 54 | // with file validation functionality: 55 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 56 | 57 | options: { 58 | /* 59 | // The regular expression for allowed file types, matches 60 | // against either file type or file name: 61 | acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, 62 | // The maximum allowed file size in bytes: 63 | maxFileSize: 10000000, // 10 MB 64 | // The minimum allowed file size in bytes: 65 | minFileSize: undefined, // No minimal file size 66 | // The limit of files to be uploaded: 67 | maxNumberOfFiles: 10, 68 | */ 69 | 70 | // Function returning the current number of files, 71 | // has to be overriden for maxNumberOfFiles validation: 72 | getNumberOfFiles: $.noop, 73 | 74 | // Error and info messages: 75 | messages: { 76 | maxNumberOfFiles: 'Maximum number of files exceeded', 77 | acceptFileTypes: 'File type not allowed', 78 | maxFileSize: 'File is too large', 79 | minFileSize: 'File is too small' 80 | } 81 | }, 82 | 83 | processActions: { 84 | 85 | validate: function (data, options) { 86 | if (options.disabled) { 87 | return data; 88 | } 89 | var dfd = $.Deferred(), 90 | settings = this.options, 91 | file = data.files[data.index], 92 | fileSize; 93 | if (options.minFileSize || options.maxFileSize) { 94 | fileSize = file.size; 95 | } 96 | if ($.type(options.maxNumberOfFiles) === 'number' && 97 | (settings.getNumberOfFiles() || 0) + data.files.length > 98 | options.maxNumberOfFiles) { 99 | file.error = settings.i18n('maxNumberOfFiles'); 100 | } else if (options.acceptFileTypes && 101 | !(options.acceptFileTypes.test(file.type) || 102 | options.acceptFileTypes.test(file.name))) { 103 | file.error = settings.i18n('acceptFileTypes'); 104 | } else if (fileSize > options.maxFileSize) { 105 | file.error = settings.i18n('maxFileSize'); 106 | } else if ($.type(fileSize) === 'number' && 107 | fileSize < options.minFileSize) { 108 | file.error = settings.i18n('minFileSize'); 109 | } else { 110 | delete file.error; 111 | } 112 | if (file.error || data.files.error) { 113 | data.files.error = true; 114 | dfd.rejectWith(this, [data]); 115 | } else { 116 | dfd.resolveWith(this, [data]); 117 | } 118 | return dfd.promise(); 119 | } 120 | 121 | } 122 | 123 | }); 124 | 125 | })); 126 | -------------------------------------------------------------------------------- /Resources/public/libs/jquery-lazy/jquery.lazy.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery & Zepto Lazy v1.7.10 - http://jquery.eisbehr.de/lazy - MIT&GPL-2.0 license - Copyright 2012-2018 Daniel 'Eisbehr' Kern */ 2 | !function(t,e){"use strict";function r(r,a,i,u,l){function f(){L=t.devicePixelRatio>1,i=c(i),a.delay>=0&&setTimeout(function(){s(!0)},a.delay),(a.delay<0||a.combined)&&(u.e=v(a.throttle,function(t){"resize"===t.type&&(w=B=-1),s(t.all)}),u.a=function(t){t=c(t),i.push.apply(i,t)},u.g=function(){return i=n(i).filter(function(){return!n(this).data(a.loadedName)})},u.f=function(t){for(var e=0;ee.top&&-ne.left&&-n=0?w:w=n(t).width()}function h(){return B>=0?B:B=n(t).height()}function m(t){return t.tagName.toLowerCase()}function b(t,e){if(e){var r=t.split(",");t="";for(var a=0,n=r.length;at||!a.enableThrottle||u?l():n=setTimeout(l,t-f)}}function p(){--z,i.length||z||y("onFinishedAll")}function y(t,e,n){return!!(t=a[t])&&(t.apply(r,[].slice.call(arguments,1)),!0)}var z=0,w=-1,B=-1,L=!1,T="afterLoad",D="load",I="error",N="img",E="src",F="srcset",C="sizes",O="background-image";"event"===a.bind||o?f():n(t).on(D+"."+l,f)}function a(a,o){var u=this,l=n.extend({},u.config,o),f={},c=l.name+"-"+ ++i;return u.config=function(t,r){return r===e?l[t]:(l[t]=r,u)},u.addItems=function(t){return f.a&&f.a("string"===n.type(t)?n(t):t),u},u.getItems=function(){return f.g?f.g():{}},u.update=function(t){return f.e&&f.e({},!t),u},u.force=function(t){return f.f&&f.f("string"===n.type(t)?n(t):t),u},u.loadAll=function(){return f.e&&f.e({all:!0},!0),u},u.destroy=function(){return n(l.appendScroll).off("."+c,f.e),n(t).off("."+c),f={},e},r(u,l,a,f,c),l.chainable?a:u}var n=t.jQuery||t.Zepto,i=0,o=!1;n.fn.Lazy=n.fn.lazy=function(t){return new a(this,t)},n.Lazy=n.lazy=function(t,r,i){if(n.isFunction(r)&&(i=r,r=[]),n.isFunction(i)){t=n.isArray(t)?t:[t],r=n.isArray(r)?r:[r];for(var o=a.prototype.config,u=o._f||(o._f={}),l=0,f=t.length;l') 29 | var cell = $('') 30 | var prop 31 | if (thumbnail) { 32 | thumbNode.empty() 33 | loadImage(thumbnail, function (img) { 34 | thumbNode.append(img).show() 35 | }, {orientation: exif.get('Orientation')}) 36 | } 37 | for (prop in tags) { 38 | if (tags.hasOwnProperty(prop)) { 39 | table.append( 40 | row.clone() 41 | .append(cell.clone().text(prop)) 42 | .append(cell.clone().text(tags[prop])) 43 | ) 44 | } 45 | } 46 | exifNode.show() 47 | } 48 | 49 | function updateResults (img, data) { 50 | var content 51 | if (!(img.src || img instanceof HTMLCanvasElement)) { 52 | content = $('Loading image file failed') 53 | } else { 54 | content = $('').append(img) 55 | .attr('download', currentFile.name) 56 | .attr('href', img.src || img.toDataURL()) 57 | } 58 | result.children().replaceWith(content) 59 | if (img.getContext) { 60 | actionsNode.show() 61 | } 62 | if (data && data.exif) { 63 | displayExifData(data.exif) 64 | } 65 | } 66 | 67 | function displayImage (file, options) { 68 | currentFile = file 69 | if (!loadImage( 70 | file, 71 | updateResults, 72 | options 73 | )) { 74 | result.children().replaceWith( 75 | $('' + 76 | 'Your browser does not support the URL or FileReader API.' + 77 | '') 78 | ) 79 | } 80 | } 81 | 82 | function dropChangeHandler (e) { 83 | e.preventDefault() 84 | e = e.originalEvent 85 | var target = e.dataTransfer || e.target 86 | var file = target && target.files && target.files[0] 87 | var options = { 88 | maxWidth: result.width(), 89 | canvas: true, 90 | pixelRatio: window.devicePixelRatio, 91 | downsamplingRatio: 0.5, 92 | orientation: true 93 | } 94 | if (!file) { 95 | return 96 | } 97 | exifNode.hide() 98 | thumbNode.hide() 99 | displayImage(file, options) 100 | } 101 | 102 | // Hide URL/FileReader API requirement message in capable browsers: 103 | if (window.createObjectURL || window.URL || window.webkitURL || 104 | window.FileReader) { 105 | result.children().hide() 106 | } 107 | 108 | $(document) 109 | .on('dragover', function (e) { 110 | e.preventDefault() 111 | e = e.originalEvent 112 | e.dataTransfer.dropEffect = 'copy' 113 | }) 114 | .on('drop', dropChangeHandler) 115 | 116 | $('#file-input') 117 | .on('change', dropChangeHandler) 118 | 119 | $('#edit') 120 | .on('click', function (event) { 121 | event.preventDefault() 122 | var imgNode = result.find('img, canvas') 123 | var img = imgNode[0] 124 | var pixelRatio = window.devicePixelRatio || 1 125 | imgNode.Jcrop({ 126 | setSelect: [ 127 | 40, 128 | 40, 129 | (img.width / pixelRatio) - 40, 130 | (img.height / pixelRatio) - 40 131 | ], 132 | onSelect: function (coords) { 133 | coordinates = coords 134 | }, 135 | onRelease: function () { 136 | coordinates = null 137 | } 138 | }).parent().on('click', function (event) { 139 | event.preventDefault() 140 | }) 141 | }) 142 | 143 | $('#crop') 144 | .on('click', function (event) { 145 | event.preventDefault() 146 | var img = result.find('img, canvas')[0] 147 | var pixelRatio = window.devicePixelRatio || 1 148 | if (img && coordinates) { 149 | updateResults(loadImage.scale(img, { 150 | left: coordinates.x * pixelRatio, 151 | top: coordinates.y * pixelRatio, 152 | sourceWidth: coordinates.w * pixelRatio, 153 | sourceHeight: coordinates.h * pixelRatio, 154 | minWidth: result.width(), 155 | maxWidth: result.width(), 156 | pixelRatio: pixelRatio, 157 | downsamplingRatio: 0.5 158 | })) 159 | coordinates = null 160 | } 161 | }) 162 | }) 163 | -------------------------------------------------------------------------------- /Resources/doc/tutorials/integrate-tinymce.md: -------------------------------------------------------------------------------- 1 | How to integrate FileManagerBundle into TinyMCE 2 | =============================================== 3 | 4 | Tinymce has [`file_browser_callback`](https://www.tinymce.com/docs/configure/file-image-upload/) option who enables you to add your own file or image browser to TinyMCE. 5 | 6 | 7 | ### Step 1 - Create a `tiny` conf 8 | 9 | ```yml 10 | artgris_file_manager: 11 | conf: 12 | tiny: 13 | dir: "%kernel.project_dir%/public/uploads" 14 | ``` 15 | 16 | ### Step 2 - Add TinyMCE textarea 17 | ```html 18 | 19 | ``` 20 | 21 | ### Step 3 - Init TinyMCE with `file_browser_callback: myFileBrowser,` option : 22 | 23 | TinyMCE v4 24 | ```javascript 25 | 26 | 64 | ``` 65 | TinyMCE v5 66 | ```javascript 67 | 68 | 119 | ``` -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/cors/jquery.postmessage-transport.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery postMessage Transport Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2011, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define, require, window, document */ 13 | 14 | ;(function (factory) { 15 | 'use strict'; 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['jquery'], factory); 19 | } else if (typeof exports === 'object') { 20 | // Node/CommonJS: 21 | factory(require('jquery')); 22 | } else { 23 | // Browser globals: 24 | factory(window.jQuery); 25 | } 26 | }(function ($) { 27 | 'use strict'; 28 | 29 | var counter = 0, 30 | names = [ 31 | 'accepts', 32 | 'cache', 33 | 'contents', 34 | 'contentType', 35 | 'crossDomain', 36 | 'data', 37 | 'dataType', 38 | 'headers', 39 | 'ifModified', 40 | 'mimeType', 41 | 'password', 42 | 'processData', 43 | 'timeout', 44 | 'traditional', 45 | 'type', 46 | 'url', 47 | 'username' 48 | ], 49 | convert = function (p) { 50 | return p; 51 | }; 52 | 53 | $.ajaxSetup({ 54 | converters: { 55 | 'postmessage text': convert, 56 | 'postmessage json': convert, 57 | 'postmessage html': convert 58 | } 59 | }); 60 | 61 | $.ajaxTransport('postmessage', function (options) { 62 | if (options.postMessage && window.postMessage) { 63 | var iframe, 64 | loc = $('').prop('href', options.postMessage)[0], 65 | target = loc.protocol + '//' + loc.host, 66 | xhrUpload = options.xhr().upload; 67 | // IE always includes the port for the host property of a link 68 | // element, but not in the location.host or origin property for the 69 | // default http port 80 and https port 443, so we strip it: 70 | if (/^(http:\/\/.+:80)|(https:\/\/.+:443)$/.test(target)) { 71 | target = target.replace(/:(80|443)$/, ''); 72 | } 73 | return { 74 | send: function (_, completeCallback) { 75 | counter += 1; 76 | var message = { 77 | id: 'postmessage-transport-' + counter 78 | }, 79 | eventName = 'message.' + message.id; 80 | iframe = $( 81 | '' 84 | ).bind('load', function () { 85 | $.each(names, function (i, name) { 86 | message[name] = options[name]; 87 | }); 88 | message.dataType = message.dataType.replace('postmessage ', ''); 89 | $(window).bind(eventName, function (e) { 90 | e = e.originalEvent; 91 | var data = e.data, 92 | ev; 93 | if (e.origin === target && data.id === message.id) { 94 | if (data.type === 'progress') { 95 | ev = document.createEvent('Event'); 96 | ev.initEvent(data.type, false, true); 97 | $.extend(ev, data); 98 | xhrUpload.dispatchEvent(ev); 99 | } else { 100 | completeCallback( 101 | data.status, 102 | data.statusText, 103 | {postmessage: data.result}, 104 | data.headers 105 | ); 106 | iframe.remove(); 107 | $(window).unbind(eventName); 108 | } 109 | } 110 | }); 111 | iframe[0].contentWindow.postMessage( 112 | message, 113 | target 114 | ); 115 | }).appendTo(document.body); 116 | }, 117 | abort: function () { 118 | if (iframe) { 119 | iframe.remove(); 120 | } 121 | } 122 | }; 123 | } 124 | }); 125 | 126 | })); 127 | -------------------------------------------------------------------------------- /Resources/views/views/_thumbnail.html.twig: -------------------------------------------------------------------------------- 1 | 89 | -------------------------------------------------------------------------------- /Resources/public/libs/jQuery-contextMenu/dist/jquery.ui.position.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2016-09-16 2 | * http://jqueryui.com 3 | * Includes: position.js 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 | 6 | (function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1",function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,l=/top|center|bottom/,h=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};h>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),l.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,l=n-r,h=r+e.collisionWidth-a-n;e.collisionWidth>a?l>0&&0>=h?(i=t.left+l+e.collisionWidth-a-n,t.left+=l-i):t.left=h>0&&0>=l?n:l>h?n+a-e.collisionWidth:n:l>0?t.left+=l:h>0?t.left-=h:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,l=n-r,h=r+e.collisionHeight-a-n;e.collisionHeight>a?l>0&&0>=h?(i=t.top+l+e.collisionHeight-a-n,t.top+=l-i):t.top=h>0&&0>=l?n:l>h?n+a-e.collisionHeight:n:l>0?t.top+=l:h>0?t.top-=h:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,l=n.isWindow?n.scrollLeft:n.offset.left,h=t.left-e.collisionPosition.marginLeft,c=h-l,u=h+e.collisionWidth-r-l,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-l,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,l=n.isWindow?n.scrollTop:n.offset.top,h=t.top-e.collisionPosition.marginTop,c=h-l,u=h+e.collisionHeight-r-l,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-l,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position}); -------------------------------------------------------------------------------- /Resources/public/libs/jQuery-contextMenu/dist/jquery.contextMenu.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | * jQuery contextMenu - Plugin for simple contextMenu handling 3 | * 4 | * Version: v2.8.0 5 | * 6 | * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) 7 | * Web: http://swisnl.github.io/jQuery-contextMenu/ 8 | * 9 | * Copyright (c) 2011-2019 SWIS BV and contributors 10 | * 11 | * Licensed under 12 | * MIT License http://www.opensource.org/licenses/mit-license 13 | * 14 | * Date: 2019-01-16T15:45:48.418Z 15 | */@-webkit-keyframes cm-spin{0%{-webkit-transform:translateY(-50%) rotate(0);transform:translateY(-50%) rotate(0)}100%{-webkit-transform:translateY(-50%) rotate(359deg);transform:translateY(-50%) rotate(359deg)}}@-o-keyframes cm-spin{0%{-webkit-transform:translateY(-50%) rotate(0);-o-transform:translateY(-50%) rotate(0);transform:translateY(-50%) rotate(0)}100%{-webkit-transform:translateY(-50%) rotate(359deg);-o-transform:translateY(-50%) rotate(359deg);transform:translateY(-50%) rotate(359deg)}}@keyframes cm-spin{0%{-webkit-transform:translateY(-50%) rotate(0);-o-transform:translateY(-50%) rotate(0);transform:translateY(-50%) rotate(0)}100%{-webkit-transform:translateY(-50%) rotate(359deg);-o-transform:translateY(-50%) rotate(359deg);transform:translateY(-50%) rotate(359deg)}}@font-face{font-family:context-menu-icons;font-style:normal;font-weight:400;src:url(font/context-menu-icons.eot?2lkho);src:url(font/context-menu-icons.eot?2lkho#iefix) format("embedded-opentype"),url(font/context-menu-icons.woff2?2lkho) format("woff2"),url(font/context-menu-icons.woff?2lkho) format("woff"),url(font/context-menu-icons.ttf?2lkho) format("truetype")}.context-menu-icon-add:before{content:"\EA01"}.context-menu-icon-copy:before{content:"\EA02"}.context-menu-icon-cut:before{content:"\EA03"}.context-menu-icon-delete:before{content:"\EA04"}.context-menu-icon-edit:before{content:"\EA05"}.context-menu-icon-loading:before{content:"\EA06"}.context-menu-icon-paste:before{content:"\EA07"}.context-menu-icon-quit:before{content:"\EA08"}.context-menu-icon::before{position:absolute;top:50%;left:0;width:2em;font-family:context-menu-icons;font-size:1em;font-style:normal;font-weight:400;line-height:1;color:#2980b9;text-align:center;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);-o-transform:translateY(-50%);transform:translateY(-50%);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.context-menu-icon.context-menu-hover:before{color:#fff}.context-menu-icon.context-menu-disabled::before{color:#bbb}.context-menu-icon.context-menu-icon-loading:before{-webkit-animation:cm-spin 2s infinite;-o-animation:cm-spin 2s infinite;animation:cm-spin 2s infinite}.context-menu-icon.context-menu-icon--fa{display:list-item;font-family:inherit;line-height:inherit}.context-menu-icon.context-menu-icon--fa::before{position:absolute;top:50%;left:0;width:2em;font-family:FontAwesome;font-size:1em;font-style:normal;font-weight:400;line-height:1;color:#2980b9;text-align:center;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);-o-transform:translateY(-50%);transform:translateY(-50%);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.context-menu-icon.context-menu-icon--fa.context-menu-hover:before{color:#fff}.context-menu-icon.context-menu-icon--fa.context-menu-disabled::before{color:#bbb}.context-menu-icon.context-menu-icon--fa5{display:list-item;font-family:inherit;line-height:inherit}.context-menu-icon.context-menu-icon--fa5 i,.context-menu-icon.context-menu-icon--fa5 svg{position:absolute;top:.3em;left:.5em;color:#2980b9}.context-menu-icon.context-menu-icon--fa5.context-menu-hover>i,.context-menu-icon.context-menu-icon--fa5.context-menu-hover>svg{color:#fff}.context-menu-icon.context-menu-icon--fa5.context-menu-disabled i,.context-menu-icon.context-menu-icon--fa5.context-menu-disabled svg{color:#bbb}.context-menu-list{position:absolute;display:inline-block;min-width:13em;max-width:26em;padding:.25em 0;margin:.3em;font-family:inherit;font-size:inherit;list-style-type:none;background:#fff;border:1px solid #bebebe;border-radius:.2em;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.5);box-shadow:0 2px 5px rgba(0,0,0,.5)}.context-menu-item{position:relative;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;padding:.2em 2em;color:#2f2f2f;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff}.context-menu-separator{padding:0;margin:.35em 0;border-bottom:1px solid #e6e6e6}.context-menu-item>label>input,.context-menu-item>label>textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.context-menu-item.context-menu-hover{color:#fff;cursor:pointer;background-color:#2980b9}.context-menu-item.context-menu-disabled{color:#bbb;cursor:default;background-color:#fff}.context-menu-input.context-menu-hover{color:#2f2f2f;cursor:default}.context-menu-submenu:after{position:absolute;top:50%;right:.5em;z-index:1;width:0;height:0;content:'';border-color:transparent transparent transparent #2f2f2f;border-style:solid;border-width:.25em 0 .25em .25em;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);-o-transform:translateY(-50%);transform:translateY(-50%)}.context-menu-item.context-menu-input{padding:.3em .6em}.context-menu-input>label>*{vertical-align:top}.context-menu-input>label>input[type=checkbox],.context-menu-input>label>input[type=radio]{position:relative;top:.12em;margin-right:.4em}.context-menu-input>label{margin:0}.context-menu-input>label,.context-menu-input>label>input[type=text],.context-menu-input>label>select,.context-menu-input>label>textarea{display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.context-menu-input>label>textarea{height:7em}.context-menu-item>.context-menu-list{top:.3em;right:-.3em;display:none}.context-menu-item.context-menu-visible>.context-menu-list{display:block}.context-menu-accesskey{text-decoration:underline} 16 | /*# sourceMappingURL=jquery.contextMenu.min.css.map */ 17 | -------------------------------------------------------------------------------- /Service/FileTypeService.php: -------------------------------------------------------------------------------- 1 | '22', 13 | FileManager::VIEW_THUMBNAIL => '100', 14 | ]; 15 | 16 | /** 17 | * FileTypeService constructor. 18 | */ 19 | public function __construct(private RouterInterface $router, private Environment $twig) { 20 | } 21 | 22 | public function preview(FileManager $fileManager, SplFileInfo $file) { 23 | 24 | if ($fileManager->getImagePath()) { 25 | $filePath = $fileManager->getImagePath().rawurlencode($file->getFilename()); 26 | } else { 27 | $filePath = $this->router->generate( 28 | 'file_manager_file', 29 | array_merge($fileManager->getQueryParameters(), ['fileName' => $file->getFilename()]) 30 | ); 31 | } 32 | $extension = $file->getExtension(); 33 | $type = $file->getType(); 34 | if ('file' === $type) { 35 | $size = $this::IMAGE_SIZE[$fileManager->getView()]; 36 | 37 | return $this->fileIcon($filePath, $extension, $size, true, $fileManager->getConfigurationParameter('twig_extension'), $fileManager->getConfigurationParameter('cachebreaker')); 38 | } 39 | if ('dir' === $type) { 40 | 41 | $href = $this->router->generate( 42 | 'file_manager', array_merge( 43 | $fileManager->getQueryParameters(), 44 | ['route' => $fileManager->getRoute().'/'.$file->getFilename()] 45 | ) 46 | ); 47 | 48 | return [ 49 | 'path' => $filePath, 50 | 'html' => "", 51 | 'folder' => ''.$file->getFilename().'', 52 | ]; 53 | } 54 | } 55 | 56 | public function accept($type): bool|string { 57 | switch ($type) { 58 | case 'image': 59 | $accept = 'image/*'; 60 | break; 61 | case 'media': 62 | $accept = 'video/*'; 63 | break; 64 | default: 65 | return false; 66 | } 67 | 68 | return $accept; 69 | } 70 | 71 | public function fileIcon(string $filePath,?string $extension = null, ?int $size = 75, ?bool $lazy = false, ?string $twigExtension = null, ?bool $cachebreaker = null): array { 72 | 73 | $imageTemplate = null; 74 | 75 | if (null === $extension) { 76 | $filePathTmp = strtok($filePath, '?'); 77 | $extension = pathinfo($filePathTmp, PATHINFO_EXTENSION); 78 | } 79 | switch (true) { 80 | case $this->isYoutubeVideo($filePath): 81 | case preg_match('/(mp4|ogg|webm|avi|wmv|mov)$/i', $extension): 82 | $fa = 'far fa-file-video'; 83 | break; 84 | case preg_match('/(mp3|wav)$/i', $extension): 85 | $fa = 'far fa-file-audio'; 86 | break; 87 | case preg_match('/(gif|png|jpe?g|svg|webp)$/i', $extension): 88 | 89 | $fileName = $filePath; 90 | if ($cachebreaker) { 91 | $query = parse_url($filePath, PHP_URL_QUERY); 92 | $time = 'time='.time(); 93 | $fileName = $query ? $filePath.'&'.$time : $filePath.'?'.$time; 94 | } 95 | 96 | if ($twigExtension) { 97 | $imageTemplate = str_replace('$IMAGE$', 'file_path', $twigExtension); 98 | } 99 | 100 | $html = $this->twig->render('@ArtgrisFileManager/views/preview.html.twig', [ 101 | 'filename' => $fileName, 102 | 'size' => $size, 103 | 'lazy' => $lazy, 104 | 'twig_extension' => $twigExtension, 105 | 'image_template' => $imageTemplate, 106 | 'file_path' => $filePath, 107 | 108 | ]); 109 | 110 | return [ 111 | 'path' => $filePath, 112 | 'html' => $html, 113 | 'image' => true, 114 | ]; 115 | case preg_match('/(pdf)$/i', $extension): 116 | $fa = 'far fa-file-pdf'; 117 | break; 118 | case preg_match('/(docx?)$/i', $extension): 119 | $fa = 'far fa-file-word'; 120 | break; 121 | case preg_match('/(xlsx?|csv)$/i', $extension): 122 | $fa = 'far fa-file-excel'; 123 | break; 124 | case preg_match('/(pptx?)$/i', $extension): 125 | $fa = 'far fa-file-powerpoint'; 126 | break; 127 | case preg_match('/(zip|rar|gz)$/i', $extension): 128 | $fa = 'far fa-file-archive'; 129 | break; 130 | case filter_var($filePath, FILTER_VALIDATE_URL): 131 | $fa = 'fab fa-internet-explorer'; 132 | break; 133 | default: 134 | $fa = 'far fa-file'; 135 | } 136 | 137 | return [ 138 | 'path' => $filePath, 139 | 'html' => "", 140 | ]; 141 | } 142 | 143 | public function isYoutubeVideo($url): bool|int { 144 | $rx = '~ 145 | ^(?:https?://)? 146 | (?:www[.])? 147 | (?:youtube[.]com/watch[?]v=|youtu[.]be/) 148 | ([^&]{11}) 149 | ~x'; 150 | 151 | return preg_match($rx, $url, $matches); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/jquery.fileupload-jquery-ui.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload jQuery UI Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | './jquery.fileupload-ui' 22 | ], factory); 23 | } else if (typeof exports === 'object') { 24 | // Node/CommonJS: 25 | factory( 26 | require('jquery'), 27 | require('./jquery.fileupload-ui') 28 | ); 29 | } else { 30 | // Browser globals: 31 | factory(window.jQuery); 32 | } 33 | }(function ($) { 34 | 'use strict'; 35 | 36 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 37 | 38 | options: { 39 | processdone: function (e, data) { 40 | data.context.find('.start').button('enable'); 41 | }, 42 | progress: function (e, data) { 43 | if (data.context) { 44 | data.context.find('.progress').progressbar( 45 | 'option', 46 | 'value', 47 | parseInt(data.loaded / data.total * 100, 10) 48 | ); 49 | } 50 | }, 51 | progressall: function (e, data) { 52 | var $this = $(this); 53 | $this.find('.fileupload-progress') 54 | .find('.progress').progressbar( 55 | 'option', 56 | 'value', 57 | parseInt(data.loaded / data.total * 100, 10) 58 | ).end() 59 | .find('.progress-extended').each(function () { 60 | $(this).html( 61 | ($this.data('blueimp-fileupload') || 62 | $this.data('fileupload')) 63 | ._renderExtendedProgress(data) 64 | ); 65 | }); 66 | } 67 | }, 68 | 69 | _renderUpload: function (func, files) { 70 | var node = this._super(func, files), 71 | showIconText = $(window).width() > 480; 72 | node.find('.progress').empty().progressbar(); 73 | node.find('.start').button({ 74 | icons: {primary: 'ui-icon-circle-arrow-e'}, 75 | text: showIconText 76 | }); 77 | node.find('.cancel').button({ 78 | icons: {primary: 'ui-icon-cancel'}, 79 | text: showIconText 80 | }); 81 | if (node.hasClass('fade')) { 82 | node.hide(); 83 | } 84 | return node; 85 | }, 86 | 87 | _renderDownload: function (func, files) { 88 | var node = this._super(func, files), 89 | showIconText = $(window).width() > 480; 90 | node.find('.delete').button({ 91 | icons: {primary: 'ui-icon-trash'}, 92 | text: showIconText 93 | }); 94 | if (node.hasClass('fade')) { 95 | node.hide(); 96 | } 97 | return node; 98 | }, 99 | 100 | _startHandler: function (e) { 101 | $(e.currentTarget).button('disable'); 102 | this._super(e); 103 | }, 104 | 105 | _transition: function (node) { 106 | var deferred = $.Deferred(); 107 | if (node.hasClass('fade')) { 108 | node.fadeToggle( 109 | this.options.transitionDuration, 110 | this.options.transitionEasing, 111 | function () { 112 | deferred.resolveWith(node); 113 | } 114 | ); 115 | } else { 116 | deferred.resolveWith(node); 117 | } 118 | return deferred; 119 | }, 120 | 121 | _create: function () { 122 | this._super(); 123 | this.element 124 | .find('.fileupload-buttonbar') 125 | .find('.fileinput-button').each(function () { 126 | var input = $(this).find('input:file').detach(); 127 | $(this) 128 | .button({icons: {primary: 'ui-icon-plusthick'}}) 129 | .append(input); 130 | }) 131 | .end().find('.start') 132 | .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) 133 | .end().find('.cancel') 134 | .button({icons: {primary: 'ui-icon-cancel'}}) 135 | .end().find('.delete') 136 | .button({icons: {primary: 'ui-icon-trash'}}) 137 | .end().find('.progress').progressbar(); 138 | }, 139 | 140 | _destroy: function () { 141 | this.element 142 | .find('.fileupload-buttonbar') 143 | .find('.fileinput-button').each(function () { 144 | var input = $(this).find('input:file').detach(); 145 | $(this) 146 | .button('destroy') 147 | .append(input); 148 | }) 149 | .end().find('.start') 150 | .button('destroy') 151 | .end().find('.cancel') 152 | .button('destroy') 153 | .end().find('.delete') 154 | .button('destroy') 155 | .end().find('.progress').progressbar('destroy'); 156 | this._super(); 157 | } 158 | 159 | }); 160 | 161 | })); 162 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/js/load-image-orientation.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Load Image Orientation 3 | * https://github.com/blueimp/JavaScript-Load-Image 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* global define */ 13 | 14 | ;(function (factory) { 15 | 'use strict' 16 | if (typeof define === 'function' && define.amd) { 17 | // Register as an anonymous AMD module: 18 | define(['./load-image', './load-image-scale', './load-image-meta'], factory) 19 | } else if (typeof module === 'object' && module.exports) { 20 | factory( 21 | require('./load-image'), 22 | require('./load-image-scale'), 23 | require('./load-image-meta') 24 | ) 25 | } else { 26 | // Browser globals: 27 | factory(window.loadImage) 28 | } 29 | }(function (loadImage) { 30 | 'use strict' 31 | 32 | var originalHasCanvasOption = loadImage.hasCanvasOption 33 | var originalHasMetaOption = loadImage.hasMetaOption 34 | var originalTransformCoordinates = loadImage.transformCoordinates 35 | var originalGetTransformedOptions = loadImage.getTransformedOptions 36 | 37 | // Determines if the target image should be a canvas element: 38 | loadImage.hasCanvasOption = function (options) { 39 | return !!options.orientation || 40 | originalHasCanvasOption.call(loadImage, options) 41 | } 42 | 43 | // Determines if meta data should be loaded automatically: 44 | loadImage.hasMetaOption = function (options) { 45 | return options && options.orientation === true || 46 | originalHasMetaOption.call(loadImage, options) 47 | } 48 | 49 | // Transform image orientation based on 50 | // the given EXIF orientation option: 51 | loadImage.transformCoordinates = function (canvas, options) { 52 | originalTransformCoordinates.call(loadImage, canvas, options) 53 | var ctx = canvas.getContext('2d') 54 | var width = canvas.width 55 | var height = canvas.height 56 | var styleWidth = canvas.style.width 57 | var styleHeight = canvas.style.height 58 | var orientation = options.orientation 59 | if (!orientation || orientation > 8) { 60 | return 61 | } 62 | if (orientation > 4) { 63 | canvas.width = height 64 | canvas.height = width 65 | canvas.style.width = styleHeight 66 | canvas.style.height = styleWidth 67 | } 68 | switch (orientation) { 69 | case 2: 70 | // horizontal flip 71 | ctx.translate(width, 0) 72 | ctx.scale(-1, 1) 73 | break 74 | case 3: 75 | // 180° rotate left 76 | ctx.translate(width, height) 77 | ctx.rotate(Math.PI) 78 | break 79 | case 4: 80 | // vertical flip 81 | ctx.translate(0, height) 82 | ctx.scale(1, -1) 83 | break 84 | case 5: 85 | // vertical flip + 90 rotate right 86 | ctx.rotate(0.5 * Math.PI) 87 | ctx.scale(1, -1) 88 | break 89 | case 6: 90 | // 90° rotate right 91 | ctx.rotate(0.5 * Math.PI) 92 | ctx.translate(0, -height) 93 | break 94 | case 7: 95 | // horizontal flip + 90 rotate right 96 | ctx.rotate(0.5 * Math.PI) 97 | ctx.translate(width, -height) 98 | ctx.scale(-1, 1) 99 | break 100 | case 8: 101 | // 90° rotate left 102 | ctx.rotate(-0.5 * Math.PI) 103 | ctx.translate(-width, 0) 104 | break 105 | } 106 | } 107 | 108 | // Transforms coordinate and dimension options 109 | // based on the given orientation option: 110 | loadImage.getTransformedOptions = function (img, opts, data) { 111 | var options = originalGetTransformedOptions.call(loadImage, img, opts) 112 | var orientation = options.orientation 113 | var newOptions 114 | var i 115 | if (orientation === true && data && data.exif) { 116 | orientation = data.exif.get('Orientation') 117 | } 118 | if (!orientation || orientation > 8 || orientation === 1) { 119 | return options 120 | } 121 | newOptions = {} 122 | for (i in options) { 123 | if (options.hasOwnProperty(i)) { 124 | newOptions[i] = options[i] 125 | } 126 | } 127 | newOptions.orientation = orientation 128 | switch (orientation) { 129 | case 2: 130 | // horizontal flip 131 | newOptions.left = options.right 132 | newOptions.right = options.left 133 | break 134 | case 3: 135 | // 180° rotate left 136 | newOptions.left = options.right 137 | newOptions.top = options.bottom 138 | newOptions.right = options.left 139 | newOptions.bottom = options.top 140 | break 141 | case 4: 142 | // vertical flip 143 | newOptions.top = options.bottom 144 | newOptions.bottom = options.top 145 | break 146 | case 5: 147 | // vertical flip + 90 rotate right 148 | newOptions.left = options.top 149 | newOptions.top = options.left 150 | newOptions.right = options.bottom 151 | newOptions.bottom = options.right 152 | break 153 | case 6: 154 | // 90° rotate right 155 | newOptions.left = options.top 156 | newOptions.top = options.right 157 | newOptions.right = options.bottom 158 | newOptions.bottom = options.left 159 | break 160 | case 7: 161 | // horizontal flip + 90 rotate right 162 | newOptions.left = options.bottom 163 | newOptions.top = options.right 164 | newOptions.right = options.top 165 | newOptions.bottom = options.left 166 | break 167 | case 8: 168 | // 90° rotate left 169 | newOptions.left = options.bottom 170 | newOptions.top = options.left 171 | newOptions.right = options.top 172 | newOptions.bottom = options.right 173 | break 174 | } 175 | if (newOptions.orientation > 4) { 176 | newOptions.maxWidth = options.maxHeight 177 | newOptions.maxHeight = options.maxWidth 178 | newOptions.minWidth = options.minHeight 179 | newOptions.minHeight = options.minWidth 180 | newOptions.sourceWidth = options.sourceHeight 181 | newOptions.sourceHeight = options.sourceWidth 182 | } 183 | return newOptions 184 | } 185 | })) 186 | -------------------------------------------------------------------------------- /Resources/public/libs/blueimp-load-image/js/load-image-meta.js: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaScript Load Image Meta 3 | * https://github.com/blueimp/JavaScript-Load-Image 4 | * 5 | * Copyright 2013, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Image meta data handling implementation 9 | * based on the help and contribution of 10 | * Achim Stöhr. 11 | * 12 | * Licensed under the MIT license: 13 | * https://opensource.org/licenses/MIT 14 | */ 15 | 16 | /* global define, Blob */ 17 | 18 | ;(function (factory) { 19 | 'use strict' 20 | if (typeof define === 'function' && define.amd) { 21 | // Register as an anonymous AMD module: 22 | define(['./load-image'], factory) 23 | } else if (typeof module === 'object' && module.exports) { 24 | factory(require('./load-image')) 25 | } else { 26 | // Browser globals: 27 | factory(window.loadImage) 28 | } 29 | }(function (loadImage) { 30 | 'use strict' 31 | 32 | var hasblobSlice = window.Blob && (Blob.prototype.slice || 33 | Blob.prototype.webkitSlice || Blob.prototype.mozSlice) 34 | 35 | loadImage.blobSlice = hasblobSlice && function () { 36 | var slice = this.slice || this.webkitSlice || this.mozSlice 37 | return slice.apply(this, arguments) 38 | } 39 | 40 | loadImage.metaDataParsers = { 41 | jpeg: { 42 | 0xffe1: [] // APP1 marker 43 | } 44 | } 45 | 46 | // Parses image meta data and calls the callback with an object argument 47 | // with the following properties: 48 | // * imageHead: The complete image head as ArrayBuffer (Uint8Array for IE10) 49 | // The options arguments accepts an object and supports the following properties: 50 | // * maxMetaDataSize: Defines the maximum number of bytes to parse. 51 | // * disableImageHead: Disables creating the imageHead property. 52 | loadImage.parseMetaData = function (file, callback, options, data) { 53 | options = options || {} 54 | data = data || {} 55 | var that = this 56 | // 256 KiB should contain all EXIF/ICC/IPTC segments: 57 | var maxMetaDataSize = options.maxMetaDataSize || 262144 58 | var noMetaData = !(window.DataView && file && file.size >= 12 && 59 | file.type === 'image/jpeg' && loadImage.blobSlice) 60 | if (noMetaData || !loadImage.readFile( 61 | loadImage.blobSlice.call(file, 0, maxMetaDataSize), 62 | function (e) { 63 | if (e.target.error) { 64 | // FileReader error 65 | console.log(e.target.error) 66 | callback(data) 67 | return 68 | } 69 | // Note on endianness: 70 | // Since the marker and length bytes in JPEG files are always 71 | // stored in big endian order, we can leave the endian parameter 72 | // of the DataView methods undefined, defaulting to big endian. 73 | var buffer = e.target.result 74 | var dataView = new DataView(buffer) 75 | var offset = 2 76 | var maxOffset = dataView.byteLength - 4 77 | var headLength = offset 78 | var markerBytes 79 | var markerLength 80 | var parsers 81 | var i 82 | // Check for the JPEG marker (0xffd8): 83 | if (dataView.getUint16(0) === 0xffd8) { 84 | while (offset < maxOffset) { 85 | markerBytes = dataView.getUint16(offset) 86 | // Search for APPn (0xffeN) and COM (0xfffe) markers, 87 | // which contain application-specific meta-data like 88 | // Exif, ICC and IPTC data and text comments: 89 | if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || 90 | markerBytes === 0xfffe) { 91 | // The marker bytes (2) are always followed by 92 | // the length bytes (2), indicating the length of the 93 | // marker segment, which includes the length bytes, 94 | // but not the marker bytes, so we add 2: 95 | markerLength = dataView.getUint16(offset + 2) + 2 96 | if (offset + markerLength > dataView.byteLength) { 97 | console.log('Invalid meta data: Invalid segment size.') 98 | break 99 | } 100 | parsers = loadImage.metaDataParsers.jpeg[markerBytes] 101 | if (parsers) { 102 | for (i = 0; i < parsers.length; i += 1) { 103 | parsers[i].call( 104 | that, 105 | dataView, 106 | offset, 107 | markerLength, 108 | data, 109 | options 110 | ) 111 | } 112 | } 113 | offset += markerLength 114 | headLength = offset 115 | } else { 116 | // Not an APPn or COM marker, probably safe to 117 | // assume that this is the end of the meta data 118 | break 119 | } 120 | } 121 | // Meta length must be longer than JPEG marker (2) 122 | // plus APPn marker (2), followed by length bytes (2): 123 | if (!options.disableImageHead && headLength > 6) { 124 | if (buffer.slice) { 125 | data.imageHead = buffer.slice(0, headLength) 126 | } else { 127 | // Workaround for IE10, which does not yet 128 | // support ArrayBuffer.slice: 129 | data.imageHead = new Uint8Array(buffer) 130 | .subarray(0, headLength) 131 | } 132 | } 133 | } else { 134 | console.log('Invalid JPEG file: Missing JPEG marker.') 135 | } 136 | callback(data) 137 | }, 138 | 'readAsArrayBuffer' 139 | )) { 140 | callback(data) 141 | } 142 | } 143 | 144 | // Determines if meta data should be loaded automatically: 145 | loadImage.hasMetaOption = function (options) { 146 | return options && options.meta 147 | } 148 | 149 | var originalTransform = loadImage.transform 150 | loadImage.transform = function (img, options, callback, file, data) { 151 | if (loadImage.hasMetaOption(options)) { 152 | loadImage.parseMetaData(file, function (data) { 153 | originalTransform.call(loadImage, img, options, callback, file, data) 154 | }, options, data) 155 | } else { 156 | originalTransform.apply(loadImage, arguments) 157 | } 158 | } 159 | })) 160 | -------------------------------------------------------------------------------- /Resources/views/views/_list.html.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 35 | 36 | {% for fileEntity in fileArray %} 37 | {% set file = fileEntity.file %} 38 | 39 | 45 | 50 | 55 | 60 | 65 | 70 | 124 | 125 | {% endfor %} 126 | 127 |
15 | {% block select_all %} 16 | 17 | {% endblock %} 18 | 21 | {{ order(fileManager, 'name') }} 22 | {{ 'table.actions'|trans }}
40 | {% block file_checkbox %} 41 | 43 | {% endblock %} 44 | 46 | {% block file_preview %} 47 | {{ fileEntity.preview ? fileEntity.preview.html|raw }} 48 | {% endblock %} 49 | 51 | {% block file_name %} 52 | {{ (fileEntity.preview.folder is defined ? fileEntity.preview.folder|raw : file.fileName) }} 53 | {% endblock %} 54 | 71 | {% block file_action %} 72 | 73 | 84 | 85 | 86 | 99 | 100 | {% if file.type == "file" %} 101 | 105 | 106 | 107 | {% if fileEntity.isImage() %} 108 | 109 | 119 | 120 | {% endif %} 121 | {% endif %} 122 | {% endblock %} 123 |
128 |
-------------------------------------------------------------------------------- /Resources/public/libs/blueimp-file-upload/js/jquery.fileupload-process.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery File Upload Processing Plugin 3 | * https://github.com/blueimp/jQuery-File-Upload 4 | * 5 | * Copyright 2012, Sebastian Tschan 6 | * https://blueimp.net 7 | * 8 | * Licensed under the MIT license: 9 | * https://opensource.org/licenses/MIT 10 | */ 11 | 12 | /* jshint nomen:false */ 13 | /* global define, require, window */ 14 | 15 | ;(function (factory) { 16 | 'use strict'; 17 | if (typeof define === 'function' && define.amd) { 18 | // Register as an anonymous AMD module: 19 | define([ 20 | 'jquery', 21 | './jquery.fileupload' 22 | ], factory); 23 | } else if (typeof exports === 'object') { 24 | // Node/CommonJS: 25 | factory( 26 | require('jquery'), 27 | require('./jquery.fileupload') 28 | ); 29 | } else { 30 | // Browser globals: 31 | factory( 32 | window.jQuery 33 | ); 34 | } 35 | }(function ($) { 36 | 'use strict'; 37 | 38 | var originalAdd = $.blueimp.fileupload.prototype.options.add; 39 | 40 | // The File Upload Processing plugin extends the fileupload widget 41 | // with file processing functionality: 42 | $.widget('blueimp.fileupload', $.blueimp.fileupload, { 43 | 44 | options: { 45 | // The list of processing actions: 46 | processQueue: [ 47 | /* 48 | { 49 | action: 'log', 50 | type: 'debug' 51 | } 52 | */ 53 | ], 54 | add: function (e, data) { 55 | var $this = $(this); 56 | data.process(function () { 57 | return $this.fileupload('process', data); 58 | }); 59 | originalAdd.call(this, e, data); 60 | } 61 | }, 62 | 63 | processActions: { 64 | /* 65 | log: function (data, options) { 66 | console[options.type]( 67 | 'Processing "' + data.files[data.index].name + '"' 68 | ); 69 | } 70 | */ 71 | }, 72 | 73 | _processFile: function (data, originalData) { 74 | var that = this, 75 | dfd = $.Deferred().resolveWith(that, [data]), 76 | chain = dfd.promise(); 77 | this._trigger('process', null, data); 78 | $.each(data.processQueue, function (i, settings) { 79 | var func = function (data) { 80 | if (originalData.errorThrown) { 81 | return $.Deferred() 82 | .rejectWith(that, [originalData]).promise(); 83 | } 84 | return that.processActions[settings.action].call( 85 | that, 86 | data, 87 | settings 88 | ); 89 | }; 90 | chain = chain.then(func, settings.always && func); 91 | }); 92 | chain 93 | .done(function () { 94 | that._trigger('processdone', null, data); 95 | that._trigger('processalways', null, data); 96 | }) 97 | .fail(function () { 98 | that._trigger('processfail', null, data); 99 | that._trigger('processalways', null, data); 100 | }); 101 | return chain; 102 | }, 103 | 104 | // Replaces the settings of each processQueue item that 105 | // are strings starting with an "@", using the remaining 106 | // substring as key for the option map, 107 | // e.g. "@autoUpload" is replaced with options.autoUpload: 108 | _transformProcessQueue: function (options) { 109 | var processQueue = []; 110 | $.each(options.processQueue, function () { 111 | var settings = {}, 112 | action = this.action, 113 | prefix = this.prefix === true ? action : this.prefix; 114 | $.each(this, function (key, value) { 115 | if ($.type(value) === 'string' && 116 | value.charAt(0) === '@') { 117 | settings[key] = options[ 118 | value.slice(1) || (prefix ? prefix + 119 | key.charAt(0).toUpperCase() + key.slice(1) : key) 120 | ]; 121 | } else { 122 | settings[key] = value; 123 | } 124 | 125 | }); 126 | processQueue.push(settings); 127 | }); 128 | options.processQueue = processQueue; 129 | }, 130 | 131 | // Returns the number of files currently in the processsing queue: 132 | processing: function () { 133 | return this._processing; 134 | }, 135 | 136 | // Processes the files given as files property of the data parameter, 137 | // returns a Promise object that allows to bind callbacks: 138 | process: function (data) { 139 | var that = this, 140 | options = $.extend({}, this.options, data); 141 | if (options.processQueue && options.processQueue.length) { 142 | this._transformProcessQueue(options); 143 | if (this._processing === 0) { 144 | this._trigger('processstart'); 145 | } 146 | $.each(data.files, function (index) { 147 | var opts = index ? $.extend({}, options) : options, 148 | func = function () { 149 | if (data.errorThrown) { 150 | return $.Deferred() 151 | .rejectWith(that, [data]).promise(); 152 | } 153 | return that._processFile(opts, data); 154 | }; 155 | opts.index = index; 156 | that._processing += 1; 157 | that._processingQueue = that._processingQueue.then(func, func) 158 | .always(function () { 159 | that._processing -= 1; 160 | if (that._processing === 0) { 161 | that._trigger('processstop'); 162 | } 163 | }); 164 | }); 165 | } 166 | return this._processingQueue; 167 | }, 168 | 169 | _create: function () { 170 | this._super(); 171 | this._processing = 0; 172 | this._processingQueue = $.Deferred().resolveWith(this) 173 | .promise(); 174 | } 175 | 176 | }); 177 | 178 | })); 179 | --------------------------------------------------------------------------------