From 154aab8ab2438e39d2ec66e0d69ea3ad9319fced Mon Sep 17 00:00:00 2001 From: guohongze Date: Tue, 9 Oct 2018 12:28:36 +0800 Subject: [PATCH] new feature file management --- accounts/permission.py | 13 +- adminset/settings.py | 8 + adminset/urls.py | 2 + elfinder/.gitignore | 1 + elfinder/__init__.py | 1 + elfinder/apps.py | 7 + elfinder/conf/__init__.py | 0 elfinder/conf/settings.py | 203 + elfinder/connector.py | 810 + elfinder/exceptions.py | 87 + elfinder/locale/el/LC_MESSAGES/django.mo | Bin 0 -> 1359 bytes elfinder/locale/el/LC_MESSAGES/django.po | 78 + elfinder/locale/zh-Hans/LC_MESSAGES/django.po | 78 + elfinder/locale/zh_Hans/LC_MESSAGES/django.po | 79 + elfinder/locale/zh_cn/LC_MESSAGES/django.po | 78 + elfinder/tests/__init__.py | 2 + elfinder/tests/connector.py | 249 + elfinder/tests/media/files/2bytes.txt | 1 + .../tests/media/files/directory/yawd-logo.png | Bin 0 -> 2865 bytes elfinder/tests/volumes.py | 232 + elfinder/urls.py | 21 + elfinder/utils/__init__.py | 0 elfinder/utils/accesscontrol.py | 28 + elfinder/utils/archivers.py | 41 + elfinder/utils/volumes.py | 52 + elfinder/views.py | 137 + elfinder/volumes/__init__.py | 0 elfinder/volumes/base.py | 2148 ++ elfinder/volumes/filesystem.py | 446 + elfinder/volumes/storage.py | 667 + elfinder/wsgi.py | 16 + install/server/auto_install.sh | 4 + media/files/HammondOrgan.pdf | Bin 0 -> 109218 bytes media/images/hammond_b3.jpg | Bin 0 -> 22654 bytes media/pdf/HammondOrgan.pdf | Bin 0 -> 109218 bytes mfile/__init__.py | 0 mfile/apps.py | 7 + mfile/settings.py | 113 + mfile/urls.py | 33 + mfile/views.py | 8 + static/elfinder/.gitignore | 12 + static/elfinder/css/elfinder.full.css | 3324 ++ static/elfinder/css/elfinder.min.css | 9 + static/elfinder/css/theme.css | 113 + static/elfinder/img/arrows-active.png | Bin 0 -> 173 bytes static/elfinder/img/arrows-normal.png | Bin 0 -> 198 bytes static/elfinder/img/crop.gif | Bin 0 -> 329 bytes static/elfinder/img/dialogs.png | Bin 0 -> 17744 bytes static/elfinder/img/edit_aceeditor.png | Bin 0 -> 532 bytes static/elfinder/img/edit_ckeditor.png | Bin 0 -> 770 bytes static/elfinder/img/edit_codemirror.png | Bin 0 -> 550 bytes static/elfinder/img/edit_creativecloud.png | Bin 0 -> 662 bytes static/elfinder/img/edit_pixlreditor.png | Bin 0 -> 993 bytes static/elfinder/img/edit_pixlrexpress.png | Bin 0 -> 979 bytes static/elfinder/img/edit_simplemde.png | Bin 0 -> 398 bytes static/elfinder/img/edit_tinymce.png | Bin 0 -> 242 bytes static/elfinder/img/icons-big.png | Bin 0 -> 32223 bytes static/elfinder/img/icons-small.png | Bin 0 -> 7235 bytes static/elfinder/img/logo.png | Bin 0 -> 11400 bytes static/elfinder/img/progress.gif | Bin 0 -> 1727 bytes static/elfinder/img/quicklook-bg.png | Bin 0 -> 75 bytes static/elfinder/img/quicklook-icons.png | Bin 0 -> 1902 bytes static/elfinder/img/resize.png | Bin 0 -> 83 bytes static/elfinder/img/spinner-mini.gif | Bin 0 -> 1849 bytes static/elfinder/img/toolbar.png | Bin 0 -> 20943 bytes static/elfinder/img/volume_icon_box.png | Bin 0 -> 621 bytes static/elfinder/img/volume_icon_dropbox.png | Bin 0 -> 419 bytes static/elfinder/img/volume_icon_ftp.png | Bin 0 -> 403 bytes .../elfinder/img/volume_icon_googledrive.png | Bin 0 -> 680 bytes static/elfinder/img/volume_icon_local.png | Bin 0 -> 381 bytes static/elfinder/img/volume_icon_onedrive.png | Bin 0 -> 206 bytes static/elfinder/img/volume_icon_sql.png | Bin 0 -> 589 bytes static/elfinder/img/volume_icon_trash.png | Bin 0 -> 768 bytes static/elfinder/js/elfinder.full.js | 28602 ++++++++++++++++ static/elfinder/js/elfinder.min.js | 22 + static/elfinder/js/extras/editors.default.js | 1040 + .../elfinder/js/extras/editors.default.min.js | 1 + .../js/extras/encoding-japanese.min.js | 35 + .../js/extras/quicklook.googledocs.js | 69 + .../js/extras/quicklook.googledocs.min.js | 1 + static/elfinder/js/i18n/elfinder.LANG.js | 526 + static/elfinder/js/i18n/elfinder.ar.js | 516 + static/elfinder/js/i18n/elfinder.bg.js | 412 + static/elfinder/js/i18n/elfinder.ca.js | 375 + static/elfinder/js/i18n/elfinder.cs.js | 517 + static/elfinder/js/i18n/elfinder.da.js | 374 + static/elfinder/js/i18n/elfinder.de.js | 517 + static/elfinder/js/i18n/elfinder.el.js | 374 + static/elfinder/js/i18n/elfinder.es.js | 433 + static/elfinder/js/i18n/elfinder.fa.js | 374 + static/elfinder/js/i18n/elfinder.fallback.js | 11 + static/elfinder/js/i18n/elfinder.fo.js | 419 + static/elfinder/js/i18n/elfinder.fr.js | 508 + static/elfinder/js/i18n/elfinder.he.js | 375 + static/elfinder/js/i18n/elfinder.hr.js | 434 + static/elfinder/js/i18n/elfinder.hu.js | 447 + static/elfinder/js/i18n/elfinder.id.js | 498 + static/elfinder/js/i18n/elfinder.it.js | 448 + static/elfinder/js/i18n/elfinder.ja.js | 532 + static/elfinder/js/i18n/elfinder.jp.js | 520 + static/elfinder/js/i18n/elfinder.ko.js | 374 + static/elfinder/js/i18n/elfinder.nl.js | 419 + static/elfinder/js/i18n/elfinder.no.js | 374 + static/elfinder/js/i18n/elfinder.pl.js | 517 + static/elfinder/js/i18n/elfinder.pt_BR.js | 438 + static/elfinder/js/i18n/elfinder.ro.js | 417 + static/elfinder/js/i18n/elfinder.ru.js | 521 + static/elfinder/js/i18n/elfinder.si.js | 518 + static/elfinder/js/i18n/elfinder.sk.js | 519 + static/elfinder/js/i18n/elfinder.sl.js | 374 + static/elfinder/js/i18n/elfinder.sr.js | 374 + static/elfinder/js/i18n/elfinder.sv.js | 375 + static/elfinder/js/i18n/elfinder.tr.js | 468 + static/elfinder/js/i18n/elfinder.ug_CN.js | 374 + static/elfinder/js/i18n/elfinder.uk.js | 391 + static/elfinder/js/i18n/elfinder.vi.js | 374 + static/elfinder/js/i18n/elfinder.zh_CN.js | 487 + static/elfinder/js/i18n/elfinder.zh_TW.js | 520 + static/elfinder/js/i18n/help/cs.html.js | 10 + static/elfinder/js/i18n/help/en.html.js | 10 + static/elfinder/js/i18n/help/ja.html.js | 10 + static/elfinder/js/i18n/help/jp.html.js | 10 + static/elfinder/js/i18n/help/ko.html.js | 10 + static/elfinder/js/i18n/help/pl.html.js | 10 + static/elfinder/js/i18n/help/ru.html.js | 10 + static/elfinder/js/i18n/help/sk.html.js | 10 + .../elfinder/js/proxy/elFinderSupportVer1.js | 414 + static/elfinder/sounds/rm.wav | Bin 0 -> 92204 bytes static/plugins/jquery-ui/jquery-ui.css | 1225 + static/plugins/jquery-ui/jquery-ui.js | 16617 +++++++++ static/plugins/jquery-ui/jquery-ui.min.css | 7 + static/plugins/jquery-ui/jquery-ui.min.js | 13 + .../plugins/jquery-ui/jquery-ui.structure.css | 833 + .../jquery-ui/jquery-ui.structure.min.css | 5 + static/plugins/jquery-ui/jquery-ui.theme.css | 410 + .../plugins/jquery-ui/jquery-ui.theme.min.css | 5 + static/plugins/toastr/toastr.css | 228 + static/plugins/toastr/toastr.js.map | 1 + static/plugins/toastr/toastr.min.css | 1 + static/plugins/toastr/toastr.min.js | 2 + templates/base.html | 1 - templates/main-sidebar.html | 2 + templates/mfile/base.html | 297 + templates/mfile/finder.html | 122 + templates/mfile/mfile-header.html | 24 + templates/monitor/test.html | 39 - 146 files changed, 75603 insertions(+), 45 deletions(-) create mode 100644 elfinder/.gitignore create mode 100644 elfinder/__init__.py create mode 100644 elfinder/apps.py create mode 100644 elfinder/conf/__init__.py create mode 100644 elfinder/conf/settings.py create mode 100644 elfinder/connector.py create mode 100644 elfinder/exceptions.py create mode 100644 elfinder/locale/el/LC_MESSAGES/django.mo create mode 100644 elfinder/locale/el/LC_MESSAGES/django.po create mode 100644 elfinder/locale/zh-Hans/LC_MESSAGES/django.po create mode 100644 elfinder/locale/zh_Hans/LC_MESSAGES/django.po create mode 100644 elfinder/locale/zh_cn/LC_MESSAGES/django.po create mode 100644 elfinder/tests/__init__.py create mode 100644 elfinder/tests/connector.py create mode 100644 elfinder/tests/media/files/2bytes.txt create mode 100644 elfinder/tests/media/files/directory/yawd-logo.png create mode 100644 elfinder/tests/volumes.py create mode 100644 elfinder/urls.py create mode 100644 elfinder/utils/__init__.py create mode 100644 elfinder/utils/accesscontrol.py create mode 100644 elfinder/utils/archivers.py create mode 100644 elfinder/utils/volumes.py create mode 100644 elfinder/views.py create mode 100644 elfinder/volumes/__init__.py create mode 100644 elfinder/volumes/base.py create mode 100644 elfinder/volumes/filesystem.py create mode 100644 elfinder/volumes/storage.py create mode 100644 elfinder/wsgi.py create mode 100644 media/files/HammondOrgan.pdf create mode 100644 media/images/hammond_b3.jpg create mode 100644 media/pdf/HammondOrgan.pdf create mode 100644 mfile/__init__.py create mode 100644 mfile/apps.py create mode 100644 mfile/settings.py create mode 100644 mfile/urls.py create mode 100644 mfile/views.py create mode 100644 static/elfinder/.gitignore create mode 100644 static/elfinder/css/elfinder.full.css create mode 100644 static/elfinder/css/elfinder.min.css create mode 100644 static/elfinder/css/theme.css create mode 100644 static/elfinder/img/arrows-active.png create mode 100644 static/elfinder/img/arrows-normal.png create mode 100644 static/elfinder/img/crop.gif create mode 100644 static/elfinder/img/dialogs.png create mode 100644 static/elfinder/img/edit_aceeditor.png create mode 100644 static/elfinder/img/edit_ckeditor.png create mode 100644 static/elfinder/img/edit_codemirror.png create mode 100644 static/elfinder/img/edit_creativecloud.png create mode 100644 static/elfinder/img/edit_pixlreditor.png create mode 100644 static/elfinder/img/edit_pixlrexpress.png create mode 100644 static/elfinder/img/edit_simplemde.png create mode 100644 static/elfinder/img/edit_tinymce.png create mode 100644 static/elfinder/img/icons-big.png create mode 100644 static/elfinder/img/icons-small.png create mode 100644 static/elfinder/img/logo.png create mode 100644 static/elfinder/img/progress.gif create mode 100644 static/elfinder/img/quicklook-bg.png create mode 100644 static/elfinder/img/quicklook-icons.png create mode 100644 static/elfinder/img/resize.png create mode 100644 static/elfinder/img/spinner-mini.gif create mode 100644 static/elfinder/img/toolbar.png create mode 100644 static/elfinder/img/volume_icon_box.png create mode 100644 static/elfinder/img/volume_icon_dropbox.png create mode 100644 static/elfinder/img/volume_icon_ftp.png create mode 100644 static/elfinder/img/volume_icon_googledrive.png create mode 100644 static/elfinder/img/volume_icon_local.png create mode 100644 static/elfinder/img/volume_icon_onedrive.png create mode 100644 static/elfinder/img/volume_icon_sql.png create mode 100644 static/elfinder/img/volume_icon_trash.png create mode 100644 static/elfinder/js/elfinder.full.js create mode 100644 static/elfinder/js/elfinder.min.js create mode 100644 static/elfinder/js/extras/editors.default.js create mode 100644 static/elfinder/js/extras/editors.default.min.js create mode 100644 static/elfinder/js/extras/encoding-japanese.min.js create mode 100644 static/elfinder/js/extras/quicklook.googledocs.js create mode 100644 static/elfinder/js/extras/quicklook.googledocs.min.js create mode 100644 static/elfinder/js/i18n/elfinder.LANG.js create mode 100644 static/elfinder/js/i18n/elfinder.ar.js create mode 100644 static/elfinder/js/i18n/elfinder.bg.js create mode 100644 static/elfinder/js/i18n/elfinder.ca.js create mode 100644 static/elfinder/js/i18n/elfinder.cs.js create mode 100644 static/elfinder/js/i18n/elfinder.da.js create mode 100644 static/elfinder/js/i18n/elfinder.de.js create mode 100644 static/elfinder/js/i18n/elfinder.el.js create mode 100644 static/elfinder/js/i18n/elfinder.es.js create mode 100644 static/elfinder/js/i18n/elfinder.fa.js create mode 100644 static/elfinder/js/i18n/elfinder.fallback.js create mode 100644 static/elfinder/js/i18n/elfinder.fo.js create mode 100644 static/elfinder/js/i18n/elfinder.fr.js create mode 100644 static/elfinder/js/i18n/elfinder.he.js create mode 100644 static/elfinder/js/i18n/elfinder.hr.js create mode 100644 static/elfinder/js/i18n/elfinder.hu.js create mode 100644 static/elfinder/js/i18n/elfinder.id.js create mode 100644 static/elfinder/js/i18n/elfinder.it.js create mode 100644 static/elfinder/js/i18n/elfinder.ja.js create mode 100644 static/elfinder/js/i18n/elfinder.jp.js create mode 100644 static/elfinder/js/i18n/elfinder.ko.js create mode 100644 static/elfinder/js/i18n/elfinder.nl.js create mode 100644 static/elfinder/js/i18n/elfinder.no.js create mode 100644 static/elfinder/js/i18n/elfinder.pl.js create mode 100644 static/elfinder/js/i18n/elfinder.pt_BR.js create mode 100644 static/elfinder/js/i18n/elfinder.ro.js create mode 100644 static/elfinder/js/i18n/elfinder.ru.js create mode 100644 static/elfinder/js/i18n/elfinder.si.js create mode 100644 static/elfinder/js/i18n/elfinder.sk.js create mode 100644 static/elfinder/js/i18n/elfinder.sl.js create mode 100644 static/elfinder/js/i18n/elfinder.sr.js create mode 100644 static/elfinder/js/i18n/elfinder.sv.js create mode 100644 static/elfinder/js/i18n/elfinder.tr.js create mode 100644 static/elfinder/js/i18n/elfinder.ug_CN.js create mode 100644 static/elfinder/js/i18n/elfinder.uk.js create mode 100644 static/elfinder/js/i18n/elfinder.vi.js create mode 100644 static/elfinder/js/i18n/elfinder.zh_CN.js create mode 100644 static/elfinder/js/i18n/elfinder.zh_TW.js create mode 100644 static/elfinder/js/i18n/help/cs.html.js create mode 100644 static/elfinder/js/i18n/help/en.html.js create mode 100644 static/elfinder/js/i18n/help/ja.html.js create mode 100644 static/elfinder/js/i18n/help/jp.html.js create mode 100644 static/elfinder/js/i18n/help/ko.html.js create mode 100644 static/elfinder/js/i18n/help/pl.html.js create mode 100644 static/elfinder/js/i18n/help/ru.html.js create mode 100644 static/elfinder/js/i18n/help/sk.html.js create mode 100644 static/elfinder/js/proxy/elFinderSupportVer1.js create mode 100644 static/elfinder/sounds/rm.wav create mode 100644 static/plugins/jquery-ui/jquery-ui.css create mode 100644 static/plugins/jquery-ui/jquery-ui.js create mode 100644 static/plugins/jquery-ui/jquery-ui.min.css create mode 100644 static/plugins/jquery-ui/jquery-ui.min.js create mode 100644 static/plugins/jquery-ui/jquery-ui.structure.css create mode 100644 static/plugins/jquery-ui/jquery-ui.structure.min.css create mode 100644 static/plugins/jquery-ui/jquery-ui.theme.css create mode 100644 static/plugins/jquery-ui/jquery-ui.theme.min.css create mode 100644 static/plugins/toastr/toastr.css create mode 100644 static/plugins/toastr/toastr.js.map create mode 100644 static/plugins/toastr/toastr.min.css create mode 100644 static/plugins/toastr/toastr.min.js create mode 100644 templates/mfile/base.html create mode 100644 templates/mfile/finder.html create mode 100644 templates/mfile/mfile-header.html delete mode 100644 templates/monitor/test.html diff --git a/accounts/permission.py b/accounts/permission.py index 3022710e..db9cc768 100644 --- a/accounts/permission.py +++ b/accounts/permission.py @@ -124,10 +124,13 @@ def permission_del(request, ids): def get_user_permission(request): ret = [] iUser = UserInfo.objects.get(username=request.user) - role_permission = RoleList.objects.get(name=iUser.role) - role_permission_list = role_permission.permission.all() - for p in role_permission_list: - d = p.name - ret.append(d.encode('ascii')) + try: + role_permission = RoleList.objects.get(name=iUser.role) + role_permission_list = role_permission.permission.all() + for p in role_permission_list: + d = p.name + ret.append(d.encode('ascii')) + except: + data = "Role list is empty" data = ",".join(ret) return HttpResponse(str(data)) diff --git a/adminset/settings.py b/adminset/settings.py index 5ca6fe0d..3a33b4e6 100644 --- a/adminset/settings.py +++ b/adminset/settings.py @@ -66,6 +66,9 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'elfinder', + 'storages', + 'mfile' ] MIDDLEWARE_CLASSES = [ @@ -295,3 +298,8 @@ ) AUTH_USER_MODEL = 'accounts.UserInfo' +# MEDIA_ROOT = os.path.join(BASE_DIR,'mfile/media') +MEDIA_ROOT = os.path.join('/var/opt/adminset/data') +MEDIA_URL = '/media/' + +DEFAULT_FILE_STORAGE = 'storages.backends.sftpstorage.SFTPStorage' \ No newline at end of file diff --git a/adminset/urls.py b/adminset/urls.py index 7f448d69..c1c6c896 100644 --- a/adminset/urls.py +++ b/adminset/urls.py @@ -14,4 +14,6 @@ url(r'^accounts/', include('accounts.urls')), url(r'^appconf/', include('appconf.urls')), url(r'^delivery/', include('delivery.urls')), + url(r'^mfile/', include('mfile.urls')), + url(r'^elfinder/',include('elfinder.urls')), ] \ No newline at end of file diff --git a/elfinder/.gitignore b/elfinder/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/elfinder/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/elfinder/__init__.py b/elfinder/__init__.py new file mode 100644 index 00000000..99c4176c --- /dev/null +++ b/elfinder/__init__.py @@ -0,0 +1 @@ +__version__ = '0.0.1' \ No newline at end of file diff --git a/elfinder/apps.py b/elfinder/apps.py new file mode 100644 index 00000000..b4079372 --- /dev/null +++ b/elfinder/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class ElfinderConfig(AppConfig): + name = 'elfinder' diff --git a/elfinder/conf/__init__.py b/elfinder/conf/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/elfinder/conf/settings.py b/elfinder/conf/settings.py new file mode 100644 index 00000000..b16f5321 --- /dev/null +++ b/elfinder/conf/settings.py @@ -0,0 +1,203 @@ +from os.path import join +from django.conf import settings +from elfinder.utils.accesscontrol import fs_standard_access +from elfinder.volumes.filesystem import ElfinderVolumeLocalFileSystem +from elfinder.volumes.storage import ElfinderVolumeStorage +ELFINDER_JS_URLS = { + 'a_jquery' : 'http://apps.bdimg.com/libs/jquery/1.8.2/jquery.min.js', + 'b_jqueryui' : 'http://apps.bdimg.com/libs/jqueryui/1.9.2/jquery-ui.min.js', + 'c_elfinder' : '%selfinder/js/elfinder.full.js' % settings.STATIC_URL, +} +#allow to override any key in the project settings file +ELFINDER_JS_URLS.update(getattr(settings, 'ELFINDER_JS_URLS', {})) + +ELFINDER_CSS_URLS = { + 'a_jqueryui' : 'http://apps.bdimg.com/libs/jqueryui/1.9.2/themes/smoothness/jquery-ui.css', + 'b_elfinder' : '%selfinder/css/elfinder.min.css' % settings.STATIC_URL +} +#allow to override any key in the project settings file +ELFINDER_CSS_URLS.update(getattr(settings, 'ELFINDER_CSS_URLS', {})) + +ELFINDER_WIDGET_JS_URL = '%sjs/jquery.elfinder-widget.full.js' % settings.STATIC_URL +ELFINDER_WIDGET_CSS_URL = '%scss/jquery.elfinder-widget.full.css' % settings.STATIC_URL + +ELFINDER_LANGUAGES_ROOT_URL = getattr(settings, 'ELFINDER_LANGUAGES_ROOT_URL', '%splugins/elfinder/js/i18n/' % settings.STATIC_URL) + +#The available language codes. A corresponding ELFINDER_LANGUAGES_ROOT_URL/elfinder.{ext}.js url must be available +ELFINDER_LANGUAGES = getattr(settings, 'ELFINDER_LANGUAGES', ['ar', 'bg', 'ca', 'cs', 'de', 'el', 'es', 'fa', 'fr', 'hu', 'it', 'jp', 'ko', 'nl', 'no', 'pl', 'pt_BR', 'ru', 'tr', 'zh_CN']) + +ELFINDER_CONNECTOR_OPTION_SETS = { + #the default keywords demonstrates all possible configuration options + #it allowes all file types, except from hidden files + 'default' : { + 'debug' : True, #optionally set debug to True for additional debug messages + 'roots' : [ + #{ + # 'driver' : ElfinderVolumeLocalFileSystem, + # 'path' : join(settings.MEDIA_ROOT, 'files'), + #}, + { + 'id' : 'lff', + 'driver' : ElfinderVolumeLocalFileSystem, + 'path' : settings.MEDIA_ROOT, + # 'alias' : 'Files', + #open this path on initial request instead of root path + #'startPath' : '', + 'URL' : '%sfiles/' % settings.MEDIA_URL, + #the depth of sub-directory listings that should return per request + #'treeDeep' : 1, + #directory separator. required by client to show paths correctly + #'separator' : os.sep, + #directory for thumbnails + #'tmbPath' : '.tmb', + #Thumbnails dir URL. Set this if you're storing thumbnails outside the root directory + #'tmbURL' : '', + #Thumbnail size (in px) + #'tmbSize' : 48, + #Whether to crop (scale image to fit) thumbnails or not. + #'tmbCrop' : True, + #thumbnails background color (hex #rrggbb or 'transparent') + #'tmbBgColor' : '#ffffff', + #on paste file - if True - old file will be replaced with new one, if False new file get name - original_name-number.ext + 'copyOverwrite' : False, + #if True - join new and old directories content on paste + #'copyJoin' : True, + #filter mime types to show + #'onlyMimes' : [], + #on upload - if True - old file will be replaced with new one, if False new file get name - original_name-number.ext + #'uploadOverwrite' : True, + #mimetypes allowed to upload + 'uploadAllow' : ['all',], + 'mimeDetect' : 'internal', + #mimetypes not allowed to upload + 'uploadDeny' : ['all',], + #order to proccess uploadAllow and uploadDeny options + 'uploadOrder' : ['deny', 'allow'], + #maximum upload file size. NOTE - this is size for every uploaded files + 'uploadMaxSize' : '128m', + #if True - every folder will be check for children folders, otherwise all folders will be marked as having subfolders + #'checkSubfolders' : True, + #allow to copy from this volume to other ones? + #'copyFrom' : True, + #allow to copy from other volumes to this one? + #'copyTo' : True, + #Regular expression against which all new file names will be validated. + #'disabled' : [], + #regexp against which new file names will be validated + #enable this to allow creating hidden files + #'acceptedName' : r'.*', + #callable to control file permissions + #`fs_standard_access` hides all files starting with . + 'accessControl' : fs_standard_access, + #default permissions. not set hidden/locked here - take no effect + #'defaults' : { + # 'read' : True, + # 'write' : True + #}, + 'attributes' : [ + { + 'pattern' : r'\.tmb$', + 'read' : True, + 'write': True, + 'hidden' : True, + 'locked' : True + }, + #{ + # 'pattern' : r'\/my-inaccessible-folder$', + # 'write' : False, + # 'read' : False, + # 'hidden' : True, + # 'locked' : True + #}, + ], + #quarantine folder name - required to check archive (must be hidden) + #'quarantine' : '.quarantine', + #Allowed archive's mimetypes to create. Leave empty for all available types. + #'archiveMimes' : [], + #Manual config for archivers. Leave empty for auto detect + 'archivers' : { + #create archivers must be a dictionary containing a class implementing the open, add, close methods and the archiver's file extension + #they should operate like the python's built-in tarfile.TarFile classes + #http://docs.python.org/library/tarfile.html + #'create' : { 'ext' : 'rar', 'archiver' : MyRarArchiver }, + #extract archiver class must implement the open, extractall and close methods + #they should operate like python's built-in tarfile.TarFile classes + #for more information see http://docs.python.org/library/tarfile.html + #'extract' : { 'ext' : 'rar', 'archiver' : MyRarExtractor }, + }, + #seconds to cache the file and dir data used by the driver + 'cache' : 6 + }, + ] + }, + #option set to only allow image files + # 'image' : { + # 'debug' : True, + # 'roots' : [ + # { + # 'id' : 'imageid', + # 'driver' : ElfinderVolumeLocalFileSystem, + # 'path' : join(settings.MEDIA_ROOT, u'images'), + # 'alias' : 'Elfinder images', + # 'URL' : '%simages/' % settings.MEDIA_URL, + # 'onlyMimes' : ['image',], + # 'uploadAllow' : ['image',], + # 'uploadDeny' : ['all',], + # 'uploadMaxSize' : '128m', + # 'disabled' : ['mkfile', 'archive'], + # 'accessControl' : fs_standard_access, + # 'attributes' : [ + # { + # 'pattern' : r'\.tmb$', + # 'read' : True, + # 'write': True, + # 'hidden' : True, + # 'locked' : True + # }, + # ], + # } + # ] + # }, + # 'pdf':{ + # 'debug':True, + # 'roots':[ + # { + # 'id' : 'pdf', + # 'driver' : ElfinderVolumeLocalFileSystem, + # 'path' : join(settings.MEDIA_ROOT, u'pdf'), + # 'alias' : 'pdf', + # 'URL' : '%spdf/' % settings.MEDIA_URL, + # 'onlyMimes' : ['application/pdf',], + # 'uploadAllow' : ['application/pdf',], + # 'uploadDeny' : ['all',], + # 'uploadMaxSize' : '128m', + # 'disabled' : ['mkfile', 'archive'], + # 'accessControl' : fs_standard_access, + # 'attributes' : [ + # { + # 'pattern' : r'\.tmb$', + # 'read' : True, + # 'write': True, + # 'hidden' : True, + # 'locked' : True + # }, + # ], + # } + # ] + # }, + 'sftp' : { + 'debug' : True, + 'roots' : [ + { + 'id' : 'pdfid', + 'alias' : '127.0.0.1', + 'driver' : ElfinderVolumeStorage, + 'storageClass': 'storages.backends.sftpstorage.SFTPStorage', + 'keepAlive' : True, + 'cache' : 300 + } + ] + }, +} + +ELFINDER_CONNECTOR_OPTION_SETS.update(getattr(settings, 'ELFINDER_CONNECTOR_OPTION_SETS', {})) diff --git a/elfinder/connector.py b/elfinder/connector.py new file mode 100644 index 00000000..bfcbf492 --- /dev/null +++ b/elfinder/connector.py @@ -0,0 +1,810 @@ +import os, re, time, urllib +from django.utils.translation import ugettext as _ +from exceptions import ElfinderErrorMessages, VolumeNotFoundError, DirNotFoundError, FileNotFoundError, NamedError, NotAnImageError +from utils.volumes import instantiate_driver +import sys +reload(sys) +sys.setdefaultencoding("utf-8")#fix ascii code bug +from collections import defaultdict + +class ElfinderConnector: + """ + A python implementation of the + `elfinder connector api v2.1 `_. At the moment, it supports all elfinder commands except from ``netDrivers``. + """ + + _version = '2.1' + _commit = 'b0144a0' + _netDrivers = {} + _commands = { + 'open' : { 'target' : False, 'tree' : False, 'init' : False, 'mimes' : False }, + 'ls' : { 'target' : True, 'mimes' : False }, + 'tree' : { 'target' : True }, + 'parents' : { 'target' : True }, + 'tmb' : { 'targets' : True }, + 'file' : { 'target' : True, 'download' : False, 'request' : False }, + 'size' : { 'targets' : True }, + 'mkdir' : { 'target' : True, 'name' : True }, + 'mkfile' : { 'target' : True, 'name' : True, 'mimes' : False }, + 'rm' : { 'targets' : True }, + 'rename' : { 'target' : True, 'name' : True, 'mimes' : False }, + 'duplicate' : { 'targets' : True }, + 'paste' : { 'dst' : True, 'targets' : True, 'cut' : False, 'mimes' : False }, + 'upload' : { 'target' : True, 'FILES' : True, 'mimes' : False, 'html' : False , 'upload_path': False, 'chunk' : False, 'range' : False, 'cid' : False }, + 'get' : { 'target' : True }, + 'put' : { 'target' : True, 'content' : '', 'mimes' : False }, + 'archive' : { 'targets' : True, 'type_' : True, 'mimes' : False }, + 'extract' : { 'target' : True, 'mimes' : False }, + 'search' : { 'q' : True, 'mimes' : False }, + 'info' : { 'targets' : True, 'options': False }, + 'dim' : { 'target' : True }, + 'resize' : {'target' : True, 'width' : True, 'height' : True, 'mode' : False, 'x' : False, 'y' : False, 'degree' : False }, + #TODO: implement netmount + 'netmount' : { 'protocol' : True, 'host' : True, 'path' : False, 'port' : False, 'user' : True, 'pass' : True, 'alias' : False, 'options' : False} + } + + def __init__(self, opts, session = None): + + if not 'roots' in opts: + opts['roots'] = [] + + self._volumes = {} + self._default = None + self._loaded = False + self._session = session + self._time = time.time() + self._debug = 'debug' in opts and opts['debug'] + self._uploadDebug = '' + self._mountErrors = [] + + #TODO: Use signals instead of the original connector's binding mechanism + + #for root in self.getNetVolumes(): + # opts['roots'].append(root) + + for o in opts['roots']: + + try: + volume = instantiate_driver(o) + except Exception as e: + self._mountErrors.append(e.__unicode__()) + continue + + id_ = volume.id() + self._volumes[id_] = volume + if not self._default and volume.is_readable(): + self._default = self._volumes[id_] + + self._loaded = (self._default is not None) + + def loaded(self): + """ + Check if the volume driver is loaded + """ + return self._loaded + + def version(self, commit=False): + """ + Get api version. The commit number refers to the corresponding official elfinder github commit number. + """ + return '%s - %s' % (self._version, self._commit) if commit else self._version + + def commandExists(self, cmd): + """ + Check if command exists + """ + return cmd in self._commands and hasattr(self, '_%s' % cmd) and callable(getattr(self, '_%s' % cmd)) + + def commandArgsList(self, cmd): + """ + Return command required arguments info + """ + return self._commands[cmd] if self.commandExists(cmd) else {} + + #def getNetVolumes(self): + # """ + # Return network volumes config. + # """ + # return self._session.get('elFinderNetVolumes', []) if self._session else [] + + #def setNetVolumes(self, volumes): + # """ + # Save network volumes config. + # """ + # self._session['elFinderNetVolumes'] = volumes + + def error(self, *args): + """ + Normalize error messages + """ + errors = [] + for msg in args: + if not isinstance(msg, basestring): + errors += msg + else: + errors.append(msg) + + if not errors: + return [ElfinderErrorMessages.ERROR_UNKNOWN,] + return errors + + def execute(self, cmd, **kwargs): + """ + Exec command and return result + """ + if not self._loaded: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_CONF, ElfinderErrorMessages.ERROR_CONF_NO_VOL)} + + if not self.commandExists(cmd): + return { 'error' : self.error(ElfinderErrorMessages.ERROR_UNKNOWN_CMD, cmd)} + + #check all required arguments are provided + for arg, req in self.commandArgsList(cmd).items(): + if req and (not arg in kwargs or not kwargs[arg]): + return {'error' : self.error(ElfinderErrorMessages.ERROR_INV_PARAMS, cmd)} + + #set mimes filter and pop mimes from the arguments list + if 'mimes' in kwargs: + for id_ in self._volumes: + self._volumes[id_].set_mimes_filter(kwargs['mimes']) + kwargs.pop('mimes') + + debug = self._debug or ('debug' in kwargs and int(kwargs['debug'])) + #remove debug kewyord argument + if 'debug' in kwargs: + kwargs.pop('debug') + + result = getattr(self, '_%s' % cmd)(**kwargs) + + #checked for removed items as these are not directly returned + if 'removed' in result: + for id_ in self._volumes: + result['removed'] += self._volumes[id_].removed() + self._volumes[id_].reset_removed() + #replace removed files info with removed files hashes and filter out duplicates + result['removed'] = list(set([f['hash'] for f in result['removed']])) + + #call handlers for this command + #TODO: a signal must be sent here + + if debug: + result['debug'] = { + 'connector' : 'yawd-elfinder', + 'time' : time.time() - self._time, + 'upload' : self._uploadDebug, + 'volumes' : [v.debug() for v in self._volumes.values()], + 'mountErrors' : self._mountErrors + } + return result + + def _open(self, target='', init=False, tree=False): + """ + **Command**: Open a directory + + Return: + An array with following elements: + :cwd: opened directory information + :options: the volume options + :files: opened directory content [and dirs tree if 'tree' argument is ``True``] + :api: api version (if 'init' argument is ``True``) + :uplMaxSize: The maximum allowed upload size (if 'init' argument is ``True``) + :error: on failed + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + if isinstance(init, basestring): + init = int(init) + + if isinstance(tree, basestring): + tree = int(tree) + + if not init and not target: + return {'error' : self.error(ElfinderErrorMessages.ERROR_INV_PARAMS, 'open')} + + #display name for use in error messages + display_hash = 'default folder' if init else '#%s' % target + + #detect volume + try: + volume = self._volume(target) + except VolumeNotFoundError as e: + if not init: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, display_hash, e)} + else: + #on init request we can get invalid dir hash - + #dir which can not be opened now, but remembered by client, + #so open default volume + volume = self._default + + try: + cwd = volume.dir(hash_=target, resolve_link=True) + if not cwd['read'] and init: + try: + cwd = volume.dir(hash_=volume.default_path(), resolve_link=True) + except (DirNotFoundError, FileNotFoundError) as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, display_hash, e)} + except (DirNotFoundError, FileNotFoundError) as e: + if init: + cwd = volume.dir(hash_=volume.default_path(), resolve_link=True) + else: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, display_hash, e)} + + if not cwd['read']: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, display_hash, ElfinderErrorMessages.ERROR_PERM_DENIED)} + + files = [] + #get folder trees + if tree: + for id_ in self._volumes: + files += self._volumes[id_].tree(exclude=target) + + #get current working directory files list and add to files if not already present + try: + ls = volume.scandir(cwd['hash']) + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, cwd['name'], e)} + + for file_ in ls: + if not file_ in files: + files.append(file_) + + result = { + 'cwd' : cwd, + 'options' : volume.options(cwd['hash']), + 'files' : files + } + + if init: + result['api'] = self._version + result['netDrivers'] = self._netDrivers.keys() + result['uplMaxSize'] = volume.upload_max_size() + + return result + + def _ls(self, target): + """ + **Command**: Return a directory's file list. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + return { 'list' : self._volume(target).ls(target) } + except: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, '#%s' % target) } + + def _tree(self, target): + """ + **Command**: Return subdirs for required directory. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + return { 'tree' : self._volume(target).tree(target) } + except: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, '#%s' % target) } + + def _parents(self, target): + """ + **Command**: Return parents dir for required directory. this method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + return {'tree' : self._volume(target).parents(target) } + except: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, u'#%s' % target) } + + def _tmb(self, targets): + """ + **Command**: Return new automatically-created thumbnails list. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + result = { 'images' : {} } + for target in targets: + try: + thumb = self._volume(target).tmb(target) + if thumb: + result['images'][target] = thumb + except (VolumeNotFoundError, NotAnImageError): + continue + + return result + + def _file(self, target, request=None, download=False): + """ + **Command**: Get a file + + Required to output file in browser when volume URL is not set. + Used to download the file as well. + + Return: + An array containing an opened file pointer, the root itself and the required response headers + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + if isinstance(download, basestring): + download = int(download) + + try: + volume = self._volume(target) + file_ = volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + return { 'error' : _('File not found'), 'header' : { 'Status' : 404 }, 'raw' : True } + + if not file_['read']: + return { 'error' : _('Access denied'), 'header' : { 'Status' : 403 }, 'raw' : True } + + try: + fp = volume.open(target) + except os.error: #Normally this could raise a FileNotFoundError as well, but we already checked this + return { 'error' : _('File not found'), 'header' : { 'Status' : 404 }, 'raw' : True } + + if download: + disp = 'attachment' + mime = 'application/octet-stream' + else: + disp = 'inline' if re.match('(image|text)', file_['mime'], re.IGNORECASE) or file_['mime'] == 'application/x-shockwave-flash' else 'attachment' + mime = file_['mime'] + + filenameEncoded = urllib.quote(file_['name'].encode('utf-8')) #unicode filename support + if not '%' in filenameEncoded: #ASCII only + filename = 'filename="%s"' % file_['name'] + elif request and hasattr(request, 'META') and 'HTTP_USER_AGENT' in request.META: + ua = request.META['HTTP_USER_AGENT'] + if re.search('MSIE [4-8]', ua): #IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) + filename = 'filename="%s"' % filenameEncoded + elif not 'Chrome'in ua and 'Safari' in ua: # Safari + filename = 'filename="%s"' % file_['name'].replace('"','') + else: #RFC 6266 (RFC 2231/RFC 5987) + filename = "filename*=UTF-8''%s" % filenameEncoded + else: + filename = '' + + result = { + 'volume' : volume, + 'pointer' : fp, + 'info' : file_, + 'header' : { + 'Content-Type' : mime, + 'Content-Disposition' : '%s; %s' % (disp, filename), + 'Content-Location' : file_['name'].encode('utf-8'), #unicode filename support + 'Content-Transfer-Encoding' : 'binary', + 'Content-Length' : file_['size'], + #'Connection' : 'close' + } + } + + return result + + def _size(self, targets): + """ + **Command**: Count total file size of all directories in ``targets`` param. + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + size = 0 + + for target in targets: + try: + volume = self._volume(target) + file_ = volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + file_ = { 'read' : 0 } + + if not file_['read']: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, u'#%s' % target) } + + size += volume.size(target) + + return { 'size' : size } + + def _mkdir(self, target, name): + """ + **Command**: Create a new directory. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + volume = self._volume(target) + except VolumeNotFoundError: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_MKDIR, name, ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % target)} + + try: + result = {'added': []} + for dirs in name: + try: + if str(dirs).startswith('/'): + dirs = dirs[1:] + dir_ = volume.mkdir(target, dirs) + result['added'].append(dir_) + except Exception, e: + result['warning'] = self.error(ElfinderErrorMessages.ERROR_UPLOAD_FILE, dirs, e) + return result + except NamedError as e: + return { 'error' : self.error(e, e.name, ElfinderErrorMessages.ERROR_MKDIR) } + except Exception as e: + return { 'error': self.error(ElfinderErrorMessages.ERROR_MKDIR, name, e) } + + def _mkfile(self, target, name): + """ + **Command**: Create a new, empty file. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + volume = self._volume(target) + except VolumeNotFoundError: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_MKFILE, name, ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % target)} + + try: + return { 'added' : [volume.mkfile(target, name)] } + except NamedError as e: + return { 'error' : self.error(e, e.name, ElfinderErrorMessages.ERROR_MKFILE, name ) } + except Exception as e: + return { 'error': self.error(ElfinderErrorMessages.ERROR_MKFILE, name, e) } + + def _rename(self, target, name): + """ + **Command**: Rename a file. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + volume = self._volume(target) + except (VolumeNotFoundError): + return { 'error' : self.error(ElfinderErrorMessages.ERROR_RENAME, '#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) } + + try: + return { 'added' : [volume.rename(target, name)], 'removed' : volume.removed() } + except NamedError as e: + return { 'error' : self.error(e, e.name, ElfinderErrorMessages.ERROR_RENAME) } + except FileNotFoundError: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_RENAME, '#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) } + except Exception as e: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_RENAME, e) } + + def _duplicate(self, targets, suffix='copy'): + """ + **Command**: Duplicate a file. Create a copy with "{suffix} %d" suffix, + where "%d" is an integer and ``suffix`` an argument that defaults to `'copy`'. + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + result = { 'added' : [] } + + for target in targets: + try: + volume = self._volume(target) + volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + result['warning'] = self.error(ElfinderErrorMessages.ERROR_COPY, u'#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) + continue + + try: + result['added'].append(volume.duplicate(target, suffix)) + except Exception as e: + result['warning'] = self.error(e) + + return result + + def _rm(self, targets): + """ + **Command**: Remove directories or files. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + result = {'removed' : []} + + for target in targets: + try: + volume = self._volume(target) + except VolumeNotFoundError: + result['warning'] = self.error(ElfinderErrorMessages.ERROR_RM, '#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) + continue + + try: + volume.rm(target) + except NamedError as e: + result['warning'] = self.error(e, e.name) + except Exception as e: + result['warning'] = self.error(e) + + return result + + def _upload(self, target, FILES, html=False, upload_path=False, chunk=False, range=False, cid=False): + """ + **Command**: Save uploaded files. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + chunk_flag = False + if isinstance(range,(unicode,basestring)): + chunk_range = range.rsplit(',') + chunk_file_size = chunk_range[2] + if chunk_range[0] == '0' or chunk_range[0] == 0: + chunk_flag = True + if isinstance(html, basestring): + html = int(html) + + header = { 'Content-Type' : 'text/html; charset=utf-8' } if html else {} + result = { 'added' : [], 'header' : header } + + try: + files = FILES.getlist('upload[]') + except KeyError: + files = [] + + if not isinstance(files, list) or not files: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_UPLOAD, ElfinderErrorMessages.ERROR_UPLOAD_NO_FILES), 'header' : header } + + try: + volume = self._volume(target) + except VolumeNotFoundError: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_UPLOAD, ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % target), 'header' : header } + if not upload_path: # not is directory + for uploaded_file in files: + try: + if chunk: + chunked_file_name = '.'.join(chunk.rsplit('.')[:-2]) + uploaded_file.name = chunked_file_name + if chunk is True: + file_ = volume.upload(uploaded_file, target, chunk=True, first_chunk=chunk_flag) + file_.update({'size':chunk_file_size}) + result['added'].append(file_) + else: + file_ = volume.upload(uploaded_file, target) + result['added'].append(file_) + except Exception, e: + result['warning'] = self.error(ElfinderErrorMessages.ERROR_UPLOAD_FILE, uploaded_file.name, e) + self._uploadDebug = 'Upload error: Django handler error' + else: # directory + try: + all_ = defaultdict(list) + for key, value in [(v, i) for i, v in enumerate(upload_path)]: # upload directory list + if key.startswith('/'): + key = (os.path.split(key[1:]))[0] # get path + all_[key].append(value) + except Exception as e: + return {'error': 'get directory error, %s' % e, 'header': header} + + for item in all_.keys(): + real_path = "%s/%s" % (volume.decode(target), item) # get real path + new_target = volume.encode(real_path) # get new target + try: + volume = self._volume(new_target) # get volume object + except VolumeNotFoundError: + return {'error': self.error(ElfinderErrorMessages.ERROR_UPLOAD, + ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % new_target), + 'header': header} + + for file_index in all_[item]: + try: + #if upload files number exceed 1 it will cause a weird bug,the connector can't find the target directory. + #This function will caused another bug,if the upload directory file name contains dot will cause the file upload to the wrong directory. + if chunk: + chunked_file_name = '.'.join(chunk.rsplit('.')[:-2]) + files[file_index].name = chunked_file_name + if len(all_[item]) >=1 and isinstance(upload_path,list) and target not in upload_path: + if chunk: + file_ = volume.upload(files[file_index], new_target, chunk=True, first_chunk=chunk_flag) + file_.update({'size':chunk_file_size}) + else: + file_ = volume.upload(files[file_index], new_target) + else: + if chunk: + file_ = volume.upload(files[file_index], target, chunk=True, first_chunk=chunk_flag)#This is a weird bug + file_.update({'size':chunk_file_size}) + else: + file_ = volume.upload(files[file_index], target) + result['added'].append(file_) + except Exception, e: + result['warning'] = self.error(ElfinderErrorMessages.ERROR_UPLOAD_FILE, files[file_index].name, e) + self._uploadDebug = 'Upload error: Django handler error' + return result + + def _paste(self, targets, dst, cut=False): + """ + **Command**: Copy/move ``targets`` files into a new destination ``dst``. + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + if isinstance(cut, basestring): + cut = int(cut) + + error = ElfinderErrorMessages.ERROR_MOVE if cut else ElfinderErrorMessages.ERROR_COPY + result = { 'added' : [], 'removed' : [] } + + try: + dstVolume = self._volume(dst) + except VolumeNotFoundError: + return { 'error' : self.error(error, u'#%s' % targets[0], ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, u'#%s' % dst) } + + for target in targets: + try: + srcVolume = self._volume(target) + except VolumeNotFoundError: + result['warning'] = self.error(error, u'#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) + continue + + try: + result['added'].append(dstVolume.paste(srcVolume, target, dst, cut)) + except NamedError as e: + result['warning'] = self.error(e, e.name) + except Exception as e: + result['warning'] = self.error(e) + + return result + + def _get(self, target): + """ + **Command**: Return file contents. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + volume = self._volume(target) + volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, u'#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND)} + + try: + content = volume.get_contents(target) + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_OPEN, volume.path(target), e)} + + #the content will be returned as json, so try to json encode it + #throw an error if it cannot be properly serialized + try: + import json + json.dumps(content) + except: + return {'error' : self.error(ElfinderErrorMessages.ERROR_NOT_UTF8_CONTENT, volume.path(target))} + + return {'content' : content } + + def _put(self, target, content): + """ + **Command**: Save ``content`` into a text file. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + volume = self._volume(target) + volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + return {'error' : self.error(ElfinderErrorMessages.ERROR_SAVE, u'#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND)} + + try: + return {'changed' : [volume.put_contents(target, content)]} + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_SAVE, volume.path(target), e)} + + def _extract(self, target): + """ + **Command**: Extract files from archive. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + try: + volume = self._volume(target) + volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + return { 'error' : self.error(ElfinderErrorMessages.ERROR_EXTRACT, u'#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) } + + try: + return {'added' : [volume.extract(target)] } + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_EXTRACT, volume.path(target), e)} + + def _archive(self, targets, type_): + """ + **Command**: Create a new archive file containing all files in + ``targets`` param. + + This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + try: + volume = self._volume(targets[0]) + except: + return { 'error' : self.error(ElfinderErrorMessages.ERROR_ARCHIVE, ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND) } + + try: + return {'added' : [volume.archive(targets, type_)]} + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_ARCHIVE, e)} + + def _search(self, q): + """ + **Command**: Search files for ``q``. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + q = q.strip() + result = [] + for volume in self._volumes.values(): + result += volume.search(q) + return {'files' : result} + + def _info(self, targets, options=False): + """ + **Command**: Return file info (used by client "places" ui). This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + + if isinstance(options, basestring): + options = int(options) + + files = [] + for hash_ in targets: + try: + volume = self._volume(hash_) + if options: + options = volume.options(hash_) + options.update(volume.file(hash_)) + files.append(options) + else: + files.append(volume.file(hash_)) + except: + continue + + return {'files' : files} + + def _dim(self, target): + """ + **Command**: Return image dimensions. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + try: + return { 'dim' : self._volume(target).dimensions(target) } + except (VolumeNotFoundError, FileNotFoundError, NotAnImageError): + return {} + + def _resize(self, target, width, height, mode=None, x='0', y='0', degree='0'): + """ + **Command**: Resize ``target`` image. This method should not be invoked + directly, the :meth:`elfinder.connector.ElfinderConnector.execute` + method must be used. + """ + width, height, x, y, degree = int(width), int(height), int(x), int(y), int(degree) + bg = '' + + try: + volume = self._volume(target) + volume.file(target) + except (VolumeNotFoundError, FileNotFoundError): + return { 'error' : self.error(ElfinderErrorMessages.ERROR_RESIZE, '#%s' % target, ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) } + + try: + return { 'changed' : [volume.resize(target, width, height, x, y, mode, bg, degree)]} + except Exception as e: + return {'error' : self.error(ElfinderErrorMessages.ERROR_RESIZE, volume.path(target), e)} + + def _volume(self, hash_): + """ + Return root - file's owner + """ + if hash_: + for id_, v in self._volumes.items(): + if hash_.find(id_) == 0: + return v + raise VolumeNotFoundError() diff --git a/elfinder/exceptions.py b/elfinder/exceptions.py new file mode 100644 index 00000000..05a23c31 --- /dev/null +++ b/elfinder/exceptions.py @@ -0,0 +1,87 @@ +from django.utils.translation import ugettext as _ + +class ElfinderErrorMessages: + """ + Standard error message codes, the text message of which is handled by the + elFinder client + """ + + ERROR_UNKNOWN = 'errUnknown' + ERROR_UNKNOWN_CMD = 'errUnknownCmd' + ERROR_CONF = 'errConf' + ERROR_CONF_NO_JSON = 'errJSON' + ERROR_CONF_NO_VOL = 'errNoVolumes' + ERROR_INV_PARAMS = 'errCmdParams' + ERROR_OPEN = 'errOpen' + ERROR_DIR_NOT_FOUND = 'errFolderNotFound' + ERROR_FILE_NOT_FOUND = 'errFileNotFound' #'File not found.' + ERROR_TRGDIR_NOT_FOUND = 'errTrgFolderNotFound' #'Target folder "$1" not found.' + ERROR_NOT_DIR = 'errNotFolder' + ERROR_NOT_FILE = 'errNotFile' + ERROR_PERM_DENIED = 'errPerm' + ERROR_LOCKED = 'errLocked' #'"$1" is locked and can not be renamed, moved or removed.' + ERROR_EXISTS = 'errExists' #'File named "$1" already exists.' + ERROR_INVALID_NAME = 'errInvName' #'Invalid file name.' + ERROR_MKDIR = 'errMkdir' + ERROR_MKFILE = 'errMkfile' + ERROR_RENAME = 'errRename' + ERROR_COPY = 'errCopy' + ERROR_MOVE = 'errMove' + ERROR_COPY_FROM = 'errCopyFrom' + ERROR_COPY_TO = 'errCopyTo' + ERROR_COPY_ITSELF = 'errCopyInItself' + ERROR_REPLACE = 'errReplace' #'Unable to replace "$1".' + ERROR_RM = 'errRm' #'Unable to remove "$1".' + ERROR_RM_SRC = 'errRmSrc' #'Unable remove source file(s)' + ERROR_UPLOAD = 'errUpload' #'Upload error.' + ERROR_UPLOAD_FILE = 'errUploadFile' #'Unable to upload "$1".' + ERROR_UPLOAD_NO_FILES = 'errUploadNoFiles' #'No files found for upload.' + ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize' #'Data exceeds the maximum allowed size.' + ERROR_UPLOAD_FILE_SIZE = 'errUploadFileSize' #'File exceeds maximum allowed size.' + ERROR_UPLOAD_FILE_MIME = 'errUploadMime' #'File type not allowed.' + ERROR_UPLOAD_TRANSFER = 'errUploadTransfer' #'"$1" transfer error.' + ERROR_ACCESS_DENIED = 'errAccess' + ERROR_NOT_REPLACE = 'errNotReplace' #Object "$1" already exists at this location and can not be replaced with object of another type. + ERROR_SAVE = 'errSave' + ERROR_EXTRACT = 'errExtract' + ERROR_ARCHIVE = 'errArchive' + ERROR_NOT_ARCHIVE = 'errNoArchive' + ERROR_ARCHIVE_TYPE = 'errArcType' + ERROR_ARC_SYMLINKS = 'errArcSymlinks' + ERROR_ARC_MAXSIZE = 'errArcMaxSize' + ERROR_RESIZE = 'errResize' + ERROR_UNSUPPORT_TYPE = 'errUsupportType' + ERROR_NOT_UTF8_CONTENT = 'errNotUTF8Content' + ERROR_NETMOUNT = 'errNetMount' + ERROR_NETMOUNT_NO_DRIVER = 'errNetMountNoDriver' + ERROR_NETMOUNT_FAILED = 'errNetMountFailed' + +class VolumeNotFoundError(Exception): + def __init__(self): + super(VolumeNotFoundError, self).__init__(_("Volume could not be found")) + +class FileNotFoundError(Exception): + def __init__(self): + super(FileNotFoundError, self).__init__(ElfinderErrorMessages.ERROR_FILE_NOT_FOUND) + +class DirNotFoundError(Exception): + def __init__(self): + super(DirNotFoundError, self).__init__(ElfinderErrorMessages.ERROR_DIR_NOT_FOUND) + +class PermissionDeniedError(Exception): + def __init__(self): + super(PermissionDeniedError, self).__init__(ElfinderErrorMessages.ERROR_PERM_DENIED) + +class NamedError(Exception): + """ + Elfinder-specific exception. + `msg` contains the error code + `name` holds the path for which operation failed + """ + def __init__(self, msg, name): + self.name = name + super(NamedError, self).__init__(msg) + +class NotAnImageError(Exception): + def __init__(self): + super(NotAnImageError, self).__init__(_('This is not a valid image file')) \ No newline at end of file diff --git a/elfinder/locale/el/LC_MESSAGES/django.mo b/elfinder/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4c5ca7e4861ed1c6e4d97dfd5486163c9a9852ba GIT binary patch literal 1359 zcmZvaU1%It6vwYxwXPqPP!vVVsUM)k+ip^&$Fy zeQMfj5z>c13qBMS6#5b^X|rq-8}jOlcM!x!!AGBcm;UeUw4vBL-1*&m=bZEZpS%0l z*nw*d<3-HZFt202Y}SwAg>e>q9y|v=30?+s;1%!%@LTWzcmq5LZh&LpAUppRd;&KQjIUzJ>jNpwW91CSC&H z2VVy(py}yz(D=NNaUGn+{(F#ve`n{1(A;y_9|7M0$3e)a!}Mi(eijpQXfIJb%$dR}`(Npx+hbds#rujh9$M#H`_eDOhvKk7&`90HvZp$&LtV#SMIK^f5h; z$sL`M-*r18&0sCLEY%m1wR)Z#3$`#4YO8+WrH0NRF7;Fk)n}p|^P;M5z%Y9&_}Jr%~h9Cdt;f7tItys0e8)v8TC7Ya8<5-&i;qRITk37$X6^HVfA zX}x!HJbxmeM|yN^TVMX6VW&aAOr(G~X(f zsA88LI^~q@VrkYc6zWc+@c}|*r;l!VQ@CA=N_ORR%UC{DD$NG|F%@?9V_>yhEIa%C zO&rVT=9G+ugxt9ve8=K!e7qO9zMQ7^k{d=Mo@q7b`P6=#v9%~d?#MQNLD{ir>Wm-f zYC%7A13s_9Ze)?{rQ2v`a+*fVnYSe!ouP?$rgKcMC+GF1zODC?RXs?qU|zz0oAi*9 z^T}$mmR!`g^d{azrmyK8Je&HC-az>F=MPw7O|@V>~S>pl3p8cF!jTP7dHerEc+ z%;Q}&fy&q6jD*&cuaZm2+W&2lF{F1XHMyH!2K=Blr3H472MJSe_|VBiy_xK7 py_2k=zfGh5HMDn=Z_;~0^1A*7kGXgleZ*y%tJ=~x(fm$o_Z~p*, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-06-08 22:56+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: connector.py:336 connector.py:344 +msgid "File not found" +msgstr "Δε βρέθηκε το αρχείο" + +#: connector.py:339 +msgid "Access denied" +msgstr "Απαγορεύεται η πρόσβαση" + +#: exceptions.py:61 +msgid "Volume could not be found" +msgstr "Δε βρέθηκε ο δίσκος" + +#: exceptions.py:87 +msgid "This is not a valid image file" +msgstr "Μη έγκυρο αρχείο εικόνας" + +#: fields.py:50 +msgid "This file is no longer valid" +msgstr "Αυτό το αρχείο δεν είναι πια έγκυρο" + +#: widgets.py:93 +msgid "Size" +msgstr "Μέγεθος" + +#: widgets.py:94 +msgid "Path" +msgstr "Διαδρομή" + +#: widgets.py:95 +msgid "Link" +msgstr "Σύνδεσμος" + +#: widgets.py:96 +msgid "Modified" +msgstr "Τροποποίηση" + +#: widgets.py:97 +msgid "Dimensions" +msgstr "Διαστάσεις" + +#: widgets.py:98 +msgid "Update" +msgstr "Αλλαγή" + +#: widgets.py:99 +msgid "Set" +msgstr "Ορισμός" + +#: widgets.py:100 +msgid "Clear" +msgstr "Εκκαθάριση" + +#: volumes/base.py:192 +msgid "No volume id found" +msgstr "Δε βρέθηκε το volume id" + +#: volumes/base.py:1189 +msgid "Unknown" +msgstr "Άγνωστο" diff --git a/elfinder/locale/zh-Hans/LC_MESSAGES/django.po b/elfinder/locale/zh-Hans/LC_MESSAGES/django.po new file mode 100644 index 00000000..de3aae72 --- /dev/null +++ b/elfinder/locale/zh-Hans/LC_MESSAGES/django.po @@ -0,0 +1,78 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-08-17 16:15+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: elfinder/connector.py:336 elfinder/connector.py:344 +msgid "File not found" +msgstr "" + +#: elfinder/connector.py:339 +msgid "Access denied" +msgstr "" + +#: elfinder/exceptions.py:61 +msgid "Volume could not be found" +msgstr "" + +#: elfinder/exceptions.py:87 +msgid "This is not a valid image file" +msgstr "" + +#: elfinder/fields.py:50 +msgid "This file is no longer valid" +msgstr "" + +#: elfinder/volumes/base.py:192 +msgid "No volume id found" +msgstr "" + +#: elfinder/volumes/base.py:1191 +msgid "Unknown" +msgstr "" + +#: elfinder/widgets.py:97 +msgid "Size" +msgstr "" + +#: elfinder/widgets.py:98 +msgid "Path" +msgstr "" + +#: elfinder/widgets.py:99 +msgid "Link" +msgstr "" + +#: elfinder/widgets.py:100 +msgid "Modified" +msgstr "" + +#: elfinder/widgets.py:101 +msgid "Dimensions" +msgstr "" + +#: elfinder/widgets.py:102 +msgid "Update" +msgstr "" + +#: elfinder/widgets.py:103 +msgid "Set" +msgstr "" + +#: elfinder/widgets.py:104 +msgid "Clear" +msgstr "" diff --git a/elfinder/locale/zh_Hans/LC_MESSAGES/django.po b/elfinder/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 00000000..341f2f91 --- /dev/null +++ b/elfinder/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,79 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-09-07 21:31+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: elfinder/connector.py:336 elfinder/connector.py:344 +msgid "File not found" +msgstr "" + +#: elfinder/connector.py:339 +msgid "Access denied" +msgstr "" + +#: elfinder/exceptions.py:61 +msgid "Volume could not be found" +msgstr "" + +#: elfinder/exceptions.py:87 +msgid "This is not a valid image file" +msgstr "" + +#: elfinder/fields.py:50 +msgid "This file is no longer valid" +msgstr "" + +#: elfinder/volumes/base.py:192 +msgid "No volume id found" +msgstr "" + +#: elfinder/volumes/base.py:1191 +msgid "Unknown" +msgstr "" + +#: elfinder/widgets.py:97 +msgid "Size" +msgstr "" + +#: elfinder/widgets.py:98 +msgid "Path" +msgstr "" + +#: elfinder/widgets.py:99 +msgid "Link" +msgstr "" + +#: elfinder/widgets.py:100 +msgid "Modified" +msgstr "" + +#: elfinder/widgets.py:101 +msgid "Dimensions" +msgstr "" + +#: elfinder/widgets.py:102 +msgid "Update" +msgstr "" + +#: elfinder/widgets.py:103 +msgid "Set" +msgstr "" + +#: elfinder/widgets.py:104 +msgid "Clear" +msgstr "" diff --git a/elfinder/locale/zh_cn/LC_MESSAGES/django.po b/elfinder/locale/zh_cn/LC_MESSAGES/django.po new file mode 100644 index 00000000..028b67d8 --- /dev/null +++ b/elfinder/locale/zh_cn/LC_MESSAGES/django.po @@ -0,0 +1,78 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-08-17 15:59+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: elfinder/connector.py:336 elfinder/connector.py:344 +msgid "File not found" +msgstr "" + +#: elfinder/connector.py:339 +msgid "Access denied" +msgstr "" + +#: elfinder/exceptions.py:61 +msgid "Volume could not be found" +msgstr "" + +#: elfinder/exceptions.py:87 +msgid "This is not a valid image file" +msgstr "" + +#: elfinder/fields.py:50 +msgid "This file is no longer valid" +msgstr "" + +#: elfinder/volumes/base.py:192 +msgid "No volume id found" +msgstr "" + +#: elfinder/volumes/base.py:1191 +msgid "Unknown" +msgstr "" + +#: elfinder/widgets.py:97 +msgid "Size" +msgstr "" + +#: elfinder/widgets.py:98 +msgid "Path" +msgstr "" + +#: elfinder/widgets.py:99 +msgid "Link" +msgstr "" + +#: elfinder/widgets.py:100 +msgid "Modified" +msgstr "" + +#: elfinder/widgets.py:101 +msgid "Dimensions" +msgstr "" + +#: elfinder/widgets.py:102 +msgid "Update" +msgstr "" + +#: elfinder/widgets.py:103 +msgid "Set" +msgstr "" + +#: elfinder/widgets.py:104 +msgid "Clear" +msgstr "" diff --git a/elfinder/tests/__init__.py b/elfinder/tests/__init__.py new file mode 100644 index 00000000..e6823f6b --- /dev/null +++ b/elfinder/tests/__init__.py @@ -0,0 +1,2 @@ +from connector import * +from volumes import * \ No newline at end of file diff --git a/elfinder/tests/connector.py b/elfinder/tests/connector.py new file mode 100644 index 00000000..eb538ab4 --- /dev/null +++ b/elfinder/tests/connector.py @@ -0,0 +1,249 @@ +import os +from django.conf import settings +from django.utils import unittest +from elfinder.conf import settings as ls +from elfinder.connector import ElfinderConnector +from elfinder.exceptions import ElfinderErrorMessages + +class ConnectorInitTestCase(unittest.TestCase): + + def setUp(self): + settings.MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media') + + def test_init(self): + """ + Test the ElfinderConnector __init__ method + """ + #fault-tolerant initialization + connector = ElfinderConnector({}) + self.assertEqual(connector.loaded(), False) + + connector = ElfinderConnector({}) + self.assertEqual(connector.loaded(), False) + + #initialize with 'default' optionset + connector = ElfinderConnector(ls.ELFINDER_CONNECTOR_OPTION_SETS['default']) + self.assertEqual(connector.loaded(), True) + + def test_execute(self): + """ + Test the execute method. + """ + + #test invalid configuration + connector = ElfinderConnector({}) + self.assertEqual(ElfinderErrorMessages.ERROR_CONF in connector.execute('open')['error'], True) + + connector = ElfinderConnector(ls.ELFINDER_CONNECTOR_OPTION_SETS['default']) + #test invalid command + self.assertEqual(ElfinderErrorMessages.ERROR_UNKNOWN_CMD in connector.execute('dummy')['error'], True) + #test missing arguments + self.assertEqual(ElfinderErrorMessages.ERROR_INV_PARAMS in connector.execute('ls')['error'], True) + #test it is actually doing something + self.assertEqual('error' in connector.execute('open', mimes=['image'], init=True), False) + #test debug keyword + self.assertEqual('debug' in connector.execute('open', init=True), False) + self.assertEqual('debug' in connector.execute('open', init=True, debug=True), True) + +class ConnectorEVLFOpen(unittest.TestCase): + """ + Test that open command is implemented and behaves as expected. It also checks the response's conformance with + the `elfinder 2.1 Server API specification `_ + """ + + def setUp(self): + settings.MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media') + + self.opts = ls.ELFINDER_CONNECTOR_OPTION_SETS['default'].copy() + self.opts['roots'][0]['path'] = settings.MEDIA_ROOT + self.opts['roots'][0]['URL'] = settings.MEDIA_URL + + self.maxDiff = None + + def test_open_specs(self): + """ + Test the command compiles to the API specification + """ + + connector = ElfinderConnector(self.opts) + + #command accepts the specification arguments + argslist = connector.commandArgsList('open') + self.assertIn('target', argslist) + self.assertIn('init', argslist) + self.assertIn('tree', argslist) + self.assertIn('mimes', argslist) + + #test invalid keyword arguments + self.assertEqual(ElfinderErrorMessages.ERROR_INV_PARAMS in connector.execute('open')['error'], True) + + #test invalid target + self.assertEqual(ElfinderErrorMessages.ERROR_OPEN in connector.execute('open', target='dummy')['error'], True) + + def test_open_default(self): + """ + Test the default optionset + """ + + connector = ElfinderConnector(self.opts) + + #************ init without tree *********** + ret = connector.execute('open', target='dummy', init='1') + + #check files and cwd + self.assertEqual(len(ret['files']), 2) + self.assertNotEqual(ret['files'][0]['hash'], ret['files'][1]['hash']) + self.assertEqual(ret['files'][0]['name'], 'files') + self.assertEqual(ret['files'][1]['name'], 'test') + self.assertEqual(ret['cwd']['dirs'], 1) + self.assertEqual(ret['cwd']['name'], connector._default._root_name) + self.assertEqual(ret['cwd']['read'], 1) + self.assertEqual(ret['cwd']['write'], 1) + self.assertEqual(ret['cwd']['locked'], 1) + self.assertEqual(ret['cwd']['hidden'], 0) + self.assertEqual(ret['cwd']['size'], 'unknown') + self.assertEqual(ret['cwd']['mime'], 'directory') + self.assertEqual(ret['cwd']['volumeid'], 'llff_') + self.assertIsInstance(ret['cwd']['ts'], float) + self.assertNotIn('phash', ret['cwd']) + self.assertGreater(len(ret['cwd']['hash']), 0) + + #other response attributes + self.assertNotIn('error', ret) + self.assertIn('netDrivers', ret) + self.assertEqual(ret['uplMaxSize'], 128 * 1048576) + self.assertEqual(ret['api'], '2.1') + self.assertEqual(ret['options']['pathUrl'], settings.MEDIA_URL) + self.assertEqual(ret['options']['tmbUrl'], '%s.tmb/' % settings.MEDIA_URL) + self.assertIn('create', ret['options']['archivers']) + self.assertIn('extract', ret['options']['archivers']) + self.assertEqual(ret['options']['disabled'], []) + self.assertEqual(ret['options']['copyOverwrite'], 1) + self.assertEqual(ret['options']['separator'], os.sep) + self.assertEqual(ret['options']['path'], connector._default._root_name) + + + #********* init with tree *********** + ret_tree = connector.execute('open', target='dummy', init='1', tree='1') + self.check_root_tree(ret_tree, 3, connector._default._root_name) + + ret['files'][:0] = [ret['cwd']] + self.assertEqual(ret, ret_tree) + + #******** init with tree and debug ******* + ret_tree_debug = connector.execute('open', target='dummy', init='1', tree='1', debug='1') + + self.assertEqual(ret_tree_debug['debug']['connector'], 'yawd-elfinder') + self.assertEqual(ret_tree_debug['debug']['mountErrors'], []) + self.assertEqual(ret_tree_debug['debug']['upload'], '') + self.assertEqual(ret_tree_debug['debug']['volumes'], [{'id': 'llff_', 'name': 'localfilesystem'}]) + self.assertIsInstance(ret_tree_debug['debug']['time'], float) + + del ret_tree_debug['debug'] + self.assertEqual(ret_tree, ret_tree_debug) + + def test_open_startpath(self): + """ + Test startpath option + """ + + self.opts['roots'][0]['startPath'] = 'files' + connector = ElfinderConnector(self.opts) + + #************ init without tree *********** + ret = connector.execute('open', target='dummy', init='1') + + #check files and cwd + self.assertEqual(len(ret['files']), 2) + self.assertNotEqual(ret['files'][0]['hash'], ret['files'][1]['hash']) + self.assertEqual(ret['files'][0]['name'], '2bytes.txt') + self.assertEqual(ret['files'][1]['name'], 'directory') + self.assertEqual(ret['cwd']['dirs'], 1) + self.assertEqual(ret['cwd']['name'], 'files') + self.assertEqual(ret['cwd']['read'], 1) + self.assertEqual(ret['cwd']['write'], 1) + self.assertEqual(ret['cwd']['locked'], 0) + self.assertEqual(ret['cwd']['hidden'], 0) + self.assertEqual(ret['cwd']['size'], 'unknown') + self.assertEqual(ret['cwd']['mime'], 'directory') + self.assertNotIn('volumeid', ret['cwd']) + self.assertIsInstance(ret['cwd']['ts'], float) + self.assertGreater(len(ret['cwd']['phash']), 0) + self.assertGreater(len(ret['cwd']['hash']), 0) + + #other response attributes + self.assertNotIn('error', ret) + self.assertIn('netDrivers', ret) + self.assertEqual(ret['uplMaxSize'], 128 * 1048576) + self.assertEqual(ret['api'], '2.1') + self.assertEqual(ret['options']['pathUrl'], '%sfiles' % settings.MEDIA_URL) + self.assertEqual(ret['options']['tmbUrl'], '%s.tmb/' % settings.MEDIA_URL) + self.assertIn('create', ret['options']['archivers']) + self.assertIn('extract', ret['options']['archivers']) + self.assertEqual(ret['options']['disabled'], []) + self.assertEqual(ret['options']['copyOverwrite'], 1) + self.assertEqual(ret['options']['separator'], os.sep) + self.assertEqual(ret['options']['path'], '%s%sfiles' % (connector._default._root_name, os.sep)) + + #********* init with tree *********** + ret_tree = connector.execute('open', target='dummy', init='1', tree='1') + self.check_root_tree(ret_tree, 5, connector._default._root_name) + + #cleanup startpath + self.opts['startpath'] = '' + + def test_open_path(self): + + connector = ElfinderConnector(self.opts) + + #************ init without tree *********** + ret = connector.execute('open', target=connector._default.encode( + connector._default._join_path(settings.MEDIA_ROOT, + connector._default._join_path('files', 'directory'))), + init='1') + + #check files and cwd + self.assertEqual(len(ret['files']), 1) + self.assertEqual(ret['files'][0]['name'], 'yawd-logo.png') + self.assertNotIn('dirs', ret['cwd']) + self.assertEqual(ret['cwd']['name'], 'directory') + self.assertEqual(ret['cwd']['read'], 1) + self.assertEqual(ret['cwd']['write'], 1) + self.assertEqual(ret['cwd']['locked'], 0) + self.assertEqual(ret['cwd']['hidden'], 0) + self.assertEqual(ret['cwd']['size'], 'unknown') + self.assertEqual(ret['cwd']['mime'], 'directory') + self.assertNotIn('volumeid', ret['cwd']) + self.assertIsInstance(ret['cwd']['ts'], float) + self.assertGreater(len(ret['cwd']['phash']), 0) + self.assertGreater(len(ret['cwd']['hash']), 0) + + #other response attributes + self.assertNotIn('error', ret) + self.assertIn('netDrivers', ret) + self.assertEqual(ret['uplMaxSize'], 128 * 1048576) + self.assertEqual(ret['api'], '2.1') + self.assertEqual(ret['options']['pathUrl'], '%sfiles/directory' % settings.MEDIA_URL) + self.assertEqual(ret['options']['tmbUrl'], '%s.tmb/' % settings.MEDIA_URL) + self.assertIn('create', ret['options']['archivers']) + self.assertIn('extract', ret['options']['archivers']) + self.assertEqual(ret['options']['disabled'], []) + self.assertEqual(ret['options']['copyOverwrite'], 1) + self.assertEqual(ret['options']['separator'], os.sep) + self.assertEqual(ret['options']['path'], '%s%sfiles%sdirectory' % (connector._default._root_name, os.sep, os.sep)) + + + def check_root_tree(self, ret, len_, name): + """ + Check that result contains the root tree + """ + + self.assertEqual(len(ret['files']), len_) + self.assertEqual(ret['files'][0]['name'], name) + self.assertEqual(ret['files'][1]['name'], 'files') + self.assertEqual(ret['files'][2]['name'], 'test') + + for i in range(1, len_): + for j in range(i-1, -1, -1): + self.assertNotEqual(ret['files'][i]['hash'], ret['files'][j]['hash']) + self.assertNotEqual(ret['files'][i]['name'], ret['files'][j]['name']) diff --git a/elfinder/tests/media/files/2bytes.txt b/elfinder/tests/media/files/2bytes.txt new file mode 100644 index 00000000..a616ad49 --- /dev/null +++ b/elfinder/tests/media/files/2bytes.txt @@ -0,0 +1 @@ +01 \ No newline at end of file diff --git a/elfinder/tests/media/files/directory/yawd-logo.png b/elfinder/tests/media/files/directory/yawd-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4fbe6ec0e9f930250b74fd07be49ba6c0e4f48d7 GIT binary patch literal 2865 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 P00000NkvXXu0mjfUn^4e literal 0 HcmV?d00001 diff --git a/elfinder/tests/volumes.py b/elfinder/tests/volumes.py new file mode 100644 index 00000000..bc408aba --- /dev/null +++ b/elfinder/tests/volumes.py @@ -0,0 +1,232 @@ +import os, re +from django.conf import settings +from django.utils import unittest +from elfinder.volumes.filesystem import ElfinderVolumeLocalFileSystem +from elfinder.volumes.storage import ElfinderVolumeStorage + +class ElfinderVolumeLocalFileSystemTestCase(unittest.TestCase): + volume_class = ElfinderVolumeLocalFileSystem + + def setUp(self): + settings.MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media') + + self.driver = self.volume_class() + self.options = { + 'id' : 'lfTest1', + 'path' : settings.MEDIA_ROOT, + 'alias' : 'Elfinder files', + 'URL' : settings.MEDIA_URL, + 'uploadAllow' : ['all',], + 'uploadDeny' : ['all',], + 'uploadOrder' : ['deny', 'allow'], + 'attributes' : [ + { + 'pattern' : '^%(sep)sfiles%(sep)sdirectory' % {'sep' : os.sep}, + 'read' : True, + 'write': True, + 'hidden' : True, + 'locked' : True + }, + ] + } + + self.driver.mount(self.options) + self.default_path = self.driver.default_path() + self.realPath = self.driver.decode(self.default_path) + + def test_defaultpath(self): + self.assertEqual(isinstance(self.default_path, basestring), True) + self.assertEqual(len(self.default_path) > 0, True) + + def test_dir(self): + + root = self.driver.dir(self.default_path, False) + self.assertEqual(root['read'], 1) + self.assertEqual(root['write'], 1) + self.assertEqual(root['mime'], 'directory') + self.assertIn('volumeid', root) + self.assertIn('ts', root) + self.assertIn('name', root) + self.assertIn('hash', root) + self.assertIn('size', root) + self.assertIn('locked', root) + + def test_stat_dir(self): + stat = self.driver.stat(self.realPath) + self.assertEqual(stat['size'], 'unknown') + self.assertEqual(stat['mime'], 'directory') + self.assertEqual(stat['read'], 1) + self.assertEqual(stat['write'], 1) + self.assertIsInstance(stat['ts'], float) + self.assertEqual(stat['dirs'], 1) + + def test_stat_file(self): + stat = self.driver.stat(self.driver._join_path(self.driver._options['path'], self.driver._join_path('files','2bytes.txt'))) + self.assertEqual(stat['name'], '2bytes.txt') + self.assertEqual(stat['read'], 1) + self.assertEqual(stat['write'], 1) + self.assertEqual(stat['mime'].startswith('text/'), True) + self.assertEqual(stat['size'], 2) + self.assertEqual(stat['hash'], self.driver.encode(self.driver._join_path(self.options['path'], self.driver._join_path('files','2bytes.txt')))) + self.assertEqual(stat['phash'], self.driver.encode(self.driver._join_path(self.options['path'],'files'))) + self.assertIsInstance(stat['ts'], float) + self.assertNotIn('dirs', stat) + + def test_dimensions(self): + dim = self.driver.dimensions(self.driver.encode(self.driver._join_path(self.driver._options['path'], self.driver._join_path('files', self.driver._join_path('directory', 'yawd-logo.png'))))) + self.assertEqual(dim, '260x35') + + def test_tree(self): + tree = self.driver.tree(self.default_path, 2) + self.assertEquals(len(tree), 3) + self.assertEquals(tree[0]['hash'], self.default_path) + self.assertEquals(tree[1]['hash'], self.driver.encode(self.driver._join_path(self.driver._options['path'],'files'))) + self.assertEquals(tree[2]['hash'], self.driver.encode(self.driver._join_path(self.driver._options['path'],'test'))) + + def test_open_close(self): + hash_ = self.driver.encode(self.driver._join_path(self.options['path'], self.driver._join_path('files','2bytes.txt'))) + fp = self.driver.open(hash_) + self.assertEqual(fp.read(), '01') + self.driver.close(fp, hash_) + + def test_mkfile_unlink(self): + path = self.driver._join_path(self.options['path'], 'files') + name = 'tmpfile' + joined_path = self.driver._join_path(path, name) + + enc_path = self.driver.encode(path) + enc_joined_path = self.driver.encode(joined_path) + + stat = self.driver.mkfile(enc_path, name) + self.driver.rm(enc_joined_path) + removed = self.driver.removed() + + self.assertEqual(stat['hash'], enc_joined_path) + self.assertEqual(len(removed), 1) + self.assertEqual(removed[0]['name'], name) + self.assertEqual(removed[0]['hash'], enc_joined_path) + self.assertEqual(removed[0]['phash'], enc_path) + self.assertEqual(removed[0]['realpath'], joined_path) + self.assertEqual(removed[0]['read'], 1) + self.assertEqual(removed[0]['write'], 1) + self.assertEqual(removed[0]['size'], 0) + self.assertIn('mime', removed[0]) + self.assertIn('ts', removed[0]) + + def test_mkdir_rmdir(self): + path = self.driver._join_path(self.options['path'], 'files') + name = 'tmpdir' + joined_path = self.driver._join_path(path, name) + + enc_path = self.driver.encode(path) + enc_joined_path = self.driver.encode(joined_path) + + stat = self.driver.mkdir(enc_path, name) + self.driver.rm(enc_joined_path) + removed = self.driver.removed() + + self.assertEqual(stat['hash'], enc_joined_path) + self.assertEqual(len(removed), 1) + self.assertEqual(removed[0]['name'], name) + self.assertEqual(removed[0]['hash'], enc_joined_path) + self.assertEqual(removed[0]['phash'], enc_path) + self.assertEqual(removed[0]['realpath'], joined_path) + self.assertEqual(removed[0]['read'], 1) + self.assertEqual(removed[0]['write'], 1) + self.assertEqual(removed[0]['size'], 'unknown') + self.assertEqual(removed[0]['mime'], 'directory') + self.assertIn('ts', removed[0]) + + def test_locked(self): + stat = self.driver.stat(self.driver._join_path(self.options['path'], self.driver._join_path('files', 'directory'))) + self.assertEqual(stat['locked'], 1) + + stat = self.driver.stat(self.driver._join_path(self.options['path'], 'files')) + self.assertEqual(stat['locked'], 0) + + def test_hidden(self): + stat = self.driver.stat(self.driver._join_path(self.options['path'], self.driver._join_path('files', 'directory'))) + self.assertEqual(stat['hidden'], 1) + + stat = self.driver.stat(self.driver._join_path(self.options['path'], 'files')) + self.assertEqual(stat['hidden'], 0) + + def tearDown(self): + self.driver.reset_removed() + +class ElfinderVolumeLocalFileSystemThumbnailTestCase(unittest.TestCase): + volume_class = ElfinderVolumeLocalFileSystem + + def setUp(self): + settings.MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media') + self.driver = self.volume_class() + + options = { + 'id' : 'test', + 'tmpPath' : self.driver._join_path(os.path.dirname(__file__), 'tmbtest'), + 'tmbURL' : 'http://example.com/files', #test _urlize + 'tmbSize' : 32 + } + + self.driver.mount(options) + self.default_path = self.driver.default_path() + self.realPath = self.driver.decode(self.default_path) + + def test_options(self): + + options = self.driver.options(self.default_path) + self.assertEqual(options['tmbUrl'], 'http://example.com/files/') + self.assertEqual(options['separator'], os.sep) + self.assertEqual(options['path'].startswith(settings.MEDIA_ROOT), False) + self.assertIn('url', options) + self.assertIn('archivers', options) + self.assertIn('disabled', options) + self.assertIn('copyOverwrite', options) + +class ElfinderVolumeStorageTestCase(ElfinderVolumeLocalFileSystemTestCase): + volume_class = ElfinderVolumeStorage + + def test_tree(self): + tree = self.driver.tree(self.default_path, 2) + self.assertEquals(len(tree), 3) + self.assertEquals(tree[0]['hash'], self.default_path) + self.assertEquals(tree[1]['hash'], self.driver.encode(self.driver._join_path(self.driver._options['path'],'files'))) + self.assertEquals(tree[2]['hash'], self.driver.encode(self.driver._join_path(self.driver._options['path'],'test'))) + +class ElfinderVolumeFilePermissionTestcase(unittest.TestCase): + + def setUp(self): + + options = { + 'id' : 'stTest1', + 'attributes' : [{ + 'pattern' : r'a%stmp' % re.escape(os.sep), + 'read' : True, + 'write' : False, + 'locked' : True, + 'hidden' : True, + },{ + 'pattern' : r'tmp', + 'read' : False, + 'write' : False, + 'locked' : True, + 'hidden' : True, + }], + 'defaults' : { + 'read' : False + } + } + + self.driver = ElfinderVolumeLocalFileSystem() + self.driver.mount(options) + self.root = self.driver.decode(self.driver.default_path()) + + def test_read(self): + + self.assertEqual(self.driver._attr('%(root)s%(sep)sa%(sep)sb%(sep)sc' % {'root': self.root, 'sep':os.sep}, 'read'), False) + self.assertEqual(self.driver._attr('%(root)s%(sep)sa%(sep)stmp%(sep)sc' % {'root': self.root, 'sep':os.sep}, 'read'), True) + self.assertEqual(self.driver._attr('%(root)s%(sep)sb%(sep)stmp%(sep)sc' % {'root': self.root, 'sep':os.sep}, 'read'), False) + + def test_locked(self): + + self.assertEqual(self.driver._attr(self.root, 'locked'), True) \ No newline at end of file diff --git a/elfinder/urls.py b/elfinder/urls.py new file mode 100644 index 00000000..31a27e26 --- /dev/null +++ b/elfinder/urls.py @@ -0,0 +1,21 @@ +"""elfinder URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.8/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import include, url +from django.contrib.admin.views.decorators import staff_member_required +from elfinder.views import ElfinderConnectorView + +urlpatterns = [ + url(r'^yawd-connector/(?P.+)/(?P.+)/$',staff_member_required(ElfinderConnectorView.as_view()),name='yawdElfinderConnectorView'), +] \ No newline at end of file diff --git a/elfinder/utils/__init__.py b/elfinder/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/elfinder/utils/accesscontrol.py b/elfinder/utils/accesscontrol.py new file mode 100644 index 00000000..6e2318ba --- /dev/null +++ b/elfinder/utils/accesscontrol.py @@ -0,0 +1,28 @@ +import os + + +def fs_standard_access(attr, path, volume): + """ + Make dotfiles not readable, not writable, hidden and locked. + Should return None to allow for original attribute value, boolean otherwise. + This can be used in the :ref:`setting-accessControl` setting. + + Args: + :attr: One of `read`, `write`, `hidden` and `locked`. + :path: The path to check against. + :volume: The volume responsible for managing the path. + + Returns: + ``True`` if `path` has `attr` permissions, ``False`` if not and + ``None`` to apply the default permission rules. + """ + + if os.path.basename(path) in ['.tmb', '.quarantine']: + #keep reserved folder names intact + return None + + if volume.name() == 'localfilesystem': + if attr in ['read', 'write'] and os.path.basename(path).startswith('.'): + return False + elif attr in ['hidden', 'locked'] and os.path.basename(path).startswith('.'): + return True diff --git a/elfinder/utils/archivers.py b/elfinder/utils/archivers.py new file mode 100644 index 00000000..157cb6d8 --- /dev/null +++ b/elfinder/utils/archivers.py @@ -0,0 +1,41 @@ +from zipfile import ZipFile + + +class ZipFileArchiver(object): + """ + An archiver used to generate .zip files. + This wraps Python's built in :class:`zipfile.ZipFile` + methods to operate exactly like :class:`tarfile.TarFile` does. + """ + + def __init__(self, *args, **kwargs): + """ + Create a :class:`.ZipFileArchiver` instance. We create a new + :class:`zipfile.ZipFile` and store it to the ``zipfile`` member. + """ + self.zipfile = ZipFile(*args, **kwargs) + + @classmethod + def open(self, *args, **kwargs): + """ + Open the archive. This must be a classmethod. + """ + return ZipFileArchiver(*args,**kwargs) + + def add(self, *args, **kwargs): + """ + Add file to the archive. + """ + self.zipfile.write(*args, **kwargs) + + def extractall(self, *args, **kwargs): + """ + Extract all files from the archive. + """ + self.zipfile.extractall(*args, **kwargs) + + def close(self): + """ + Close the archive. + """ + self.zipfile.close() diff --git a/elfinder/utils/volumes.py b/elfinder/utils/volumes.py new file mode 100644 index 00000000..f836f4f8 --- /dev/null +++ b/elfinder/utils/volumes.py @@ -0,0 +1,52 @@ +#from django.utils.importlib import import_module +from importlib import import_module +from elfinder.conf import settings as ls + + +def get_path_driver(hash_, optionset): + """ + Given an ``optionset`` and a path ``hash_`` this function returns + a mounted volume driver for this path. + + This method assumes that the driver uses the default driver + :func:`elfinder.volumes.base.ElfinderVolumeDriver.id` implementation + to generate its id. + """ + for root_options in ls.ELFINDER_CONNECTOR_OPTION_SETS[optionset]['roots']: + if 'driver' in root_options: + if hash_.startswith('%s%s_' % (root_options['driver']._driver_id, root_options['id'])): + return instantiate_driver(root_options) + + +def instantiate_driver(root_options): + """ + Instantiate and return a driver, given its ``root_options``. + """ + class_ = root_options['driver'] if 'driver' in root_options else '' + + if 'driverInstance' in root_options and isinstance(root_options['driverInstance'], class_): + return root_options['driverInstance'] + + if isinstance(class_, basestring) and class_: + try: + split = class_.split('.') + storage_module = import_module('.'.join(split[:-1])) + volume = getattr(storage_module, split[-1])() + except: + raise Exception('Could not import driver "%s"' % class_) + else: + try: + volume = class_() + except TypeError: + raise Exception('Driver "%s" does not exist' % class_) + + try: + volume.mount(root_options) + except Exception as e: + raise Exception('Driver "%s" " %s' % (class_, e)) + + #store driver instance in memory, if the 'keepAlive' option is set + if 'keepAlive' in root_options and root_options['keepAlive']: + root_options['driverInstance'] = volume + + return volume diff --git a/elfinder/views.py b/elfinder/views.py new file mode 100644 index 00000000..9cdfaa71 --- /dev/null +++ b/elfinder/views.py @@ -0,0 +1,137 @@ +import json +from django.http import HttpResponse, Http404 +from django.utils.decorators import method_decorator +from django.views.generic.base import View +from django.views.decorators.csrf import csrf_exempt +from exceptions import ElfinderErrorMessages +from elfinder.connector import ElfinderConnector +from elfinder.conf import settings as ls +from django.shortcuts import render_to_response + +class ElfinderConnectorView(View): + """ + Default elfinder backend view + """ + + def render_to_response(self, context, **kwargs): + """ + It returns a json-encoded response, unless it was otherwise requested + by the command operation + """ + kwargs = {} + additional_headers = {} + #create response headers + if 'header' in context: + for key in context['header']: + if key == 'Content-Type': + kwargs['content_type'] = context['header'][key] + elif key.lower() == 'status': + kwargs['status'] = context['header'][key] + else: + additional_headers[key] = context['header'][key] + del context['header'] + + #return json if not header + if not 'content_type' in kwargs: + kwargs['content_type'] = 'application/json' + + if 'pointer' in context: #return file + context['pointer'].seek(0) + kwargs['content'] = context['pointer'].read() + context['volume'].close(context['pointer'], context['info']['hash']) + elif 'raw' in context and context['raw'] and 'error' in context and context['error']: #raw error, return only the error list + kwargs['content'] = context['error'] + elif kwargs['content_type'] == 'application/json': #return json + kwargs['content'] = json.dumps(context) + else: #return context as is! + kwargs['content'] = context + + response = HttpResponse(**kwargs) + for key, value in additional_headers.items(): + response[key] = value + + return response + + def output(self, cmd, src): + """ + Collect command arguments, operate and return self.render_to_response() + """ + args = {} + + for name in self.elfinder.commandArgsList(cmd): + if name == 'request': + args['request'] = self.request + elif name == 'FILES': + args['FILES'] = self.request.FILES + elif name == 'targets': + args[name] = src.getlist('targets[]') + elif name == 'upload_path': + args[name] = src.getlist('upload_path[]') + else: + arg = name + if name.endswith('_'): + name = name[:-1] + if name in src: + try: + args[arg] = src.get(name).strip() + except: + args[arg] = src.get(name) + if cmd == 'mkdir': + args['name'] = src.getlist('dirs[]') if 'dirs[]' in src else src.getlist('name') + elif cmd == "upload": + args['upload_path'] = src.getlist('upload_path[]') if 'upload_path[]' in src else False + elif cmd == "size": + args['targets'] = src.getlist('targets[0]') + args['debug'] = src['debug'] if 'debug' in src else False + return self.render_to_response(self.elfinder.execute(cmd, **args)) + + def get_command(self, src): + """ + Get requested command + """ + try: + return src['cmd'] + except KeyError: + return 'open' + + def get_optionset(self, **kwargs): + set_ = ls.ELFINDER_CONNECTOR_OPTION_SETS[kwargs['optionset']] + if kwargs['start_path'] != 'default': + for root in set_['roots']: + root['startPath'] = kwargs['start_path'] + return set_ + + @method_decorator(csrf_exempt) + def dispatch(self, *args, **kwargs): + if not kwargs['optionset'] in ls.ELFINDER_CONNECTOR_OPTION_SETS: + raise Http404 + return super(ElfinderConnectorView, self).dispatch(*args, **kwargs) + + def get(self, request, *args, **kwargs): + """ + used in get method calls + """ + if kwargs['optionset'] == 'sftp': + optinon_sets = self.get_optionset(**kwargs) + optinon_sets['roots'][0]['storageKwArgs'] = {'host':'127.0.0.1','params':{'port':22,'username':'test','password':'password','timeout':30},'root_path':'/','interactive':False} + self.elfinder = ElfinderConnector(optinon_sets, request.session) + else: + self.elfinder = ElfinderConnector(self.get_optionset(**kwargs), request.session) + return self.output(self.get_command(request.GET), request.GET) + + def post(self, request, *args, **kwargs): + """ + called in post method calls. + It only allows for the 'upload' command + """ + if kwargs['optionset'] == 'sftp': + optinon_sets = self.get_optionset(**kwargs) + optinon_sets['roots'][0]['storageKwArgs'] = {'host':'127.0.0.1','params':{'port':22,'username':'test','password':'password','timeout':30},'root_path':'/','interactive':False} + self.elfinder = ElfinderConnector(optinon_sets, request.session) + else: + self.elfinder = ElfinderConnector(self.get_optionset(**kwargs), request.session) + cmd = self.get_command(request.POST) + + if not cmd in ['upload']: + self.render_to_response({'error' : self.elfinder.error(ElfinderErrorMessages.ERROR_UPLOAD, ElfinderErrorMessages.ERROR_UPLOAD_TOTAL_SIZE)}) + return self.output(cmd, request.POST) \ No newline at end of file diff --git a/elfinder/volumes/__init__.py b/elfinder/volumes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/elfinder/volumes/base.py b/elfinder/volumes/base.py new file mode 100644 index 00000000..a9dff0f2 --- /dev/null +++ b/elfinder/volumes/base.py @@ -0,0 +1,2148 @@ +import os, datetime, mimetypes, re, inspect, time, logging +try: + from PIL import Image +except ImportError: + import Image +from base64 import b64encode, b64decode +from string import maketrans +from tarfile import TarFile +from django.core.cache import cache +from django.utils.translation import ugettext as _ +from elfinder.exceptions import ElfinderErrorMessages, FileNotFoundError, DirNotFoundError, PermissionDeniedError, NamedError, NotAnImageError +from elfinder.utils.archivers import ZipFileArchiver + +class ElfinderVolumeDriver(object): + """ + The base volume driver. Every elfinder volume driver should subclass + this volume. + """ + + #The driver id. + #Must start with a letter and contain only [a-z0-9] + #Used as part of volume id + _driver_id = 'a' + + #Directory separator - required by the client + _separator = os.sep + + #*********************************************************************# + #* INITIALIZATION *# + #*********************************************************************# + + def __init__(self): + """ + Default constructor + """ + # files is in type key file value type + self._files = {} + # key label + self._key_label = '' + #logger + self.logger = logging.getLogger(__name__) + #Volume id - used as prefix for files hashes + self._id = '' + #Flag - volume "mounted" and available + self._mounted = False + #Root directory path + self._root = '' + #Root basename | alias + self._root_name = '' + #Default directory to open + self._start_path = '' + #Store moved or overwrited files info + self._removed = [] + #Is thumbnails dir writable + self._tmb_path_writable = False + #Today 24:00 timestamp + self._today = 0 + #Yesterday 24:00 timestamp + self._yesterday = 0 + #list of attributes + self._attributes = [] + #Default permissions + self._defaults = {} + #Archivers config + self._archivers = { + 'create' : {}, + 'extract' : {} + } + + #Object configuration + self._options = { + 'id' : '', + #root directory path + 'path' : '/', + #alias to replace root dir_ name + 'alias' : '', + #root url, not set to disable sending URL to client (replacement for old "fileURL" option) + 'URL' : '', + #open this path on initial request instead of root path + 'startPath' : '', + #how many subdirs levels return per request + 'treeDeep' : 1, + #directory separator. required by client to show paths correctly + 'separator' : os.sep, + #directory for thumbnails + 'tmbPath' : '.tmb', + #thumbnails dir URL. Set it if store thumbnails outside root directory + 'tmbURL' : '', + #thumbnails size (px) + 'tmbSize' : 48, + #thumbnails crop (True - crop, False - scale image to fit thumbnail size) + 'tmbCrop' : True, + #thumbnails background color (hex #rrggbb or 'transparent') + 'tmbBgColor' : '#ffffff', + #on paste file - if True - old file will be replaced with new one, if False new file get name - original_name-number.ext + 'copyOverwrite' : True, + #if True - join new and old directories content on paste + 'copyJoin' : True, + #on upload - if True - old file will be replaced with new one, if False new file get name - original_name-number.ext + 'uploadOverwrite' : True, + #filter mime types to allow + 'onlyMimes' : [], + #mimetypes allowed to upload + 'uploadAllow' : [], + #mimetypes not allowed to upload + 'uploadDeny' : [], + #order to proccess uploadAllow and uploadDeny options + 'uploadOrder' : ['deny', 'allow'], + #maximum upload file size. Set as number or string with unit - "10M", "500K", "1G". NOTE - applies to each uploaded file individually + 'uploadMaxSize' : 0, + #files dates format. CURRENTLY NOT IMPLEMENTED + 'dateFormat' : 'j M Y H:i', + #files time format. CURRENTLY NOT IMPLEMENTED + 'timeFormat' : 'H:i', + #if True - every folder will be check for children folders, otherwise all folders will be marked as having subfolders + 'checkSubfolders' : True, + #allow to copy from this volume to other ones? + 'copyFrom' : True, + #allow to copy from other volumes to this one? + 'copyTo' : True, + #list of commands disabled on this root + 'disabled' : [], + #regexp or function name to validate new file name + 'acceptedName' : r'^[^\.].*', #<-- DONT touch this! Use constructor options to overwrite it! + #callable to control file permissions + 'accessControl' : None, + # allow rmDir + 'rmDir' : None, + #default permissions. Do not set hidden/locked here - take no effect + 'defaults' : { + 'read' : True, + 'write' : True + }, + #a list of dictionaries, each defining a 'pattern' and values for at + #least one of the 'hidden', 'locked', 'read' and 'write' attributes for this pattern + 'attributes' : [], + #quarantine folder name - required to check archive (must be hidden) + 'quarantine' : '.quarantine', + #Allowed archive's mimetypes to create. Leave empty for all available types. + 'archiveMimes' : [], + #Manual config for archivers. + 'archivers' : {}, + #max allowed archive files size (0 - no limit) + 'archiveMaxSize' : 0, + #seconds to cache the file and dir data used by the driver + 'cache' : 600 + } + + #*********************************************************************# + #* PUBLIC API *# + #*********************************************************************# + + def name(self): + """ + Return the driver name. + """ + return self.__class__.__name__[len('elfindervolume'):].lower() + + def driver_id(self): + """ + Return the driver id. Used as a part of volume id. + """ + return self._driver_id + + def id(self): + """ + Return volume id. + """ + return self._id + + def debug(self): + """ + Return debug info for client. The returned dictionary contains + the following keys: + + :id: the volume id + :name: the volume name + """ + return { + 'id' : self.id(), + 'name' : self.name(), + } + + def mount(self, opts): + """ + "Mount" volume. Return ``True`` if volume available for read + or write, ``False`` otherwise. + + It is common for drivers to override this method. + """ + + self._options.update(opts) + + if self._options['id']: + self._id = '%s%s_' % (self._driver_id, self._options['id']) + else: + raise Exception(_('No volume id found')) + + self._root = self._normpath(unicode(self._options['path'])) + self._separator = self._options['separator'] if 'separator' in self._options else os.sep + + #default file attribute + self._defaults = { + 'read' : self._options['defaults']['read'] if 'read' in self._options['defaults'] else True, + 'write' : self._options['defaults']['write'] if 'write' in self._options['defaults'] else True, + 'locked' : False, + 'hidden' : False + } + + #root attributes + self._attributes.insert(0, { + 'pattern' : '^%s$' % re.escape(self._separator), + 'locked' : True, + 'hidden' : False + }) + + #set files attributes + for a in self._options['attributes']: + #attributes must contain pattern and at least one rule + if 'pattern' in a and len(a) > 1: + self._attributes.append(a) + + #assign some options to private members + self._today = time.mktime(datetime.date.today().timetuple()) + self._yesterday = self._today-86400 + + #set uploadMaxSize, archiveMaxSize + units = { + 'k' : 1024, + 'm' : 1048576, + 'g' : 1073741824, + 'b' : 1 + } + for opt in ['uploadMaxSize', 'archiveMaxSize']: + if not isinstance(self._options[opt], int): + try: + self._options[opt] = int(self._options[opt][:-1]) * units[self._options[opt][-1].lower()] + except (TypeError, KeyError): + self._options[opt] = 0 + + self._root_name = self._basename(self._root) if not self._options['alias'] else self._options['alias'] + + try: + root = self.stat(self._root) + except os.error: + raise DirNotFoundError + + if (not 'read' in root or not root['read']) and (not 'write' in root and not root['write']): + raise PermissionDeniedError + + if 'read' in root and root['read']: + #check startPath - path to open by default instead of root + if self._options['startPath']: + try: + startpath = self._join_path(self._root, self._options['startPath']) + start = self.stat(startpath) + if start['mime'] == 'directory' and start['read'] and not self._is_hidden(start): + self._start_path = self._normpath(startpath) + except os.error: + #Fail silently if startPath does not exist + pass + else: + self._options['URL'] = '' + self._options['tmbURL'] = '' + self._options['tmbPath'] = '' + #read only volume + self._attributes.insert(0, { + 'pattern' : r'.*', + 'read' : False + }) + + self._options['URL'] = self._urlize(self._options['URL']) + self._options['tmbURL'] = self._urlize(self._options['tmbURL']) + + self._checkArchivers() + + #add quarantine folder to locked and hidden patterns + self._attributes.append({ + 'pattern' : '^%s$' % re.escape('%s%s' % (self._separator, self._options['quarantine'])), + 'read' : False, + 'write' : False, + 'locked' : True, + 'hidden': True + }) + + #check quarantine dir + if self._options['quarantine']: + self._quarantine = self._join_path(self._root, self._options['quarantine']) + isdir = os.path.isdir(self._quarantine) + + if not self._options['quarantine'] or (isdir and not os.access(self._quarantine, os.W_OK)): + self._archivers['extract'] = {} + self._options['disabled'].append('extract') + elif self._options['quarantine'] and not isdir: + try: + os.mkdir(self._quarantine) + except os.error: + self._archivers['extract'] = {} + self._options['disabled'].append('extract') + + self._configure() + + self._mounted = True + + def _configure(self): + """ + Configure after successful mount. The default implementation + sets the thumbnail path. + + It is common for drivers to override this method. + """ + #set thumbnails path + if self._options['tmbPath']: + path = self._join_path(self._root, self._options['tmbPath']) + + self._attributes.append({ + 'pattern' : '^%s$' % re.escape('%s%s' % (self._separator, self._relpath(path))), + 'locked' : True, + 'hidden' : True + }) + + try: + stat = self.stat(path) + except os.error: + try: + self._mkdir(path=path) + stat = self.stat(path) + except os.error: + stat = None + + if stat and stat['mime'] == 'directory' and stat['read']: + self._options['tmbPath'] = path + self._tmb_path_writable = stat['write'] + else: + self._options['tmbPath'] = '' + + def unmount(self): + """ + The unmunt method is currently not used, but in the future it + might be useful to some drivers. + """ + pass + + def default_path(self): + """ + Return volume root or startPath hash. + """ + return self.encode(self._start_path if self._start_path else self._root) + + def upload_max_size(self): + """ + Return the upload max size. + """ + return self._options['uploadMaxSize'] + + def options(self, hash_): + """ + Return volume options required by client. The returned dictionary + contains the following keys: + + :path: the path to the root as it will be displayed to the end user + :url: the root volume url + :pathUrl: url of the path provided in the ``hash_`` argument + :tmbUrl: the root thumbnail url + :disabled: a list of the disabled commands + :separator: the path separator for this volume + :copyOverwrite: whether it is allowed or not to overwrite a file + :archivers: the available create and extract archives (e.g. tar, gzip etc.) + + """ + path = self.decode(hash_) + return { + 'path' : self._path(self.decode(hash_)), + 'url' : self._options['URL'], + #this custom attribute (not part of the original response) is used to return the hash url + 'pathUrl' : '%s%s' % (self._options['URL'], self._relpath(path).replace(self._options['separator'], '/')), + 'tmbUrl' : self._options['tmbURL'], + 'disabled' : self._options['disabled'], + 'separator' : self._separator, + 'copyOverwrite' : int(self._options['copyOverwrite']), + 'archivers' : { + 'create' : self._archivers['create'].keys(), + 'extract' : self._archivers['extract'].keys() + } + } + + def command_disabled(self, cmd): + """ + Return ``True`` if command ``cmd`` is disabled. + """ + return cmd in self._options['disabled'] + + def set_mimes_filter(self, mimes): + """ + Set mimetypes allowed to display to the client. + """ + self._options['onlyMimes'] = mimes + + def mime_accepted(self, mime, mimes = [], empty = True): + """ + Return ``True`` if ``mime`` is in required mimes list. + """ + mimes = mimes if mimes else self._options['onlyMimes'] + if not mimes: + return empty + + return mime == 'directory' or 'all' in mimes or 'All' in mimes or mime in mimes or mime[0:mime.find('/')] in mimes + + def is_readable(self): + """ + Return ``True`` if root is readable. + """ + return self.stat(self._root)['read'] + + def copy_from_allowed(self): + """ + Return ``True`` if copy from this volume is allowed. + """ + return self._options['copyFrom'] + + def path(self, hash_): + """ + Return file path related to the volume root. + """ + return self._path(self.decode(hash_)) + + def removed(self): + """ + Return a list of moved/overwrited files. + """ + return self._removed + + def reset_removed(self): + """ + Clean removed files list. + """ + self._removed = [] + + def closest(self, hash_, attr, val): + """ + Return the file/directory hash or the first found child hash + for which ``attr`` == ``val``. + """ + path = self._closest_by_attr(self.decode(hash_), attr, val) + return self.encode(path) if path else False + + def file(self, hash_): + """ + Return file info or raises a ``FileNotFoundError`` if file was + not found. + """ + try: + return self.stat(self.decode(hash_)) + except os.error: + raise FileNotFoundError + + def dir(self, hash_, resolve_link=False): + """ + Return folder info. Raises a ``DirNotFoundError`` if ``hash_`` path + is not a directory, or ``FileNotFoundError`` if the ``hash_`` + path is not a valid file at all. + """ + dir_ = self.file(hash_) + if resolve_link and 'thash' in dir_ and dir_['thash']: + dir_ = self.file(dir_['thash']) + + if dir_['mime'] != 'directory' or self._is_hidden(dir_): + raise DirNotFoundError + + return dir_ + + def scandir(self, hash_): + """ + Return directory contents. + Raises a ``DirNotFoundError`` if ``hash_`` is not a valid dir, + or a ``PermissionDenied Error`` if the user cannot access the data. + """ + if not self.dir(hash_)['read']: + raise PermissionDeniedError + return self._get_scandir(self.decode(hash_)) + + def ls(self, hash_): + """ + List directory files. Can raise + ``PermissionDeniedError``, ``FileNotFoundError``, ``DirNotFoundError`` + If a mime filter is set, use it to return only accepted listings. + """ + if not self.dir(hash_)['read']: + raise PermissionDeniedError + + list_ = [] + path = self.decode(hash_) + + for stat in self._get_scandir(path): + if self.mime_accepted(stat['mime']): + list_.append(stat['name']) + + return list_ + + def tree(self, hash_='', deep=0, exclude=''): + """ + Return sub-directories for the required folder ``has_``, + or raise an ``Exception``. + """ + path = self.decode(hash_) if hash_ else self._root + + dirs = [self.stat(path)] + if dirs[0]['mime'] != 'directory': + return [] + + try: + excluded = self.decode(exclude) + except FileNotFoundError: + excluded = None + + return dirs + self._get_tree(path, (deep - 1) if deep > 0 else (self._options['treeDeep'] - 1), excluded) + + def parents(self, hash_): + """ + Return part of dirs tree from required dir up to the root dir. + Raises ``DirNotFoundError``, ``FileNotFoundError``, ``PermissionDeniedError``. + """ + current = self.dir(hash_) + path = self.decode(hash_) + tree = [] + + while path and path != self._root: + stat = self.stat(path) + if self._is_hidden(stat) or not stat['read']: + raise PermissionDeniedError + + tree[:0] = [stat] + if path != self._root: + for dir_ in self._get_tree(path, 0): + if not dir_ in tree: + tree.append(dir_) + path = self._dirname(path) + + return tree if tree else [current] + + def tmb(self, hash_): + """ + Create thumbnail for the required file ``hash_`` and return + its name. It will raise an ``Exception`` on fail. + """ + + path = self.decode(hash_) + stat = self.file(hash_) + name = self._tmb_name(stat) + + if 'tmb' in stat and stat['tmb'] != 1: + return stat['tmb'] + + if not self._can_create_tmb(path, stat): + raise PermissionDeniedError + + #copy the image to the thumbnail + tmb = self._join_path(self._options['tmbPath'], name) + tmb_size = self._options['tmbSize'] + + try: + im = self._openimage(path) + if im.mode == "CMYK": + im = im.convert("RGB") + s = im.size + except: + raise NotAnImageError + + # If image smaller or equal thumbnail size - just fitting to thumbnail square + if s[0] <= tmb_size and s[1] <= tmb_size: + self._img_square_fit(im, tmb, tmb_size, tmb_size, self._options['tmbBgColor'], 'png') + elif self._options['tmbCrop']: + #Resize and crop if image bigger than thumbnail + if s[0] > tmb_size and s[1] > tmb_size: + resized = self._img_resize(im, None, tmb_size, tmb_size, True, False, 'png') + s = resized.size + self._img_crop(resized, tmb, tmb_size, tmb_size, int((s[0] - tmb_size)/2), int((s[1] - tmb_size)/2), 'png') + else: + fit = self._img_square_fit(im, None, s[0] if s[0] > s[1] else s[1], s[0] if s[0] > s[1] else s[1], self._options['tmbBgColor'], 'png') + self._img_crop(fit, tmb, tmb_size, tmb_size, + int((s[0] - tmb_size)/2) if s[0] > tmb_size else 0, + int((s[1] - tmb_size)/2) if s[1] > tmb_size else 0, 'png') + else: + try: + im.thumbnail((tmb_size, tmb_size), Image.ANTIALIAS) + self._img_square_fit(im, tmb, tmb_size, tmb_size, self._options['tmbBgColor'], 'png' ) + except: + self._unlink(tmb) + raise + + if hasattr(im, 'fp') and im.fp: + im.fp.close() + + self._clear_cached_stat(path) + return name + + def size(self, hash_): + """ + Return file size or total directory size. + """ + return self._size(self.decode(hash_)) + + def open(self, hash_): + """ + Open file for reading and return a file pointer. + """ + + if self.file(hash_)['mime'] == 'directory': + raise FileNotFoundError + + return self._fopen(self.decode(hash_), 'r') + + def close(self, fp, hash_): + """ + Close a file pointer. + """ + self._fclose(fp, path=self.decode(hash_)) + + def mkdir(self, hash_dst, name): + """ + Create directory and return its stat info. + """ + + if self.command_disabled('mkdir'): + raise PermissionDeniedError + + if not self._name_accepted(name): + raise Exception(ElfinderErrorMessages.ERROR_INVALID_NAME) + + error_path = self.path(hash_dst) + + try: + dir_ = self.dir(hash_dst) + except (FileNotFoundError, DirNotFoundError): + raise NamedError(ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % error_path) + + if not dir_['write']: + raise PermissionDeniedError + + dst_dir = self.decode(hash_dst) + dst = self._join_path(dst_dir, name) + + try: + self.stat(dst) + raise NamedError(ElfinderErrorMessages.ERROR_EXISTS, name) + except: + self._clear_cached_dir(dst_dir) + + return self.stat(self._mkdir(dst)) + + def mkfile(self, hash_dst, name): + """ + Create empty file and return its stat info. + """ + + if self.command_disabled('mkfile'): + raise PermissionDeniedError + + if not self._name_accepted(name): + raise Exception(ElfinderErrorMessages.ERROR_INVALID_NAME) + + error_path = self.path(hash_dst) + + try: + dir_ = self.dir(hash_dst) + except (FileNotFoundError, DirNotFoundError): + raise NamedError(ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % error_path) + + path = self.decode(hash_dst) + if not dir_['write'] or not self._attr(self._join_path(path, name), 'write'): + raise PermissionDeniedError + + try: + self.stat(self._join_path(path, name)) + raise NamedError(ElfinderErrorMessages.ERROR_EXISTS, name) + except os.error: + pass + + self._clear_cached_dir(path) + + return self.stat(self._mkfile(path, name)) + + def rename(self, hash_, name): + """ + Rename file and return file info. + """ + + path = self.decode(hash_) + dir_ = self._dirname(path) + + if self.command_disabled('rename') or not self._attr(self._join_path(dir_, name), 'write'): + raise PermissionDeniedError + + if not self._name_accepted(name): + raise Exception(ElfinderErrorMessages.ERROR_INVALID_NAME) + + file_ = self.file(hash_) + file_['realpath'] = path + + if file_['mime'] == 'directory' and self.command_disabled('rmdir'): + raise PermissionDeniedError + + if name == self._basename(path): + return file_ + + if self._is_locked(file_): + raise NamedError(ElfinderErrorMessages.ERROR_LOCKED, file_['name']) + + try: + self.stat(self._join_path(dir_, name)) + raise NamedError(ElfinderErrorMessages.ERROR_EXISTS, name) + except os.error: + pass + + self._rm_tmb(file_) #remove old name tmbs, we cannot do this after dir move + + try: + ret = self._move(path, dir_, name) + except: + raise NamedError(ElfinderErrorMessages.ERROR_RENAME, name) + + self._clear_cached_dir(dir_) + #path may not be a dir, _clear_cached_dir() will just fail on the dir key and clear the file stat anyway + self._clear_cached_dir(path) + + self._removed.append(file_) + + return self.stat(ret) + + def duplicate(self, hash_, suffix='copy'): + """ + Create file copy with suffix "copy ``" + and return its info. + """ + + if self.command_disabled('duplicate'): + raise PermissionDeniedError + + #check if source file exists, throw FileNotFoundError if it doesn't + self.file(hash_) + + path = self.decode(hash_) + dir_ = self._dirname(path) + name = self._unique_name(dir_, self._basename(path), ' %s ' % suffix) + + if not self._attr(self._join_path(dir_, name), 'write'): + raise PermissionDeniedError + + return self.stat(self.copy(path, dir_, name)) + + def upload(self, uploaded_file, hash_dst, chunk=False, first_chunk=False): + """ + Save uploaded file. + On success return a list of file stat information. + If an already existing file was replaced, it will be added to the + removed file list and can be retrieved using the + :func:`elfinder.volumes.base.ElfinderVolumeDriver.remove` + method. + """ + + if self.command_disabled('upload'): + raise PermissionDeniedError + + error_path = self.path(hash_dst) + + try: + dir_ = self.dir(hash_dst) + except (FileNotFoundError, DirNotFoundError): + raise NamedError(ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % error_path) + + if not dir_['write']: + raise PermissionDeniedError + + if not self._name_accepted(uploaded_file.name): + raise Exception(ElfinderErrorMessages.ERROR_INVALID_NAME) + + mime = uploaded_file.content_type + + #logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order + allow = self.mime_accepted(mime, self._options['uploadAllow'], None) + deny = self.mime_accepted(mime, self._options['uploadDeny'], None) + if self._options['uploadOrder'][0].lower() == 'allow': #['allow', 'deny'], default is to 'deny' + upload = False #default is deny + if not deny and allow == True: #match only allow + upload = True + #else: (both match | no match | match only deny): deny + else: #['deny', 'allow'], default is to 'allow' - this is the default rule + upload = True #default is allow + if deny == True and not allow: #match only deny + upload = False + #else: (both match | no match | match only allow): allow } + + if not upload: + raise Exception(ElfinderErrorMessages.ERROR_UPLOAD_FILE_MIME) + + if self._options['uploadMaxSize'] > 0 and uploaded_file.size > self._options['uploadMaxSize']: + raise Exception(ElfinderErrorMessages.ERROR_UPLOAD_FILE_SIZE) + + dst = self.decode(hash_dst) + name = uploaded_file.name + test = self._join_path(dst, name) + + try: + file_ = self.stat(test) + #file exists + if self._options['uploadOverwrite']: + if not file_['write']: + raise PermissionDeniedError + elif file_['mime'] == 'directory': + raise NamedError(ElfinderErrorMessages.ERROR_NOT_REPLACE, uploaded_file.name) + if chunk is False: + self.remove(test) + else: + name = self._unique_name(dst, uploaded_file.name, '-', False) + except os.error: #file does not exist + pass + + kwargs = {} + try: + im = Image.open(uploaded_file.temporary_file_path) + (kwargs['w'], kwargs['h']) = im.size + except: + pass #file is not an image + + self._clear_cached_dir(dst) + + kwargs['first_chunk'] = first_chunk + kwargs['chunk'] = chunk + try: + uploaded_path = self._save_uploaded(uploaded_file, dst, name, **kwargs) + except: + raise Exception(ElfinderErrorMessages.ERROR_UPLOAD_FILE_SIZE) + + return self.stat(uploaded_path) + + def paste(self, volume, hash_src, dst, rm_src = False): + """ + Paste files. Raises exception if the operation fails. + """ + + if self.command_disabled('paste') or (volume==self and rm_src and self.command_disabled('rm')) or (volume!=self and rm_src and volume.command_disabled('rm')): + raise PermissionDeniedError + + #check if src file exists, throw FileNotFoundError if it doesn't + file_ = volume.file(hash_src) + name = file_['name'] + error_path = volume.path(hash_src) + + if file_['mime'] == 'directory' and ((volume==self and rm_src and self.command_disabled('rmdir')) or (volume!=self and rm_src and volume.command_disabled('rmdir'))): + raise PermissionDeniedError + + try: + dir_ = self.dir(dst) + except (FileNotFoundError, DirNotFoundError): + raise NamedError(ElfinderErrorMessages.ERROR_TRGDIR_NOT_FOUND, '#%s' % dst) + + if not dir_['write'] or not file_['read']: + raise PermissionDeniedError + + destination = self.decode(dst) + + test = volume.closest(hash_src, 'locked' if rm_src else 'read', rm_src) + if test: + raise NamedError(ElfinderErrorMessages.ERROR_LOCKED, volume.path(test)) if rm_src else PermissionDeniedError + + test = self._join_path(destination, name) + try: + stat = self.stat(test) + #file exists + if self._options['copyOverwrite']: + #do not replace file with dir or dir with file + if (file_['mime'] == 'directory' and stat['mime'] != 'directory') or (file_['mime'] != 'directory' and stat['mime'] == 'directory'): + raise NamedError(ElfinderErrorMessages.ERROR_NOT_REPLACE, self._path(test)) + #existed file is not writable + if not stat['write']: + raise PermissionDeniedError + #existed file locked or has locked child + locked = self._closest_by_attr(test, 'locked', True) + if locked: + raise NamedError(ElfinderErrorMessages.ERROR_LOCKED, self._path(locked)) + #target is entity file of alias + if volume == self and (('target' in file_ and test == file_['target']) or test == self.decode(hash_src)): + raise NamedError(ElfinderErrorMessages.ERROR_REPLACE, error_path) + #remove existing file + self.remove(test) + else: + name = self._unique_name(destination, name, ' ', False) + except os.error: + pass + + #copy/move inside current volume + if (volume == self): + source = self.decode(hash_src) + #do not copy into itself + if self._inpath(destination, source): + raise NamedError(ElfinderErrorMessages.ERROR_COPY_ITSELF, error_path) + if rm_src: + path = self.move(source, destination, name) + else: + path = self.copy(source, destination, name) + else: + #copy/move from another volume + if not self._options['copyTo'] or not volume.copy_from_allowed(): + raise PermissionDeniedError + path = self._copy_from(volume, hash_src, destination, name) + if rm_src: + try: + volume.rm(hash_src) + except: + raise Exception(ElfinderErrorMessages.ERROR_RM_SRC) + + return self.stat(path) + + def get_contents(self, hash_): + """ + Return file contents + """ + + file_ = self.file(hash_) + + if file_['mime'] == 'directory': + raise Exception(ElfinderErrorMessages.ERROR_NOT_FILE) + + if not file_['read']: + raise PermissionDeniedError + + return self._get_contents(self.decode(hash_)) + + def put_contents(self, hash_, content): + """ + Put content in text file and return file info. + """ + if self.command_disabled('edit'): + raise PermissionDeniedError + + path = self.decode(hash_) + file_ = self.file(hash_) + + if not file_['write']: + raise PermissionDeniedError + + self._clear_cached_stat(path) + self._put_contents(path, content) + + return self.stat(path) + + def extract(self, hash_): + """ + Extract files from archive + """ + + if self.command_disabled('extract'): + raise PermissionDeniedError + + file_ = self.file(hash_) + + archiver = self._archivers['extract'][file_['mime']] if file_['mime'] in self._archivers['extract'] else False + if not archiver: + raise Exception(ElfinderErrorMessages.ERROR_NOT_ARCHIVE) + + path = self.decode(hash_) + dst = self._dirname(path) + parent = self.stat(dst) + + if not file_['read'] or not parent['write']: + raise PermissionDeniedError + + self._clear_cached_dir(dst) + path = self._extract(path, archiver) + + return self.stat(path) + + def archive(self, hashes, mime): + """ + Add files to archive + """ + + if self.command_disabled('archive'): + raise PermissionDeniedError + + archiver = self._archivers['create'][mime] if mime in self._archivers['create'] else False + if not archiver: + raise Exception(ElfinderErrorMessages.ERROR_ARCHIVE_TYPE) + + files = [] + for hash_ in hashes: + file_ = self.file(hash_) + + if not file_['read']: + raise PermissionDeniedError + + path = self.decode(hash_) + if not vars().has_key('dir'): + dir_ = self._dirname(path) + stat = self.stat(dir_) + if not stat['write']: + raise PermissionDeniedError + + files.append(path) + + name = '%s.%s' % (self._basename(files[0]) if len(files) == 1 else 'Archive', archiver['ext']) + name = self._unique_name(dir_, name, '') + + self._clear_cached_dir(dir_) + path = self._archive(dir_, files, name, archiver) + + return self.stat(path) + + def resize(self, hash_, width, height, x, y, mode = 'resize', bg = '', degree = 0): + """ + Resize image. Raises PermissionDeniedError if the command is disabled + or there is no file 'write' permission. Raises NotAnImageError if + file is not an image. + """ + + if self.command_disabled('resize'): + raise PermissionDeniedError + + file_ = self.file(hash_) + + if not file_['write'] or not file_['read']: + raise PermissionDeniedError + + if not file_['mime'].startswith('image'): + raise NotAnImageError + + path = self.decode(hash_) + + try: + im = self._openimage(path) + except: + NotAnImageError + + if mode == 'propresize': + self._img_resize(im, path, width, height, True, True) + elif mode == 'crop': + self._img_crop(im, path, width, height, x, y) + elif mode == 'fitsquare': + self._img_square_fit(im, path, width, height, bg if bg else self._options['tmbBgColor']) + elif mode == 'rotate': + self._img_rotate(im, path, degree, bg if bg else self._options['tmbBgColor']) + else: + self._img_resize(im, path, width, height, False, True) + + if hasattr(im, 'fp') and im.fp: + im.fp.close() + + self._rm_tmb(file_) + self._clear_cached_stat(path) + return self.stat(path) + + + def rm(self, hash_): + """ + Remove file/dir. Raises PermisionDeniedError if 'rm' command + is disabled. + """ + if self.command_disabled('rm'): + raise PermissionDeniedError + return self.remove(self.decode(hash_)) + + def search(self, q): + """ + Search files based on query ``q``. + """ + return self._search(self._root, q) + + def dimensions(self, hash_): + """ + Return image dimensions. + Raises FileNotFoundError or NotAnImageError. + """ + stat = self.file(hash_) + + if 'dim' in stat: + return stat['dim'] + + if stat['mime'].startswith('image'): + return self._dimensions(self.decode(hash_)) + + #*********************************************************************# + #* FS API *# + #*********************************************************************# + + #***************** paths *******************# + + def encode(self, path): + """ + Encode path into hash + """ + if path: + #cut ROOT from path for security reason, even if hacker decodes the path he will not know the root + #files hashes will also be valid, even if root changes + p = self._relpath(path) + #if reqesting root dir path will be empty, then assign '/' as we cannot leave it blank for crypt + if not p: + p = self._separator + + hash_ = self._crypt(p) + #hash is used as id in HTML that means it must contain vaild chars + #make base64 html safe and append prefix in begining + hash_ = hash_.encode('utf-8') # unicode filename support + hash_ = b64encode(hash_).translate(maketrans('+/=', '-_.')) + + #remove dots '.' at the end (used to be '=' in base64, before the translation) + hash_ = hash_.rstrip('.') + + #append volume id to make hash unique + return self.id()+hash_ + + def decode(self, hash_): + """ + Decode path from hash. + """ + if hash_.startswith(self.id()): + #cut volume id after it was prepended in encode + h = hash_[len(self.id()):] + #replace HTML safe base64 to normal + h = h.encode('ascii').translate(maketrans('-_.', '+/=')) + #put cut = at the end + h += "=" * ((4 - len(h) % 4) % 4) + h = b64decode(h) + h = h.decode('utf-8') # unicode filename support + + path = self._uncrypt(h) + #append ROOT to path after it was cut in encode + return self._abspath(path) + + raise FileNotFoundError + + def _crypt(self, path): + """ + Return crypted path. + """ + #TODO: crypt and encrypt paths + return path + + def _uncrypt(self, hash_): + """ + Return uncrypted path. + """ + return hash_ + + #*********************** file stat *********************# + + def stat(self, path): + """ + Return fileinfo. Raises os.error if the path is invalid + """ + + cache_key = 'elfinder::stat::%s' % self.encode(path) + stat_cache = cache.get(cache_key, None) + root_cache = cache.get('elfinder::stat::%sroot' % self.id()) + + if stat_cache is None or root_cache != self._root: + #print cache_key, stat_cache, root_cache, self._root + stat = self._stat(path) + stat['hash'] = self.encode(path) + + if path == self._root: + stat['volumeid'] = self.id() + stat['name'] = self._root_name + else: + if not 'name' in stat or not stat['name']: + stat['name'] = self._basename(path) + + if not 'phash' in stat or not stat['phash']: + stat['phash'] = self.encode(self._dirname(path)) + + if not 'size' in stat or (not stat['size'] and stat['mime'] == 'directory'): + stat['size'] = 'unknown' + + stat['read'] = int(self._attr(path, 'read', stat['read'])) + stat['write'] = int(self._attr(path, 'write', stat['write'])) + stat['locked'] = int(self._attr(path, 'locked', self._is_locked(stat))) + stat['hidden'] = int(self._attr(path, 'hidden', self._is_hidden(stat)) if \ + self.mime_accepted(stat['mime']) else True) + + if stat['read'] and not self._is_hidden(stat): + + if stat['mime'] == 'directory': #handle directories + if self._options['checkSubfolders']: + try: + if 'dirs' in stat: + if not stat['dirs']: + del stat['dirs'] + elif 'alias' in stat and stat['alias'] and 'target' in stat and stat['target']: + stat['dirs'] = int('dirs' in stat_cache[stat['target']]) if stat['target'] in stat_cache else int(self._subdirs(stat['target'])) + elif self._subdirs(path): + stat['dirs'] = 1 + except: + stat['mime'] = 'application/empty' + else: + stat['dirs'] = 1 + else: #file + if not 'tmb' in stat and self._can_create_tmb(path, stat): + stat['tmb'] = self._get_tmb(stat['target'] if 'target' in stat else path, stat) + if not 'dim' in stat and stat['mime'].startswith('image'): + try: + stat['dim'] = self._dimensions(path) + except NotAnImageError: + stat['dim'] = _('Unknown') + + if 'alias' in stat and stat['alias'] and 'target' in stat and stat['target']: + stat['thash'] = self.encode(stat['target']) + del stat['target'] + + stat_cache = stat + + if self._options['cache']: + cache.set(cache_key, stat_cache, self._options['cache']) + self.logger.debug('%s: Caching STAT %s' % (self.id(), path)) + if root_cache != self._root: + cache.set('elfinder::stat::%sroot' % self.id(), self._root, 60 * 60 * 24 * 10) + + return stat_cache + + def mimetype(self, path, name = ''): + """ + Return file mimetype. + """ + mime = self._mimetype(path) + int_mime = None + + if not mime or mime in ['inode/x-empty', 'application/empty']: + int_mime = mimetypes.guess_type(name if name else path)[0] + + return int_mime if int_mime else mime + + def _attr(self, path, attr, val=False): + """ + Check a file attribute. ``attr`` can be one of `'read'`, `'write'` + `'hidden'` or `'locked'`. + """ + + if not attr in self._defaults: + return False + + #TODO: replace this with signals?? + if self._options['accessControl'] and hasattr(self._options['accessControl'], '__call__'): + perm = self._options['accessControl'](attr, path, self) + if perm != None: + return perm + + for attrs in self._attributes: + if attr in attrs and re.search(attrs['pattern'], '%s%s' % (self._separator, self._relpath(path))): + return attrs[attr] + + return self._defaults[attr] if not val else val + + def _size(self, path): + """ + Return file or directory total size. + """ + try: + stat = self.stat(path) + except os.error: + return 0 + + if not stat['read'] or self._is_hidden(stat): + return 0 + + if stat['mime'] != 'directory': + return stat['size'] + + subdirs = self._options['checkSubfolders'] + self._options['checkSubfolders'] = True + result = 0 + + for stat in self._get_scandir(path): + size = self._size(self._join_path(path, stat['name'])) if stat['mime'] == 'directory' and stat['read'] else stat['size'] + if (size > 0): + try: + result += size + except TypeError: + pass + + + self._options['checkSubfolders'] = subdirs + return result + + def _closest_by_attr(self, path, attr, val): + """ + If file has required attr == val - return file path, + If dir has child with has required attr == val - return child path + """ + try: + stat = self.stat(path) + except os.error: + return False + + if (attr in stat and stat[attr] == val) or (not attr in stat and val==False): + return path + + if stat['mime'] != 'directory': + return False + + #check children + for p in self._get_cached_dir(path): + _p = self._closest_by_attr(p, attr, val) + if _p != False: + return _p + return False + + #***************** get content *******************# + + def _get_scandir(self, path): + """ + Return required directory files info. + """ + + files = [] + for p in self._get_cached_dir(path): + stat = self.stat(p) + if not self._is_hidden(stat): + files.append(stat) + + return files + + def _get_tree(self, path, deep, exclude=''): + """ + Return subdirs tree + """ + + dirs = [] + for p in self._get_cached_dir(path): + stat = self.stat(p) + if not self._is_hidden(stat) and p != exclude and stat['mime'] == 'directory': + dirs.append(stat) + if deep > 0 and 'dirs' in stat and stat['dirs']: + dirs += self._get_tree(p, deep-1) + return dirs + + def _search(self, path, q): + """ + Recursively search for files in the specified path, + based on the ``q`` query. + """ + result = [] + for p in self._get_cached_dir(path): + try: + stat = self.stat(p) + except os.error: #invalid links + continue + + if self._is_hidden(stat) or not self.mime_accepted(stat['mime']): + continue + + name = stat['name'] + + if q in name: + stat['path'] = self._path(p) + if self._options['URL'] and not 'url' in stat: + stat['url'] = self._options['URL'] + p[len(self._root) + 1:].replace(self._separator, '/') + result.append(stat) + + if stat['mime'] == 'directory' and stat['read'] and not 'alias' in stat: + result += self._search(p, q) + + return result + + #********************** manipulations ******************# + + def copy(self, src, dst, name): + """ + Copy file/recursive copy dir only in current volume. + Return new file path or raise an Exception. + """ + + src_stat = self.stat(src) + + if not src_stat['read']: + raise PermissionDeniedError + + path = self._join_path(dst, name) + + if 'thash' in src_stat and src_stat['thash']: #symlink + target = self.decode(src_stat['thash']) + stat = self.stat(target) + + try: + self._symlink(target, dst, name) + except: + raise NamedError(ElfinderErrorMessages.ERROR_COPY, self._path(src)) + elif src_stat['mime'] == 'directory': + + try: + test = self.stat(path) + if test['mime'] != 'directory': + raise NamedError(ElfinderErrorMessages.ERROR_COPY, self._path(src)) + except os.error: + try: + self._mkdir(path) + except: + raise NamedError(ElfinderErrorMessages.ERROR_COPY, self._path(src)) + + for stat in self._get_scandir(src): + name = stat['name'] + try: + self.copy(self._join_path(src, name), path, name) + except: + self.remove(path, True) #fall back + raise + else: #file + try: + self._copy(src, dst, name) + except: + raise NamedError(ElfinderErrorMessages.ERROR_COPY, self._path(src)) + + self._clear_cached_dir(dst) + return path + + def move(self, src, dst, name): + """ + Move file. Return new file path or raise an Exception. + """ + + stat = self.stat(src) + + if not stat['read'] or (stat['mime'] == 'directory' and self.command_disabled('rmdir')): + raise PermissionDeniedError + + stat['realpath'] = src + self._rm_tmb(stat) #can not do rmTmb() after _move() + + try: + self._move(src, dst, name) + except: + raise NamedError(ElfinderErrorMessages.ERROR_MOVE, self._path(src)) + + self._clear_cached_dir(self._dirname(src)) + self._clear_cached_stat(src) + self._clear_cached_dir(dst) + self._removed.append(stat) + + return self._join_path(dst, name) + + def _copy_from(self, volume, src, dst, name): + """ + Copy file from another volume and return the new file path. + Raises PermissionDeniedError if source is not readable. + """ + + try: + source = volume.file(src) + except FileNotFoundError: + raise NamedError(ElfinderErrorMessages.ERROR_COPY, '#'.src, volume.error()) + + errpath = volume.path(src) + + if not self._name_accepted(source['name']): + raise Exception(ElfinderErrorMessages.ERROR_INVALID_NAME) + + if not source['read']: + raise PermissionDeniedError + + if source['mime'] == 'directory': + path = self._join_path(dst, name) + + try: + stat = self.stat(path) + #dir exists + if stat['mime'] != 'directory': + raise NamedError(ElfinderErrorMessages.ERROR_COPY, errpath) + except os.error: #directory does not exist, create it + try: + self._mkdir(path) + except: + raise NamedError(ElfinderErrorMessages.ERROR_COPY, errpath) + + for entry in volume.scandir(src): + self._copy_from(volume, entry['hash'], path, entry['name']) + else: + try: + fp = volume.open(src) + path = self._save(fp, dst, name) + volume.close(fp, src) + except: + raise + raise NamedError(ElfinderErrorMessages.ERROR_COPY, errpath) + + self._clear_cached_dir(dst) + return path + + def remove(self, path, force = False): + """ + Remove file/ recursive remove dir + """ + try: + stat = self.stat(path) + except os.error: + raise NamedError(ElfinderErrorMessages.ERROR_RM, self._path(path)) + + stat['realpath'] = path + self._rm_tmb(stat, False) + + if not force and self._is_locked(stat): + raise NamedError(ElfinderErrorMessages.ERROR_LOCKED, self._path(path)) + + if stat['mime'] == 'directory': + if self.command_disabled('rmdir'): + raise PermissionDeniedError + + for p in self._get_cached_dir(path): + self.remove(p) + + try: + self._rmdir(path) + except: + raise NamedError(ElfinderErrorMessages.ERROR_RM, self._path(path)) + + else: + try: + self._unlink(path) + except: + raise NamedError(ElfinderErrorMessages.ERROR_RM, self._path(path)) + + self._clear_cached_dir(path) + self._clear_cached_dir(self._dirname(path)) + self._removed.append(stat) + + #************************* thumbnails **************************# + + def _tmb_name(self, stat): + """ + Return thumbnail file name for required file + """ + return '%s%s.png' % (stat['hash'], stat['ts']) + + def _get_tmb(self, path, stat): + """ + Return thumnbnail name if exists + """ + if self._options['tmbURL'] and self._options['tmbPath']: + #file itself thumnbnail + if path.startswith(self._options['tmbPath']): + return self._basename(path) + + name = self._tmb_name(stat) + try: + self.stat(self._join_path(self._options['tmbPath'], name)) + return name + except os.error: + pass + #default thumbnail value + return 1 + + def _can_create_tmb(self, path, stat): + """ + Return True if thumnbnail for required file can be created. + """ + return self._tmb_path_writable and not path.startswith(self._options['tmbPath']) and stat['mime'].startswith('image') + + def _img_resize(self, im, target, width, height, keepProportions = False, resizeByBiggerSide = True, destformat = None): + """ + Resize image and return the new image. + """ + + s = im.size + size_w = width + size_h = height + + if keepProportions: + orig_w, orig_h = s[0], s[1] + + #Resizing by biggest side + if resizeByBiggerSide: + if (orig_w > orig_h): + size_h = orig_h * width / orig_w + size_w = width + else: + size_w = orig_w * height / orig_h + size_h = height + elif orig_w > orig_h: + size_w = orig_w * height / orig_h + size_h = height + else: + size_h = orig_h * width / orig_w + size_w = width + + resized = im.resize((size_w, size_h), Image.ANTIALIAS) + + if target: + self._saveimage(resized, target, destformat if destformat else im.format) + + return resized + + def _img_crop(self, im, target, width, height, x, y, destformat = None): + """ + Crop image. + """ + cropped = im.crop((x, y, width+x, height+y)) + self._saveimage(cropped, target, destformat if destformat else im.format) + + def _img_square_fit(self, im, target, width, height, bgcolor = '#ffffff', destformat = None): + """ + Put image to square + """ + + bg = Image.new('RGB', (width, height), bgcolor) + + if im.mode == 'RGBA': + bg.paste(im, ((width-im.size[0])/2, (height-im.size[1])/2), im) + else: #do not use a mask if file is not in RGBA mode. + bg.paste(im, ((width-im.size[0])/2, (height-im.size[1])/2)) + + if target: + self._saveimage(bg, target, destformat if destformat else im.format) + + return bg + + def _img_rotate(self, im, target, degree, bgcolor = '#ffffff', destformat = None): + """ + Rotate image. The ``degree`` argument is measured clock-wise. + """ + #rotated = im.convert('RGBA').rotate(angle=360-degree) + alpha = Image.new('RGBA', im.size, bgcolor) + alpha.paste(im) + rotated = alpha.rotate(angle=360-degree, resample=Image.BILINEAR) + + bg = Image.new('RGBA', im.size, bgcolor) + result = Image.composite(rotated, bg, rotated) + self._saveimage(result, target, destformat if destformat else im.format) + + def _rm_tmb(self, stat, recursion=True): + """ + Remove thumbnail, also remove recursively if stat is directory + """ + if stat['mime'] == 'directory' and recursion: + for p in self._get_cached_dir(self.decode(stat['hash'])): + self._rm_tmb(self.stat(p)) + elif 'tmb' in stat and stat['tmb'] != 1: + tmb = self._join_path(self._options['tmbPath'], stat['tmb']) + try: + self._clear_cached_dir(self._options['tmbPath']) + self._clear_cached_stat(tmb) + self._unlink(tmb) + except: + return + + #******************* archive files **********************# + + def _checkArchivers(self): + """ + Detect available archivers + """ + self._archivers = { + 'create' : { 'application/x-tar' : { 'ext' : 'tar' , 'archiver' : TarFile }, + 'application/x-gzip' : { 'ext' : 'tgz' , 'archiver' : TarFile }, + 'application/x-bzip2' : { 'ext' : 'tbz' , 'archiver' : TarFile }, + 'application/zip' : { 'ext' : 'zip' , 'archiver' : ZipFileArchiver } + }, + 'extract' : { 'application/x-tar' : { 'ext' : 'tar' , 'archiver' : TarFile }, + 'application/x-gzip' : { 'ext' : 'tgz' , 'archiver' : TarFile }, + 'application/x-bzip2' : { 'ext' : 'tbz' , 'archiver' : TarFile }, + 'application/zip' : { 'ext' : 'zip' , 'archiver' : ZipFileArchiver } + } + } + + #control available archive types from the options + if 'archiveMimes' in self._options and self._options['archiveMimes']: + for mime in self._archivers['create']: + if not mime in self._options['archiveMimes']: + del self._archivers['create'][mime] + + #manualy add archivers + if 'create' in self._options['archivers']: + for mime, archiver in self._options['archivers']['create'].items(): + try: + conf = archiver['archiver'] + archiver['ext'] + except: + continue + #check if conf is class and implements open, add and close methods + if re.match(r'application/', mime) and inspect.isclass(conf) and hasattr(conf, 'open') and callable(getattr(conf, 'open')) and hasattr(conf, 'add') and callable(getattr(conf, 'add')) and hasattr(conf, 'close') and callable(getattr(conf, 'close')): + self._archivers['create'][mime] = archiver + + if 'extract' in self._options['archivers']: + for mime, archiver in self._options['archivers']['extract'].items(): + try: + conf = archiver['archiver'] + archiver['ext'] + except: + continue + #check if conf is class and implements open, extractall and close methods + if re.match(r'application/', mime) and inspect.isclass(conf) and hasattr(conf, 'open') and callable(getattr(conf, 'open')) and hasattr(conf, 'extractall') and callable(getattr(conf, 'extractall')) and hasattr(conf, 'close') and callable(getattr(conf, 'close')): + self._archivers['extract'][mime] = archiver + + def _unpack(self, path, archiver): + """ + Unpack archive + """ + try: + archiver = archiver['archiver'] + except KeyError: + raise Exception('Invalid archiver') + + cwd = os.getcwd() + dir_ = os.path.dirname(path) + os.chdir(dir_) + + try: + archive = archiver.open(os.path.basename(path)) + archive.extractall() + archive.close() + except: + raise Exception('Could not create archive') + + os.chdir(cwd) + + #****************util methods ********************# + + def _name_accepted(self, name): + """ + Validate file name based on self._options['acceptedName'] regular + expression. + """ + if self._options['acceptedName']: + return re.search(self._options['acceptedName'], name) + return True + + def _unique_name(self, dir_, name, suffix = ' copy', check_num=True): + """ + Return new unique name based on file name and suffix + """ + + ext = '' + m = re.search(r'\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$', name, re.IGNORECASE) + if m: + ext = '.%s' % m.group(1) + name = name[0:len(name)-len(m.group(0))] + + m = re.search('(%s)(\d*)$' % suffix, name, re.IGNORECASE) + if check_num and m and m.group(2): + i = int(m.group(2)) + name = name[0:len(name)-len(m.group(2))] + else: + i = 1 + name += suffix + + return self._get_available_name(dir_, name, ext, i) + + def _is_hidden(self, stat): + """ + Check if the file/directory is hidden + """ + return 'hidden' in stat and stat['hidden'] + + def _is_locked(self, stat): + """ + Check if the file/directory is locked + """ + return 'locked' in stat and stat['locked'] + + def _urlize(self, url): + if re.search("[^/?&=]$", url): + url += '/' + return url + + def _relpath(self, path): + """ + Return file path related to root dir + """ + return '' if path == self._root else path[len(self._root)+1:] + + def _abspath(self, path): + """ + Convert ``path`` (that should be relative to the volume root) into a real path. + """ + return self._root if path == self._separator else self._join_path(self._root, path) + + def _path(self, path): + """ + Return fake path starting from the root dir. + Used for displaying the path to the client. + """ + return self._root_name if path == self._root else self._join_path(self._root_name, self._relpath(path)) + + def _inpath(self, path, parent): + """ + Return ``True`` if ``path`` is child of ``parent``. + """ + return path == parent or path.startswith('%s%s' % (parent, self._separator)) + + def _isabs(self, path): + """ + Check if ``path`` is absolute. + """ + if self._separator =='\\': + return not re.match(r'([a-zA-Z]+:)?\\$') is None + return path.startswith(os.sep) + + def _clear_cached_stat(self, path): + """ + Clear the cache for this file ``path``. + """ + cache.delete('elfinder::stat::%s' % self.encode(path)) + + def _get_cached_dir(self, path): + """ + Get the cached stat info for this directory ``path``, if any. + """ + cache_key = 'elfinder::listdir::%s' % self.encode(path) + dir_cache = cache.get(cache_key, None) + root_cache = cache.get('elfinder::stat::%sroot' % self.id()) + + if dir_cache is None or root_cache != self._root: + dir_cache = self._scandir(path) + if self._options['cache']: + self.logger.debug('%s: Caching DIR %s' % (self.id(), path)) + cache.set(cache_key, dir_cache, self._options['cache']) + if root_cache != self._root: + cache.set('elfinder::stat::%sroot' % self.id(), self._root, 60 * 60 * 24 * 10) + + return dir_cache + + def _clear_cached_dir(self, path): + """ + Clear cache for this directory ``path``. + """ + cache.delete('elfinder::listdir::%s' % self.encode(path)) + #clear the stat record as well + self._clear_cached_stat(path) + + #*********************************************************************# + #* API TO BE IMPLEMENTED IN SUB-CLASSES *# + #*********************************************************************# + + def _dirname(self, path): + """ + Return parent directory path. This method + should behave like :py:func:`os.path.dirname` does. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _basename(self, path): + """ + Return file name. This method + should behave like :py:func:`os.path.basename` does. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _join_path(self, path1, path2): + """ + Join two paths and return full path. If the latter path is + absolute, return it. This method + should behave like :py:func:`os.path.join` does, but accept + only two paths. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _normpath(self, path): + """ + Return normalized path. This method + should behave like :py:func:`os.path.normpath` does. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + #************************* file/dir info *********************# + + def _stat(self, path): + """ + Return stat for given path. The returned dictionary must contain + the following keys: + + :size: file size in b. **Required** + :ts: file modification time in unix time. **Required** + :mime: mimetype. required for folders, others. Optional + :read: read permissions. **Required** + :write: write permissions. **Required** + :alias: link target path relative to root path (for symlinks). Optional + :target: link target path (for symlinks). Optional + + This method should raise an os.error on fail. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _subdirs(self, path): + """ + Return ``True`` if path is dir and has at least one child directory. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _dimensions(self, path): + """ + Return object width and height as a string (e.g. `'32x46'`). + It is used for images, but it could also be realized for video + etc. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + #******************** file/dir content *********************# + + def _mimetype(self, path): + """ + Attempt to read the file's mimetype. Should return ``None`` + on fail. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _scandir(self, path): + """ + Return files list in directory. The `'.'` and `'..'` special + directories are omitted and the returned paths must be relative + to the driver root. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _fopen(self, path, mode="rb"): + """ + Open file and return file pointer. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _fclose(self, fp, **kwargs): + """ + Close opened file. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _openimage(self, path): + """ + Open an image file. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _saveimage(self, im, path, form): + """ + Save an image file. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + #******************** file/dir manipulations *************************# + + def _mkdir(self, path, mode): + """ + Create directory and return the path or raise an ``os.error`` + on fail. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _mkfile(self, path, name): + """ + Create file and return it's path or raise an ``os.error`` on fail. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _symlink(self, source, target_dir, name): + """ + Create symlink. Some drivers may not support this. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _copy(self, source, target_dir, name): + """ + Copy file into another file (both paths belong to + this volume driver). + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _move(self, source, target_dir, name): + """ + Move file into another parent directory. + Return the new file path or raise ``os.error``. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + + def _unlink(self, path): + """ + Remove file. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _rmdir(self, path): + """ + Remove directory (not recursively). + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _save(self, fp, dir_, name): + """ + Create new file and write into it from file pointer. + Return the new file path or raise an py:class:`Exception`. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _save_uploaded(self, uploaded_file, dir_, name, **kwargs): + """ + Save the Django + `UploadedFile `_ + object and return its new path. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _get_contents(self, path): + """ + Get file contents. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _put_contents(self, path, content): + """ + Write a string to a file. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _extract(self, path, archiver): + """ + Extract files from archive. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError + + def _archive(self, dir_, files, name, arc): + """ + Create an archive file and return its path. + + .. warning:: + + **Not implemented**, each driver must provide its own + imlementation. + """ + raise NotImplementedError diff --git a/elfinder/volumes/filesystem.py b/elfinder/volumes/filesystem.py new file mode 100644 index 00000000..4beaeae2 --- /dev/null +++ b/elfinder/volumes/filesystem.py @@ -0,0 +1,446 @@ +import os, re, time, shutil, magic +try: + from PIL import Image +except ImportError: + import Image +from hashlib import md5 +from django.conf import settings +from elfinder.exceptions import ElfinderErrorMessages, NotAnImageError, DirNotFoundError +from base import ElfinderVolumeDriver + +class ElfinderVolumeLocalFileSystem(ElfinderVolumeDriver): + """ + elFinder driver for local filesystem. It implements the + :class:`elfinder.volumes.base.ElfinderVolumeDriver` API. + """ + + _driver_id = 'l' + + def __init__(self): + """ + Override the original __init__ method to define some + ElfinderVolumeLocalFileSystem-specific options. + """ + super(ElfinderVolumeLocalFileSystem, self).__init__() + + #Required to count total archive files size + self._archiveSize = 0 + + self._options['dirMode'] = 0755 #new dirs mode + self._options['fileMode'] = 0644 #new files mode + + #*********************************************************************# + #* INIT AND CONFIGURE *# + #*********************************************************************# + + def mount(self, opts): + """ + Override the original mount method so that + ``path`` and ``URL`` settings point to the ``MEDIA_ROOT`` + and ``MEDIA_URL`` Django settings by default. + """ + + try: + rootpath = opts['path'] + except KeyError: + self._options['path'] = settings.MEDIA_ROOT + rootpath = settings.MEDIA_ROOT + + #attempt to create root if it does not exist + if not os.path.exists(rootpath): + try: + os.makedirs(rootpath) + except: + raise DirNotFoundError + + if not 'URL' in opts or not opts['URL']: + self._options['URL'] = settings.MEDIA_URL + + return super(ElfinderVolumeLocalFileSystem, self).mount(opts) + + def _configure(self): + """ + Configure after successful mount. + """ + self._aroot = os.path.realpath(self._root) + + super(ElfinderVolumeLocalFileSystem, self)._configure() + + #if no thumbnails url - try to detect it + if not self._options['tmbURL'] and self._options['URL']: + if self._options['tmbPath'].startswith(self._root): + self._options['tmbURL'] = self._urlize(self._options['URL'] + self._options['tmbPath'][len(self._root)+1:].replace(self._separator, '/')) + + #*********************************************************************# + #* API TO BE IMPLEMENTED IN SUB-CLASSES *# + #*********************************************************************# + + def _dirname(self, path): + """ + Return parent directory path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._dirname`. + """ + return os.path.dirname(path) + + def _basename(self, path): + """ + Return file name. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._basename`. + """ + return os.path.basename(path) + + def _join_path(self, path1, path2): + """ + Join two paths and return full path. If the latter path is + absolute, return it. + + See :func:`elfinder.volumes.base.ElfinderVolumeDriver._join_path`. + """ + + return os.path.join(path1, path2) + + def _normpath(self, path): + """ + Return normalized path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._normpath`. + """ + return os.path.normpath(path) + + def _get_available_name(self, dir_, name, ext, i): + """ + Get an available name for this file name. + """ + + while i <= 10000: + n = '%s%s%s' % (name, (i if i > 0 else ''), ext) + if not os.path.exists(self._join_path(dir_, n)): + return n + i+=1 + + return name+md5(dir_)+ext + + #************************* file/dir info *********************# + + def _stat(self, path): + """ + Return stat for given path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._stat`. + """ + stat = {} + + if path != self._root and os.path.islink(path): + target = self._readlink(path) + if not target or target == path: + stat['mime'] = 'symlink-broken' + stat['read'] = False + stat['write'] = False + stat['size'] = 0 + return stat + stat['alias'] = self._path(target) + stat['target'] = target + path = target + size = os.lstat(path).st_size + else: #raise os.error on fail + size = os.path.getsize(path) + + dir_ = os.path.isdir(path) + + stat['mime'] = 'directory' if dir_ else self.mimetype(path) + stat['ts'] = os.path.getmtime(path) + stat['read'] = os.access(path, os.R_OK) + stat['write'] = os.access(path, os.W_OK) + if stat['read']: + stat['size'] = 0 if dir_ else size + return stat + + def _subdirs(self, path): + """ + Return True if path is dir and has at least one childs directory + """ + for entry in os.listdir(path): + p = self._join_path(path, entry) + if os.path.isdir(p) and not self._attr(p, 'hidden'): + return True + + def _dimensions(self, path): + """ + Return object width and height + Ususaly used for images, but can be realize for video etc... + Can Raise a NotAnImageError + """ + try: + im = Image.open(path) + return '%sx%s' % im.size + except: + raise NotAnImageError + + #******************** file/dir content *********************# + + def _mimetype(self, path): + """ + Attempt to read the file's mimetype + """ + return magic.Magic(mime=True).from_file(path.encode('utf-8')) #unicode filename support + + def _readlink(self, path): + """ + Return symlink target file + """ + target = os.readlink(path) + try: + if target[0] != self._separator: + target = self._join_path(self._dirname(path), target) + except TypeError: + return None + + atarget = os.path.realpath(target) + if self._inpath(atarget, self._aroot): + return self._normpath(self._join_path(self._root, atarget[len(self._aroot)+1:])) + + def _scandir(self, path): + """ + Return files list in directory. + The '.' and '..' special directories are omitted. + """ + return map(lambda x: self._join_path(path, x), os.listdir(path)) + + def _fopen(self, path, mode='rb'): + """ + Open file and return file pointer + """ + return open(path, mode) + + def _fclose(self, fp, **kwargs): + """ + Close opened file + """ + return fp.close() + + def _openimage(self, path): + """ + Open an image file. + """ + return Image.open(path) + + def _saveimage(self, im, path, form): + """ + Save an image file + """ + im.save(path, form) + + #******************** file/dir manipulations *************************# + + def _mkdir(self, path, mode=None): + """ + Create dir and return created dir path or raise an os.error + """ + os.mkdir(path, mode) if mode else os.mkdir(path, self._options['dirMode']) + return path + + def _mkfile(self, path, name): + """ + Create file and return it's path or False on failed + """ + path = self._join_path(path, name) + + open(path, 'w').close() + os.chmod(path, self._options['fileMode']) + return path + + def _symlink(self, source, target_dir, name): + """ + Create symlink + """ + return os.symlink(source, self._join_path(target_dir, name)) + + def _copy(self, source, target_dir, name): + """ + Copy file into another file + """ + return shutil.copy(source, self._join_path(target_dir, name)) + + def _move(self, source, target_dir, name): + """ + Move file into another parent dir. + Return new file path or raise os.error. + """ + target = self._join_path(target_dir, name) + os.rename(source, target) + return target + + def _unlink(self, path): + """ + Remove file + """ + return os.unlink(path) + + def _rmdir(self, path): + """ + Remove dir + """ + return os.rmdir(path) + + def _save(self, fp, dir_, name): + """ + Create new file and write into it from file pointer. + Return new file path or raise an Exception. + """ + path = self._join_path(dir_, name) + target = open(path, 'wb') + + read = fp.read(8192) + while read: + target.write(read) + read = fp.read(8192) + + target.close() + os.chmod(path, self._options['fileMode']) + + return path + + def _save_uploaded(self, uploaded_file, dir_, name, **kwargs): + """ + Save the django UploadedFile object and return its new path + """ + path = self._join_path(dir_, name) + first_chunk = kwargs.get('first_chunk',False) + chunk = kwargs.get('chunk',False) + if chunk is False: + target = self._fopen(path, 'wb+') + else: + if first_chunk is True: + target = self._fopen(path, 'wb+') + else: + target = self._fopen(path, 'ab+') + for chunk in uploaded_file.chunks(): + target.write(chunk) + target.close() + os.chmod(path, self._options['fileMode']) + + return path + + def _get_contents(self, path): + """ + Get file contents + """ + return open(path).read() + + def _put_contents(self, path, content): + """ + Write a string to a file. + """ + f = open(path, 'w') + f.write(content) + f.close() + + def _archive(self, dir_, files, name, arc): + """ + Create archive and return its path + """ + try: + archiver = arc['archiver'] + except KeyError: + raise Exception('Invalid archiver') + + cwd = os.getcwd() + os.chdir(dir_) + + try: + archive = archiver.open(name, "w") + for file_ in files: + archive.add(self._basename(file_)) + archive.close() + except: + raise Exception('Could not create archive') + + os.chdir(cwd) + path = u'%s%s%s' % (dir_, self._separator, name) + + if not os.path.isfile(path): + raise Exception('Could not create archive') + + return path + + def _find_symlinks(self, path): + """ + Recursive symlinks search + """ + if os.path.islink(path): + return True + + if os.path.isdir(path): + for p in self._scandir(path): + if os.path.islink(p): + return True + elif os.path.isdir(p) and self._find_symlinks(p): + return True + elif os.path.isfile(p): + self._archiveSize += os.path.getsize(p) + else: + self._archiveSize += os.path.getsize(path) + + return False + + def _remove_unaccepted_files(self, path): + """ + Recursively delete unaccepted files based on their mimetype or + accepted name and return files in the directory. + """ + ls = [] + for p in self._scandir(path): + mime = self.stat(p)['mime'] + if not self.mime_accepted(mime) or not self._name_accepted(self._basename(p)): + self.remove(p) + elif mime != 'directory' or self._remove_unaccepted_files(p): + ls.append(p) + self._clear_cached_stat(p) + return ls + + def _extract(self, path, archiver): + """ + Extract files from archive. + """ + + archive_name = self._basename(path) + archive_dir = self._dirname(path) + quarantine_dir = self._join_path(self._quarantine, u'%s%s' % (str(time.time()).replace(' ', '_'), archive_name)) + archive_copy = self._join_path(quarantine_dir, archive_name) + + self._mkdir(quarantine_dir) + + #copy archive file in quarantine + self._copy(path, quarantine_dir, archive_name) + + #extract in quarantine + self._unpack(archive_copy, archiver) + self._unlink(archive_copy) + + ls = self._remove_unaccepted_files(quarantine_dir) + self._archiveSize = 0 + + #find symlinks + if self._find_symlinks(quarantine_dir): + raise Exception(ElfinderErrorMessages.ERROR_ARC_SYMLINKS) + + #check max files size + if self._options['archiveMaxSize'] > 0 and self._options['archiveMaxSize'] < self._archiveSize: + raise Exception(ElfinderErrorMessages.ERROR_ARC_MAXSIZE) + + #for several files - create new directory + #create unique name for directory + if len(ls) >= 1: + name = archive_name + m =re.search(r'\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$', name, re.IGNORECASE) + if m and m.group(0): + name = name[0:len(name)-len(m.group(0))] + + test = self._join_path(archive_dir, name) + if os.path.exists(test) or os.path.islink(test): + name = self._unique_name(archive_dir, name, ' extracted', False) + + self._move(quarantine_dir, archive_dir, name) + result = self._join_path(archive_dir, name) + else: + os.rmdir(quarantine_dir) + raise Exception('No valid files in archive') + + if not os.path.exists(result): + raise Exception('Could not extract archive') + + return result \ No newline at end of file diff --git a/elfinder/volumes/storage.py b/elfinder/volumes/storage.py new file mode 100644 index 00000000..699a14c7 --- /dev/null +++ b/elfinder/volumes/storage.py @@ -0,0 +1,667 @@ +import os, re, magic, time, tempfile, shutil, mimetypes +try: + from PIL import Image +except ImportError: + import Image +from django.core.files.storage import FileSystemStorage +from django.core.files.base import ContentFile +from django.core.files import File as DjangoFile +#from django.utils.importlib import import_module +from importlib import import_module +from elfinder.exceptions import NotAnImageError, ElfinderErrorMessages +from base import ElfinderVolumeDriver + +class ElfinderVolumeStorage(ElfinderVolumeDriver): + """ + elFinder driver for `Django file storages `_. + It implements the + :class:`elfinder.volumes.base.ElfinderVolumeDriver` API. + + Due to the Django filesystem storage API not supporting all operations (i.e. it is + intended for use with file and not directory manipulations), you should + take at look at the :func:`elfinder.volumes.storage.ElfinderVolumeStorage._configure` + method to understand how this driver operates on certain scenarios. + + For more information on how to specify the storage instance that the + driver will use, take a look at the + :func:`elfinder.volumes.storage.ElfinderVolumeStorage.mount` method. + + .. note:: + + This driver might be require a large amount of memory on some + operations such as copy and remove when using large files. + """ + + _driver_id = 's' + + #*********************************************************************# + #* INIT AND CONFIGURE *# + #*********************************************************************# + + def mount(self, opts): + """ + This method mounts the driver. + + A 'storage' option must be set and point to + a valid file storage instance. Alternatively, you can define the + 'storageClass' and 'storageKwArgs' options to let driver + instantiate the storage. The latter method is useful when the + storage depends on other django settings, since yawd-elfinder + reads custom optionsets from the settings.py module as well. + + .. note:: + + The 'storageClass' argument can also be a string to + to the absolute pythonpath of the class (e.g. + 'django_dropbox.storage.DropoxStorage') + + The provided storage must implement both + `listdir() `_ + and `url() `_ + methods to be valid. + """ + if "key_label" in opts['storageKwArgs'].keys(): + self._key_label = opts['storageKwArgs']['key_label'] + del opts['storageKwArgs']['key_label'] + if not 'storage' in opts: + if not 'storageClass' in opts: + opts['storage'] = FileSystemStorage() + else: + + #load the class if string + if isinstance(opts['storageClass'], basestring): + split = opts['storageClass'].split('.') + storage_module = import_module('.'.join(split[:-1])) + opts['storageClass'] = getattr(storage_module, split[-1]) + + if not 'storageKwArgs' in opts: + opts['storageKwArgs'] = {} + #store in opts so that the instantiation happens only once + opts['storage'] = opts['storageClass'](**opts['storageKwArgs']) + + #do not accept the storage if listdir or url are not implemented + try: + opts['storage'].listdir(self._root) + opts['storage'].url(self._root) + except NotImplementedError: + raise Exception('Storage %s should implement both the listdir() and url() methods to be valid for use with yawd-elfinder.' % self._options['storage'].__class__) + + #set default path and URL + self._options['path'] = '.' + if (not 'URL' in opts or not opts['URL']): + self._options['URL'] = opts['storage'].url(self._root) + + if not 'alias' in opts or not opts['alias']: + self._options['alias'] = opts['storage'].__class__.__name__ + + return super(ElfinderVolumeStorage, self).mount(opts) + + def _configure(self): + """ + If the storage does not implement the + `delete() `_ + method, the `'rm'` command will be disabled. + + As the storage API does not support removing directories, this + driver will not allow removing directories by default, + unless an :ref:`setting-rmDir` option is provided. `'rmDir'` must be a callable + that accepts a single dir path argument and deletes it. If the + storage is an instance of Django's own default FileSystemStorage, + the driver uses a built-in `'rmDir'` callback. Note that the + storage's delete() method must also be implemented, otherwise + `'rm'` command will be disabled anyway. + + As far as thumbnails are concerned, if :ref:`setting-tmbPath` is absolute + an exception will be thrown. + """ + + #if tmbPath is relative store thumbnails in the storage + if not self._isabs(self._options['tmbPath']): + super(ElfinderVolumeStorage, self)._configure() + + if not self._options['tmbURL'] and self._options['URL']: + self._options['tmbURL'] = self._options['URL'] + self._options['tmbPath'][len(self._root)+1:].replace(self._separator, '/') + '/' + + #if tmbPath is absolute try to create the directory locally + elif self._isabs(self._options['tmbPath']): + raise Exception('tmbPath must be relative') + + #disable rm command if delete is not implemented + try: + #check against a non-existing file + self._options['storage'].delete(self.encode(str(time.time()))) + except NotImplementedError: + if not 'rm' in self._options['disabled']: + self._options['disabled'].append('rm') + except: + pass + + #disable rmdir command if a custom implementation is not provided + if not 'rmDir' in self._options or not callable(self._options['rmDir']): + if isinstance(self._options['storage'], FileSystemStorage): + self._options['rmDir'] = self._rmdir_callable + elif not 'rmdir' in self._options['disabled']: + pass + #self._options['disabled'].append('rmdir') + + #*********************************************************************# + #* API TO BE IMPLEMENTED IN SUB-CLASSES *# + #*********************************************************************# + + def _dirname(self, path): + """ + Return parent directory path. Return stat for given path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._dirname`. + """ + return self._separator.join(path.split(self._separator)[:-1]) + + def _basename(self, path): + """ + Return file name. + See :func:`elfinder.volumes.base.ElfinderVolumeDriver._basename`. + """ + return path.split(self._separator)[-1] + + def _join_path(self, path1, path2): + """ + Join two paths and return full path. If the latter path is + absolute, return it. This does not use the default + :py:func:`os.path.join` + implementation as we might be operating on a remote system. + + Return stat for given path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._join_path`. + """ + + if self._separator == '\\' and re.match(r'([a-zA-Z]+:)?\\$', path2): + return path2 + elif path2.startswith(self._separator): + return path2 + + if not path1.endswith(self._separator): + return '%s%s%s' % (path1, self._separator, path2) + else: + return '%s%s' % (path1, path2) + + def _normpath(self, path): + """ + Return normalized path. The root path of this driver is always `'.'`, + so we just need to return the path. + + Return stat for given path. See :func:`elfinder.volumes.base.ElfinderVolumeDriver._normpath`. + """ + + if path[-1] == self._separator: + return path[:-1] + + return path + + def _get_available_name(self, dir_, name, ext, i): + """ + Get an available name for this file name. + """ + path = self._options['storage'].get_available_name(self._join_path(dir_, '%s%s' % (name, ext))) + return self._basename(path) + + #************************* file/dir info *********************# + + def _stat(self, path): + """ + Return stat for given path. See + :func:`elfinder.volumes.base.ElfinderVolumeDriver._stat`. + """ + stat = {} + + if not self._options['storage'].exists(path): + raise os.error + + try: + stat['mime'] = self.mimetype(path) + try: + stat['size'] = self._options['storage'].size(path) + except NotImplementedError: + stat['size'] = 0 + except: + stat['mime'] = 'directory' + stat['size'] = 0 + try: + stat['ts'] = time.mktime(self._options['storage'].modified_time(path).timetuple()) + except NotImplementedError: + stat['ts'] = '' + + stat['read'] = True + stat['write'] = True + return stat + + def _subdirs(self, path): + """ + Return ``True`` if path is a directory and has at least one + child directory. + """ + try: + for entry in self._options['storage'].listdir(path)[0]: + if not self._attr(self._join_path(path, entry), 'hidden'): + return True + except NotImplementedError: + pass + + def _dimensions(self, path): + """ + Return object width and height. + Ususaly used for images. It could raise a ``NotAnImageError`` + exception. + """ + try: + im = self._openimage(path) + return '%sx%s' % im.size + except: + raise NotAnImageError + + #******************** file/dir content *********************# + + def _mimetype(self, path): + """ + Attempt to read the file's mimetype. + """ + """ + The function below is implemented to handle linux system sys dev and proc directory + bugs + """ + file_name = str(path.split("/")[-1]).strip() + + if re.search(r'^\./proc/', path) or re.search(r'^\./sys/', path): # handler /proc /path + if file_name in self._files: # handler is files + try: + fp = self._fopen(path) + mime = magic.Magic(mime=True).from_buffer(fp.read(10)) # read 10 bytes + fp.close() + return mime + except: + return "application/empty" + + # not handler /dev directory slink + if re.search(r'^\./dev/', path) and self._files[file_name] in 'l': + return "application/empty" + + if file_name in self._files: + if self._files[file_name] not in '-l': # is not normal file link + return "application/empty" + + fp = self._fopen(path) + mime = magic.Magic(mime=True).from_buffer(fp.read(10))# read 10 bytes + fp.close() + return mime + + def _scandir(self, path): + """ + Return files list in directory. + The '.' and '..' special directories are omitted. + """ + try: + all_ = self._options['storage'].listdir(path) + return map(lambda x: self._join_path(path, x), all_[0]+all_[1]) + except NotImplementedError: + return [] + + def _fopen(self, path, mode='rb'): + """ + Open file and return a file pointer. + """ + return self._options['storage'].open(path, mode) + + def _fclose(self, fp, **kwargs): + """ + Close opened file. + """ + return fp.close() + + def _openimage(self, path): + """ + Open an image file. + """ + fp = self._fopen(path) + #place the file contents in a temp file + #this is necessary for remote storages, since PIL reads contents byte-by-byte + tmp_file = tempfile.TemporaryFile() + tmp_file.write(fp.read()) + fp.close() + + tmp_file.seek(0) + im = Image.open(tmp_file) + + return im + + def _saveimage(self, im, path, form): + """ + Save an image file. + """ + #PIL saves only in binary mode + tmp_file = tempfile.TemporaryFile() + im.save(tmp_file, form) + tmp_file.seek(0) + + fp = self._fopen(path, 'w+') + fp.write(tmp_file.read()) + tmp_file.close() + fp.close() + + #******************** file/dir manipulations *************************# + + def _mkdir(self, path, mode=None): + """ + Create dir and return created dir path or raise an os.error. Due to + the storage API not dealing with directory creation, this implementation + will attempt to create an empty temporary file inside the specified path. + This way the parent folder will also be created. The temp file will be + be deleted on exit. + """ + + fname = '.%s-mkdir' % self.encode(path) + + #on failure this will raise an os.error + self._mkfile(path, fname) + self._unlink(self._join_path(path, fname)) + + return path + + def _mkfile(self, path, name): + """ + Create file and return it's path or rais an ``os.error`` on fail. + """ + try: + return self._options['storage'].save(self._join_path(path, name), ContentFile('')) + except: + raise os.error + + def _copy(self, source, target_dir, name): + """ + Copy file into another file. + """ + fp = self._fopen(source) + + #place the file contents in a temp file + #this is necessary for remote storages since reading in chunks may not be supported + tmp_file = tempfile.NamedTemporaryFile() + tmp_file.write(fp.read()) + fp.close() + + self._options['storage'].save(self._join_path(target_dir, name), DjangoFile(tmp_file)) + tmp_file.close() + + def _move(self, source, target_dir, name): + """ + Move file into a different parent directory. + Return new file path or raise ``os.error``. + """ + + stat = self.stat(source) + try: + if stat['mime'] == 'directory': + dest = self._join_path(target_dir, name) + self._mkdir(dest) + for p in self._get_cached_dir(source): + self._move(p, dest, self._basename(p)) + self._rmdir(source) + else: + self._copy(source, target_dir, name) + self._unlink(source) + except: + raise os.error + + return self._join_path(target_dir, name) + + def _unlink(self, path): + """ + Remove the ``path`` file. + """ + try: + self._options['storage'].delete(path) + return True + except: + return False + + def _rmdir(self, path): + """ + Remove a directory. This implementation calls the + :ref:`setting-rmDir` callable driver option, if it is available. + If not, it raises an ``os.error``. + """ + if 'rmDir' in self._options and callable(self._options['rmDir']): + return self._options['rmDir'](path, self._options['storage']) + raise os.error + + def _rmdir_callable(self, path, storage): + """ + Remove directory when using a + `FileSystemStorage `_ + storage backend. See also the :ref:`setting-rmDir` setting. + """ + return os.rmdir(self._join_path(storage.location, path)) + + def _save(self, fp, dir_, name): + """ + Create new file and write into it from file pointer. + Return new file path or raise an ``Exception``. + """ + + #place the file contents in a temp file + #this is necessary for remote storages since reading in chunks may not be supported + tmp_file = tempfile.NamedTemporaryFile() + tmp_file.write(fp.read()) + fp.close() + tmp_file.seek(0) + + path = self._join_path(dir_, name) + self._options['storage'].save(path, DjangoFile(tmp_file)) + tmp_file.close() + + return path + + def _save_uploaded(self, uploaded_file, dir_, name, **kwargs): + """ + Save the Django + `UploadedFile `_ + object and return its new path. + """ + path = self._join_path(dir_, name) + first_chunk = kwargs.get('first_chunk',False) + chunk = kwargs.get('chunk',False) + if chunk is False: + target = self._fopen(path, 'w+') + else: + if first_chunk is True: + target = self._fopen(path, 'w+') + else: + target = self._fopen(path, 'a+') + for chunk in uploaded_file.chunks(): + target.write(chunk) + target.close() + + return path + + def _get_contents(self, path): + """ + Get file contents + """ + return self._fopen(path, 'rb').read() + + def _put_contents(self, path, content): + """ + Write a string to a file. + """ + f = self._fopen(path, 'w+') + f.write(content) + f.close() + + def _archive_copy(self, file_, dest): + stat = self.stat(file_) + dest_path = os.path.join(dest, self._basename(file_)) + if stat['mime'] == 'directory': + #use os.path.join because we operate on the local filesystem + os.mkdir(dest_path) + for p in self._get_cached_dir(file_): + self._archive_copy(p, dest_path) + else: + fp = self._fopen(file_) + #place the file contents in a temp file + #this is necessary for remote storages since reading in chunks may not be supported + tmp_file = open(dest_path, 'w+') + tmp_file.write(fp.read()) + fp.close() + tmp_file.close() + + def _archive(self, dir_, files, name, arc): + """ + Create a new archive file and return its path. This implementation + temporarily copies the remote storage files to the **local + filesystem** to accomplish quick access. Perhaps you would + like to check the + :ref:`setting-quarantine` setting to control where temporary files + will be stored. + """ + try: + archiver = arc['archiver'] + except KeyError: + raise Exception('Invalid archiver') + + quarantine_dir = os.path.join(self._options['quarantine'], '%s-temp' % name) + + if os.path.exists(quarantine_dir): + if not os.path.isdir(quarantine_dir): + raise Exception('Could not create temporary directory') + else: + shutil.rmtree(quarantine_dir) + #print os.getcwd() + os.mkdir(quarantine_dir) + + for file_ in files: + self._archive_copy(file_, quarantine_dir) + + files = os.listdir(quarantine_dir) + cwd = os.getcwd() + os.chdir(quarantine_dir) + + archive = archiver.open(name, "w") + for file_ in files: + archive.add(file_) + archive.close() + + path = self._join_path(dir_, name) + fp = self._fopen(path, 'w+') + fp.write(open(name).read()) + fp.close() + + os.chdir(cwd) + shutil.rmtree(quarantine_dir) + + return path + + def _local_file_mimetype(self, path, name = ''): + """ + Return local file mimetype. Used on quarantined files. + """ + if os.path.isdir(path): + return 'directory' + + mime = magic.Magic(mime=True).from_file(path.encode('utf-8')) #unicode filename support + int_mime = None + + if not mime or mime in ['inode/x-empty', 'application/empty']: + int_mime = mimetypes.guess_type(name if name else path)[0] + + return int_mime if int_mime else mime + + def _local_dir_size(self, path): + """ + Get the size of items in the ``path`` directory. + """ + size = 0 + ls = map(lambda x:os.path.join(path, x), os.listdir(path)) + for p in ls: + if os.path.isdir(p): + size += self._local_dir_size(p) + else: + size += os.path.getsize(p) + return size + + def _remove_unaccepted_files(self, path): + """ + Recursively delete unaccepted files based on their mimetype + and return the final number or files in the directory. + """ + ls = [] + for p in map(lambda x:os.path.join(path, x), os.listdir(path)): + if os.path.islink(p): + raise Exception(ElfinderErrorMessages.ERROR_ARC_SYMLINKS) + mime = self._local_file_mimetype(p) + if not self.mime_accepted(mime) or not self._name_accepted(self._basename(p)): + if mime != 'directory': + os.unlink(p) + else: + shutil.rmtree(p) + elif mime != 'directory' or self._remove_unaccepted_files(p): + ls.append(p) + return ls + + def _move_from_local(self, path, dst, name): + """ + Move from local file to storage file. + """ + if os.path.isdir(path): + for p in map(lambda x:os.path.join(path, x), os.listdir(path)): + self._move_from_local(p, self._join_path(dst, name), os.path.basename(p)) + shutil.rmtree(path) + else: + dst_path = self._join_path(dst, name) + fp = open(path) + self._options['storage'].save(dst_path, DjangoFile(fp)) + fp.close() + os.unlink(path) + + def _extract(self, path, archiver): + """ + Extract files from archive. + """ + #print os.getcwd() + archive_name = self._basename(path) + archive_dir = self._dirname(path) + quarantine_dir = self._join_path(self._quarantine, u'%s%s' % (str(time.time()).replace(' ', '_'), archive_name)) + archive_copy = self._join_path(quarantine_dir, archive_name) + + os.mkdir(quarantine_dir) + + #copy archive file in quarantine + self._archive_copy(path, quarantine_dir) + + #extract in quarantine + self._unpack(archive_copy, archiver) + os.unlink(archive_copy) + + try: + ls = self._remove_unaccepted_files(quarantine_dir) + except: + shutil.rmtree(quarantine_dir) + raise + + #check max files size + if self._options['archiveMaxSize'] > 0 and self._options['archiveMaxSize'] < self._local_dir_size(quarantine_dir): + raise Exception(ElfinderErrorMessages.ERROR_ARC_MAXSIZE) + + #for several files - create new directory + #create unique name for directory + if len(ls) >= 1: + + name = archive_name + m =re.search(r'\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$', name, re.IGNORECASE) + if m and m.group(0): + name = name[0:(len(name)-len(m.group(0)))] + + test = self._join_path(archive_dir, name) + if self._options['storage'].exists(test): + name = self._unique_name(archive_dir, name, ' extracted', False) + + self._move_from_local(quarantine_dir, archive_dir, name) + result = self._join_path(archive_dir, name) + else: + os.rmdir(quarantine_dir) + raise Exception('No valid files in archive') + + return result diff --git a/elfinder/wsgi.py b/elfinder/wsgi.py new file mode 100644 index 00000000..a7227735 --- /dev/null +++ b/elfinder/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for elfinder project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "elfinder.settings") + +application = get_wsgi_application() diff --git a/install/server/auto_install.sh b/install/server/auto_install.sh index 0e573ee8..8903d247 100755 --- a/install/server/auto_install.sh +++ b/install/server/auto_install.sh @@ -111,6 +111,10 @@ systemctl daemon-reload chkconfig adminset on service adminset start +#安装elfinder +cd $adminset_dir/vendor/elfinder +python setup.py install + #安装redis echo "####install redis####" yum install redis -y diff --git a/media/files/HammondOrgan.pdf b/media/files/HammondOrgan.pdf new file mode 100644 index 0000000000000000000000000000000000000000..da9da8358d1cb83473e9d49d7b22834f1958371c GIT binary patch literal 109218 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 e{H?HmOT*p6%FW~7vH(fQ-jZN|!8G;mF#I1.*)$', serve, { 'document_root': settings.MEDIA_ROOT, }), + ] diff --git a/mfile/views.py b/mfile/views.py new file mode 100644 index 00000000..bf81c14d --- /dev/null +++ b/mfile/views.py @@ -0,0 +1,8 @@ +from django.views.generic.base import View +from django.shortcuts import render_to_response +from django.contrib.auth.mixins import LoginRequiredMixin + +class finder(LoginRequiredMixin,View): + def get(self,request): + temp_name = "mfile/mfile-header.html" + return render_to_response('mfile/finder.html',locals()) \ No newline at end of file diff --git a/static/elfinder/.gitignore b/static/elfinder/.gitignore new file mode 100644 index 00000000..a7f48027 --- /dev/null +++ b/static/elfinder/.gitignore @@ -0,0 +1,12 @@ +*~ +._* +_* +.DS_Store +php-old +extensions +build +files2 +elFinderVolumeSVN.class.php +connector-svn.php +node_modules +connector.php diff --git a/static/elfinder/css/elfinder.full.css b/static/elfinder/css/elfinder.full.css new file mode 100644 index 00000000..e51bbe5f --- /dev/null +++ b/static/elfinder/css/elfinder.full.css @@ -0,0 +1,3324 @@ +/*! + * elFinder - file manager for web + * Version 2.1.29 (2017-10-07) + * http://elfinder.org + * + * Copyright 2009-2017, Studio 42 + * Licensed under a 3-clauses BSD license + */ + +/* File: /css/commands.css */ +/******************************************************************/ +/* COMMANDS STYLES */ +/******************************************************************/ + +/********************** COMMAND "RESIZE" ****************************/ +.elfinder-dialog-resize { margin-top:.3em; } +.elfinder-resize-type { float:left; margin-bottom: .4em; } +.elfinder-resize-control { float: left; } +.elfinder-resize-control input[type=text] { + border:1px solid #aaa; + text-align: right; + width: 4em; +} +.elfinder-resize-control input.elfinder-resize-bg { + text-align: center; + width: 5em; + direction: ltr; +} +.elfinder-dialog-resize .elfinder-resize-imgrotate, +.elfinder-dialog-resize .elfinder-resize-pallet { + cursor: pointer; +} +.elfinder-dialog-resize .elfinder-resize-picking { + cursor: crosshair; +} +.elfinder-dialog-resize .elfinder-resize-grid8 + button { + padding-top: 2px; + padding-bottom: 2px; +} +.elfinder-resize-preview { + width:400px; + height:400px; + padding:10px; + background:#fff; + border:1px solid #aaa; + float:right; + position:relative; + overflow:hidden; + text-align: left; + direction: ltr; +} + +.elfinder-resize-handle { position:relative;} + +.elfinder-resize-handle-hline, +.elfinder-resize-handle-vline { + position:absolute; + background-image:url("../img/crop.gif"); +} + +.elfinder-resize-handle-hline { + width:100%; + height:1px !important; + background-repeat:repeat-x; +} +.elfinder-resize-handle-vline { + width:1px !important; + height:100%; + background-repeat:repeat-y; +} + +.elfinder-resize-handle-hline-top { top:0; left:0; } +.elfinder-resize-handle-hline-bottom { bottom:0; left:0; } +.elfinder-resize-handle-vline-left { top:0; left:0; } +.elfinder-resize-handle-vline-right { top:0; right:0; } + +.elfinder-resize-handle-point { + position:absolute; + width:8px; + height:8px; + border:1px solid #777; + background:transparent; +} + +.elfinder-resize-handle-point-n { + top:0; + left:50%; + margin-top:-5px; + margin-left:-5px; +} +.elfinder-resize-handle-point-ne { + top:0; + right:0; + margin-top:-5px; + margin-right:-5px; +} +.elfinder-resize-handle-point-e { + top:50%; + right:0; + margin-top:-5px; + margin-right:-5px; +} +.elfinder-resize-handle-point-se { + bottom:0; + right:0; + margin-bottom:-5px; + margin-right:-5px; +} +.elfinder-resize-handle-point-s { + bottom:0; + left:50%; + margin-bottom:-5px; + margin-left:-5px; +} +.elfinder-resize-handle-point-sw { + bottom:0; + left:0; + margin-bottom:-5px; + margin-left:-5px; +} +.elfinder-resize-handle-point-w { + top:50%; + left:0; + margin-top:-5px; + margin-left:-5px; +} +.elfinder-resize-handle-point-nw { + top:0; + left:0; + margin-top:-5px; + margin-left:-5px; +} + +.elfinder-resize-spinner { + position:absolute; + width:200px; + height:30px; + top:50%; + margin-top:-25px; + left:50%; + margin-left:-100px; + text-align:center; + background:url(../img/progress.gif) center bottom repeat-x; +} + +.elfinder-resize-row { margin-bottom:9px; position:relative;} + +.elfinder-resize-label { float:left; width:80px; padding-top: 3px; } + +.elfinder-resize-checkbox-label { border: 1px solid transparent; } + +.elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls { + margin: -20px 5px 0 5px; +} +.elfinder-ltr .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls { + float: right; +} +.elfinder-rtl .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls { + float: left; +} + +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-e, +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-w { + height:100%; + width:10px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-s, +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-n { + width:100%; + height:10px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-e { margin-right: -7px; } +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-w { margin-left: -7px; } +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-s { margin-bottom: -7px; } +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-n { margin-top: -7px; } + +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-se, +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw, +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne, +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw { + width: 10px; + height: 10px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-se { + background:transparent; + bottom:0; + right:0; + margin-right:-7px; + margin-bottom:-7px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw { + margin-left: -7px; + margin-bottom: -7px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne { + margin-right:-7px; + margin-top:-7px; +} +.elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw { + margin-left: -7px; + margin-top: -7px; +} + +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-s, +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-n { + height: 20px; +} +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-e, +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-w { + width: 20px; +} +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-se, +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw, +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne, +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw { + width: 30px; + height: 30px; +} +.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-preview .ui-resizable-se { + width: 30px; + height: 30px; + zoom: 1; + margin: 0; +} +.elfinder-dialog-resize .ui-icon-grip-solid-vertical { + position:absolute; + top:50%; + right:0; + margin-top:-8px; + margin-right:-11px; +} +.elfinder-dialog-resize .ui-icon-grip-solid-horizontal { + position:absolute; + left:50%; + bottom:0; + margin-left:-8px; + margin-bottom:-11px;; +} + +.elfinder-dialog-resize .elfinder-resize-row .ui-buttonset { + float:right; +} + +.elfinder-dialog-resize .elfinder-resize-degree input, +.elfinder-dialog-resize .elfinder-resize-quality input { + width: 2.5em; +} +.elfinder-dialog-resize .elfinder-resize-degree button.ui-button { + padding: 6px 8px; +} +.elfinder-dialog-resize button.ui-button span { + padding: 0; +} + +.ui-widget-content .elfinder-dialog-resize .elfinder-resize-rotate-slider { + width: 195px; + margin: 10px 7px; + background-color: #fafafa; +} + +.elfinder-dialog-resize .elfinder-resize-type span.ui-checkboxradio-icon { + display: none; +} + +.elfinder-resize-preset-container { + box-sizing: border-box; + border-radius: 5px; +} + +/********************** COMMAND "EDIT" ****************************/ +/* edit text file textarea */ +.elfinder-file-edit { + width:100%; + height:99%; + margin:0; + padding:2px; + border:1px solid #ccc; + box-sizing: border-box; + resize: none; +} +.elfinder-touch .elfinder-file-edit { + font-size: 16px; +} +/* bottom margen for softkeyboard on fullscreen mode */ +.elfinder-touch.elfinder-fullscreen-native textarea.elfinder-file-edit { + padding-bottom: 20em; + margin-bottom: -20em; +} +.std42-dialog .ui-dialog-titlebar select { font-size: 12px; } +.std42-dialog .ui-dialog-buttonpane .elfinder-dialog-confirm-encoding { font-size: 12px; } + + +/********************** COMMAND "SORT" ****************************/ +/* for list table header sort triangle icon */ +div.elfinder-cwd-wrapper-list tr.ui-state-default td { + position: relative; +} +div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + position: absolute; + top: 4px; + left: 0; + right: 0; + margin: auto 0px auto auto; +} +.elfinder-touch div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + top: 7px; +} +.elfinder-rtl div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + margin: auto auto auto 0px; +} +/********************** COMMAND "HELP" ****************************/ +/* help dialog */ +.elfinder-help { margin-bottom:.5em; } + +/* fix tabs */ +.elfinder-help .ui-tabs-panel { + padding:.5em; + overflow: auto; + padding: 10px; +} +.elfinder-dialog .ui-tabs .ui-tabs-nav li a { padding:.2em 1em;} + +.elfinder-help-shortcuts { + height: auto; + padding: 10px; + margin: 0; + box-sizing: border-box; +} +.elfinder-help-shortcut { white-space:nowrap; clear:both;} + +.elfinder-help-shortcut-pattern { float:left; width:160px;} + +.elfinder-help-logo { + width:100px; + height:96px; + float:left; + margin-right:1em; + background:url('../img/logo.png') center center no-repeat; +} + +.elfinder-help h3 { font-size:1.5em; margin:.2em 0 .3em 0; } + +.elfinder-help-separator { clear:both; padding:.5em; } + +.elfinder-help-link { padding:2px; } + +.elfinder-help .ui-priority-secondary { font-size:.9em;} + +.elfinder-help .ui-priority-primary { margin-bottom:7px;} + +.elfinder-help-team { + clear: both; + text-align:right; + border-bottom:1px solid #ccc; + margin:.5em 0; + font-size:.9em; +} + +.elfinder-help-team div { float:left; } +.elfinder-help-license { font-size:.9em;} + +.elfinder-help-disabled { + font-weight:bold; + text-align:center; + margin:90px 0; +} + +.elfinder-help .elfinder-dont-panic { + display:block; + border:1px solid transparent; + width:200px; + height:200px; + margin:30px auto; + text-decoration:none; + text-align:center; + position:relative; + background:#d90004; + -moz-box-shadow: 5px 5px 9px #111; + -webkit-box-shadow: 5px 5px 9px #111; + box-shadow: 5px 5px 9px #111; + background: -moz-radial-gradient(80px 80px, circle farthest-corner, #d90004 35%, #960004 100%); + background: -webkit-gradient(radial, 80 80, 60, 80 80, 120, from(#d90004), to(#960004)); + -moz-border-radius: 100px; + -webkit-border-radius: 100px; + border-radius: 100px; + outline:none; +} + +.elfinder-help .elfinder-dont-panic span { + font-size:3em; + font-weight:bold; + text-align:center; + color:#fff; + position:absolute; + left:0; + top:45px; +} + +.elfinder-help-debug { + height:100%; + padding:0; + margin:0; + overflow:none; + border: none; +} + +.elfinder-help-debug .ui-tabs-panel { + padding: 0; + margin: 0; + overflow:auto; +} + +.elfinder-help-debug fieldset { + margin-bottom: 10px; + border-color: #778899; + border-radius: 10px; +} + +.elfinder-help-debug legend { + font-size: 1.2em; + font-weight: bold; + color: #2e8b57; +} + +.elfinder-help-debug dl { + margin: 0; +} + +.elfinder-help-debug dt { + color: #778899; +} + +.elfinder-help-debug dt:before { + content: "["; +} +.elfinder-help-debug dt:after { + content: "]"; +} + +.elfinder-help-debug dd { + margin-left: 1em; +} + +.elfinder-help-debug dd span { + /*font-size: 1.2em;*/ +} + +.elfinder-help-preference { + padding: 10px; + height: auto; + min-height: 100%; + box-sizing: border-box; +} + +.elfinder-help-preference dl { + width: 100%; +} +.elfinder-help-preference dt { + display: block; + width: 200px; + clear: left; + float: left; + max-width: 50%; +} +.elfinder-rtl .elfinder-help-preference dt { + clear: right; + float: right; +} +.elfinder-help-preference dd { + margin-bottom: 1em; +} +.elfinder-help-preference dd label, +.elfinder-help-preference dd input[type=checkbox] { + white-space: nowrap; + display: inline-block; + cursor: pointer; +} + +/********************** COMMAND "INFO" ****************************/ +.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon:before { + right: 33px; + left: auto; +} +.elfinder-info-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: none; +} + +/********************** COMMAND "UPLOAD" ****************************/ +.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + position: absolute; + bottom: 2px; + width: 16px; + height: 16px; + padding: 10px; + border: none; + overflow: hidden; + cursor: pointer; +} +.elfinder-ltr .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + left: 2px; +} +.elfinder-rtl .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + right: 2px; +} + +/********************** COMMAND "RM" ****************************/ +.elfinder-ltr .elfinder-rm-title .elfinder-cwd-icon:before { + left: 38px; +} +.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon:before { + right: 86px; + left: auto; +} +.elfinder-rm-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: none; +} +/* File: /css/common.css */ +/*********************************************/ +/* COMMON ELFINDER STUFFS */ +/*********************************************/ + +/* for old jQuery UI */ +.ui-front { + z-index: 100; +} + +/* common container */ +.elfinder { + padding: 0; + position:relative; + display:block; + visibility: visible; + font-size: 18px; + font-family: Verdana,Arial,Helvetica,sans-serif; +} + +/* in lazy execution status */ +.elfinder.elfinder-processing * { + cursor: progress !important +} +.elfinder.elfinder-processing.elfinder-touch .elfinder-workzone:after { + position: absolute; + top: 0; + width: 100%; + height: 3px; + content: ''; + left: 0; + background-image: url(../img/progress.gif); + opacity: .6; + pointer-events: none; +} + +/* for disable select of Touch devices */ +.elfinder *:not(input):not(textarea):not(select):not([contenteditable=true]), +.elfinder-contextmenu *:not(input):not(textarea):not(select):not([contenteditable=true]) { + -webkit-tap-highlight-color: rgba(0,0,0,0); + /*-webkit-touch-callout:none;*/ + -webkit-user-select: none; + -moz-user-select: none; + -khtml-user-select: none; + user-select: none; +} + +.elfinder .overflow-scrolling-touch { + -webkit-overflow-scrolling: touch; +} + +/* right to left enviroment */ +.elfinder-rtl { text-align:right; direction:rtl; } + +/* nav and cwd container */ +.elfinder-workzone { + padding: 0; + position:relative; + overflow:hidden; +} + +/* dir/file permissions and symlink markers */ +.elfinder-lock, +.elfinder-perms, +.elfinder-symlink { + position:absolute; + width:16px; + height:16px; + background-image:url(../img/toolbar.png); + background-repeat:no-repeat; + background-position:0 -528px; +} + +.elfinder-symlink { } + +/* noaccess */ +.elfinder-na .elfinder-perms { background-position:0 -96px; } + +/* read only */ +.elfinder-ro .elfinder-perms { background-position:0 -64px;} + +/* write only */ +.elfinder-wo .elfinder-perms { background-position:0 -80px;} + +/* volume type group */ +.elfinder-group .elfinder-perms { background-position:0 0px;} + +/* locked */ +.elfinder-lock { + background-position:0 -656px; +} + +/* drag helper */ +.elfinder-drag-helper { + top: 0px; + left: 0px; + width:70px; + height:60px; + padding:0 0 0 25px; + z-index:100000; + will-change: left, top; +} +.elfinder-drag-helper.html5-native { + position: absolute; + top: -1000px; + left: -1000px; +} + +/* drag helper status icon (default no-drop) */ +.elfinder-drag-helper-icon-status { + position:absolute; + width:16px; + height:16px; + left:42px; + top:60px; + background:url('../img/toolbar.png') 0 -96px no-repeat; + display: block; +} + +/* show "up-arrow" icon for move item */ +.elfinder-drag-helper-move .elfinder-drag-helper-icon-status { + background-position:0 -720px; +} +/* show "plus" icon when ctrl/shift pressed */ +.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status { + background-position:0 -544px; +} + +/* files num in drag helper */ +.elfinder-drag-num { + position:absolute; + top:0; + left:0; + width:16px; + height:14px; + text-align:center; + padding-top:2px; + + font-weight:bold; + color:#fff; + background-color:red; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +/* icon in drag helper */ +.elfinder-drag-helper .elfinder-cwd-icon { margin:0 0 0 -24px; float:left; } + +/* transparent overlay */ +.elfinder-overlay { + position: absolute; + opacity: .2; + filter: Alpha(Opacity=20); +} + +/* panels under/below cwd (for search field etc) */ +.elfinder .elfinder-panel { + position:relative; + background-image:none; + padding:7px 12px; +} + +/* for html5 drag and drop */ +[draggable=true] { + -khtml-user-drag: element; +} + +/* for place holder to content editable elements */ +.elfinder [contentEditable=true]:empty:not(:focus):before { + content:attr(data-ph); +} + +/* bottom tray */ +.elfinder div.elfinder-bottomtray { + position: fixed; + bottom: 0; + max-width:100%; + opacity: .8; +} +.elfinder.elfinder-ltr div.elfinder-bottomtray { + left: 0; +} +.elfinder.elfinder-rtl div.elfinder-bottomtray { + right: 0; +} + +/* tooltip */ +.elfinder-ui-tooltip { + font-size: 0.78em; + padding: 2px; +} + +/* File: /css/contextmenu.css */ +/* menu and submenu */ +.elfinder .elfinder-contextmenu, +.elfinder .elfinder-contextmenu-sub { + position:absolute; + border:1px solid #aaa; + background:#fff; + color:#555; + padding:4px 0; + top: 0; + left: 0; +} + +/* submenu */ +.elfinder .elfinder-contextmenu-sub { top:5px; } +/* submenu in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub { margin-left:-5px; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub { margin-right:-5px; } + +/* menu item */ +.elfinder .elfinder-contextmenu-header { + margin-top: -4px; + padding: 0 .5em .2ex; + border: none; + text-align: center; +} +.elfinder .elfinder-contextmenu-header span { + font-weight: normal; + font-size: 0.8em; + font-weight: bolder; +} +.elfinder .elfinder-contextmenu-item { + position:relative; + display:block; + padding:4px 30px; + text-decoration:none; + white-space:nowrap; + cursor:default; +} +.elfinder .elfinder-contextmenu-item.ui-state-active { + border: none; +} +.elfinder .elfinder-contextmenu-item .ui-icon { + width:16px; + height:16px; + position:absolute; + left:auto; + right:auto; + top:50%; + margin-top:-8px; +} +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item .ui-icon { + left: 2px; +} +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item .ui-icon { + right: 2px; +} +.elfinder-touch .elfinder-contextmenu-item { + padding:12px 38px; +} + +/* root icon of each volume */ +.elfinder-navbar-root-local.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_local.png"); } +.elfinder-navbar-root-ftp.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_ftp.png"); } +.elfinder-navbar-root-sql.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_sql.png"); } +.elfinder-navbar-root-dropbox.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_dropbox.png"); } +.elfinder-navbar-root-googledrive.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_googledrive.png"); } +.elfinder-navbar-root-onedrive.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_onedrive.png"); } +.elfinder-navbar-root-box.elfinder-contextmenu-icon { background-image:url("../img/volume_icon_box.png"); } + +/* text in item */ +.elfinder .elfinder-contextmenu .elfinder-contextmenu-item span { display:block; } + +/* submenu item in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-sub .elfinder-contextmenu-item { padding-left:12px; padding-right:12px; } +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item { text-align:left; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item { text-align:right; } +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { padding-left:28px; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { padding-right:28px; } +.elfinder-touch .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { padding-left:36px; } +.elfinder-touch .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { padding-right:36px; } + +/* command/submenu icon */ +.elfinder .elfinder-contextmenu-extra-icon, +.elfinder .elfinder-contextmenu-arrow, +.elfinder .elfinder-contextmenu-icon { + position:absolute; + top:50%; + margin-top:-8px; + overflow: hidden; +} + +/* command icon in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-icon { left:8px; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-icon { right:8px; } +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-extra-icon { right:8px; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-extra-icon { left:8px; } + +/* arrow icon */ +.elfinder .elfinder-contextmenu-arrow { + width:16px; + height:16px; + background:url('../img/arrows-normal.png') 5px 4px no-repeat; +} + +/* arrow icon in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-arrow { right:5px; } +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-arrow { left:5px; background-position: 0 -10px; } + +/* command extra icon's , tag */ +.elfinder .elfinder-contextmenu-extra-icon a, +.elfinder .elfinder-contextmenu-extra-icon span { + display: inline-block; + width: 100%; + height: 100%; + padding: 20px; + margin: 0; + color: transparent !important; + text-decoration: none; + cursor: pointer; +} + +/* disable ui border/bg image on hover */ +.elfinder .elfinder-contextmenu .ui-state-hover { border:0 solid; background-image:none;} + +/* separator */ +.elfinder .elfinder-contextmenu-separator { + height:0px; + border-top:1px solid #ccc; + margin:0 1px; +} + +/* for CSS style priority to ui-state-disabled - "background-image: none" */ +.elfinder .elfinder-button-icon.ui-state-disabled { + background-image: url('../img/toolbar.png') !important; +} +/* File: /css/cwd.css */ +/******************************************************************/ +/* CURRENT DIRECTORY STYLES */ +/******************************************************************/ +/* cwd container to avoid selectable on scrollbar */ +.elfinder-cwd-wrapper { + overflow: auto; + position:relative; + padding:2px; + margin:0; +} + +.elfinder-cwd-wrapper-list { padding:0; } + +/* container */ +.elfinder-cwd { + position:relative; + cursor:default; + padding:0; + margin:0; + -ms-touch-action: auto; + touch-action: auto; +} + +/* container active on dropenter */ +.elfinder .elfinder-cwd-wrapper.elfinder-droppable-active { + outline: 2px solid #8cafed; + outline-offset: -2px; +} + +.elfinder-cwd-wrapper-empty .elfinder-cwd:after { + display: block; + position: absolute; + top: 40%; + left: 0; + right: 0; + margin-top: -2em; + line-height: 1.5em; + text-align: center; + white-space: pre-wrap; + opacity: 0.6; + filter: Alpha(Opacity=60); + font-weight: bold; +} + +.elfinder-cwd-file .elfinder-cwd-select { + position: absolute; + top: 0px; + left: 0px; + width: 30px; + height: 30px; + background-color: transparent; + opacity: .4; + filter:Alpha(Opacity=40); +} + +.elfinder-cwd-file.ui-selected .elfinder-cwd-select { + opacity: .8; + filter:Alpha(Opacity=80); +} +.elfinder-rtl .elfinder-cwd-file .elfinder-cwd-select { + left: auto; + right: 0px; +} + +.elfinder .elfinder-cwd-selectall { + position: absolute; + width: 30px; + height: 30px; + top: 0px; + opacity: .8; + filter:Alpha(Opacity=80); +} + +.elfinder .elfinder-workzone.elfinder-cwd-wrapper-empty .elfinder-cwd-selectall { + display: none; +} + +/************************** ICONS VIEW ********************************/ + +.elfinder-ltr .elfinder-workzone .elfinder-cwd-selectall { + text-align: right; + right: 18px; + left: auto; +} + +.elfinder-rtl .elfinder-workzone .elfinder-cwd-selectall { + text-align: left; + right: auto; + left: 18px; +} + +.elfinder-ltr.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall { + right: 0px; +} + +.elfinder-rtl.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall { + left: 0px; +} + +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select.ui-state-hover { + background-color: transparent; +} + +/* file container */ +.elfinder-cwd-view-icons .elfinder-cwd-file { + width:120px; + height:90px; + padding-bottom:2px; + cursor:default; + border:none; +/* overflow:hidden;*/ + position:relative; +} + +/*.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select { + top: 0px; + left: 0px; +}*/ + +/*.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select { + left: auto; + right: 7px; +}*/ + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-icons .elfinder-cwd-file { float:left; margin:0 3px 2px 0; } +.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file { float:right; margin:0 0 5px 3px; } + +/* remove ui hover class border */ +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover { border:0 solid; } + +/* icon wrapper to create selected highlight around icon */ +.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper { + width:52px; + height:52px; + margin:1px auto 1px auto; + padding:2px; + position:relative; +} + +/* file name place */ +.elfinder-cwd-view-icons .elfinder-cwd-filename { + text-align: center; + max-height: 2.4em; + line-height: 1.2em; + white-space: pre-line; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + margin: 3px 1px 0 1px; + padding: 1px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + /* for webkit CSS3 */ + word-break: break-word; + overflow-wrap: break-word; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +/* permissions/symlink markers */ +.elfinder-cwd-view-icons .elfinder-perms { bottom:4px; right:2px; } +.elfinder-cwd-view-icons .elfinder-lock { top:-3px; right:-2px; } +.elfinder-cwd-view-icons .elfinder-symlink { bottom:6px; left:0px; } + +/* icon/thumbnail */ +.elfinder-cwd-icon { + display:block; + width:48px; + height:48px; + margin:0 auto; + background: url('../img/icons-big.png') 0 0 no-repeat; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} + +/* volume icon of root in folder */ +.elfinder-navbar-root-local .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_local.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-trash .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_trash.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-ftp .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_ftp.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-sql .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_sql.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-dropbox .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_dropbox.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-googledrive .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_googledrive.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-navbar-root-onedrive .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_onedrive.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-navbar-root-box .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon { + background-image:url("../img/volume_icon_box.png"); + background-position:0 0; + background-size: contain; +} +.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} +.elfinder-navbar-root-network .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon { + background-image:url("../img/toolbar.png"); + background-position: 0 71.65%; /* Don't forget change % when toolbar.png edited */ + background-size: cover; +} +.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon { + background-position:1px -1px; +} + +/* type badge in "icons" view */ +.elfinder-cwd-icon:before { + content: none; + position: absolute; + left: 0px; + top: 5px; + min-width: 20px; + max-width: 84px; + text-align: center; + padding: 1px 4px; + border-radius: 4px; + font-family: Verdana; + font-size: 10px; + -webkit-transform: scale(0.9); + -moz-transform: scale(0.9); + -ms-transform: scale(0.9); + -o-transform: scale(0.9); + transform: scale(0.9); +} +.elfinder-cwd-view-icons .elfinder-cwd-icon.elfinder-cwd-bgurl:before { + left: -10px; +} + +/* icon image has type */ +.elfinder-cwd-icon.elfinder-cwd-icon-x-empty:before, +.elfinder-cwd-icon.elfinder-cwd-icon-plain:before, +.elfinder-cwd-icon.elfinder-cwd-icon-rtf:before, +.elfinder-cwd-icon.elfinder-cwd-icon-rtfd:before, +.elfinder-cwd-icon.elfinder-cwd-icon-pdf:before, +.elfinder-cwd-icon.elfinder-cwd-icon-html:before, +.elfinder-cwd-icon.elfinder-cwd-icon-css:before, +.elfinder-cwd-icon.elfinder-cwd-icon-javascript:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-javascript:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-perl:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-python:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-ruby:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-sh:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-shellscript:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-c:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-csrc:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-chdr:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-c--:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-c--src:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-c--hdr:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-java:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-java-source:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-php:before, +.elfinder-cwd-icon.elfinder-cwd-icon-xml:before, +.elfinder-cwd-icon.elfinder-cwd-icon-zip:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-zip:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-xz:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-7z-compressed:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-gzip:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-tar:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-bzip:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-bzip2:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-rar:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-rar-compressed:before, +.elfinder-cwd-icon.elfinder-cwd-icon-x-shockwave-flash:before { content: none } + +/* addtional type badge name */ +.elfinder-cwd-icon.elfinder-cwd-icon-mp2t:before { content: 'ts' } +.elfinder-cwd-icon.elfinder-cwd-icon-dash-xml:before { content: 'dash' } +.elfinder-cwd-icon.elfinder-cwd-icon-x-mpegurl:before { content: 'hls' } + +/* thumbnail image */ +.elfinder-cwd-icon.elfinder-cwd-bgurl { + background-position: center center; + background-repeat: no-repeat; + -moz-background-size: contain; + background-size: contain; +} +/* thumbnail self */ +.elfinder-cwd-icon.elfinder-cwd-bgurl.elfinder-cwd-bgself { + -moz-background-size: cover; + background-size: cover; +} +/* thumbnail crop*/ +.elfinder-cwd-icon.elfinder-cwd-bgurl { + -moz-background-size: cover; + background-size: cover; +} +.elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: ' '; +} +.elfinder-cwd-bgurl:after { + position: relative; + display: inline-block; + top: 36px; + left: -38px; + width: 48px; + height: 48px; + background: url('../img/icons-big.png') 0 0 no-repeat; + background-size: auto !important; + opacity: .8; + filter: Alpha(Opacity=60); + -webkit-transform-origin: 54px -24px; + -webkit-transform: scale(.6); + -moz-transform-origin: 54px -24px; + -moz-transform: scale(.6); + -ms-transform-origin: 54px -24px; + -ms-transform: scale(.6); + -o-transform-origin: 54px -24px; + -o-transform: scale(.6); + transform-origin: 54px -24px; + transform: scale(.6); +} +/* thumbnail image and draging icon overlay none */ +.elfinder-cwd-icon.elfinder-cwd-icon-drag:before, +.elfinder-cwd-icon.elfinder-cwd-icon-drag:after, +.elfinder-cwd-icon-image.elfinder-cwd-bgurl:after { + content: none; +} +/* thumbnail image video overlay */ +.elfinder-cwd-icon-video:after { + top: 32px; + left: -26px; + height: 25px; + width: 22px; + background-position: 0px -373px; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); +} + +/* "opened folder" icon on dragover */ +.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon { background-position: 0 -100px; } +.elfinder-cwd .elfinder-droppable-active { + outline: 2px solid #8cafed; + outline-offset: -2px; +} + +/* mimetypes icons */ +.elfinder-cwd-icon-directory { background-position:0 -50px; } + +.elfinder-cwd-icon-application:after, +.elfinder-cwd-icon-application { background-position:0 -150px; } + +.elfinder-cwd-icon-text:after, +.elfinder-cwd-icon-text { background-position:0 -1350px; } + +.elfinder-cwd-icon-plain:after, +.elfinder-cwd-icon-plain, +.elfinder-cwd-icon-x-empty:after, +.elfinder-cwd-icon-x-empty { background-position:0 -200px; } + +.elfinder-cwd-icon-image:after, +.elfinder-cwd-icon-vnd-adobe-photoshop:after, +.elfinder-cwd-icon-postscript:after, +.elfinder-cwd-icon-image, +.elfinder-cwd-icon-vnd-adobe-photoshop, +.elfinder-cwd-icon-postscript { background-position:0 -250px; } + +.elfinder-cwd-icon-audio:after, +.elfinder-cwd-icon-audio { background-position:0 -300px; } + +.elfinder-cwd-icon-video, +.elfinder-cwd-icon-flash-video, +.elfinder-cwd-icon-dash-xml, +.elfinder-cwd-icon-vnd-apple-mpegurl, +.elfinder-cwd-icon-x-mpegurl { background-position:0 -350px; } + +.elfinder-cwd-icon-rtf:after, +.elfinder-cwd-icon-rtfd:after, +.elfinder-cwd-icon-rtf, +.elfinder-cwd-icon-rtfd { background-position: 0 -401px; } + +.elfinder-cwd-icon-pdf:after, +.elfinder-cwd-icon-pdf { background-position: 0 -450px; } + +.elfinder-cwd-icon-ms-excel:after, +.elfinder-cwd-icon-msword:after, +.elfinder-cwd-icon-vnd-ms-excel:after, +.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-office:after, +.elfinder-cwd-icon-vnd-ms-powerpoint:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-word:after, +.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-chart:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-database:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-formula:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-image:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-master:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-web:after, +.elfinder-cwd-icon-vnd-openofficeorg-extension:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template:after, +.elfinder-cwd-icon-ms-excel, +.elfinder-cwd-icon-msword, +.elfinder-cwd-icon-vnd-ms-excel, +.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-office, +.elfinder-cwd-icon-vnd-ms-powerpoint, +.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-word, +.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-oasis-opendocument-chart, +.elfinder-cwd-icon-vnd-oasis-opendocument-database, +.elfinder-cwd-icon-vnd-oasis-opendocument-formula, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-image, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-text, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-master, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-web, +.elfinder-cwd-icon-vnd-openofficeorg-extension, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template { background-position: 0 -500px; } + +.elfinder-cwd-icon-html:after, +.elfinder-cwd-icon-html { background-position: 0 -550px; } + +.elfinder-cwd-icon-css:after, +.elfinder-cwd-icon-css { background-position: 0 -600px; } + +.elfinder-cwd-icon-javascript:after, +.elfinder-cwd-icon-x-javascript:after, +.elfinder-cwd-icon-javascript, +.elfinder-cwd-icon-x-javascript { background-position: 0 -650px; } + +.elfinder-cwd-icon-x-perl:after, +.elfinder-cwd-icon-x-perl { background-position: 0 -700px; } + +.elfinder-cwd-icon-x-python:after, +.elfinder-cwd-icon-x-python { background-position: 0 -750px; } + +.elfinder-cwd-icon-x-ruby:after, +.elfinder-cwd-icon-x-ruby { background-position: 0 -800px; } + + +.elfinder-cwd-icon-x-sh:after, +.elfinder-cwd-icon-x-shellscript:after, +.elfinder-cwd-icon-x-sh, +.elfinder-cwd-icon-x-shellscript { background-position: 0 -850px; } + +.elfinder-cwd-icon-x-c:after, +.elfinder-cwd-icon-x-csrc:after, +.elfinder-cwd-icon-x-chdr:after, +.elfinder-cwd-icon-x-c--:after, +.elfinder-cwd-icon-x-c--src:after, +.elfinder-cwd-icon-x-c--hdr:after, +.elfinder-cwd-icon-x-java:after, +.elfinder-cwd-icon-x-java-source:after, +.elfinder-cwd-icon-x-c, +.elfinder-cwd-icon-x-csrc, +.elfinder-cwd-icon-x-chdr, +.elfinder-cwd-icon-x-c--, +.elfinder-cwd-icon-x-c--src, +.elfinder-cwd-icon-x-c--hdr, +.elfinder-cwd-icon-x-java, +.elfinder-cwd-icon-x-java-source { background-position: 0 -900px; } + +.elfinder-cwd-icon-x-php:after, +.elfinder-cwd-icon-x-php { background-position: 0 -950px; } + +.elfinder-cwd-icon-xml:after, +.elfinder-cwd-icon-xml { background-position: 0 -1000px; } + +.elfinder-cwd-icon-zip:after, +.elfinder-cwd-icon-x-zip:after, +.elfinder-cwd-icon-x-xz:after, +.elfinder-cwd-icon-x-7z-compressed:after, +.elfinder-cwd-icon-zip, +.elfinder-cwd-icon-x-zip, +.elfinder-cwd-icon-x-xz, +.elfinder-cwd-icon-x-7z-compressed { background-position: 0 -1050px; } + +.elfinder-cwd-icon-x-gzip:after, +.elfinder-cwd-icon-x-tar:after, +.elfinder-cwd-icon-x-gzip, +.elfinder-cwd-icon-x-tar { background-position: 0 -1100px; } + +.elfinder-cwd-icon-x-bzip:after, +.elfinder-cwd-icon-x-bzip2:after, +.elfinder-cwd-icon-x-bzip, +.elfinder-cwd-icon-x-bzip2 { background-position: 0 -1150px; } + +.elfinder-cwd-icon-x-rar:after, +.elfinder-cwd-icon-x-rar-compressed:after, +.elfinder-cwd-icon-x-rar, +.elfinder-cwd-icon-x-rar-compressed { background-position: 0 -1200px; } + +.elfinder-cwd-icon-x-shockwave-flash:after, +.elfinder-cwd-icon-x-shockwave-flash { background-position: 0 -1250px; } + +.elfinder-cwd-icon-group { background-position:0 -1300px;} + +/* textfield inside icon */ +.elfinder-cwd-filename input { width:100%; border:none; margin:0; padding:0; } +.elfinder-cwd-view-icons input {text-align:center; } +.elfinder-cwd-view-icons textarea { + width: 100%; + border: 0px solid; + margin: 0; + padding: 0; + text-align: center; + overflow: hidden; + resize: none; +} + +.elfinder-cwd-view-icons { text-align:center; } + + +/************************************ LIST VIEW ************************************/ + +/*.elfinder-cwd-view-list { padding:0 0 4px 0; }*/ + +.elfinder-cwd-wrapper.elfinder-cwd-fixheader .elfinder-cwd::after { + display: none; +} + +.elfinder-cwd table { + width: 100%; + border-collapse: separate; + border: 0 solid; + margin: 0 0 10px 0; + border-spacing: 0; + box-sizing: padding-box; + padding: 2px; + position: relative; +} + +.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader { + position: absolute; + overflow: hidden; +} + +.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before { + content: ''; + position: absolute; + width: 100%; + top: 0; + height: 3px; + background-color: white; +} +.elfinder-droppable-active + .elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before { + background-color: #8cafed; +} + +.elfinder .elfinder-workzone div.elfinder-cwd-fixheader table { + table-layout: fixed; +} + +.elfinder .elfinder-cwd table tbody.elfinder-cwd-fixheader { + position: relative; +} + +.elfinder-ltr .elfinder-cwd thead .elfinder-cwd-selectall { + text-align: left; + right: auto; + left: 0px; + padding-top: 3px; +} + +.elfinder-rtl .elfinder-cwd thead .elfinder-cwd-selectall { + text-align: right; + right: 0px; + left: auto; + padding-top: 3px; +} + +.elfinder-touch .elfinder-cwd thead .elfinder-cwd-selectall { + padding-top: 5px; +} + +.elfinder .elfinder-cwd table thead tr { border-left:0 solid; border-top:0 solid; border-right:0 solid; } + +.elfinder .elfinder-cwd table thead td { + padding: 4px 14px; +} +.elfinder-ltr .elfinder-cwd.elfinder-has-checkbox table thead td:first-child { + padding: 4px 14px 4px 22px; +} +.elfinder-rtl .elfinder-cwd.elfinder-has-checkbox table thead td:first-child { + padding: 4px 22px 4px 14px; +} + +.elfinder .elfinder-cwd table thead td.ui-state-active { + background: #ebf1f6; + background: -moz-linear-gradient(top, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ebf1f6), color-stop(50%,#abd3ee), color-stop(51%,#89c3eb), color-stop(100%,#d5ebfb)); + background: -webkit-linear-gradient(top, #ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%); + background: -o-linear-gradient(top, #ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%); + background: -ms-linear-gradient(top, #ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%); + background: linear-gradient(to bottom, #ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebf1f6', endColorstr='#d5ebfb',GradientType=0 ); +} + +.elfinder .elfinder-cwd table td { + padding:4px 12px; + white-space:pre; + overflow:hidden; + text-align:right; + cursor:default; + border:0 solid; +} + +.elfinder .elfinder-cwd table tbody td:first-child { + position: relative +} + +.elfinder .elfinder-cwd table td div { + box-sizing: content-box; +} + +tr.elfinder-cwd-file td .elfinder-cwd-select { + width: 40px; + padding-top: 3px; +} + +.elfinder-touch tr.elfinder-cwd-file td .elfinder-cwd-select { + padding-top: 10px; +} + +.elfinder-touch .elfinder-cwd tr td { + padding: 10px 12px; +} + +.elfinder-touch .elfinder-cwd table thead td { + padding: 8px 14px; +} + +.elfinder-touch .elfinder-cwd tr.elfinder-cwd-file td { + padding: 13px 12px; +} + +.elfinder-ltr .elfinder-cwd table td { text-align:right; } +.elfinder-ltr .elfinder-cwd table td:first-child { text-align:left; } +.elfinder-rtl .elfinder-cwd table td { text-align:left; } +.elfinder-rtl .elfinder-cwd table td:first-child { text-align:right; } + +.elfinder-odd-row { background:#eee; } + +/* filename container */ +.elfinder-cwd-view-list .elfinder-cwd-file-wrapper { width:97%; position:relative; } +/* filename container in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper { margin-left: 8px; } +.elfinder-rtl .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper { margin-right: 8px; } +.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-filename { padding-left:23px; } +.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-filename { padding-right:23px; } + +/* premissions/symlink marker */ +.elfinder-cwd-view-list .elfinder-perms, +.elfinder-cwd-view-list .elfinder-lock, +.elfinder-cwd-view-list .elfinder-symlink { + margin-top:-6px; + opacity: .6; + filter:Alpha(Opacity=60); +} +/* markers in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list .elfinder-perms { left:8px; bottom:-4px; } +.elfinder-ltr .elfinder-cwd-view-list .elfinder-lock { left:10px; top:0px; } +.elfinder-ltr .elfinder-cwd-view-list .elfinder-symlink { left:-7px; bottom:-4px; } + +/* file icon */ +.elfinder-cwd-view-list td .elfinder-cwd-icon { + width:16px; + height:16px; + position:absolute; + top:50%; + margin-top:-8px; + background-image:url(../img/icons-small.png); +} +/* icon in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-icon { left:0; } +.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-icon { right:0; } + +/* type badge, thumbnail image overlay */ +.elfinder-cwd-view-list .elfinder-cwd-icon:before, +.elfinder-cwd-view-list .elfinder-cwd-icon:after { + content: none; +} + +/* table header resize handle */ +.elfinder-cwd-view-list thead td .ui-resizable-handle { + height: 100%; + top: 3px; +} +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-handle { + top: -5px; + margin: 10px; +} +.elfinder-cwd-view-list thead td .ui-resizable-e { + right: -7px; +} +.elfinder-cwd-view-list thead td .ui-resizable-w { + left: -7px; +} +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-e { + right: -16px; +} +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-w { + left: -16px; +} + +/* empty message */ +.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list.elfinder-cwd:after { + margin-top: 0; +} + +/* File: /css/dialog.css */ +/*********************************************/ +/* DIALOGS STYLES */ +/*********************************************/ + +/* common dialogs class */ +.std42-dialog { + padding:0; + position:absolute; + left:auto; + right:auto; +} +.std42-dialog.elfinder-dialog-minimized { + overFlow: hidden; + position: relative; + float: left; + width: auto; +} +.elfinder-rtl .std42-dialog.elfinder-dialog-minimized { + float: right; +} + +/* titlebar */ +.std42-dialog .ui-dialog-titlebar { + border-left:0 solid transparent; + border-top:0 solid transparent; + border-right:0 solid transparent; + -moz-border-radius-bottomleft: 0; + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomright: 0; + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + font-weight:normal; + padding:.2em 1em; +} +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar { + padding: 0 .5em; + height: 20px; +} +.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar { + padding:.3em .5em; +} +.std42-dialog.ui-draggable-disabled .ui-dialog-titlebar { + cursor: default; +} + +.std42-dialog .ui-dialog-titlebar .ui-widget-header { + border : none; + cursor: pointer; +} + +.std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title { + display: inherit; + word-break: break-all; +} +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title { + display: list-item; + display: -moz-inline-box; + white-space: nowrap; + word-break: normal; + overflow: hidden; + word-wrap: normal; + overflow-wrap: normal; + max-width: -webkit-calc(100% - 24px); + max-width: -moz-calc(100% - 24px); + max-width: calc(100% - 24px); +} +.elfinder-touch .std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title { + padding-top: .15em; +} +.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title { + max-width: -webkit-calc(100% - 36px); + max-width: -moz-calc(100% - 36px); + max-width: calc(100% - 36px); +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button { + position: relative; + float: left; + top: 10px; + left: -10px; + right: 10px; + width: 20px; + height: 20px; + padding:1px; + margin: -10px 1px 0 1px; + background-color: transparent; + background-image: none; +} +.elfinder-touch .std42-dialog/*:not(.elfinder-dialog-minimized)*/ .ui-dialog-titlebar .elfinder-titlebar-button { + transform: scale(1.1); + zoom: 1.1; + margin-left: 5px; + margin-right: 5px; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button-right { + float: right; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right { + left: 10px; + right: -10px; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon { + width: 17px; + height: 17px; + border-width: 1px; + border-color: transparent; + opacity: .7; + filter:Alpha(Opacity=70); + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon { + opacity: 1; + filter:Alpha(Opacity=100); +} +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar select { + display: none; +} +.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon { + background-color: #ff6252; + border-color: #e5695d; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon { + background-color: #ffbc00; + border-color: #e3a40b; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon { + background-color: #26c82f; + border-color: #13ae10; +} + +/* resize handle for touch devices */ +.elfinder-touch .std42-dialog.ui-dialog:not(ui-resizable-disabled) .ui-resizable-se { + width: 12px; + height: 12px; + zoom: 1.5; + right: -7px; + bottom: -7px; + margin: 3px 7px 7px 3px; + background-position: -64px -224px; +} + +.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar { text-align:right; } + +/* content */ +.std42-dialog .ui-dialog-content { + padding:.3em .5em; + box-sizing: border-box; +} +.elfinder .std42-dialog .ui-dialog-content, +.elfinder .std42-dialog .ui-dialog-content * { + -webkit-user-select: auto; + -moz-user-select: text; + -khtml-user-select: text; + user-select: text; +} + +.elfinder .std42-dialog .ui-dialog-content form label { + border: none; +} + +/* buttons */ +.std42-dialog .ui-dialog-buttonpane { + border: 0 solid; + margin: 0; + padding: .5em; + text-align: right; +} +.elfinder-rtl .std42-dialog .ui-dialog-buttonpane { text-align: left; } + +.std42-dialog .ui-dialog-buttonpane button { margin:.2em 0 0 .4em; padding: .2em; outline:0px solid; } +.std42-dialog .ui-dialog-buttonpane button span { padding:2px 9px; } +.std42-dialog .ui-dialog-buttonpane button span.ui-icon { padding: 2px; } + +.elfinder-dialog .ui-resizable-e, +.elfinder-dialog .ui-resizable-s { width:0; height:0;} + +.std42-dialog .ui-button input { cursor: pointer;} + +.std42-dialog select { border: 1px solid #ccc; } + +/* error/notify/confirm dialogs icon */ +.elfinder-dialog-icon { + position:absolute; + width:32px; + height:32px; + left:10px; + top:50%; + margin-top:-15px; + background:url("../img/dialogs.png") 0 0 no-repeat; +} + +.elfinder-rtl .elfinder-dialog-icon { left:auto; right:10px;} + + + +/*********************** ERROR DIALOG **************************/ + +.elfinder-dialog-error .ui-dialog-content, +.elfinder-dialog-confirm .ui-dialog-content { padding-left: 56px; min-height:35px; } + +.elfinder-rtl .elfinder-dialog-error .ui-dialog-content, +.elfinder-rtl .elfinder-dialog-confirm .ui-dialog-content { padding-left:0; padding-right: 56px; } + +/*********************** NOTIFY DIALOG **************************/ + +.elfinder-dialog-notify .ui-dialog-titlebar-close { display:none; } +.elfinder-dialog-notify .ui-dialog-content { padding:0; } + +/* one notification container */ +.elfinder-notify { + border-bottom:1px solid #ccc; + position:relative; + padding:.5em; + + text-align:center; + overflow:hidden; +} + +.elfinder-ltr .elfinder-notify { padding-left:36px; } +.elfinder-rtl .elfinder-notify { padding-right:36px; } + +.elfinder-notify:last-child { border:0 solid; } + +/* progressbar */ +.elfinder-notify-progressbar { + width:180px; + height:8px; + border:1px solid #aaa; + background:#f5f5f5; + margin:5px auto; + overflow:hidden; +} + +.elfinder-notify-progress { + width:100%; + height:8px; + background:url(../img/progress.gif) center center repeat-x; +} + +.elfinder-notify-progressbar, .elfinder-notify-progress { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; +} + +/* icons */ +.elfinder-dialog-icon-open, +.elfinder-dialog-icon-readdir, +.elfinder-dialog-icon-file { background-position: 0 -225px; } +.elfinder-dialog-icon-reload { background-position: 0 -225px; } +.elfinder-dialog-icon-mkdir { background-position: 0 -64px; } +.elfinder-dialog-icon-mkfile { background-position: 0 -96px; } +.elfinder-dialog-icon-copy, +.elfinder-dialog-icon-prepare, +.elfinder-dialog-icon-move { background-position: 0 -128px;} +.elfinder-dialog-icon-upload { background-position: 0 -160px; } +.elfinder-dialog-icon-chunkmerge { background-position: 0 -160px; } +.elfinder-dialog-icon-rm { background-position: 0 -192px; } +.elfinder-dialog-icon-download { background-position: 0 -260px; } +.elfinder-dialog-icon-save { background-position: 0 -295px; } +.elfinder-dialog-icon-rename { background-position: 0 -330px; } +.elfinder-dialog-icon-zipdl, +.elfinder-dialog-icon-archive, +.elfinder-dialog-icon-extract { background-position: 0 -365px; } +.elfinder-dialog-icon-search { background-position: 0 -402px; } +.elfinder-dialog-icon-resize, +.elfinder-dialog-icon-loadimg, +.elfinder-dialog-icon-netmount, +.elfinder-dialog-icon-netunmount, +.elfinder-dialog-icon-chmod, +.elfinder-dialog-icon-preupload, +.elfinder-dialog-icon-url, +.elfinder-dialog-icon-dim { background-position: 0 -434px; } + +/*********************** CONFIRM DIALOG **************************/ + +.elfinder-dialog-confirm-applyall, +.elfinder-dialog-confirm-encoding { + padding: 0 1em; + margin: 0; +} +.elfinder-ltr .elfinder-dialog-confirm-applyall, +.elfinder-ltr .elfinder-dialog-confirm-encoding { text-align: left; } +.elfinder-rtl .elfinder-dialog-confirm-applyall, +.elfinder-rtl .elfinder-dialog-confirm-encoding { text-align: right; } + +.elfinder-dialog-confirm .elfinder-dialog-icon { background-position:0 -32px; } + +.elfinder-dialog-confirm .ui-dialog-buttonset { width: auto; } + +/*********************** FILE INFO DIALOG **************************/ + + +.elfinder-info-title .elfinder-cwd-icon { + float:left; + width:48px; + height:48px; + margin-right:1em; +} + +.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon { + float: right; + margin-right: 0; + margin-left: 1em; +} + +.elfinder-info-title strong { display:block; padding:.3em 0 .5em 0; } + +.elfinder-info-tb { + min-width:200px; + border:0 solid; + margin:1em .2em 1em .2em; +} + +.elfinder-info-tb td { white-space:nowrap; padding:2px; } + +.elfinder-info-tb tr td:first-child { text-align:right; } + +.elfinder-info-tb span { float:left;} +.elfinder-info-tb a { outline: none; text-decoration:underline; } +.elfinder-info-tb a:hover { text-decoration:none; } +.elfinder-info-spinner { + width:14px; + height:14px; + float:left; + background: url("../img/spinner-mini.gif") center center no-repeat; + margin:0 5px; +} + +.elfinder-netmount-tb { margin:0 auto; } +.elfinder-netmount-tb select, +.elfinder-netmount-tb input { border:1px solid #ccc; } +.elfinder-netmount-tb .elfinder-button-icon { cursor: pointer; } + +button.elfinder-info-button { + margin: -3.5px 0; + cursor: pointer; +} + +/*********************** UPLOAD DIALOG **************************/ + +.elfinder-upload-dropbox { + display: table-cell; + text-align:center; + vertical-align: middle; + padding:0.5em; + border:3px dashed #aaa; + width: 9999px; + height: 80px; + overflow: hidden; + word-break: keep-all; +} + +.elfinder-upload-dropbox.ui-state-hover { + background:#dfdfdf; + border:3px dashed #555; +} + +.elfinder-upload-dialog-or { + margin:.3em 0; + text-align:center; +} + +.elfinder-upload-dialog-wrapper { text-align:center; } + +.elfinder-upload-dialog-wrapper .ui-button { position:relative; overflow:hidden; } + +.elfinder-upload-dialog-wrapper .ui-button form { + position:absolute; + right:0; + top:0; + opacity: 0; filter:Alpha(Opacity=0); +} + +.elfinder-upload-dialog-wrapper .ui-button form input { + padding:0 20px; + font-size:3em; + +} + + +/* dialog for elFinder itself */ +.dialogelfinder .dialogelfinder-drag { + border-left:0 solid; + border-top:0 solid; + border-right:0 solid; + font-weight:normal; + padding:2px 12px; + cursor:move; + position:relative; + text-align:left; +} + +.elfinder-rtl .dialogelfinder-drag { text-align:right;} + +.dialogelfinder-drag-close { + position: absolute; + top:50%; + margin-top:-8px; +} + +.elfinder-ltr .dialogelfinder-drag-close { right:12px; } +.elfinder-rtl .dialogelfinder-drag-close { left:12px; } + + +/*********************** RM CONFIRM **************************/ +.elfinder-rm-title { + margin-bottom: .5ex; +} + +.elfinder-rm-title .elfinder-cwd-icon { + float:left; + width:48px; + height:48px; + margin-right:1em; +} + +.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon { + float: right; + margin-right: 0; + margin-left: 1em; +} + +.elfinder-rm-title strong { + display: block; + /*word-wrap: break-word;*/ + white-space: pre-wrap; + word-break: normal; + overflow: hidden; + text-overflow: ellipsis; +} + +.elfinder-rm-title+br { + display: none; +} + +/*********************** EDIT DIALOG **************************/ + +.ui-dialog-titlebar select.elfinder-edit-changed { + border-bottom: 1px solid #13ae10; +} + +/* File: /css/fonts.css */ +.elfinder-contextmenu .elfinder-contextmenu-item span { font-size:.72em; } + +.elfinder-cwd-view-icons .elfinder-cwd-filename { font-size:.7em; } +.elfinder-cwd-view-list td { font-size:.7em; } + +.std42-dialog .ui-dialog-titlebar { font-size:.82em; } +.std42-dialog .ui-dialog-content { font-size:.72em; } +.std42-dialog .ui-dialog-buttonpane { font-size:.76em; } +.elfinder-info-tb { font-size:.9em; } +.elfinder-upload-dropbox { font-size:1.2em; } +.elfinder-upload-dialog-or { font-size:1.2em; } +.dialogelfinder .dialogelfinder-drag { font-size:.9em; } +.elfinder .elfinder-navbar { font-size:.72em; } +.elfinder-place-drag .elfinder-navbar-dir { font-size:.9em;} +.elfinder-quicklook-title { font-size:.7em; } +.elfinder-quicklook-info-data { font-size:.72em; } +.elfinder-quicklook-preview-text-wrapper { font-size:.9em; } +.elfinder-button-menu-item { font-size:.72em; } +.elfinder-button-search input { font-size:.8em; } +.elfinder-statusbar div { font-size:.7em; } +.elfinder-drag-num { font-size:12px; } +.elfinder-toast { font-size:.76em; } + + +/* File: /css/navbar.css */ +/*********************************************/ +/* NAVIGATION PANEL */ +/*********************************************/ + +/* container */ +.elfinder .elfinder-navbar { + width:230px; + padding:3px 5px; + background-image:none; + border-top:0 solid; + border-bottom:0 solid; + overflow:auto; + position:relative; +} + +.elfinder .elfinder-navdock { + box-sizing: border-box; + width: 230px; + height: auto; + position: absolute; + bottom: 0; + overflow: auto; +} + +.elfinder-navdock .ui-resizable-n { + top: 0; + height: 20px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar { float:left; border-left:0 solid; } +.elfinder-rtl .elfinder-navbar { float:right; border-right:0 solid; } +.elfinder-ltr .ui-resizable-e { margin-left:10px; } + +/* folders tree container */ +.elfinder-tree { + display:table; width:100%; margin: 0 0 .5em 0; + -webkit-tap-highlight-color:rgba(0,0,0,0); +} + +/* one folder wrapper */ +.elfinder-navbar-wrapper, .elfinder-place-wrapper { } + +/* folder */ +.elfinder-navbar-dir { + position:relative; + display:block; + white-space:nowrap; + padding:3px 12px; + margin: 0; + outline:0px solid; + border:1px solid transparent; + cursor:default; +} +.elfinder-touch .elfinder-navbar-dir { + padding: 12px 12px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-dir { padding-left:35px; } +.elfinder-rtl .elfinder-navbar-dir { padding-right:35px; } + +/* arrow before icon */ +.elfinder-navbar-arrow { + width:12px; + height:14px; + position:absolute; + display:none; + top:50%; + margin-top:-8px; + background-image:url("../img/arrows-normal.png"); + background-repeat:no-repeat; +/* border:1px solid #111;*/ +} +.elfinder-ltr .elfinder-navbar-arrow { + left: 0; +} +.elfinder-rtl .elfinder-navbar-arrow { + right:0; +} +.elfinder-touch .elfinder-navbar-arrow { + zoom: 1.4; + -moz-transform-origin: top left; + -moz-transform: scale(1.4); + margin-bottom: 7px; +} +.elfinder-ltr.elfinder-touch .elfinder-navbar-arrow { + left: -3px; + margin-right: 20px; +} +.elfinder-rtl.elfinder-touch .elfinder-navbar-arrow { + right: -3px; + margin-left: 20px; +} + +.ui-state-active .elfinder-navbar-arrow { background-image:url("../img/arrows-active.png"); } + +/* collapsed/expanded arrow view */ +.elfinder-navbar-collapsed .elfinder-navbar-arrow { display:block; } + +.elfinder-subtree-chksubdir .elfinder-navbar-arrow { opacity: .25; filter:Alpha(Opacity=25); } + +/* arrow ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow { background-position: 0 4px;} +.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow { background-position: 0 -10px; } +.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow, +.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow { background-position:0 -21px; } + + +/* folder icon */ +.elfinder-navbar-icon { + width:16px; + height:16px; + position:absolute; + top:50%; + margin-top:-8px; + background-image:url("../img/toolbar.png"); + background-repeat:no-repeat; + background-position:0 -16px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-icon { left:14px; } +.elfinder-rtl .elfinder-navbar-icon { right:14px; } + +/* root folder */ +.elfinder-tree .elfinder-navbar-root .elfinder-navbar-icon { background-position:0 0; } +.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon { background-position:0 -704px; } + +/* root icon of each volume */ +.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon { background-image:url("../img/volume_icon_local.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon { background-image:url("../img/volume_icon_trash.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon { background-image:url("../img/volume_icon_ftp.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon { background-image:url("../img/volume_icon_sql.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon { background-image:url("../img/volume_icon_dropbox.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon { background-image:url("../img/volume_icon_googledrive.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon { background-image:url("../img/volume_icon_onedrive.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon { background-image:url("../img/volume_icon_box.png"); background-position:0 0; } +.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon { background-image:url("../img/toolbar.png"); background-position: 0 -688px; } + +/* icon in active/hove/dropactive state */ +.ui-state-active .elfinder-navbar-icon, +.elfinder-droppable-active .elfinder-navbar-icon, +.ui-state-hover .elfinder-navbar-icon { background-position:0 -32px; } + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-subtree { margin-left:12px; } +.elfinder-rtl .elfinder-navbar-subtree { margin-right:12px; } + + +/* spinner */ +.elfinder-navbar-spinner { + width:14px; + height:14px; + position:absolute; + display:block; + top:50%; + margin-top:-7px; + background: url("../img/spinner-mini.gif") center center no-repeat; +} +/* spinner ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-spinner { left:0; margin-left:-2px; } +.elfinder-rtl .elfinder-navbar-spinner { right:0; margin-right:-2px; } + +/* marker */ +.elfinder-navbar .elfinder-perms, +.elfinder-navbar .elfinder-lock, +.elfinder-navbar .elfinder-symlink { opacity: .6; filter:Alpha(Opacity=60); } + +/* permissions marker */ +.elfinder-navbar .elfinder-perms { bottom:-1px; margin-top:-8px; } + +/* locked marker */ +.elfinder-navbar .elfinder-lock { top:-2px; } + +/* permissions/symlink markers ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar .elfinder-perms { left: 20px; } +.elfinder-rtl .elfinder-navbar .elfinder-perms { right: 20px; } +.elfinder-ltr .elfinder-navbar .elfinder-lock { left: 20px; } +.elfinder-rtl .elfinder-navbar .elfinder-lock { right: 20px; } +.elfinder-ltr .elfinder-navbar .elfinder-symlink { left: 8px; } +.elfinder-rtl .elfinder-navbar .elfinder-symlink { right: 8px; } + +/* navbar input */ +.elfinder-navbar input { width:100%; border:0px solid; margin:0; padding:0; } + +/* resizable */ +.elfinder-navbar .ui-resizable-handle { width:12px; background:transparent url('../img/resize.png') center center no-repeat; } +.elfinder-nav-handle-icon { + position:absolute; + top:50%; + margin:-8px 2px 0 2px; + opacity: .5; filter:Alpha(Opacity=50); +} + +/* pager button */ +.elfinder-navbar-pager { + width: 100%; + box-sizing: border-box; + padding-top: 3px; + padding-bottom: 3px; +} +.elfinder-touch .elfinder-navbar-pager { + padding-top: 10px; + padding-bottom: 10px; +} + +.elfinder-places { + border: none; + margin: 0; + padding: 0; +} +.elfinder-places.elfinder-droppable-active { + /*border:1px solid #8cafed;*/ +} + +/* navbar swipe handle */ +.elfinder-navbar-swipe-handle { + position: absolute; + top: 0px; + height: 100%; + width: 50px; + pointer-events: none; +} +.elfinder-ltr .elfinder-navbar-swipe-handle { + left: 0px; + background: linear-gradient(to right, + rgba(221,228,235,1) 0, + rgba(221,228,235,0.8) 5px, + rgba(216,223,230,0.3) 8px, + rgba(0,0,0,0.1) 95%, + rgba(0,0,0,0) 100%); +} +.elfinder-rtl .elfinder-navbar-swipe-handle { + right: 0px; + background: linear-gradient(to left, + rgba(221,228,235,1) 0, + rgba(221,228,235,0.8) 5px, + rgba(216,223,230,0.3) 8px, + rgba(0,0,0,0.1) 95%, + rgba(0,0,0,0) 100%); +} +/* File: /css/places.css */ +/*********************************************/ +/* PLACES STYLES */ +/*********************************************/ +/* root extra icon */ +.elfinder-navbar-root .elfinder-places-root-icon { + position: absolute; + top: 50%; + margin-top: -9px; + cursor: pointer; +} +.elfinder-ltr .elfinder-places-root-icon { + right: 10px; +} +.elfinder-rtl .elfinder-places-root-icon { + left: 10px; +} +.elfinder-navbar-expanded .elfinder-places-root-icon { + display: block; +} + +/* dragging helper base */ +.elfinder-place-drag { + font-size: 0.8em; +} + +/* File: /css/quicklook.css */ +/* quicklook window */ +.elfinder-quicklook { + position:absolute; + background:url("../img/quicklook-bg.png"); + overflow:hidden; + -moz-border-radius:7px; + -webkit-border-radius:7px; + border-radius:7px; + padding:20px 0 40px 0; +} +.elfinder-navdock .elfinder-quicklook { + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; + font-size: 90%; + overflow: auto; +} + +.elfinder-quicklook.elfinder-touch { + padding:30px 0 40px 0; +} + +.elfinder-quicklook .ui-resizable-se { + width:14px; + height:14px; + right:5px; + bottom:3px; + background:url("../img/toolbar.png") 0 -496px no-repeat; +} +.elfinder-quicklook.elfinder-touch .ui-resizable-se { + zoom: 1.5; +} + +/* quicklook fullscreen window */ +.elfinder-quicklook.elfinder-quicklook-fullscreen { + position:fixed; + top:0; + right:0; + bottom:0; + left:0; + margin:0; + box-sizing:border-box; + width:100%; + height:100%; + object-fit:contain; + border-radius:0; + -moz-border-radius:0; + -webkit-border-radius:0; + -webkit-background-clip: padding-box; + padding:0; + background:#000; + display:block; +} +/* hide titlebar in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-titlebar, +.elfinder-quicklook-fullscreen.elfinder-quicklook .ui-resizable-handle { display:none; } + +/* hide preview border in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-preview { border:0 solid ;} + +/*.elfinder-quicklook-fullscreen iframe { + height: 100%; +}*/ + +.elfinder-quicklook-cover { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; +} + +/* quicklook titlebar */ +.elfinder-quicklook-titlebar { + text-align:center; + background:#777; + position:absolute; + left:0; + top:0; + width:100%; + height:20px; + -moz-border-radius-topleft: 7px; + -webkit-border-top-left-radius: 7px; + border-top-left-radius: 7px; + -moz-border-radius-topright: 7px; + -webkit-border-top-right-radius: 7px; + border-top-right-radius: 7px; + cursor:move; +} +.elfinder-navdock .elfinder-quicklook-titlebar { + -moz-border-radius-topleft: 0; + -webkit-border-top-left-radius: 0; + border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -webkit-border-top-right-radius: 0; + border-top-right-radius: 0; + cursor: default; +} +.elfinder-touch .elfinder-quicklook-titlebar { + height: 30px; +} + +/* window title */ +.elfinder-quicklook-title { + color:#fff; + white-space:nowrap; + overflow:hidden; + padding:2px 0; +} + +.elfinder-touch .elfinder-quicklook-title { + padding: 8px 0; +} + +/* icon "close" in titlebar */ +.elfinder-quicklook-titlebar-icon { + position: absolute; + left : 4px; + top: 50%; + margin-top: -9px; + height: 16px; +} +.elfinder-quicklook-titlebar-icon .ui-icon { + position: relative; + margin: -9px 6px 0px 0px; + cursor: pointer; + border-radius: 10px; + border: 1px solid; +} +.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon { + margin-top: -3px; +} +.elfinder-quicklook-titlebar-icon.elfinder-platformWin { + left : auto; + right : 4px; + direction: rtl; +} +.elfinder-quicklook-titlebar-icon.elfinder-platformWin .ui-icon { + margin: -9px 0px 0px 6px; +} + +.elfinder-touch .elfinder-quicklook-titlebar .ui-icon { + zoom: 1.5; +} + +/* main part of quicklook window */ +.elfinder-quicklook-preview { + overflow: hidden; + position:relative; + border:0 solid; + border-left:1px solid transparent; + border-right:1px solid transparent; + height:100%; +} +.elfinder-navdock .elfinder-quicklook-preview { + border-left: 0; + border-right: 0; +} +.elfinder-quicklook-preview.elfinder-overflow-auto { + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* wrapper for file info/icon */ +.elfinder-quicklook-info-wrapper { + display: table; + position: absolute; + width: 100%; + height: 100%; + height: calc(100% - 80px); + left: 0; + top: 20px; +} +.elfinder-navdock .elfinder-quicklook-info-wrapper { + height: calc(100% - 20px); +} + +/* file info */ +.elfinder-quicklook-info { + display: table-cell; + vertical-align: middle; +} +.elfinder-ltr .elfinder-quicklook-info { + padding: 0 12px 0 112px; +} +.elfinder-rtl .elfinder-quicklook-info { + padding: 0 112px 0 12px; +} +.elfinder-ltr .elfinder-navdock .elfinder-quicklook-info { + padding: 0 0 0 80px; +} +.elfinder-rtl .elfinder-navdock .elfinder-quicklook-info { + padding: 0 80px 0 0; +} + +/* file name in info */ +.elfinder-quicklook-info .elfinder-quicklook-info-data:first-child { + color:#fff; + font-weight:bold; + padding-bottom:.5em; +} + +/* other data in info */ +.elfinder-quicklook-info-data { + padding-bottom:.2em; + color:#fff; +} + +/* file icon */ +.elfinder-quicklook .elfinder-cwd-icon { + position:absolute; + left:32px; + top:50%; + margin-top:-20px; +} +.elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon { + left:16px; +} +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon { + left: auto; + right: 32px; +} +.elfinder-rtl .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon { + right: 6px; +} +.elfinder-quicklook .elfinder-cwd-icon:before { + top: -10px; +} +.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:before { + left: -20px; +} +.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:before { + left: -14px; +} +.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:after { + left: -15px; +} +.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:after { + left: -12px; +} +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:before { + left: auto; + right: 40px; +} +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:after { + left: auto; + right: 40px; +} + +/* image in preview */ +.elfinder-quicklook-preview img { + display:block; + margin:0 auto; +} + +/* navigation bar on quicklook window bottom */ +.elfinder-quicklook-navbar { + position:absolute; + left:50%; + bottom:4px; + width:140px; + height:32px; + padding:0px; + margin-left:-70px; + border:1px solid transparent; + border-radius:19px; + -moz-border-radius:19px; + -webkit-border-radius:19px; +} + +/* navigation bar in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar { + width:188px; + margin-left:-94px; + padding:5px; + border:1px solid #eee; + background:#000; + opacity: 0.4; + filter: Alpha(Opacity=40); +} + +/* show close icon in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-icon-close, +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-separator { + display:inline; +} + +/* icons in navbar */ +.elfinder-quicklook-navbar-icon { + width:32px; + height:32px; + margin:0 7px; + float:left; + background:url("../img/quicklook-icons.png") 0 0 no-repeat; + +} + +/* fullscreen icon */ +.elfinder-quicklook-navbar-icon-fullscreen { + background-position:0 -64px; +} + +/* exit fullscreen icon */ +.elfinder-quicklook-navbar-icon-fullscreen-off { + background-position:0 -96px; +} + +/* prev file icon */ +.elfinder-quicklook-navbar-icon-prev { + background-position:0 0; +} + +/* next file icon */ +.elfinder-quicklook-navbar-icon-next { + background-position:0 -32px; +} + +/* close icon */ +.elfinder-quicklook-navbar-icon-close { + background-position:0 -128px; + display:none; +} + +/* icons separator */ +.elfinder-quicklook-navbar-separator { + width:1px; + height:32px; + float:left; + border-left:1px solid #fff; + display:none; +} + +/* text files preview wrapper */ +.elfinder-quicklook-preview-text-wrapper { + width: 100%; + height:100%; + background:#fff; + color:#222; + overflow:auto; + -webkit-overflow-scrolling: touch; +} + +/* archive files preview wrapper */ +.elfinder-quicklook-preview-archive-wrapper { + width: 100%; + height:100%; + background:#fff; + color:#222; + font-size: 1.5ex; + overflow:auto; + -webkit-overflow-scrolling: touch +} + +/* archive files preview header */ +.elfinder-quicklook-preview-archive-wrapper strong { + padding: 0 5px; +} + +/* text preview */ +pre.elfinder-quicklook-preview-text, +pre.elfinder-quicklook-preview-text.prettyprint { + width: auto; + height: auto; + margin:0; + padding:3px 9px; + border: none; +} +.elfinder-quicklook-preview-charsleft hr { + border:none; + border-top:dashed 1px; +} +.elfinder-quicklook-preview-charsleft span { + font-size: 90%; + font-style: italic; +} +/* html/pdf preview */ +.elfinder-quicklook-preview-html, +.elfinder-quicklook-preview-pdf, +.elfinder-quicklook-preview-iframe { + width:100%; + height:100%; + background:#fff; + margin:0; + border: none; + display: block; +} + +/* swf preview container */ +.elfinder-quicklook-preview-flash { + width:100%; + height:100%; +} + +/* audio preview container */ +.elfinder-quicklook-preview-audio { + width:100%; + position:absolute; + bottom:0; + left:0; +} + +/* audio preview using embed */ +embed.elfinder-quicklook-preview-audio { + height:30px; + background:transparent; +} + +/* video preview container */ +.elfinder-quicklook-preview-video { + width:100%; + height:100%; +} + +/* allow user select */ +.elfinder .elfinder-quicklook .elfinder-quicklook-info *, +.elfinder .elfinder-quicklook .elfinder-quicklook-preview * { + -webkit-user-select: auto; + -moz-user-select: text; + -khtml-user-select: text; + user-select: text; +} + +/* File: /css/statusbar.css */ +/******************************************************************/ +/* STATUSBAR STYLES */ +/******************************************************************/ + + +/* statusbar container */ +.elfinder-statusbar { + cursor: default; + text-align:center; + font-weight:normal; + padding:.2em .5em; + + border-right:0 solid transparent; + border-bottom:0 solid transparent; + border-left:0 solid transparent; +} + +.elfinder-statusbar span { + vertical-align: bottom; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + text-overflow: ".."; + -o-text-overflow: ".."; +} +.elfinder-statusbar span.ui-state-hover, +.elfinder-statusbar span.ui-state-active { border: none; } +.elfinder-statusbar span.elfinder-path-cwd { cursor: default; } + + + +/* path in statusbar */ +.elfinder-path { + cursor: pointer; + max-width:30%; + white-space:nowrap; + overflow:hidden; + text-overflow:ellipsis; + -o-text-overflow:ellipsis; +} +.elfinder-ltr .elfinder-path { float:left; } +.elfinder-rtl .elfinder-path { float:right; } + +/* path in workzone (case of swipe to navbar close) */ +.elfinder-workzone-path { + position: relative; +} +.elfinder-workzone-path .elfinder-path { + position: relative; + font-size: .75em; + font-weight: normal; + float: none; + max-width: none; + overflow: hidden; + overflow-x: hidden; + text-overflow: initial; + -o-text-overflow: initial; +} +.elfinder-mobile .elfinder-workzone-path .elfinder-path { + overflow: auto; + overflow-x: scroll; +} +.elfinder-ltr .elfinder-workzone-path .elfinder-path { + margin-left: 24px; +} +.elfinder-rtl .elfinder-workzone-path .elfinder-path { + margin-right: 24px; +} +.elfinder-workzone-path .elfinder-path span { + display: inline-block; + padding: 5px 3px; +} +.elfinder-workzone-path .elfinder-path span.elfinder-path-cwd { + font-weight: bold; +} +.elfinder-workzone-path .elfinder-path span.ui-state-hover, +.elfinder-workzone-path .elfinder-path span.ui-state-active { border: none; } + +.elfinder-workzone-path .elfinder-path-roots { + position: absolute; + top: 0; + width: 24px; + height: 20px; + padding: 2px; + border: none; + overflow: hidden; +} +.elfinder-ltr .elfinder-workzone-path .elfinder-path-roots { + left: 0; +} +.elfinder-rtl .elfinder-workzone-path .elfinder-path-roots { + right: 0; +} +/* total/selected size in statusbar */ +.elfinder-stat-size { + overflow: hidden; + text-wrap: none; +} +.elfinder-ltr .elfinder-stat-size { float:right; } +.elfinder-rtl .elfinder-stat-size { float:left; } + +.elfinder-stat-selected { white-space:nowrap; overflow:hidden; } + +/* File: /css/toast.css */ +/* + * CSS for Toastr + * Copyright 2012-2015 + * Authors: John Papa, Hans Fjällemark, and Tim Ferrell. + * All Rights Reserved. + * Use, reproduction, distribution, and modification of this code is subject to the terms and + * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php + * + * ARIA Support: Greta Krafsig + * + * Project: https://github.com/CodeSeven/toastr + */ + +.elfinder .elfinder-toast { + position: absolute; + top: 12px; + right: 12px; + max-width: 90%; + cursor: default; +} + +.elfinder .elfinder-toast > div { + position: relative; + pointer-events: auto; + overflow: hidden; + margin: 0 0 6px; + padding: 8px 16px 8px 50px; + -moz-border-radius: 3px 3px 3px 3px; + -webkit-border-radius: 3px 3px 3px 3px; + border-radius: 3px 3px 3px 3px; + background-position: 15px center; + background-repeat: no-repeat; + -moz-box-shadow: 0 0 12px #999999; + -webkit-box-shadow: 0 0 12px #999999; + box-shadow: 0 0 12px #999999; + color: #FFFFFF; + opacity: 0.9; + filter: alpha(opacity=90); + background-color: #030303; + text-align: center; +} + +.elfinder .elfinder-toast > .toast-info { + background-color: #2F96B4; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important; +} +.elfinder .elfinder-toast > .toast-error { + background-color: #BD362F; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important; +} +.elfinder .elfinder-toast > .toast-success { + background-color: #51A351; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important; +} +.elfinder .elfinder-toast > .toast-warning { + background-color: #F89406; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important; +} + + +.elfinder .elfinder-toast > div button.ui-button { + background-image: none; + margin-top: 8px; + padding: .5em .8em; +} + +.elfinder .elfinder-toast > .toast-success button.ui-button { + background-color: green; + color: #FFF; +} + +.elfinder .elfinder-toast > .toast-success button.ui-button.ui-state-hover { + background-color: #add6ad; + color: #254b25; +} + +/* File: /css/toolbar.css */ +/*********************************************/ +/* TOOLBAR STYLES */ +/*********************************************/ +/* toolbar container */ +.elfinder-toolbar { + padding:4px 0 3px 0; + border-left:0 solid transparent; + border-top:0 solid transparent; + border-right:0 solid transparent; +} + +/* container for button's group */ +.elfinder-buttonset { + margin: 1px 4px; + float:left; + background:transparent; + padding:0; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +/*.elfinder-buttonset:first-child { margin:0; }*/ + +/* button */ +.elfinder .elfinder-button { + /*width:16px;*/ + height:16px; + margin:0; + padding:4px; + float:left; + overflow:hidden; + position:relative; + border:0 solid; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + line-height: 1; + cursor: default; +} +.elfinder-touch .elfinder-button { + /*width:20px;*/ + height:20px; +} + +.elfinder .ui-icon-search { cursor:pointer;} + +.elfinder-button:first-child { + -moz-border-radius-topleft: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.elfinder-button:last-child { + -moz-border-radius-topright: 4px; + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +/* separator between buttons, required for berder between button with ui color */ +.elfinder-toolbar-button-separator { + float:left; + padding:0; + height:24px; + border-top:0 solid; + border-right:0 solid; + border-bottom:0 solid; + width:0; +} + +.elfinder-touch .elfinder-toolbar-button-separator { + height:20px; +} + +/* change icon opacity^ not button */ +.elfinder .elfinder-button.ui-state-disabled { opacity:1; filter:Alpha(Opacity=100);} +.elfinder .elfinder-button.ui-state-disabled .elfinder-button-icon, +.elfinder .elfinder-button.ui-state-disabled .elfinder-button-text { opacity:.4; filter:Alpha(Opacity=40);} + +/* rtl enviroment */ +.elfinder-rtl .elfinder-buttonset { float:right; } + +/* icon inside button */ +.elfinder-button-icon { + width:16px; + height:16px; + /*display:block;*/ + display:inline-block; + background:url('../img/toolbar.png') no-repeat; +} +.elfinder-button-text { + position: relative; + display: inline-block; + top: -4px; + margin: 0 2px; + font-size: 12px; +} + +.elfinder-touch .elfinder-button-icon { + zoom: 1.25; + -moz-transform-origin: top left; + -moz-transform: scale(1.25); +} +.elfinder-touch .elfinder-button-text { + top: -5px; +} + +/* buttons icons */ +.elfinder-button-icon-home { background-position: 0 0; } +.elfinder-button-icon-back { background-position: 0 -112px; } +.elfinder-button-icon-forward { background-position: 0 -128px; } +.elfinder-button-icon-up { background-position: 0 -144px; } +.elfinder-button-icon-dir { background-position: 0 -16px; } +.elfinder-button-icon-opendir { background-position: 0 -32px; } +.elfinder-button-icon-reload { background-position: 0 -160px; } +.elfinder-button-icon-open { background-position: 0 -176px; } +.elfinder-button-icon-mkdir { background-position: 0 -192px; } +.elfinder-button-icon-mkfile { background-position: 0 -208px; } +.elfinder-button-icon-rm { background-position: 0 -832px; } +.elfinder-button-icon-trash { background-position: 0 -224px; } +.elfinder-button-icon-restore { background-position: 0 -816px; } +.elfinder-button-icon-copy { background-position: 0 -240px; } +.elfinder-button-icon-cut { background-position: 0 -256px; } +.elfinder-button-icon-paste { background-position: 0 -272px; } +.elfinder-button-icon-getfile { background-position: 0 -288px; } +.elfinder-button-icon-duplicate { background-position: 0 -304px; } +.elfinder-button-icon-rename { background-position: 0 -320px; } +.elfinder-button-icon-edit { background-position: 0 -336px; } +.elfinder-button-icon-quicklook { background-position: 0 -352px; } +.elfinder-button-icon-upload { background-position: 0 -368px; } +.elfinder-button-icon-download { background-position: 0 -384px; } +.elfinder-button-icon-info { background-position: 0 -400px; } +.elfinder-button-icon-extract { background-position: 0 -416px; } +.elfinder-button-icon-archive { background-position: 0 -432px; } +.elfinder-button-icon-view { background-position: 0 -448px; } +.elfinder-button-icon-view-list { background-position: 0 -464px; } +.elfinder-button-icon-help { background-position: 0 -480px; } +.elfinder-button-icon-resize { background-position: 0 -512px; } +.elfinder-button-icon-link { background-position: 0 -528px; } +.elfinder-button-icon-search { background-position: 0 -561px; } +.elfinder-button-icon-sort { background-position: 0 -577px; } +.elfinder-button-icon-rotate-r { background-position: 0 -625px; } +.elfinder-button-icon-rotate-l { background-position: 0 -641px; } +.elfinder-button-icon-netmount { background-position: 0 -688px; } +.elfinder-button-icon-netunmount { background-position: 0 -96px; } +.elfinder-button-icon-places { background-position: 0 -704px; } +.elfinder-button-icon-chmod { background-position: 0 -48px; } +.elfinder-button-icon-accept { background-position: 0 -736px; } +.elfinder-button-icon-opendir { background-position: 0 -32px; } +.elfinder-button-icon-menu { background-position: 0 -752px; } +.elfinder-button-icon-colwidth { background-position: 0 -768px; } +.elfinder-button-icon-fullscreen { background-position: 0 -784px; } +.elfinder-button-icon-unfullscreen { background-position: 0 -800px; } +.elfinder-button-icon-empty { background-position: 0 -848px; } +.elfinder-button-icon-undo { background-position: 0 -864px; } +.elfinder-button-icon-redo { background-position: 0 -880px; } +.elfinder-button-icon-preference { background-position: 0 -896px; } +.elfinder-button-icon-mkdirin { background-position: 0 -912px; } +.elfinder-button-icon-selectall { background-position: 0 -928px; } +.elfinder-button-icon-selectnone { background-position: 0 -944px; } +.elfinder-button-icon-selectinvert { background-position: 0 -960px; } + +/* button with dropdown menu*/ +.elfinder .elfinder-menubutton { overflow:visible; } + +/* button with spinner icon */ +.elfinder-button-icon-spinner { background: url("../img/spinner-mini.gif") center center no-repeat; } + +/* menu */ +.elfinder-button-menu { + position:absolute; + left:0; + top:25px; + padding:3px 0; +} + +.elfinder-touch .elfinder-button-menu { + top:35px; +} + +/* menu item */ +.elfinder-button-menu-item { + white-space:nowrap; + cursor:default; + padding:5px 19px; + position:relative; +} +.elfinder-touch .elfinder-button-menu-item { + padding: 12px 19px +} + +/* fix hover ui class */ +.elfinder-button-menu .ui-state-hover { border:0 solid; } + +.elfinder-button-menu-item-separated { border-top:1px solid #ccc; } + +.elfinder-button-menu-item .ui-icon { + width:16px; + height:16px; + position:absolute; + left:2px; + top:50%; + margin-top:-8px; + display:none; +} + +.elfinder-button-menu-item-selected .ui-icon { display:block; } +.elfinder-button-menu-item-selected-asc .ui-icon-arrowthick-1-s { display:none; } +.elfinder-button-menu-item-selected-desc .ui-icon-arrowthick-1-n { display:none; } + +/* hack for upload button */ +.elfinder-button form { + position:absolute; + top:0; + right:0; + opacity: 0; filter:Alpha(Opacity=0); + cursor: pointer; +} + +.elfinder .elfinder-button form input { background:transparent; cursor: default;} + +/* search "button" */ +.elfinder .elfinder-button-search { + border:0 solid; + background:transparent; + padding:0; + margin: 1px 4px; + height: auto; + min-height: 26px; + float:right; + width:202px; + overflow: visible; +} + +.elfinder .elfinder-button-search .elfinder-button-menu { + font-size: 8pt; + text-align: center; + width: 100%; +} + +.elfinder .elfinder-button-search .elfinder-button-menu div { + margin-left: auto; + margin-right: auto; + margin-bottom: 5px; +} + +.elfinder .elfinder-button-search .elfinder-button-menu div .ui-state-hover { + border: 1px solid; +} + +/* ltr/rte enviroment */ +.elfinder-ltr .elfinder-button-search { float:right; margin-right:10px; } +.elfinder-rtl .elfinder-button-search { float:left; margin-left:10px; } + +/* search text field */ +.elfinder-button-search input[type=text] { + width:160px; + height:22px; + padding:0 20px; + line-height: 22px; + border:0 solid; + border:1px solid #aaa; + -moz-border-radius: 12px; + -webkit-border-radius: 12px; + border-radius: 12px; + outline:0px solid; +} + +.elfinder-button-search input::-ms-clear { + display: none; +} +.elfinder-touch .elfinder-button-search input { + height:28px; + line-height: 28px; +} +.elfinder-rtl .elfinder-button-search input { direction:rtl; } + + +/* icons */ +.elfinder-button-search .ui-icon { + position:absolute; + height:18px; + top: 50%; + margin:-8px 4px 0 4px; + opacity: .6; + filter:Alpha(Opacity=60); +} +.elfinder-button-search .ui-checkboxradio-icon { + display: none; +} + +/* search/close icons */ +.elfinder-ltr .elfinder-button-search .ui-icon-search { left:0;} +.elfinder-rtl .elfinder-button-search .ui-icon-search { right:0;} +.elfinder-ltr .elfinder-button-search .ui-icon-close { right:0;} +.elfinder-rtl .elfinder-button-search .ui-icon-close { left:0;} + +/* toolbar swipe handle */ +.elfinder-toolbar-swipe-handle { + position: absolute; + top: 0px; + left: 0px; + height: 50px; + width: 100%; + pointer-events: none; + background: linear-gradient(to bottom, + rgba(221,228,235,1) 0, + rgba(221,228,235,0.8) 2px, + rgba(216,223,230,0.3) 5px, + rgba(0,0,0,0.1) 95%, + rgba(0,0,0,0) 100%); +} + diff --git a/static/elfinder/css/elfinder.min.css b/static/elfinder/css/elfinder.min.css new file mode 100644 index 00000000..1a636462 --- /dev/null +++ b/static/elfinder/css/elfinder.min.css @@ -0,0 +1,9 @@ +/*! + * elFinder - file manager for web + * Version 2.1.29 (2017-10-07) + * http://elfinder.org + * + * Copyright 2009-2017, Studio 42 + * Licensed under a 3-clauses BSD license + */ +.elfinder-dialog-resize{margin-top:.3em}.elfinder-resize-type{float:left;margin-bottom:.4em}.elfinder-resize-control{float:left}.elfinder-resize-control input[type=text]{border:1px solid #aaa;text-align:right;width:4em}.elfinder-resize-control input.elfinder-resize-bg{text-align:center;width:5em;direction:ltr}.elfinder-dialog-resize .elfinder-resize-imgrotate,.elfinder-dialog-resize .elfinder-resize-pallet{cursor:pointer}.elfinder-dialog-resize .elfinder-resize-picking{cursor:crosshair}.elfinder-dialog-resize .elfinder-resize-grid8+button{padding-top:2px;padding-bottom:2px}.elfinder-resize-preview{width:400px;height:400px;padding:10px;background:#fff;border:1px solid #aaa;float:right;position:relative;overflow:hidden;text-align:left;direction:ltr}.elfinder .elfinder-cwd table tbody.elfinder-cwd-fixheader,.elfinder-resize-handle,div.elfinder-cwd-wrapper-list tr.ui-state-default td{position:relative}.elfinder-resize-handle-hline,.elfinder-resize-handle-vline{position:absolute;background-image:url(../img/crop.gif)}.elfinder-resize-handle-hline{width:100%;height:1px!important;background-repeat:repeat-x}.elfinder-resize-handle-vline{width:1px!important;height:100%;background-repeat:repeat-y}.elfinder-resize-handle-hline-top{top:0;left:0}.elfinder-resize-handle-hline-bottom{bottom:0;left:0}.elfinder-resize-handle-vline-left{top:0;left:0}.elfinder-resize-handle-vline-right{top:0;right:0}.elfinder-resize-handle-point{position:absolute;width:8px;height:8px;border:1px solid #777;background:0 0}.elfinder-resize-handle-point-n{top:0;left:50%;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-e,.elfinder-resize-handle-point-ne{top:0;right:0;margin-top:-5px;margin-right:-5px}.elfinder-resize-handle-point-e{top:50%}.elfinder-resize-handle-point-se{bottom:0;right:0;margin-bottom:-5px;margin-right:-5px}.elfinder-resize-handle-point-s,.elfinder-resize-handle-point-sw{bottom:0;left:50%;margin-bottom:-5px;margin-left:-5px}.elfinder-resize-handle-point-sw{left:0}.elfinder-resize-handle-point-nw,.elfinder-resize-handle-point-w{top:50%;left:0;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-nw{top:0}.elfinder-resize-spinner{position:absolute;width:200px;height:30px;top:50%;margin-top:-25px;left:50%;margin-left:-100px;text-align:center;background:url(../img/progress.gif) center bottom repeat-x}.elfinder-resize-row{margin-bottom:9px;position:relative}.elfinder-resize-label{float:left;width:80px;padding-top:3px}.elfinder-resize-checkbox-label{border:1px solid transparent}.elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls{margin:-20px 5px 0}.elfinder-ltr .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls{float:right}.elfinder-help-team div,.elfinder-info-tb span,.elfinder-rtl .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-whctrls{float:left}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-e,.elfinder-dialog .elfinder-dialog-resize .ui-resizable-w{height:100%;width:10px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-n,.elfinder-dialog .elfinder-dialog-resize .ui-resizable-s{width:100%;height:10px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-e{margin-right:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-w{margin-left:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-s{margin-bottom:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-n{margin-top:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne,.elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw,.elfinder-dialog .elfinder-dialog-resize .ui-resizable-se,.elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw{width:10px;height:10px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-se{background:0 0;bottom:0;right:0;margin-right:-7px;margin-bottom:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw{margin-left:-7px;margin-bottom:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne{margin-right:-7px;margin-top:-7px}.elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw{margin-left:-7px;margin-top:-7px}.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-n,.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-s{height:20px}.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-e,.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-w{width:20px}.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-ne,.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-nw,.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-se,.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .ui-resizable-sw{width:30px;height:30px}.elfinder-touch .elfinder-dialog .elfinder-dialog-resize .elfinder-resize-preview .ui-resizable-se{width:30px;height:30px;zoom:1;margin:0}.elfinder-dialog-resize .ui-icon-grip-solid-vertical{position:absolute;top:50%;right:0;margin-top:-8px;margin-right:-11px}.elfinder-dialog-resize .ui-icon-grip-solid-horizontal{position:absolute;left:50%;bottom:0;margin-left:-8px;margin-bottom:-11px}.elfinder-dialog-resize .elfinder-resize-row .ui-buttonset{float:right}.elfinder-dialog-resize .elfinder-resize-degree input,.elfinder-dialog-resize .elfinder-resize-quality input{width:2.5em}.elfinder-dialog-resize .elfinder-resize-degree button.ui-button{padding:6px 8px}.elfinder-dialog-resize button.ui-button span{padding:0}.ui-widget-content .elfinder-dialog-resize .elfinder-resize-rotate-slider{width:195px;margin:10px 7px;background-color:#fafafa}.elfinder-dialog-resize .elfinder-resize-type span.ui-checkboxradio-icon{display:none}.elfinder-resize-preset-container{box-sizing:border-box;border-radius:5px}.elfinder-file-edit{width:100%;height:99%;margin:0;padding:2px;border:1px solid #ccc;box-sizing:border-box;resize:none}.elfinder-touch .elfinder-file-edit{font-size:16px}.elfinder-touch.elfinder-fullscreen-native textarea.elfinder-file-edit{padding-bottom:20em;margin-bottom:-20em}.std42-dialog .ui-dialog-buttonpane .elfinder-dialog-confirm-encoding,.std42-dialog .ui-dialog-titlebar select{font-size:12px}div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{position:absolute;top:4px;left:0;right:0;margin:auto 0 auto auto}.elfinder-touch div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{top:7px}.elfinder-rtl div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{margin:auto auto auto 0}.elfinder-help{margin-bottom:.5em}.elfinder-help .ui-tabs-panel{overflow:auto;padding:10px}.elfinder-dialog .ui-tabs .ui-tabs-nav li a{padding:.2em 1em}.elfinder-help-shortcuts{height:auto;padding:10px;margin:0;box-sizing:border-box}.elfinder-help-shortcut{white-space:nowrap;clear:both}.elfinder-help-shortcut-pattern{float:left;width:160px}.elfinder-help-logo{width:100px;height:96px;float:left;margin-right:1em;background:url(../img/logo.png) center center no-repeat}.elfinder-help h3{font-size:1.5em;margin:.2em 0 .3em}.elfinder-help-separator{clear:both;padding:.5em}.elfinder-help-link,.std42-dialog .ui-dialog-buttonpane button span.ui-icon{padding:2px}.elfinder-help .ui-priority-secondary{font-size:.9em}.elfinder-help .ui-priority-primary{margin-bottom:7px}.elfinder-help-team{clear:both;text-align:right;border-bottom:1px solid #ccc;margin:.5em 0;font-size:.9em}.elfinder-help-license{font-size:.9em}.elfinder-help-disabled{font-weight:700;text-align:center;margin:90px 0}.elfinder-help .elfinder-dont-panic{display:block;border:1px solid transparent;width:200px;height:200px;margin:30px auto;text-decoration:none;text-align:center;position:relative;background:#d90004;-moz-box-shadow:5px 5px 9px #111;-webkit-box-shadow:5px 5px 9px #111;box-shadow:5px 5px 9px #111;background:-moz-radial-gradient(80px 80px,circle farthest-corner,#d90004 35%,#960004 100%);background:-webkit-gradient(radial,80 80,60,80 80,120,from(#d90004),to(#960004));-moz-border-radius:100px;-webkit-border-radius:100px;border-radius:100px;outline:none}.elfinder-help .elfinder-dont-panic span{font-size:3em;font-weight:700;text-align:center;color:#fff;position:absolute;left:0;top:45px}.elfinder-help-debug{height:100%;padding:0;margin:0;overflow:none;border:none}.elfinder-help-debug .ui-tabs-panel{padding:0;margin:0;overflow:auto}.elfinder-help-debug fieldset{margin-bottom:10px;border-color:#789;border-radius:10px}.elfinder-help-debug legend{font-size:1.2em;font-weight:700;color:#2e8b57}.elfinder-help-debug dl{margin:0}.elfinder-help-debug dt{color:#789}.elfinder-help-debug dt:before{content:"["}.elfinder-help-debug dt:after{content:"]"}.elfinder-help-debug dd{margin-left:1em}.elfinder-help-preference{padding:10px;height:auto;min-height:100%;box-sizing:border-box}.elfinder-help-preference dl{width:100%}.elfinder-help-preference dt{display:block;width:200px;clear:left;float:left;max-width:50%}.elfinder-rtl .elfinder-help-preference dt{clear:right;float:right}.elfinder-help-preference dd{margin-bottom:1em}.elfinder-help-preference dd input[type=checkbox],.elfinder-help-preference dd label{white-space:nowrap;display:inline-block;cursor:pointer}.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon:before{right:33px;left:auto}.elfinder-info-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:none}.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{position:absolute;bottom:2px;width:16px;height:16px;padding:10px;border:none;overflow:hidden;cursor:pointer}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item .ui-icon,.elfinder-ltr .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{left:2px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item .ui-icon,.elfinder-rtl .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{right:2px}.elfinder-ltr .elfinder-rm-title .elfinder-cwd-icon:before{left:38px}.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon:before{right:86px;left:auto}.elfinder-rm-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:none}.ui-front{z-index:100}.elfinder{padding:0;position:relative;display:block;visibility:visible;font-size:18px;font-family:Verdana,Arial,Helvetica,sans-serif}.elfinder.elfinder-processing *{cursor:progress!important}.elfinder.elfinder-processing.elfinder-touch .elfinder-workzone:after{position:absolute;top:0;width:100%;height:3px;content:'';left:0;background-image:url(../img/progress.gif);opacity:.6;pointer-events:none}.elfinder :not(input):not(textarea):not(select):not([contenteditable=true]),.elfinder-contextmenu :not(input):not(textarea):not(select):not([contenteditable=true]){-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;user-select:none}.elfinder .overflow-scrolling-touch{-webkit-overflow-scrolling:touch}.elfinder-rtl{text-align:right;direction:rtl}.elfinder-workzone{padding:0;position:relative;overflow:hidden}.elfinder-lock,.elfinder-perms,.elfinder-symlink{position:absolute;width:16px;height:16px;background-image:url(../img/toolbar.png);background-repeat:no-repeat}.elfinder-perms,.elfinder-symlink{background-position:0 -528px}.elfinder-na .elfinder-perms{background-position:0 -96px}.elfinder-ro .elfinder-perms{background-position:0 -64px}.elfinder-wo .elfinder-perms{background-position:0 -80px}.elfinder-group .elfinder-perms{background-position:0 0}.elfinder-lock{background-position:0 -656px}.elfinder-drag-helper{top:0;left:0;width:70px;height:60px;padding:0 0 0 25px;z-index:100000;will-change:left,top}.elfinder-drag-helper.html5-native{position:absolute;top:-1000px;left:-1000px}.elfinder-drag-helper-icon-status{position:absolute;width:16px;height:16px;left:42px;top:60px;background:url(../img/toolbar.png) 0 -96px no-repeat;display:block}.elfinder-drag-helper-move .elfinder-drag-helper-icon-status{background-position:0 -720px}.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status{background-position:0 -544px}.elfinder-drag-num{position:absolute;top:0;left:0;width:16px;height:14px;text-align:center;padding-top:2px;font-weight:700;color:#fff;background-color:red;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-drag-helper .elfinder-cwd-icon{margin:0 0 0 -24px;float:left}.elfinder-overlay{position:absolute;opacity:.2;filter:Alpha(Opacity=20)}.elfinder .elfinder-panel{position:relative;background-image:none;padding:7px 12px}[draggable=true]{-khtml-user-drag:element}.elfinder [contentEditable=true]:empty:not(:focus):before{content:attr(data-ph)}.elfinder div.elfinder-bottomtray{position:fixed;bottom:0;max-width:100%;opacity:.8}.elfinder.elfinder-ltr div.elfinder-bottomtray{left:0}.elfinder.elfinder-rtl div.elfinder-bottomtray{right:0}.elfinder-ui-tooltip{font-size:.78em;padding:2px}.elfinder .elfinder-contextmenu,.elfinder .elfinder-contextmenu-sub{position:absolute;border:1px solid #aaa;background:#fff;color:#555;padding:4px 0;top:0;left:0}.elfinder .elfinder-contextmenu-sub{top:5px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub{margin-left:-5px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub{margin-right:-5px}.elfinder .elfinder-contextmenu-header{margin-top:-4px;padding:0 .5em .2ex;border:none;text-align:center}.elfinder .elfinder-contextmenu-header span{font-size:.8em;font-weight:bolder}.elfinder .elfinder-contextmenu-item{position:relative;display:block;padding:4px 30px;text-decoration:none;white-space:nowrap;cursor:default}.elfinder .elfinder-contextmenu-item.ui-state-active,.elfinder .std42-dialog .ui-dialog-content form label{border:none}.elfinder .elfinder-contextmenu-item .ui-icon{width:16px;height:16px;position:absolute;left:auto;right:auto;top:50%;margin-top:-8px}.elfinder-touch .elfinder-contextmenu-item{padding:12px 38px}.elfinder-navbar-root-local.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_local.png)}.elfinder-navbar-root-ftp.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_ftp.png)}.elfinder-navbar-root-sql.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_sql.png)}.elfinder-navbar-root-dropbox.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_dropbox.png)}.elfinder-navbar-root-googledrive.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_googledrive.png)}.elfinder-navbar-root-onedrive.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_onedrive.png)}.elfinder-navbar-root-box.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_box.png)}.elfinder .elfinder-contextmenu .elfinder-contextmenu-item span{display:block}.elfinder .elfinder-contextmenu-sub .elfinder-contextmenu-item{padding-left:12px;padding-right:12px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item{text-align:left}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item{text-align:right}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-left:28px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-right:28px}.elfinder-touch .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-left:36px}.elfinder-touch .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-right:36px}.elfinder .elfinder-contextmenu-arrow,.elfinder .elfinder-contextmenu-extra-icon,.elfinder .elfinder-contextmenu-icon{position:absolute;top:50%;margin-top:-8px;overflow:hidden}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-icon{left:8px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-extra-icon,.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-icon{right:8px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-extra-icon{left:8px}.elfinder .elfinder-contextmenu-arrow{width:16px;height:16px;background:url(../img/arrows-normal.png) 5px 4px no-repeat}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-arrow{right:5px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-arrow{left:5px;background-position:0 -10px}.elfinder .elfinder-contextmenu-extra-icon a,.elfinder .elfinder-contextmenu-extra-icon span{display:inline-block;width:100%;height:100%;padding:20px;margin:0;color:transparent!important;text-decoration:none;cursor:pointer}.elfinder .elfinder-contextmenu .ui-state-hover{border:0 solid;background-image:none}.elfinder .elfinder-contextmenu-separator{height:0;border-top:1px solid #ccc;margin:0 1px}.elfinder .elfinder-button-icon.ui-state-disabled{background-image:url(../img/toolbar.png)!important}.elfinder-cwd-wrapper{overflow:auto;position:relative;padding:2px;margin:0}.elfinder-cwd-wrapper-list{padding:0}.elfinder-cwd{position:relative;cursor:default;padding:0;margin:0;-ms-touch-action:auto;touch-action:auto}.elfinder .elfinder-cwd-wrapper.elfinder-droppable-active{outline:2px solid #8cafed;outline-offset:-2px}.elfinder-cwd-wrapper-empty .elfinder-cwd:after{display:block;position:absolute;top:40%;left:0;right:0;margin-top:-2em;line-height:1.5em;text-align:center;white-space:pre-wrap;opacity:.6;filter:Alpha(Opacity=60);font-weight:700}.elfinder-cwd-file .elfinder-cwd-select{position:absolute;top:0;left:0;width:30px;height:30px;background-color:transparent;opacity:.4;filter:Alpha(Opacity=40)}.elfinder .elfinder-cwd-selectall,.elfinder-cwd-file.ui-selected .elfinder-cwd-select{opacity:.8;filter:Alpha(Opacity=80)}.elfinder-rtl .elfinder-cwd-file .elfinder-cwd-select{left:auto;right:0}.elfinder .elfinder-cwd-selectall{position:absolute;width:30px;height:30px;top:0}.elfinder .elfinder-workzone.elfinder-cwd-wrapper-empty .elfinder-cwd-selectall{display:none}.elfinder-ltr .elfinder-workzone .elfinder-cwd-selectall{text-align:right;right:18px;left:auto}.elfinder-rtl .elfinder-workzone .elfinder-cwd-selectall{text-align:left;right:auto;left:18px}.elfinder-ltr.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall{right:0}.elfinder-rtl.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall{left:0}.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select.ui-state-hover{background-color:transparent}.elfinder-cwd-view-icons .elfinder-cwd-file{width:120px;height:90px;padding-bottom:2px;cursor:default;border:none;position:relative}.elfinder-ltr .elfinder-cwd-view-icons .elfinder-cwd-file{float:left;margin:0 3px 2px 0}.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file{float:right;margin:0 0 5px 3px}.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover{border:0 solid}.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:52px;height:52px;margin:1px auto;padding:2px;position:relative}.elfinder-cwd-view-icons .elfinder-cwd-filename{text-align:center;max-height:2.4em;line-height:1.2em;white-space:pre-line;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;margin:3px 1px 0;padding:1px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;word-break:break-word;overflow-wrap:break-word;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.elfinder-cwd-view-icons .elfinder-perms{bottom:4px;right:2px}.elfinder-cwd-view-icons .elfinder-lock{top:-3px;right:-2px}.elfinder-cwd-view-icons .elfinder-symlink{bottom:6px;left:0}.elfinder-cwd-icon{display:block;width:48px;height:48px;margin:0 auto;background:url(../img/icons-big.png) 0 0 no-repeat;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon,.elfinder-navbar-root-local .elfinder-cwd-icon{background-image:url(../img/volume_icon_local.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_local.png);background-size:contain;background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon,.elfinder-navbar-root-trash .elfinder-cwd-icon{background-image:url(../img/volume_icon_trash.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_trash.png);background-size:contain;background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon,.elfinder-navbar-root-ftp .elfinder-cwd-icon{background-image:url(../img/volume_icon_ftp.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_ftp.png);background-size:contain;background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon,.elfinder-navbar-root-sql .elfinder-cwd-icon{background-image:url(../img/volume_icon_sql.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_sql.png);background-size:contain;background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon,.elfinder-navbar-root-dropbox .elfinder-cwd-icon{background-image:url(../img/volume_icon_dropbox.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_dropbox.png);background-size:contain;background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon,.elfinder-navbar-root-googledrive .elfinder-cwd-icon{background-image:url(../img/volume_icon_googledrive.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_googledrive.png);background-size:contain}.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon,.elfinder-navbar-root-onedrive .elfinder-cwd-icon{background-image:url(../img/volume_icon_onedrive.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_onedrive.png);background-size:contain}.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon,.elfinder-navbar-root-box .elfinder-cwd-icon{background-image:url(../img/volume_icon_box.png);background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/volume_icon_box.png);background-size:contain}.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon,.elfinder-navbar-root-network .elfinder-cwd-icon{background-image:url(../img/toolbar.png);background-position:0 71.65%;background-size:cover}.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon{background-image:url(../img/toolbar.png);background-size:cover;background-position:1px -1px}.elfinder-cwd-icon:before{content:none;position:absolute;left:0;top:5px;min-width:20px;max-width:84px;text-align:center;padding:1px 4px;border-radius:4px;font-family:Verdana;font-size:10px;-webkit-transform:scale(.9);-moz-transform:scale(.9);-ms-transform:scale(.9);-o-transform:scale(.9);transform:scale(.9)}.elfinder-cwd-view-icons .elfinder-cwd-icon.elfinder-cwd-bgurl:before{left:-10px}.elfinder-cwd-icon.elfinder-cwd-icon-css:before,.elfinder-cwd-icon.elfinder-cwd-icon-html:before,.elfinder-cwd-icon.elfinder-cwd-icon-javascript:before,.elfinder-cwd-icon.elfinder-cwd-icon-pdf:before,.elfinder-cwd-icon.elfinder-cwd-icon-plain:before,.elfinder-cwd-icon.elfinder-cwd-icon-rtf:before,.elfinder-cwd-icon.elfinder-cwd-icon-rtfd:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-7z-compressed:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-bzip2:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-bzip:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-c--:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-c--hdr:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-c--src:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-c:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-chdr:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-csrc:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-empty:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-gzip:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-java-source:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-java:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-javascript:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-perl:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-php:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-python:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-rar-compressed:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-rar:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-ruby:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-sh:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-shellscript:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-shockwave-flash:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-tar:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-xz:before,.elfinder-cwd-icon.elfinder-cwd-icon-x-zip:before,.elfinder-cwd-icon.elfinder-cwd-icon-xml:before,.elfinder-cwd-icon.elfinder-cwd-icon-zip:before{content:none}.elfinder-cwd-icon.elfinder-cwd-icon-mp2t:before{content:'ts'}.elfinder-cwd-icon.elfinder-cwd-icon-dash-xml:before{content:'dash'}.elfinder-cwd-icon.elfinder-cwd-icon-x-mpegurl:before{content:'hls'}.elfinder-cwd-icon.elfinder-cwd-bgurl{background-position:center center;background-repeat:no-repeat}.elfinder-cwd-icon.elfinder-cwd-bgurl,.elfinder-cwd-icon.elfinder-cwd-bgurl.elfinder-cwd-bgself{-moz-background-size:cover;background-size:cover}.elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:' '}.elfinder-cwd-bgurl:after{position:relative;display:inline-block;top:36px;left:-38px;width:48px;height:48px;background:url(../img/icons-big.png) 0 0 no-repeat;background-size:auto!important;opacity:.8;filter:Alpha(Opacity=60);-webkit-transform-origin:54px -24px;-webkit-transform:scale(.6);-moz-transform-origin:54px -24px;-moz-transform:scale(.6);-ms-transform-origin:54px -24px;-ms-transform:scale(.6);-o-transform-origin:54px -24px;-o-transform:scale(.6);transform-origin:54px -24px;transform:scale(.6)}.elfinder-cwd-icon-image.elfinder-cwd-bgurl:after,.elfinder-cwd-icon.elfinder-cwd-icon-drag:after,.elfinder-cwd-icon.elfinder-cwd-icon-drag:before{content:none}.elfinder-cwd-icon-video:after{top:32px;left:-26px;height:25px;width:22px;background-position:0 -373px;-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon{background-position:0 -100px}.elfinder-cwd .elfinder-droppable-active{outline:2px solid #8cafed;outline-offset:-2px}.elfinder-cwd-icon-directory{background-position:0 -50px}.elfinder-cwd-icon-application,.elfinder-cwd-icon-application:after{background-position:0 -150px}.elfinder-cwd-icon-text,.elfinder-cwd-icon-text:after{background-position:0 -1350px}.elfinder-cwd-icon-plain,.elfinder-cwd-icon-plain:after,.elfinder-cwd-icon-x-empty,.elfinder-cwd-icon-x-empty:after{background-position:0 -200px}.elfinder-cwd-icon-image,.elfinder-cwd-icon-image:after,.elfinder-cwd-icon-postscript,.elfinder-cwd-icon-postscript:after,.elfinder-cwd-icon-vnd-adobe-photoshop,.elfinder-cwd-icon-vnd-adobe-photoshop:after{background-position:0 -250px}.elfinder-cwd-icon-audio,.elfinder-cwd-icon-audio:after{background-position:0 -300px}.elfinder-cwd-icon-dash-xml,.elfinder-cwd-icon-flash-video,.elfinder-cwd-icon-video,.elfinder-cwd-icon-vnd-apple-mpegurl,.elfinder-cwd-icon-x-mpegurl{background-position:0 -350px}.elfinder-cwd-icon-rtf,.elfinder-cwd-icon-rtf:after,.elfinder-cwd-icon-rtfd,.elfinder-cwd-icon-rtfd:after{background-position:0 -401px}.elfinder-cwd-icon-pdf,.elfinder-cwd-icon-pdf:after{background-position:0 -450px}.elfinder-cwd-icon-ms-excel,.elfinder-cwd-icon-ms-excel:after,.elfinder-cwd-icon-msword,.elfinder-cwd-icon-msword:after,.elfinder-cwd-icon-vnd-ms-excel,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel:after,.elfinder-cwd-icon-vnd-ms-office,.elfinder-cwd-icon-vnd-ms-office:after,.elfinder-cwd-icon-vnd-ms-powerpoint,.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint:after,.elfinder-cwd-icon-vnd-ms-word,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-word:after,.elfinder-cwd-icon-vnd-oasis-opendocument-chart,.elfinder-cwd-icon-vnd-oasis-opendocument-chart:after,.elfinder-cwd-icon-vnd-oasis-opendocument-database,.elfinder-cwd-icon-vnd-oasis-opendocument-database:after,.elfinder-cwd-icon-vnd-oasis-opendocument-formula,.elfinder-cwd-icon-vnd-oasis-opendocument-formula:after,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics:after,.elfinder-cwd-icon-vnd-oasis-opendocument-image,.elfinder-cwd-icon-vnd-oasis-opendocument-image:after,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation:after,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text,.elfinder-cwd-icon-vnd-oasis-opendocument-text-master,.elfinder-cwd-icon-vnd-oasis-opendocument-text-master:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text-template,.elfinder-cwd-icon-vnd-oasis-opendocument-text-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text-web,.elfinder-cwd-icon-vnd-oasis-opendocument-text-web:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text:after,.elfinder-cwd-icon-vnd-openofficeorg-extension,.elfinder-cwd-icon-vnd-openofficeorg-extension:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template:after{background-position:0 -500px}.elfinder-cwd-icon-html,.elfinder-cwd-icon-html:after{background-position:0 -550px}.elfinder-cwd-icon-css,.elfinder-cwd-icon-css:after{background-position:0 -600px}.elfinder-cwd-icon-javascript,.elfinder-cwd-icon-javascript:after,.elfinder-cwd-icon-x-javascript,.elfinder-cwd-icon-x-javascript:after{background-position:0 -650px}.elfinder-cwd-icon-x-perl,.elfinder-cwd-icon-x-perl:after{background-position:0 -700px}.elfinder-cwd-icon-x-python,.elfinder-cwd-icon-x-python:after{background-position:0 -750px}.elfinder-cwd-icon-x-ruby,.elfinder-cwd-icon-x-ruby:after{background-position:0 -800px}.elfinder-cwd-icon-x-sh,.elfinder-cwd-icon-x-sh:after,.elfinder-cwd-icon-x-shellscript,.elfinder-cwd-icon-x-shellscript:after{background-position:0 -850px}.elfinder-cwd-icon-x-c,.elfinder-cwd-icon-x-c--,.elfinder-cwd-icon-x-c--:after,.elfinder-cwd-icon-x-c--hdr,.elfinder-cwd-icon-x-c--hdr:after,.elfinder-cwd-icon-x-c--src,.elfinder-cwd-icon-x-c--src:after,.elfinder-cwd-icon-x-c:after,.elfinder-cwd-icon-x-chdr,.elfinder-cwd-icon-x-chdr:after,.elfinder-cwd-icon-x-csrc,.elfinder-cwd-icon-x-csrc:after,.elfinder-cwd-icon-x-java,.elfinder-cwd-icon-x-java-source,.elfinder-cwd-icon-x-java-source:after,.elfinder-cwd-icon-x-java:after{background-position:0 -900px}.elfinder-cwd-icon-x-php,.elfinder-cwd-icon-x-php:after{background-position:0 -950px}.elfinder-cwd-icon-xml,.elfinder-cwd-icon-xml:after{background-position:0 -1000px}.elfinder-cwd-icon-x-7z-compressed,.elfinder-cwd-icon-x-7z-compressed:after,.elfinder-cwd-icon-x-xz,.elfinder-cwd-icon-x-xz:after,.elfinder-cwd-icon-x-zip,.elfinder-cwd-icon-x-zip:after,.elfinder-cwd-icon-zip,.elfinder-cwd-icon-zip:after{background-position:0 -1050px}.elfinder-cwd-icon-x-gzip,.elfinder-cwd-icon-x-gzip:after,.elfinder-cwd-icon-x-tar,.elfinder-cwd-icon-x-tar:after{background-position:0 -1100px}.elfinder-cwd-icon-x-bzip,.elfinder-cwd-icon-x-bzip2,.elfinder-cwd-icon-x-bzip2:after,.elfinder-cwd-icon-x-bzip:after{background-position:0 -1150px}.elfinder-cwd-icon-x-rar,.elfinder-cwd-icon-x-rar-compressed,.elfinder-cwd-icon-x-rar-compressed:after,.elfinder-cwd-icon-x-rar:after{background-position:0 -1200px}.elfinder-cwd-icon-x-shockwave-flash,.elfinder-cwd-icon-x-shockwave-flash:after{background-position:0 -1250px}.elfinder-cwd-icon-group{background-position:0 -1300px}.elfinder-cwd-filename input{width:100%;border:none;margin:0;padding:0}.elfinder-cwd-view-icons,.elfinder-cwd-view-icons input{text-align:center}.elfinder-cwd-view-icons textarea{width:100%;border:0 solid;margin:0;padding:0;text-align:center;overflow:hidden;resize:none}.elfinder-cwd-wrapper.elfinder-cwd-fixheader .elfinder-cwd::after,.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar select{display:none}.elfinder-cwd table{width:100%;border-collapse:separate;border:0 solid;margin:0 0 10px;border-spacing:0;box-sizing:padding-box;padding:2px;position:relative}.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader{position:absolute;overflow:hidden}.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before{content:'';position:absolute;width:100%;top:0;height:3px;background-color:#fff}.elfinder-droppable-active+.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before{background-color:#8cafed}.elfinder .elfinder-workzone div.elfinder-cwd-fixheader table{table-layout:fixed}.elfinder-ltr .elfinder-cwd thead .elfinder-cwd-selectall{text-align:left;right:auto;left:0;padding-top:3px}.elfinder-rtl .elfinder-cwd thead .elfinder-cwd-selectall{text-align:right;right:0;left:auto;padding-top:3px}.elfinder-touch .elfinder-cwd thead .elfinder-cwd-selectall{padding-top:5px}.elfinder .elfinder-cwd table thead tr{border-left:0 solid;border-top:0 solid;border-right:0 solid}.elfinder .elfinder-cwd table thead td{padding:4px 14px}.elfinder-ltr .elfinder-cwd.elfinder-has-checkbox table thead td:first-child{padding:4px 14px 4px 22px}.elfinder-rtl .elfinder-cwd.elfinder-has-checkbox table thead td:first-child{padding:4px 22px 4px 14px}.elfinder .elfinder-cwd table thead td.ui-state-active{background:#ebf1f6;background:-moz-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ebf1f6),color-stop(50%,#abd3ee),color-stop(51%,#89c3eb),color-stop(100%,#d5ebfb));background:-webkit-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-o-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-ms-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:linear-gradient(to bottom,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebf1f6', endColorstr='#d5ebfb',GradientType=0 )}.elfinder .elfinder-cwd table td{padding:4px 12px;white-space:pre;overflow:hidden;text-align:right;cursor:default;border:0 solid}.elfinder .elfinder-cwd table tbody td:first-child{position:relative}.elfinder .elfinder-cwd table td div{box-sizing:content-box}tr.elfinder-cwd-file td .elfinder-cwd-select{width:40px;padding-top:3px}.elfinder-touch tr.elfinder-cwd-file td .elfinder-cwd-select{padding-top:10px}.elfinder-touch .elfinder-cwd tr td{padding:10px 12px}.elfinder-touch .elfinder-cwd table thead td{padding:8px 14px}.elfinder-touch .elfinder-cwd tr.elfinder-cwd-file td{padding:13px 12px}.elfinder-ltr .elfinder-cwd table td{text-align:right}.elfinder-ltr .elfinder-cwd table td:first-child{text-align:left}.elfinder-rtl .elfinder-cwd table td{text-align:left}.elfinder-info-tb tr td:first-child,.elfinder-rtl .elfinder-cwd table td:first-child{text-align:right}.elfinder-odd-row{background:#eee}.elfinder-cwd-view-list .elfinder-cwd-file-wrapper{width:97%;position:relative}.elfinder-ltr .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper{margin-left:8px}.elfinder-rtl .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper{margin-right:8px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-filename{padding-left:23px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-filename{padding-right:23px}.elfinder-cwd-view-list .elfinder-lock,.elfinder-cwd-view-list .elfinder-perms,.elfinder-cwd-view-list .elfinder-symlink{margin-top:-6px;opacity:.6;filter:Alpha(Opacity=60)}.elfinder-ltr .elfinder-cwd-view-list .elfinder-perms{left:8px;bottom:-4px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-lock{left:10px;top:0}.elfinder-ltr .elfinder-cwd-view-list .elfinder-symlink{left:-7px;bottom:-4px}.elfinder-cwd-view-list td .elfinder-cwd-icon{width:16px;height:16px;position:absolute;top:50%;margin-top:-8px;background-image:url(../img/icons-small.png)}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-icon{left:0}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-icon{right:0}.elfinder-cwd-view-list .elfinder-cwd-icon:after,.elfinder-cwd-view-list .elfinder-cwd-icon:before{content:none}.elfinder-cwd-view-list thead td .ui-resizable-handle{height:100%;top:3px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-handle{top:-5px;margin:10px}.elfinder-cwd-view-list thead td .ui-resizable-e{right:-7px}.elfinder-cwd-view-list thead td .ui-resizable-w{left:-7px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-e{right:-16px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-w{left:-16px}.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list.elfinder-cwd:after{margin-top:0}.std42-dialog{padding:0;position:absolute;left:auto;right:auto}.std42-dialog.elfinder-dialog-minimized{overFlow:hidden;position:relative;float:left;width:auto}.elfinder-rtl .std42-dialog.elfinder-dialog-minimized{float:right}.std42-dialog .ui-dialog-titlebar{border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent;-moz-border-radius-bottomleft:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;font-weight:400;padding:.2em 1em}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar{padding:0 .5em;height:20px}.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar{padding:.3em .5em}.std42-dialog.ui-draggable-disabled .ui-dialog-titlebar{cursor:default}.std42-dialog .ui-dialog-titlebar .ui-widget-header{border:none;cursor:pointer}.std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title{display:inherit;word-break:break-all}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title{display:list-item;display:-moz-inline-box;white-space:nowrap;word-break:normal;overflow:hidden;word-wrap:normal;overflow-wrap:normal;max-width:-webkit-calc(100% - 24px);max-width:-moz-calc(100% - 24px);max-width:calc(100% - 24px)}.elfinder-touch .std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title{padding-top:.15em}.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title{max-width:-webkit-calc(100% - 36px);max-width:-moz-calc(100% - 36px);max-width:calc(100% - 36px)}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button{position:relative;float:left;top:10px;left:-10px;right:10px;width:20px;height:20px;padding:1px;margin:-10px 1px 0;background-color:transparent;background-image:none}.elfinder-touch .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button{transform:scale(1.1);zoom:1.1;margin-left:5px;margin-right:5px}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button-right{float:right}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right{left:10px;right:-10px}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{width:17px;height:17px;border-width:1px;border-color:transparent;opacity:.7;filter:Alpha(Opacity=70);-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{opacity:1;filter:Alpha(Opacity=100)}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon,.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon{background-color:#ff6252;border-color:#e5695d}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon{background-color:#ffbc00;border-color:#e3a40b}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon,.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon{background-color:#26c82f;border-color:#13ae10}.elfinder-touch .std42-dialog.ui-dialog:not(ui-resizable-disabled) .ui-resizable-se{width:12px;height:12px;zoom:1.5;right:-7px;bottom:-7px;margin:3px 7px 7px 3px;background-position:-64px -224px}.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar{text-align:right}.std42-dialog .ui-dialog-content{padding:.3em .5em;box-sizing:border-box}.elfinder .std42-dialog .ui-dialog-content,.elfinder .std42-dialog .ui-dialog-content *{-webkit-user-select:auto;-moz-user-select:text;-khtml-user-select:text;user-select:text}.std42-dialog .ui-dialog-buttonpane{border:0 solid;margin:0;padding:.5em;text-align:right}.elfinder-rtl .std42-dialog .ui-dialog-buttonpane{text-align:left}.std42-dialog .ui-dialog-buttonpane button{margin:.2em 0 0 .4em;padding:.2em;outline:0 solid}.std42-dialog .ui-dialog-buttonpane button span{padding:2px 9px}.elfinder-dialog .ui-resizable-e,.elfinder-dialog .ui-resizable-s{width:0;height:0}.std42-dialog .ui-button input{cursor:pointer}.elfinder-netmount-tb input,.elfinder-netmount-tb select,.std42-dialog select{border:1px solid #ccc}.elfinder-dialog-icon{position:absolute;width:32px;height:32px;left:10px;top:50%;margin-top:-15px;background:url(../img/dialogs.png) 0 0 no-repeat}.elfinder-rtl .elfinder-dialog-icon{left:auto;right:10px}.elfinder-dialog-confirm .ui-dialog-content,.elfinder-dialog-error .ui-dialog-content{padding-left:56px;min-height:35px}.elfinder-rtl .elfinder-dialog-confirm .ui-dialog-content,.elfinder-rtl .elfinder-dialog-error .ui-dialog-content{padding-left:0;padding-right:56px}.elfinder-dialog-notify .ui-dialog-titlebar-close,.elfinder-rm-title+br{display:none}.elfinder-dialog-notify .ui-dialog-content{padding:0}.elfinder-notify{border-bottom:1px solid #ccc;position:relative;padding:.5em;text-align:center;overflow:hidden}.elfinder-ltr .elfinder-notify{padding-left:36px}.elfinder-rtl .elfinder-notify{padding-right:36px}.elfinder-notify:last-child{border:0 solid}.elfinder-notify-progressbar{width:180px;height:8px;border:1px solid #aaa;background:#f5f5f5;margin:5px auto;overflow:hidden}.elfinder-notify-progress{width:100%;height:8px;background:url(../img/progress.gif) center center repeat-x}.elfinder-notify-progress,.elfinder-notify-progressbar{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}.elfinder-dialog-icon-file,.elfinder-dialog-icon-open,.elfinder-dialog-icon-readdir,.elfinder-dialog-icon-reload{background-position:0 -225px}.elfinder-dialog-icon-mkdir{background-position:0 -64px}.elfinder-dialog-icon-mkfile{background-position:0 -96px}.elfinder-dialog-icon-copy,.elfinder-dialog-icon-move,.elfinder-dialog-icon-prepare{background-position:0 -128px}.elfinder-dialog-icon-chunkmerge,.elfinder-dialog-icon-upload{background-position:0 -160px}.elfinder-dialog-icon-rm{background-position:0 -192px}.elfinder-dialog-icon-download{background-position:0 -260px}.elfinder-dialog-icon-save{background-position:0 -295px}.elfinder-dialog-icon-rename{background-position:0 -330px}.elfinder-dialog-icon-archive,.elfinder-dialog-icon-extract,.elfinder-dialog-icon-zipdl{background-position:0 -365px}.elfinder-dialog-icon-search{background-position:0 -402px}.elfinder-dialog-icon-chmod,.elfinder-dialog-icon-dim,.elfinder-dialog-icon-loadimg,.elfinder-dialog-icon-netmount,.elfinder-dialog-icon-netunmount,.elfinder-dialog-icon-preupload,.elfinder-dialog-icon-resize,.elfinder-dialog-icon-url{background-position:0 -434px}.elfinder-dialog-confirm-applyall,.elfinder-dialog-confirm-encoding{padding:0 1em;margin:0}.elfinder-ltr .elfinder-dialog-confirm-applyall,.elfinder-ltr .elfinder-dialog-confirm-encoding{text-align:left}.elfinder-rtl .elfinder-dialog-confirm-applyall,.elfinder-rtl .elfinder-dialog-confirm-encoding{text-align:right}.elfinder-dialog-confirm .elfinder-dialog-icon{background-position:0 -32px}.elfinder-dialog-confirm .ui-dialog-buttonset{width:auto}.elfinder-info-title .elfinder-cwd-icon{float:left;width:48px;height:48px;margin-right:1em}.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon,.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon{float:right;margin-right:0;margin-left:1em}.elfinder-info-title strong{display:block;padding:.3em 0 .5em}.elfinder-info-tb{min-width:200px;border:0 solid;margin:1em .2em}.elfinder-info-tb td{white-space:nowrap;padding:2px}.elfinder-info-tb a{outline:none;text-decoration:underline}.elfinder-info-tb a:hover{text-decoration:none}.elfinder-info-spinner{width:14px;height:14px;float:left;background:url(../img/spinner-mini.gif) center center no-repeat;margin:0 5px}.elfinder-netmount-tb{margin:0 auto}.elfinder-netmount-tb .elfinder-button-icon{cursor:pointer}button.elfinder-info-button{margin:-3.5px 0;cursor:pointer}.elfinder-upload-dropbox{display:table-cell;text-align:center;vertical-align:middle;padding:.5em;border:3px dashed #aaa;width:9999px;height:80px;overflow:hidden;word-break:keep-all}.elfinder-upload-dropbox.ui-state-hover{background:#dfdfdf;border:3px dashed #555}.elfinder-upload-dialog-or{margin:.3em 0;text-align:center}.elfinder-upload-dialog-wrapper{text-align:center}.elfinder-upload-dialog-wrapper .ui-button{position:relative;overflow:hidden}.elfinder-upload-dialog-wrapper .ui-button form{position:absolute;right:0;top:0;opacity:0;filter:Alpha(Opacity=0)}.elfinder-upload-dialog-wrapper .ui-button form input{padding:0 20px;font-size:3em}.dialogelfinder .dialogelfinder-drag{border-left:0 solid;border-top:0 solid;border-right:0 solid;font-weight:400;padding:2px 12px;cursor:move;position:relative;text-align:left}.elfinder-rtl .dialogelfinder-drag{text-align:right}.dialogelfinder-drag-close{position:absolute;top:50%;margin-top:-8px}.elfinder-ltr .dialogelfinder-drag-close{right:12px}.elfinder-rtl .dialogelfinder-drag-close{left:12px}.elfinder-rm-title{margin-bottom:.5ex}.elfinder-rm-title .elfinder-cwd-icon{float:left;width:48px;height:48px;margin-right:1em}.elfinder-rm-title strong{display:block;white-space:pre-wrap;word-break:normal;overflow:hidden;text-overflow:ellipsis}.ui-dialog-titlebar select.elfinder-edit-changed{border-bottom:1px solid #13ae10}.elfinder-contextmenu .elfinder-contextmenu-item span{font-size:.72em}.elfinder-cwd-view-icons .elfinder-cwd-filename,.elfinder-cwd-view-list td{font-size:.7em}.std42-dialog .ui-dialog-titlebar{font-size:.82em}.std42-dialog .ui-dialog-content{font-size:.72em}.std42-dialog .ui-dialog-buttonpane{font-size:.76em}.dialogelfinder .dialogelfinder-drag,.elfinder-info-tb{font-size:.9em}.elfinder-upload-dialog-or,.elfinder-upload-dropbox{font-size:1.2em}.elfinder .elfinder-navbar{font-size:.72em}.elfinder-place-drag .elfinder-navbar-dir{font-size:.9em}.elfinder-quicklook-title,.elfinder-statusbar div{font-size:.7em}.elfinder-quicklook-info-data{font-size:.72em}.elfinder-quicklook-preview-text-wrapper{font-size:.9em}.elfinder-button-menu-item{font-size:.72em}.elfinder-button-search input{font-size:.8em}.elfinder-drag-num{font-size:12px}.elfinder-toast{font-size:.76em}.elfinder .elfinder-navbar{width:230px;padding:3px 5px;background-image:none;border-top:0 solid;border-bottom:0 solid;overflow:auto;position:relative}.elfinder .elfinder-navdock{box-sizing:border-box;width:230px;height:auto;position:absolute;bottom:0;overflow:auto}.elfinder-navdock .ui-resizable-n{top:0;height:20px}.elfinder-ltr .elfinder-navbar{float:left;border-left:0 solid}.elfinder-rtl .elfinder-navbar{float:right;border-right:0 solid}.elfinder-ltr .ui-resizable-e{margin-left:10px}.elfinder-tree{display:table;width:100%;margin:0 0 .5em;-webkit-tap-highlight-color:rgba(0,0,0,0)}.elfinder-navbar-dir{position:relative;display:block;white-space:nowrap;padding:3px 12px;margin:0;outline:0 solid;border:1px solid transparent;cursor:default}.elfinder-touch .elfinder-navbar-dir{padding:12px}.elfinder-ltr .elfinder-navbar-dir{padding-left:35px}.elfinder-rtl .elfinder-navbar-dir{padding-right:35px}.elfinder-navbar-arrow,.elfinder-navbar-icon{position:absolute;top:50%;margin-top:-8px;background-repeat:no-repeat}.elfinder-navbar-arrow{display:none;width:12px;height:14px;background-image:url(../img/arrows-normal.png)}.elfinder-ltr .elfinder-navbar-arrow{left:0}.elfinder-rtl .elfinder-navbar-arrow{right:0}.elfinder-touch .elfinder-navbar-arrow{zoom:1.4;-moz-transform-origin:top left;-moz-transform:scale(1.4);margin-bottom:7px}.elfinder-ltr.elfinder-touch .elfinder-navbar-arrow{left:-3px;margin-right:20px}.elfinder-rtl.elfinder-touch .elfinder-navbar-arrow{right:-3px;margin-left:20px}.ui-state-active .elfinder-navbar-arrow{background-image:url(../img/arrows-active.png)}.elfinder-navbar-collapsed .elfinder-navbar-arrow{display:block}.elfinder-subtree-chksubdir .elfinder-navbar-arrow{opacity:.25;filter:Alpha(Opacity=25)}.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 4px}.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 -10px}.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow,.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow{background-position:0 -21px}.elfinder-navbar-icon{width:16px;height:16px;background-image:url(../img/toolbar.png);background-position:0 -16px}.elfinder-ltr .elfinder-navbar-icon{left:14px}.elfinder-rtl .elfinder-navbar-icon{right:14px}.elfinder-tree .elfinder-navbar-root .elfinder-navbar-icon{background-position:0 0}.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon{background-position:0 -704px}.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon{background-image:url(../img/volume_icon_local.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon{background-image:url(../img/volume_icon_trash.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon{background-image:url(../img/volume_icon_ftp.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon{background-image:url(../img/volume_icon_sql.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon{background-image:url(../img/volume_icon_dropbox.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon{background-image:url(../img/volume_icon_googledrive.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon{background-image:url(../img/volume_icon_onedrive.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon{background-image:url(../img/volume_icon_box.png);background-position:0 0}.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon{background-image:url(../img/toolbar.png);background-position:0 -688px}.elfinder-droppable-active .elfinder-navbar-icon,.ui-state-active .elfinder-navbar-icon,.ui-state-hover .elfinder-navbar-icon{background-position:0 -32px}.elfinder-ltr .elfinder-navbar-subtree{margin-left:12px}.elfinder-rtl .elfinder-navbar-subtree{margin-right:12px}.elfinder-navbar-spinner{width:14px;height:14px;position:absolute;display:block;top:50%;margin-top:-7px;background:url(../img/spinner-mini.gif) center center no-repeat}.elfinder-ltr .elfinder-navbar-spinner{left:0;margin-left:-2px}.elfinder-rtl .elfinder-navbar-spinner{right:0;margin-right:-2px}.elfinder-navbar .elfinder-lock,.elfinder-navbar .elfinder-perms,.elfinder-navbar .elfinder-symlink{opacity:.6;filter:Alpha(Opacity=60)}.elfinder-navbar .elfinder-perms{bottom:-1px;margin-top:-8px}.elfinder-navbar .elfinder-lock{top:-2px}.elfinder-ltr .elfinder-navbar .elfinder-perms{left:20px}.elfinder-rtl .elfinder-navbar .elfinder-perms{right:20px}.elfinder-ltr .elfinder-navbar .elfinder-lock{left:20px}.elfinder-rtl .elfinder-navbar .elfinder-lock{right:20px}.elfinder-ltr .elfinder-navbar .elfinder-symlink{left:8px}.elfinder-rtl .elfinder-navbar .elfinder-symlink{right:8px}.elfinder-navbar input{width:100%;border:0 solid;margin:0;padding:0}.elfinder-navbar .ui-resizable-handle{width:12px;background:url(../img/resize.png) center center no-repeat}.elfinder-nav-handle-icon{position:absolute;top:50%;margin:-8px 2px 0;opacity:.5;filter:Alpha(Opacity=50)}.elfinder-navbar-pager{width:100%;box-sizing:border-box;padding-top:3px;padding-bottom:3px}.elfinder-touch .elfinder-navbar-pager{padding-top:10px;padding-bottom:10px}.elfinder-places{border:none;margin:0;padding:0}.elfinder-navbar-swipe-handle{position:absolute;top:0;height:100%;width:50px;pointer-events:none}.elfinder-ltr .elfinder-navbar-swipe-handle{left:0;background:linear-gradient(to right,#dde4eb 0,rgba(221,228,235,.8) 5px,rgba(216,223,230,.3) 8px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)}.elfinder-rtl .elfinder-navbar-swipe-handle{right:0;background:linear-gradient(to left,#dde4eb 0,rgba(221,228,235,.8) 5px,rgba(216,223,230,.3) 8px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)}.elfinder-navbar-root .elfinder-places-root-icon{position:absolute;top:50%;margin-top:-9px;cursor:pointer}.elfinder-ltr .elfinder-places-root-icon{right:10px}.elfinder-rtl .elfinder-places-root-icon{left:10px}.elfinder-navbar-expanded .elfinder-places-root-icon{display:block}.elfinder-place-drag{font-size:.8em}.elfinder-quicklook{position:absolute;background:url(../img/quicklook-bg.png);overflow:hidden;-moz-border-radius:7px;-webkit-border-radius:7px;border-radius:7px;padding:20px 0 40px}.elfinder-navdock .elfinder-quicklook{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;font-size:90%;overflow:auto}.elfinder-quicklook.elfinder-touch{padding:30px 0 40px}.elfinder-quicklook .ui-resizable-se{width:14px;height:14px;right:5px;bottom:3px;background:url(../img/toolbar.png) 0 -496px no-repeat}.elfinder-quicklook.elfinder-touch .ui-resizable-se{zoom:1.5}.elfinder-quicklook.elfinder-quicklook-fullscreen{position:fixed;top:0;right:0;bottom:0;left:0;margin:0;box-sizing:border-box;width:100%;height:100%;object-fit:contain;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-webkit-background-clip:padding-box;padding:0;background:#000;display:block}.elfinder-quicklook-fullscreen .elfinder-quicklook-titlebar,.elfinder-quicklook-fullscreen.elfinder-quicklook .ui-resizable-handle{display:none}.elfinder-quicklook-fullscreen .elfinder-quicklook-preview{border:0 solid}.elfinder-quicklook-cover,.elfinder-quicklook-titlebar{width:100%;height:100%;top:0;left:0;position:absolute}.elfinder-quicklook-titlebar{text-align:center;background:#777;height:20px;-moz-border-radius-topleft:7px;-webkit-border-top-left-radius:7px;border-top-left-radius:7px;-moz-border-radius-topright:7px;-webkit-border-top-right-radius:7px;border-top-right-radius:7px;cursor:move}.elfinder-navdock .elfinder-quicklook-titlebar{-moz-border-radius-topleft:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-topright:0;-webkit-border-top-right-radius:0;border-top-right-radius:0;cursor:default}.elfinder-touch .elfinder-quicklook-titlebar{height:30px}.elfinder-quicklook-title{color:#fff;white-space:nowrap;overflow:hidden;padding:2px 0}.elfinder-touch .elfinder-quicklook-title{padding:8px 0}.elfinder-quicklook-titlebar-icon{position:absolute;left:4px;top:50%;margin-top:-9px;height:16px}.elfinder-quicklook-titlebar-icon .ui-icon{position:relative;margin:-9px 6px 0 0;cursor:pointer;border-radius:10px;border:1px solid}.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon{margin-top:-3px}.elfinder-quicklook-titlebar-icon.elfinder-platformWin{left:auto;right:4px;direction:rtl}.elfinder-quicklook-titlebar-icon.elfinder-platformWin .ui-icon{margin:-9px 0 0 6px}.elfinder-touch .elfinder-quicklook-titlebar .ui-icon{zoom:1.5}.elfinder-quicklook-preview{overflow:hidden;position:relative;border:0 solid;border-left:1px solid transparent;border-right:1px solid transparent;height:100%}.elfinder-navdock .elfinder-quicklook-preview{border-left:0;border-right:0}.elfinder-quicklook-preview.elfinder-overflow-auto{overflow:auto;-webkit-overflow-scrolling:touch}.elfinder-quicklook-info-wrapper{display:table;position:absolute;width:100%;height:100%;height:calc(100% - 80px);left:0;top:20px}.elfinder-navdock .elfinder-quicklook-info-wrapper{height:calc(100% - 20px)}.elfinder-quicklook-info{display:table-cell;vertical-align:middle}.elfinder-ltr .elfinder-quicklook-info{padding:0 12px 0 112px}.elfinder-rtl .elfinder-quicklook-info{padding:0 112px 0 12px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook-info{padding:0 0 0 80px}.elfinder-rtl .elfinder-navdock .elfinder-quicklook-info{padding:0 80px 0 0}.elfinder-quicklook-info .elfinder-quicklook-info-data:first-child{color:#fff;font-weight:700;padding-bottom:.5em}.elfinder-quicklook-info-data{padding-bottom:.2em;color:#fff}.elfinder-quicklook .elfinder-cwd-icon{position:absolute;left:32px;top:50%;margin-top:-20px}.elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon{left:16px}.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon{left:auto;right:32px}.elfinder-rtl .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon{right:6px}.elfinder-quicklook .elfinder-cwd-icon:before{top:-10px}.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:before{left:-20px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:before{left:-14px}.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:after{left:-15px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:after{left:-12px}.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:after,.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:before{left:auto;right:40px}.elfinder-quicklook-preview img{display:block;margin:0 auto}.elfinder-quicklook-navbar{position:absolute;left:50%;bottom:4px;width:140px;height:32px;padding:0;margin-left:-70px;border:1px solid transparent;border-radius:19px;-moz-border-radius:19px;-webkit-border-radius:19px}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar{width:188px;margin-left:-94px;padding:5px;border:1px solid #eee;background:#000;opacity:.4;filter:Alpha(Opacity=40)}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-icon-close,.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-separator{display:inline}.elfinder-quicklook-navbar-icon{width:32px;height:32px;margin:0 7px;float:left;background:url(../img/quicklook-icons.png) 0 0 no-repeat}.elfinder-quicklook-navbar-icon-fullscreen{background-position:0 -64px}.elfinder-quicklook-navbar-icon-fullscreen-off{background-position:0 -96px}.elfinder-quicklook-navbar-icon-prev{background-position:0 0}.elfinder-quicklook-navbar-icon-next{background-position:0 -32px}.elfinder-quicklook-navbar-icon-close{background-position:0 -128px;display:none}.elfinder-quicklook-navbar-separator{width:1px;height:32px;float:left;border-left:1px solid #fff;display:none}.elfinder-quicklook-preview-archive-wrapper,.elfinder-quicklook-preview-text-wrapper{width:100%;height:100%;background:#fff;color:#222;overflow:auto;-webkit-overflow-scrolling:touch}.elfinder-quicklook-preview-archive-wrapper{font-size:1.5ex}.elfinder-quicklook-preview-archive-wrapper strong{padding:0 5px}pre.elfinder-quicklook-preview-text,pre.elfinder-quicklook-preview-text.prettyprint{width:auto;height:auto;margin:0;padding:3px 9px;border:none}.elfinder-quicklook-preview-charsleft hr{border:none;border-top:dashed 1px}.elfinder-quicklook-preview-charsleft span{font-size:90%;font-style:italic}.elfinder-quicklook-preview-html,.elfinder-quicklook-preview-iframe,.elfinder-quicklook-preview-pdf{width:100%;height:100%;background:#fff;margin:0;border:none;display:block}.elfinder-quicklook-preview-flash{width:100%;height:100%}.elfinder-quicklook-preview-audio{width:100%;position:absolute;bottom:0;left:0}embed.elfinder-quicklook-preview-audio{height:30px;background:0 0}.elfinder-quicklook-preview-video{width:100%;height:100%}.elfinder .elfinder-quicklook .elfinder-quicklook-info *,.elfinder .elfinder-quicklook .elfinder-quicklook-preview *{-webkit-user-select:auto;-moz-user-select:text;-khtml-user-select:text;user-select:text}.elfinder-statusbar{cursor:default;text-align:center;font-weight:400;padding:.2em .5em;border-right:0 solid transparent;border-bottom:0 solid transparent;border-left:0 solid transparent}.elfinder-statusbar span{vertical-align:bottom;overflow:hidden;text-overflow:"..";-o-text-overflow:".."}.elfinder-statusbar span.ui-state-active,.elfinder-statusbar span.ui-state-hover{border:none}.elfinder-statusbar span.elfinder-path-cwd{cursor:default}.elfinder-path{cursor:pointer;max-width:30%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis}.elfinder-ltr .elfinder-path{float:left}.elfinder-rtl .elfinder-path{float:right}.elfinder-workzone-path{position:relative}.elfinder-workzone-path .elfinder-path{position:relative;font-size:.75em;font-weight:400;float:none;max-width:none;overflow:hidden;overflow-x:hidden;text-overflow:initial;-o-text-overflow:initial}.elfinder-mobile .elfinder-workzone-path .elfinder-path{overflow:auto;overflow-x:scroll}.elfinder-ltr .elfinder-workzone-path .elfinder-path{margin-left:24px}.elfinder-rtl .elfinder-workzone-path .elfinder-path{margin-right:24px}.elfinder-workzone-path .elfinder-path span{display:inline-block;padding:5px 3px}.elfinder-workzone-path .elfinder-path span.elfinder-path-cwd{font-weight:700}.elfinder-workzone-path .elfinder-path span.ui-state-active,.elfinder-workzone-path .elfinder-path span.ui-state-hover{border:none}.elfinder-workzone-path .elfinder-path-roots{position:absolute;top:0;width:24px;height:20px;padding:2px;border:none;overflow:hidden}.elfinder-ltr .elfinder-workzone-path .elfinder-path-roots{left:0}.elfinder-rtl .elfinder-workzone-path .elfinder-path-roots{right:0}.elfinder-stat-size{overflow:hidden;text-wrap:none}.elfinder-ltr .elfinder-stat-size{float:right}.elfinder-rtl .elfinder-stat-size{float:left}.elfinder-stat-selected{white-space:nowrap;overflow:hidden}.elfinder .elfinder-toast{position:absolute;top:12px;right:12px;max-width:90%;cursor:default}.elfinder .elfinder-toast>div{position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:8px 16px 8px 50px;-moz-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.9;filter:alpha(opacity=90);background-color:#030303;text-align:center}.elfinder .elfinder-toast>.toast-info{background-color:#2f96b4;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>.toast-error{background-color:#bd362f;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>.toast-success{background-color:#51a351;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}.elfinder .elfinder-toast>.toast-warning{background-color:#f89406;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>div button.ui-button{background-image:none;margin-top:8px;padding:.5em .8em}.elfinder .elfinder-toast>.toast-success button.ui-button{background-color:green;color:#fff}.elfinder .elfinder-toast>.toast-success button.ui-button.ui-state-hover{background-color:#add6ad;color:#254b25}.elfinder-toolbar{padding:4px 0 3px;border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent}.elfinder-buttonset{margin:1px 4px;float:left;background:0 0;padding:0;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px}.elfinder .elfinder-button{height:16px;margin:0;padding:4px;float:left;overflow:hidden;position:relative;border:0 solid;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;line-height:1;cursor:default}.elfinder-touch .elfinder-button{height:20px}.elfinder .ui-icon-search{cursor:pointer}.elfinder-button:first-child{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.elfinder-button:last-child{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.elfinder-toolbar-button-separator{float:left;padding:0;height:24px;border-top:0 solid;border-right:0 solid;border-bottom:0 solid;width:0}.elfinder-touch .elfinder-toolbar-button-separator{height:20px}.elfinder .elfinder-button.ui-state-disabled{opacity:1;filter:Alpha(Opacity=100)}.elfinder .elfinder-button.ui-state-disabled .elfinder-button-icon,.elfinder .elfinder-button.ui-state-disabled .elfinder-button-text{opacity:.4;filter:Alpha(Opacity=40)}.elfinder-rtl .elfinder-buttonset{float:right}.elfinder-button-icon{width:16px;height:16px;display:inline-block;background:url(../img/toolbar.png) no-repeat}.elfinder-button-text{position:relative;display:inline-block;top:-4px;margin:0 2px;font-size:12px}.elfinder-touch .elfinder-button-icon{zoom:1.25;-moz-transform-origin:top left;-moz-transform:scale(1.25)}.elfinder-touch .elfinder-button-text{top:-5px}.elfinder-button-icon-home{background-position:0 0}.elfinder-button-icon-back{background-position:0 -112px}.elfinder-button-icon-forward{background-position:0 -128px}.elfinder-button-icon-up{background-position:0 -144px}.elfinder-button-icon-dir{background-position:0 -16px}.elfinder-button-icon-reload{background-position:0 -160px}.elfinder-button-icon-open{background-position:0 -176px}.elfinder-button-icon-mkdir{background-position:0 -192px}.elfinder-button-icon-mkfile{background-position:0 -208px}.elfinder-button-icon-rm{background-position:0 -832px}.elfinder-button-icon-trash{background-position:0 -224px}.elfinder-button-icon-restore{background-position:0 -816px}.elfinder-button-icon-copy{background-position:0 -240px}.elfinder-button-icon-cut{background-position:0 -256px}.elfinder-button-icon-paste{background-position:0 -272px}.elfinder-button-icon-getfile{background-position:0 -288px}.elfinder-button-icon-duplicate{background-position:0 -304px}.elfinder-button-icon-rename{background-position:0 -320px}.elfinder-button-icon-edit{background-position:0 -336px}.elfinder-button-icon-quicklook{background-position:0 -352px}.elfinder-button-icon-upload{background-position:0 -368px}.elfinder-button-icon-download{background-position:0 -384px}.elfinder-button-icon-info{background-position:0 -400px}.elfinder-button-icon-extract{background-position:0 -416px}.elfinder-button-icon-archive{background-position:0 -432px}.elfinder-button-icon-view{background-position:0 -448px}.elfinder-button-icon-view-list{background-position:0 -464px}.elfinder-button-icon-help{background-position:0 -480px}.elfinder-button-icon-resize{background-position:0 -512px}.elfinder-button-icon-link{background-position:0 -528px}.elfinder-button-icon-search{background-position:0 -561px}.elfinder-button-icon-sort{background-position:0 -577px}.elfinder-button-icon-rotate-r{background-position:0 -625px}.elfinder-button-icon-rotate-l{background-position:0 -641px}.elfinder-button-icon-netmount{background-position:0 -688px}.elfinder-button-icon-netunmount{background-position:0 -96px}.elfinder-button-icon-places{background-position:0 -704px}.elfinder-button-icon-chmod{background-position:0 -48px}.elfinder-button-icon-accept{background-position:0 -736px}.elfinder-button-icon-opendir{background-position:0 -32px}.elfinder-button-icon-menu{background-position:0 -752px}.elfinder-button-icon-colwidth{background-position:0 -768px}.elfinder-button-icon-fullscreen{background-position:0 -784px}.elfinder-button-icon-unfullscreen{background-position:0 -800px}.elfinder-button-icon-empty{background-position:0 -848px}.elfinder-button-icon-undo{background-position:0 -864px}.elfinder-button-icon-redo{background-position:0 -880px}.elfinder-button-icon-preference{background-position:0 -896px}.elfinder-button-icon-mkdirin{background-position:0 -912px}.elfinder-button-icon-selectall{background-position:0 -928px}.elfinder-button-icon-selectnone{background-position:0 -944px}.elfinder-button-icon-selectinvert{background-position:0 -960px}.elfinder .elfinder-menubutton{overflow:visible}.elfinder-button-icon-spinner{background:url(../img/spinner-mini.gif) center center no-repeat}.elfinder-button-menu{position:absolute;left:0;top:25px;padding:3px 0}.elfinder-touch .elfinder-button-menu{top:35px}.elfinder-button-menu-item{white-space:nowrap;cursor:default;padding:5px 19px;position:relative}.elfinder-touch .elfinder-button-menu-item{padding:12px 19px}.elfinder-button-menu .ui-state-hover{border:0 solid}.elfinder-button-menu-item-separated{border-top:1px solid #ccc}.elfinder-button-menu-item .ui-icon{width:16px;height:16px;position:absolute;left:2px;top:50%;margin-top:-8px;display:none}.elfinder-button-menu-item-selected .ui-icon{display:block}.elfinder-button-menu-item-selected-asc .ui-icon-arrowthick-1-s,.elfinder-button-menu-item-selected-desc .ui-icon-arrowthick-1-n{display:none}.elfinder-button form{position:absolute;top:0;right:0;opacity:0;filter:Alpha(Opacity=0);cursor:pointer}.elfinder .elfinder-button form input{background:0 0;cursor:default}.elfinder .elfinder-button-search{border:0 solid;background:0 0;padding:0;margin:1px 4px;height:auto;min-height:26px;float:right;width:202px;overflow:visible}.elfinder .elfinder-button-search .elfinder-button-menu{font-size:8pt;text-align:center;width:100%}.elfinder .elfinder-button-search .elfinder-button-menu div{margin-left:auto;margin-right:auto;margin-bottom:5px}.elfinder .elfinder-button-search .elfinder-button-menu div .ui-state-hover{border:1px solid}.elfinder-ltr .elfinder-button-search{float:right;margin-right:10px}.elfinder-rtl .elfinder-button-search{float:left;margin-left:10px}.elfinder-button-search input[type=text]{width:160px;height:22px;padding:0 20px;line-height:22px;border:1px solid #aaa;-moz-border-radius:12px;-webkit-border-radius:12px;border-radius:12px;outline:0 solid}.elfinder-button-search input::-ms-clear{display:none}.elfinder-touch .elfinder-button-search input{height:28px;line-height:28px}.elfinder-rtl .elfinder-button-search input{direction:rtl}.elfinder-button-search .ui-icon{position:absolute;height:18px;top:50%;margin:-8px 4px 0;opacity:.6;filter:Alpha(Opacity=60)}.elfinder-button-search .ui-checkboxradio-icon{display:none}.elfinder-ltr .elfinder-button-search .ui-icon-search{left:0}.elfinder-ltr .elfinder-button-search .ui-icon-close,.elfinder-rtl .elfinder-button-search .ui-icon-search{right:0}.elfinder-rtl .elfinder-button-search .ui-icon-close{left:0}.elfinder-toolbar-swipe-handle{position:absolute;top:0;left:0;height:50px;width:100%;pointer-events:none;background:linear-gradient(to bottom,#dde4eb 0,rgba(221,228,235,.8) 2px,rgba(216,223,230,.3) 5px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)} \ No newline at end of file diff --git a/static/elfinder/css/theme.css b/static/elfinder/css/theme.css new file mode 100644 index 00000000..698f5a6e --- /dev/null +++ b/static/elfinder/css/theme.css @@ -0,0 +1,113 @@ +/** + * MacOS X like theme for elFinder. + * Required jquery ui "smoothness" theme. + * + * @author Dmitry (dio) Levashov + **/ + +/* input textarea */ +.elfinder input, +.elfinder textarea { + color: #000; + background-color: #FFF; +} + +/* dialogs */ +.std42-dialog, .std42-dialog .ui-widget-content { background-color:#ededed; background-image:none; background-clip: content-box; } +.elfinder-quicklook-titlebar-icon .ui-icon { + background-color: #d4d4d4; + border-color: #8a8a8a; +} +.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close { + background-color: #ff6252; + border-color: #e5695d; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize { + background-color: #ffbc00; + border-color: #e3a40b; +} +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full { + background-color: #26c82f; + border-color: #13ae10; +} + +/* navbar */ +.elfinder .elfinder-navbar { background:#dde4eb; } +.elfinder-navbar .ui-state-hover { color:#000; background-color:#edf1f4; border-color:#bdcbd8; } +.elfinder-navbar .ui-state-active { background: #3875d7; border-color:#3875d7; color:#fff; } +.elfinder-navbar .elfinder-droppable-active {background:#A7C6E5 !important;} +/* disabled elfinder */ +.elfinder-disabled .elfinder-navbar .ui-state-active { background: #dadada; border-color:#aaa; color:#fff; } + +/* workzone */ +.elfinder-workzone { background:#fff; } + +/* current directory */ +/* Is in trash */ +.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash { + background-color: #f0efef; +} + +/* selected file in "icons" view */ +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover { background:#ccc; } + +/* type badge in "icons" view */ +.elfinder-cwd-icon:before { + color: white; + background-color: #798da7; +} +.elfinder-cwd-icon-text:before { background-color: #6f99e6 } +.elfinder-cwd-icon-image:before { background-color: #2ea26c } +.elfinder-cwd-icon-audio:before { background-color: #7bad2a } +.elfinder-cwd-icon-video:before { background-color: #322aad } + +/* list view*/ +.elfinder-cwd table thead td.ui-state-hover { background:#ddd; } +.elfinder-cwd table tr:nth-child(odd) { background-color:#edf3fe; } +.elfinder-cwd table tr { + border: 1px solid transparent; + border-top:1px solid #fff; +} +.elfinder-cwd .elfinder-droppable-active td { background:#A7C6E5 !important; } + + +/* common selected background/color */ +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-cwd table td.ui-state-hover, +.elfinder-button-menu .ui-state-hover { background: #3875d7; color:#fff;} +/* disabled elfinder */ +.elfinder-disabled .elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-disabled .elfinder-cwd table td.ui-state-hover { background:#dadada;} + +/* statusbar */ +.elfinder .elfinder-statusbar { color:#555; } +.elfinder .elfinder-statusbar a { text-decoration:none; color:#555;} + + +.std42-dialog .elfinder-help, .std42-dialog .elfinder-help .ui-widget-content { background:#fff;} + +/* contextmenu */ +.elfinder-contextmenu .ui-state-active { background: #6293df; color:#fff; } +.elfinder-contextmenu .ui-state-hover { background: #3875d7; color:#fff; } +.elfinder-contextmenu .ui-state-hover .elfinder-contextmenu-arrow { background-image:url('../img/arrows-active.png'); } + +/* dialog */ +.elfinder .ui-dialog input:text.ui-state-hover, +.elfinder .ui-dialog textarea.ui-state-hover { + background-image: none; + background-color: inherit; +} + +/* tooltip */ +.elfinder-ui-tooltip.ui-widget-shadow { + box-shadow: 2px 6px 4px -4px #cecdcd; +} diff --git a/static/elfinder/img/arrows-active.png b/static/elfinder/img/arrows-active.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6de0e5d316729fcb5e80903bb7d2e253913de3 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<9!3HG593zhdsS-~Y$B+ufBnS5YjSDtx2#~rE zS1HXP;G{T(yZVmSyC+P3c?*_4*7*AMkIaJwY)Z-^?rv=XUX}IIE4J1#=vlZV33YmA zzjZyOsQ>J!S)Z$lTIUV(14|{DVs`AyQZQngByn(>OxuIM>@%Id+piFeU*l%>i(mM& X@B<5}mkl3)_A_|8`njxgN@xNAE#5rr literal 0 HcmV?d00001 diff --git a/static/elfinder/img/arrows-normal.png b/static/elfinder/img/arrows-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..73f944bc769cd228609ad4bed688d73afe4e71e3 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<9!3HG593zhdsa{VP$B+ufw^NS_9yVZLaSmmP z4)kpMo*7aq!TX!*{`Dy1J5nyn4HA#n>6|`#g5luGNF7clPji)R44xc`Y22@N-LvuQ z)om1YOK4SGdc-`v=Ffc2$IB#UKiYCQB-uKLbC%oX79B>Dv*Mgg(T_M7PUcOKl;O#q x`p3+o9+zf*OX%hISYx0ddE!R_d&ReD*Ia{NP6IlO!PC{xWt~$(696%sMsolF literal 0 HcmV?d00001 diff --git a/static/elfinder/img/crop.gif b/static/elfinder/img/crop.gif new file mode 100644 index 0000000000000000000000000000000000000000..72ea7ccb5321d5384d70437cfaac73011237901e GIT binary patch literal 329 zcmZ?wbhEHb9b#5NV>2k zBC~b@b~P=nNfWAe-b%_i6tS^-1y(h@EsB~1TqDA_h@fkxG$bHgvj}VxE1JLgr!*!^ ILUxTc0Q$^Q5C8xG literal 0 HcmV?d00001 diff --git a/static/elfinder/img/dialogs.png b/static/elfinder/img/dialogs.png new file mode 100644 index 0000000000000000000000000000000000000000..be339b7f6eebee789db02b526f1eed748b891715 GIT binary patch literal 17744 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 bB;fx6F0OEaMJQ#J00000NkvXXu0mjf`p$Vs literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_aceeditor.png b/static/elfinder/img/edit_aceeditor.png new file mode 100644 index 0000000000000000000000000000000000000000..b5bc45e7ac2c6e1939d59234e6386ef9dead027c GIT binary patch literal 532 zcmV+v0_**WP)h0DNjjn~+4jgN-WXP?{9aE(!3d+ncp{^`DV?_M}@b>tJl W;#W8akR~7i0000qy+vdLME z)9zYqE9S5`H-QyJ9F~_b%`0s@7M1guS;9j{@3grLG+FUK`vF$k7~4`BJWh$RPet^wRX64G9I2I&_u$6`m7cy944MO?e ziQyV7VXHlga|3?=4`k!sLhHxdR&rIH!ok;<8F) z)pnq~p$kR=C<#8O2W?iYZ%tMV(sv%r{^-M@+&J_Exnr-wKI%r18T;DJHBT*+Bq0Cb zo74}mw2XPTlXCAVX0bmnj%A;G5Zo@oNqV+awn0Y#fjIz6ycrUTCVT5S-w&|S&W@9l zwFN057}G*9kearT!)vw$28x!-w?bkHz)XNCFPxCQbcF}SSZ(LA)m4qV^pn1bhc=Ia zlrm>jwc!|bv^6h*ebmtoiYj^Lg!G>6_kMsS6}-hj>rA1-R5Yy3NkBt@LlkXGK7%aU z$oMA?m_qdsKej>ipkhuxz`Qbk37s~WtJ@*Tj6*}Y)u|DP$@-UJ-3K3T+A492fYa`k zLwL9BO+Ub_a{doJowohd`Yy6e!?dyx6x8}GO8^VZexyViG5KyeL z%+V(7$cbUnV><-jazl8BhHn<9PPx}5C8xG07*qoM6N<$g7dg& AbN~PV literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_codemirror.png b/static/elfinder/img/edit_codemirror.png new file mode 100644 index 0000000000000000000000000000000000000000..2eed4d5541f8d89d8dfd8b8f0e6b8fe2854c0fd7 GIT binary patch literal 550 zcmV+>0@?kEP)J&9F2y!6wz-EQy5`7El8>HE4Ke*UnuijceDh!|inG zm82IM?6f-`a4Y+B@Zdp|$GLOoKok8Gj8~pCc0#t`)TvYW`ST|#N_tuvNU+Pu1r^}S zmoIqt?j1CrKYxbb>w^-aR)q!cY4FY+JE8gg`!~YDkUop96&AdF`4atm_QH^XgW>Ub zf6*33li>df3$9$fiYZOn;$YwLnA5!DAI5ogBbVG|mBr9u!?3&8DBK=74;O~cM8x6F zC?wDala`u>Lx&C(ldWIB{%?@maDDh3+#E3%S~4)!1SYGsd$BD{oje8H%FwJyQ*`dw zN#8lzdO|dC9`s-xZc(^5YCimSCzO+g}BT6ZfcWuSktx#CNyphD@i#Q3u~Gh)+zHAmMvWhEs#P~ oqjaX=Vn3x@C`1iHDP?H>0kUF$kLcbJ{Qv*}07*qoM6N<$f-M9BOaK4? literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_creativecloud.png b/static/elfinder/img/edit_creativecloud.png new file mode 100644 index 0000000000000000000000000000000000000000..a022dda3a3cbf6cd33d326176013d1f734556a77 GIT binary patch literal 662 zcmV;H0%`q;P)hPorKv>z{9``CYe51`?P6 z-~bFL3;`VgVF*M61W?rooMsOL9b-rx3Ob}dv17dMs3)j<8htQYKk^i55DKZy zTS{Mlf$G4B(W&lkskPz7dA`PaSyR2{#@k&Y0b1u=c1iIEZ*IHiVcp-4dAZT?lfvhp zZKbfBbHl+PdbKqJ<0oc}ssH5tz^Nzq{rzwE>+jf5kd`z$+UgLka~6?nM8i-;V}aI| zM6|nm$guiXp7$Nm**k1xV)Ytjv`Qv(FFHTIbeT3rlWQ1L>GZ&yxwSW4SO3J*n?C!} z3f}bY8`O!+n=iuQs%x%Lk!W=BQWcL`A-EAD6^qBWZD050H(pJ3+m|1EZ7oY4ems2g ziPaC>Q*q1n@wMx=|35U@-K|n-!x{Udx{)eq6DTV5!eN=6B|;&3f+iLhIoU=jlT4{- zG!u`bCoLlTxw?S^aK=$ wArcl~r|@M}{ayif{`LlUS&qs9Uokm504(fu0h5x>;Q#;t07*qoM6N<$f-KoJr2qf` literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_pixlreditor.png b/static/elfinder/img/edit_pixlreditor.png new file mode 100644 index 0000000000000000000000000000000000000000..78179306100cfac648d089ecd2402efd8482dd31 GIT binary patch literal 993 zcmV<710MW|P)YG1*=QLbuo6HDQH1z@RY?-0O2bQiZWSqd&Lm0G?(a1~!Y4!P z9mIuJbYzj!28_|sT~bi}r>5~hx7t6Ez@P`6uC;MjdG>Ya%|6|n`7OxaX5_z-`>#;+ z?6vRwfFLD+oQ~}glAhkK?%YX~y=1vdsOm!uU-V|r?2wgL`xd_o1{(&Ge{!W*KA3ES zSGj$s?f9?k`ZFpTJ#B9nB18p;MGsv!{l~EnPf*z8RW7Dt0Tp*?^2fVr+0@4`w#l;S zEWjRBqn~f(coK$eaao7&r||JR-A#9$Ag9B(X7>Rt$1lIMlA3N__kZ|;gA_PsuIt|7 zd|H*8u$bnI#hXD@5}1AC(}kku2Yf2KzX|F#ih?Redg7~xP@KQ;WBuAGf3}=6j>;EJ zqR@%c+()())8&fT`v4;VK$O3l`IMYbblyncM%{i6Xg!VsN6hu`TMtk|U=Rf+r;^Zr zEJ-V8Qorftt{dHAi5F7`C-Mbok(R^(e*kv>q|Rc!exx3`%`Mw>fpFt4<;=V2NwbNb zti0MDrnhZTF!Q>+6*UENvpd6G#mhVSSo{0smW-1 zPg*{lw380~CuY_sGca{wHSqLUWS3jL5=bl=>_U%q|EfxRk~X3CKHFA;o`_NVg#+5q zEGX@P)r!&{E@MdtQpscs0f1>j4eWIX=D~2j0lhxMk4_(vIQ0RGl zN8%O8N{u|n0)SirNaU>1pbHUryVc?!%1V7>C345dsWF43K?EzGC|Dl=mSRo2hHHMh P00000NkvXXu0mjfCpX=N literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_pixlrexpress.png b/static/elfinder/img/edit_pixlrexpress.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8e88a928a66acb0bc440dce4e5b6b2aefee421 GIT binary patch literal 979 zcmV;^11$WBP)Y?9eZuot|qHQD= ze_e~aI3}DRV~@V^2kvYV;AyTA!9o)TO54yUHv!x8pxba0H?kQv*y)BOEulJ^6SDcJ z;OGASkzu>vhuv@gLGP{Pqr>IFi#iJeaV6+YD@T_^ho_t4(Qds91y2S;lN$BTO8VEF zRr84=Q^NxQX?z?fzm@L24qO))~ACgVKMTCwNU zDHSO+)S19>ID6v;m+SY#H$04XHUxuOg+s?rV8O<9NZfT9k1cLk4Rx^Q)I%f^(mSu) zaGrO~LGpFgWl;qedAGT2ixa-r-Kg(lv7aZ#>UneV*I)l2KPwF{tuA;qb#P_YK^RkD z!P%RaorD*k69)hZ$;q6&q8hEQd$8XU#0gsvCr=7-?qVEj%nqn>YoX6=MhZ`Z_)G=o zdD@0;hxQxE{0&DYwRiQgPP+|PWis3j_F{t8irw}nkT*VuGSdcOd@Y3Xaww8**mdwG z8a!rN-eSa06DF^Xl~JiORRTa9BME(?$j4k~Cw8|6amE!BLSa9f|G-90z zJ?XoL3%pBKLdbYBec4trVZr);3XRpU-3!oL0zqh+C<%)URvd7@#Etset^1DQmTjN-k29=}R~6N-5O9@i0KkOnNGal=UnlrI!?P zDoc&$s%>S|-}Qi|6{h3w8PgAD7Nrt%qka^L!ldPnQmXXi*QxWST@lNjs_I%axt-K@ z#~Ja;fwu7OUi`NM7~4(#?N@Y7OgtyAUCmJ5(F)6voIuRNkYCjd7jX3PkIyJA-BsD% zdaa_Z>3V8G?ruvL=LD!?hS>BZCJrG<1`c6K1^_3lp$u|eVPOCO002ovPDHLkV1isi B+h70y literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_simplemde.png b/static/elfinder/img/edit_simplemde.png new file mode 100644 index 0000000000000000000000000000000000000000..2b88095aa21c424da32597a43adf424946b7f200 GIT binary patch literal 398 zcmV;90df9`P)$?(y`ZS)nfnu{&FS>j>h#yV-GH>&aQyxG z==0L>_~Yd9%dOU9uh(bB;*!keoy+B%-0i*k{r2hf)cpSW%;lc7+H$qoa8-KYYtiVZy4-v5_~g;(sPXvat<__<+jise%Gm3)_xteE>8rfm zf70lxh($ literal 0 HcmV?d00001 diff --git a/static/elfinder/img/edit_tinymce.png b/static/elfinder/img/edit_tinymce.png new file mode 100644 index 0000000000000000000000000000000000000000..cc654a1abdec328f70ee75821ad625561b8a14d9 GIT binary patch literal 242 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

Mxp$43f>!|PpFfgvFwi~IXT5D3KE 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 literal 0 HcmV?d00001 diff --git a/static/elfinder/img/logo.png b/static/elfinder/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aa5a6bc5c78c09e6cd02c6ff70487161cb825797 GIT binary patch literal 11400 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 literal 0 HcmV?d00001 diff --git a/static/elfinder/img/quicklook-bg.png b/static/elfinder/img/quicklook-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4010bff9efb1ec296b1513627baf09761ad2ec GIT binary patch literal 75 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=Ax{^_kP61+l!OF}!wqa1iX04Y XcCavMZGQL}D9hmK>gTe~DWM4f6=)HV literal 0 HcmV?d00001 diff --git a/static/elfinder/img/quicklook-icons.png b/static/elfinder/img/quicklook-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..cb47d31b59eca2401f1ee1cc35812a716aefa5ed GIT binary patch literal 1902 zcmV-!2a))RP)^Q}*MfL^FHB9TU>vi`|wygtuPCNXiKXZunwo?Q4csP zpIX2M6y#BfXLVS5r4Yk$RHRc3AHp`=kj9JfDd@ta?{f`L@nq(dQHoA+=Db7=RXhow zgJl>M$+d?4XrvE_U=JRo4~U=#)9C{uScUOi0bd-hkQxr-IY7t(eK-#x7c*lPa>C-U zAT=D#9nis0w$C2`1#HY20GF{jX8@FOGG_q52$tpyfC+Tx41hb>kuw157zkg23R-xE z=Xil4O1Kr>^BKF4mUJFtUx=Y8tu_YZfVw0Vc*BU;+o?OoZ)9A_dL^O_7A%!mvOyYp&I2=*~oJZd)cI+CtVK52;ux}ksZ*IfP zoGy3)cW!lpU~Q%iZun(p$J^+IaX(2vXB_o9nWSd|iYw_v-|F>xr(7;~^Z-{l${LOm zhwA~ix3`_Ku`wTj5jFrLJODzBkB@5+pBo%P{z6Cr99}AwI-{ebec{v&`96s`rJ5b_6t!}Wk%F4tj1;Ee$m z1OxO48-Niuz|ztZ8k`5f;d+2BTo2$u#sWwyEk&VWM&GcWz@o--=8WEkUYAjqH5{c6 z7Xx^CX8|z624I8@!21q4fE!$7p(_P&IHvZ<%1XKoC6110$oy8TQq6rJGmO zj{Y(&kwzu@yUK8c;eNv>hEaxXhPj40hH-}X4ObaXG*ktvao=7IEiBb_srt;mKp$Zk zEutLthV_QW4Tl@{_X>8YIhdED3;PAbWNn`6HNA|O$A%_dhj#8Pg!#>IkKt%T0WH#_ z<}%|1X&v4dYZT3i#u6wM5(&`A?hCo*6hk2u?y0qJxi)AM!>pJ@LK~0=+DD`{De$%7 zm@Z#}LR9ao$%#x$zh}fS?nHn{w3+h|C)IN2;UTTbya0Z`(y-Hz!zS&c5klm2Kf;{E zHO@DO`LN7%!)0CopSS;Mat@l$S3B_6*gOmEQw3odcN#7?Z0;mmURQ%$iLZ1ehDXsc z6XUh-FCpMB)J)8)!Qc(-I~Q(h!kpW@=B1+J#XO`~4vXHx{NE9vwV3lFYR7N77i(Su zH$ESD?grmqjE|e-wZJoY7DD{(x-(wI|Nel0dC?Ruor`V@etki{S8$1@UQ4X`D`K=X|#R7}W zbBOjEV2PhYiiT8%G7-|cj;;%f@6hBXXS&q+pF#M4R~aAyav_c=gy?x;L51k4NW%u0 zx&h2zc4?S*|MQv9gka=eGYrS_^;~WmV`7#Jy2$ftS_ePtzhaM=rJdE%2jWZkInAJk zzmB>8!Ngf)M`wagV@%*sa}&=4EX4)zD_Q{2L3tPCRC~NcS?%l5ZKxD1gs~ zYYZ!q%W{Vpus{h2)*4ulBO^LfCBL*Y0SZMAF#Le?T??a$Hi|%FYVHsL>|aXM>~btMC-VZHjL_OY3Mm;5Aqn#u#U_Q;WWGX; zu&3cs@5*<{(^9@d9h(KGf zd5;)QFziVS_xUl+P#XT$hBqike>ZG5tTl|*!^>Mb)Sf=5y~m0RFW8=VW;~qp{FByT o3R2{llz;)57WdZNLt|*{0xDe}lJwsR_y7O^07*qoM6N<$f;W(DKmY&$ literal 0 HcmV?d00001 diff --git a/static/elfinder/img/resize.png b/static/elfinder/img/resize.png new file mode 100644 index 0000000000000000000000000000000000000000..25b1fea5f950b36c25707a6f92af9b9cbd8afb99 GIT binary patch literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^>>xG=8<0#rS+W&KNqM?BhEy;nFOWGi+xY$eGc%2Q g6TWmzT*AS?P?8q*(lOS%0H}(=)78&qol`;+04F3DRR910 literal 0 HcmV?d00001 diff --git a/static/elfinder/img/spinner-mini.gif b/static/elfinder/img/spinner-mini.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/static/elfinder/img/toolbar.png b/static/elfinder/img/toolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..9f585da924d50a7210cef1ef36ad999fd0d9da1d GIT binary patch literal 20943 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

p+yeP?-W6;75eqE^ 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 DA$FNW literal 0 HcmV?d00001 diff --git a/static/elfinder/img/volume_icon_box.png b/static/elfinder/img/volume_icon_box.png new file mode 100644 index 0000000000000000000000000000000000000000..52eaec2b36dfd9f2134615d5a055a13370605b35 GIT binary patch literal 621 zcmV-z0+RiSP)u+qP}nw()G+ zwr$(S+BFG3dMNE2f+=!hO?lT=?ma zf%|@9(KQP?B{WLp%*z194Wc%(2+Y9TOJ?Y`;~VOm&74#8@zHnvm00000NkvXX Hu0mjfkToRP literal 0 HcmV?d00001 diff --git a/static/elfinder/img/volume_icon_dropbox.png b/static/elfinder/img/volume_icon_dropbox.png new file mode 100644 index 0000000000000000000000000000000000000000..2454e3f4a1ae276cb4f6257060d68db210f38859 GIT binary patch literal 419 zcmV;U0bKrxP)GuJtg{YhZ2xDuG%cub{#WK7Zft%6^qoliwUCqx>Va-1HmbvO6cZE6{G#U!P3D zL@%KFSFx~9&hs$CER;P7En$UI_~0F(uZ7U=6bL+NUkwwzg_ha8A@|q4xF2p~-wV^r zObW^!;$A@6t1xmDS_b2`FAg2fadq)ukDwxq{K@{&U5A$G!XMe^RaUYOM*dZM3;Utv zFGFPu!zwy}s(3QD7~0J1E%Z=KvF?q4H%x^O=z*aMqy_LbG3;>>wSYcvqTHOEu N002ovPDHLkV1lHy!yEtr literal 0 HcmV?d00001 diff --git a/static/elfinder/img/volume_icon_ftp.png b/static/elfinder/img/volume_icon_ftp.png new file mode 100644 index 0000000000000000000000000000000000000000..d088139858566abc2cc16dfe6a1a0aafcc1412eb GIT binary patch literal 403 zcmV;E0c`$>P)&f7inTbjKlUvciuX)Aeqdvknz zeB4Ng9L(aJ7b53ha6;>2@70YT*8NjhS>P{I0qSK!UB7H`>4IWJ+`^I z$w7vhu)x;VHm0kqi}m*Qa*$yrEHE=Oi(g+~XG=><9AuaY3-tB%lV)dU@y|CJ8ygui z%!CE1s;cP|6BFF$FD@=JWS9vH9zTBE?(6Hz45db#!zz3l9&!p+BR~kYV;v z0p6}iOJyY`C9I&JfP)M(?8p|-@$J#0M`5(kd`Ab|&1ffrc7Mthydl5HZwb_&<5~eG~n4$+q)UYAR`Z)O1Z$gZf7|KuZiehxx}U-;Zz41xdv002ovPDHLkV1n-Kxqbiu literal 0 HcmV?d00001 diff --git a/static/elfinder/img/volume_icon_googledrive.png b/static/elfinder/img/volume_icon_googledrive.png new file mode 100644 index 0000000000000000000000000000000000000000..22ae2a9f43b6c09e7ed2a6790f255c338fbaf26b GIT binary patch literal 680 zcmV;Z0$2TsP)%tyU*eBkrH~uiB?zlTD1MgC$y~~ug z5nj|C|9)}F4*+n`2kcW94Zmgp>toFGiUV&N=<4Z~yqKsc&pIf6E}hdKI)(h0`;U%!2R{{ueYe|*ow`Uvkitrd*XFd<8SlpgIsIv`~b ztA;efVf)<7|F3&^uLtyHr&@d4`Gd7l6al3av}ci9??#o?_Kg$)L?i-$fS$hRq`?o} zdV<~cfcMrdpOT`>qZi`{+S7F{^OAo5d2rhA&T$<(2WAEfLxeBy_xS~%0)SBuTyiR% zb=+^*`3nI8ps%>$=Z~1948suP;Nn{7VI7T1i zziYLI(F$5=cs<7y>-qA0P};=W`f}NMN9!M+Z=d5)$2sf*ko3VCMo%w~Gg8^IU5*NY ziQoW$Nsh~T?3^RdJ15D%>Ll2Z4*~FZwxBm~kxPB(>FGldFuH3~l2kBd+ZYZw$pwt4 zQ1zu^+s;(lKM`cYAX3oU#AZW804V?j5l*UE_3IdgNSSU;!Do(HxYx*0#rF_}PXLnz z3nB;-!Mgy_)0#c&v+n9`Yyf~KZdt2tJbUudjSszU)R`(^f^rN+3=sz+M!*q{;heyA zw@t2I`o&rRFi1ouqlmddQL?~sgmY*uSUe4fD?0#sKnj42<^pg4 O0000`qe zWD(0$RgD!C6ySoC-*%vr1H2oHrL%}-{8BibPM3s2A@KRU2%`Kr@(ZBrw*=<<=RhQS z31X4J&I{(|W)VO@YDA!cVLT-u5*{H8h(!X+#l;0oPENu2_!!x{X{1h{34z&NJCGKk zvAZ1*%g)ZugucGM#oF51!rI!J4>`E#QekXTF7@J_xKeZ z{v+HDY|cM91DaV3n7J;WWK=jS5$CX@i1CiX4uwN$>>B_48N?fS9fU&~*q+ooNv!f? zOgX@w!uV&FK{Bh<{SFPLjh+W@BrR!VVb(L?sbygJZSd(i`~DaipaU5^UHx3vIVCg! E04WVaTL1t6 literal 0 HcmV?d00001 diff --git a/static/elfinder/img/volume_icon_sql.png b/static/elfinder/img/volume_icon_sql.png new file mode 100644 index 0000000000000000000000000000000000000000..304d87e641e6ee84720a3cca231ce7526ccd5fbc GIT binary patch literal 589 zcmV-T0M_9nfi5E%J$!WNqS}lwc?{HXxFhbdB$;P z&z*;?fB*iy$x@P*SxSv~rwaNEw_w4_jmGh^k@dH4-!@rFtgWp%cI;TVA(;G6U@?6e zLI|9_f{=BiRN6v_U&wlXX*IRa->N5=y82M;^mWH*NL5vp(q4b?GD%svRETGaK>5b! z&!3ZmOMxh2^ytz5P9RfPgF(ZF4Lj2K3i0?vgy0twN@RwKl+rYc zpO+x#$~Ax1w&`au@@K`;KmY&`1K&f}?=S?Pc_5;XhN29Ux<|B_i(b#Fn z9mH=lmI0I{Y+XlKgh;azilRW(G{!hL0k%h) zX4j4!=R?leTcV_7x@_MM%p^&msRAlpOSKw`qCk?Sh~or76eFW62tzny$I7#8s^lCZ z&vR1AzWBM-erIOdK4P2An_!s+IA@d`BP7t+anb7!(d=~58w}xx;aft}J}F3C4C!#k zZMJp?qwy21?%)Wix~{ea-Ow@dd;*LJ*h9P5$9TnqrfDdECji!y{Sh}@bp;-I;Wb%f zRIAtF1%XV!VC2B{0t{RaD^ZF<7=W6gwx*6OiDJVraOr6$frElER$V!%M@cF>4lhig z>jo56qXY$lp5(Z?D7DI$A@HZ*)D)d8Qcn=436Ul6gAjS1p`c#TPW%p}_$z^&hC&2} zu7O5dJ+r*5CL)9Y&*eA;xnq@!-$noKz@X--LJ&dqtS&)7BL9B}GFBa^)M*ta5lAJK z+z4{PlTL4hQ}3Cf;P#HC@#46fZyjd}sZp&8}%0%QT4@g)0iJF{86; zDzv%@&Hu-C').append(node.contents()).attr('class', node.attr('class') || '').attr('style', node.attr('style') || ''), + + /** + * Instance ID. Required to get/set cookie + * + * @type String + **/ + id = node.attr('id') || '', + + /** + * Events namespace + * + * @type String + **/ + namespace = 'elfinder-' + (id ? id : Math.random().toString().substr(2, 7)), + + /** + * Mousedown event + * + * @type String + **/ + mousedown = 'mousedown.'+namespace, + + /** + * Keydown event + * + * @type String + **/ + keydown = 'keydown.'+namespace, + + /** + * Keypress event + * + * @type String + **/ + keypress = 'keypress.'+namespace, + + /** + * Is shortcuts/commands enabled + * + * @type Boolean + **/ + enabled = true, + + /** + * Store enabled value before ajax requiest + * + * @type Boolean + **/ + prevEnabled = true, + + /** + * List of build-in events which mapped into methods with same names + * + * @type Array + **/ + events = ['enable', 'disable', 'load', 'open', 'reload', 'select', 'add', 'remove', 'change', 'dblclick', 'getfile', 'lockfiles', 'unlockfiles', 'selectfiles', 'unselectfiles', 'dragstart', 'dragstop', 'search', 'searchend', 'viewchange'], + + /** + * Rules to validate data from backend + * + * @type Object + **/ + rules = {}, + + /** + * Current working directory hash + * + * @type String + **/ + cwd = '', + + /** + * Current working directory options default + * + * @type Object + **/ + cwdOptionsDefault = { + path : '', + url : '', + tmbUrl : '', + disabled : [], + separator : '/', + archives : [], + extract : [], + copyOverwrite : true, + uploadOverwrite : true, + uploadMaxSize : 0, + jpgQuality : 100, + tmbCrop : false, + tmb : false // old API + }, + + /** + * Current working directory options + * + * @type Object + **/ + cwdOptions = {}, + + /** + * Files/dirs cache + * + * @type Object + **/ + files = {}, + + /** + * Files/dirs hash cache of each dirs + * + * @type Object + **/ + ownFiles = {}, + + /** + * Selected files hashes + * + * @type Array + **/ + selected = [], + + /** + * Events listeners + * + * @type Object + **/ + listeners = {}, + + /** + * Shortcuts + * + * @type Object + **/ + shortcuts = {}, + + /** + * Buffer for copied files + * + * @type Array + **/ + clipboard = [], + + /** + * Copied/cuted files hashes + * Prevent from remove its from cache. + * Required for dispaly correct files names in error messages + * + * @type Object + **/ + remember = {}, + + /** + * Queue for 'open' requests + * + * @type Array + **/ + queue = [], + + /** + * Queue for only cwd requests e.g. `tmb` + * + * @type Array + **/ + cwdQueue = [], + + /** + * Commands prototype + * + * @type Object + **/ + base = new self.command(self), + + /** + * elFinder node width + * + * @type String + * @default "auto" + **/ + width = 'auto', + + /** + * elFinder node height + * Number: pixcel or String: Number + "%" + * + * @type Number | String + * @default 400 + **/ + height = 400, + + /** + * Base node object or selector + * Element which is the reference of the height percentage + * + * @type Object|String + * @default null | $(window) (if height is percentage) + **/ + heightBase = null, + + /** + * MIME type list(Associative array) handled as a text file + * + * @type Object|null + */ + textMimes = null, + + /** + * elfinder path for sound played on remove + * @type String + * @default ./sounds/ + **/ + soundPath = './sounds/', + + beeper = $(document.createElement('audio')).hide().appendTo('body')[0], + + syncInterval, + autoSyncStop = 0, + + uiCmdMapPrev = '', + + gcJobRes = null, + + open = function(data) { + // NOTES: Do not touch data object + + var volumeid, contextmenu, emptyDirs = {}, stayDirs = {}, + rmClass, hashes, calc, gc, collapsed, prevcwd; + + if (self.api >= 2.1) { + // support volume driver option `uiCmdMap` + self.commandMap = (data.options.uiCmdMap && Object.keys(data.options.uiCmdMap).length)? data.options.uiCmdMap : {}; + if (uiCmdMapPrev !== JSON.stringify(self.commandMap)) { + uiCmdMapPrev = JSON.stringify(self.commandMap); + } + } else { + self.options.sync = 0; + } + + if (data.init) { + // init - reset cache + files = {}; + ownFiles = {}; + } else { + // remove only files from prev cwd + // and collapsed directory (included 100+ directories) to empty for perfomance tune in DnD + prevcwd = cwd; + rmClass = 'elfinder-subtree-loaded ' + self.res('class', 'navexpand'); + collapsed = self.res('class', 'navcollapse'); + hashes = Object.keys(files); + calc = function(i) { + if (!files[i]) { + return true; + } + + var isDir = (files[i].mime === 'directory'), + phash = files[i].phash, + pnav; + + if ( + (!isDir + || emptyDirs[phash] + || (!stayDirs[phash] + && $('#'+self.navHash2Id(files[i].hash)).is(':hidden') + && $('#'+self.navHash2Id(phash)).next('.elfinder-navbar-subtree').children().length > 100 + ) + ) + && (isDir || phash !== cwd) + && ! remember[i] + ) { + if (isDir && !emptyDirs[phash]) { + emptyDirs[phash] = true; + $('#'+self.navHash2Id(phash)) + .removeClass(rmClass) + .next('.elfinder-navbar-subtree').empty(); + } + deleteCache(files[i]); + } else if (isDir) { + stayDirs[phash] = true; + } + }; + gc = function() { + if (hashes.length) { + gcJobRes && gcJobRes._abort(); + gcJobRes = self.asyncJob(calc, hashes, { + interval : 20, + numPerOnce : 100 + }); + } + }; + + self.trigger('filesgc').one('filesgc', function() { + hashes = []; + }); + + self.one('opendone', function() { + if (prevcwd !== cwd) { + if (! node.data('lazycnt')) { + gc(); + } else { + self.one('lazydone', gc); + } + } + }); + } + + self.sorters = []; + cwd = data.cwd.hash; + cache(data.files); + if (!files[cwd]) { + cache([data.cwd]); + } + self.lastDir(cwd); + + self.autoSync(); + }, + + /** + * Store info about files/dirs in "files" object. + * + * @param Array files + * @param String data type + * @return void + **/ + cache = function(data, type) { + var defsorter = { name: true, perm: true, date: true, size: true, kind: true }, + sorterChk = (self.sorters.length === 0), + l = data.length, + setSorter = function(f) { + var f = f || {}; + self.sorters = []; + $.each(self.sortRules, function(key) { + if (defsorter[key] || typeof f[key] !== 'undefined' || (key === 'mode' && typeof f.perm !== 'undefined')) { + self.sorters.push(key); + } + }); + }, + keeps = ['sizeInfo'], + changedParents = {}, + f, i, keepProp, parents; + + for (i = 0; i < l; i++) { + f = Object.assign({}, data[i]); + if (f.name && f.hash && f.mime) { + if (sorterChk && f.phash === cwd) { + setSorter(f); + sorterChk = false; + } + + // make or update of leaf roots cache + if (f.isroot && f.phash) { + if (! self.leafRoots[f.phash]) { + self.leafRoots[f.phash] = [ f.hash ]; + } else { + if ($.inArray(f.hash, self.leafRoots[f.phash]) === -1) { + self.leafRoots[f.phash].push(f.hash); + } + } + if (files[f.phash]) { + if (! files[f.phash].dirs) { + files[f.phash].dirs = 1; + } + if (f.ts && (files[f.phash].ts || 0) < f.ts) { + files[f.phash].ts = f.ts; + } + } + } + + if (f.phash && (type === 'add' || type === 'change')) { + if (parents = self.parents(f.phash)) { + $.each(parents, function() { + changedParents[this] = true; + }); + } + } + + if (files[f.hash]) { + $.each(keeps, function() { + if(files[f.hash][this] && ! f[this]) { + f[this] = files[f.hash][this]; + } + }); + if (f.sizeInfo && !f.size) { + f.size = f.sizeInfo.size; + } + deleteCache(files[f.hash], true); + } + files[f.hash] = f; + if (f.mime === 'directory' && !ownFiles[f.hash]) { + ownFiles[f.hash] = {}; + } + if (f.phash) { + if (!ownFiles[f.phash]) { + ownFiles[f.phash] = {}; + } + ownFiles[f.phash][f.hash] = true; + } + } + } + // delete sizeInfo cache + $.each(Object.keys(changedParents), function() { + var target = files[this]; + if (target && target.sizeInfo) { + delete target.sizeInfo; + } + }); + + // for empty folder + sorterChk && setSorter(); + }, + + /** + * Delete file object from files caches + * + * @param Array removed hashes + * @return void + */ + remove = function(removed) { + var l = removed.length, + roots = {}, + rm = function(hash) { + var file = files[hash], i; + if (file) { + if (file.mime === 'directory') { + if (roots[hash]) { + delete self.roots[roots[hash]]; + } + if (self.searchStatus.state < 2) { + $.each(files, function(h, f) { + f.phash == hash && rm(h); + }); + } + } + if (file.phash) { + if (parents = self.parents(file.phash)) { + $.each(parents, function() { + changedParents[this] = true; + }); + } + } + deleteCache(files[hash]); + } + }, + changedParents = {}, + parents; + + $.each(self.roots, function(k, v) { + roots[v] = k; + }); + while (l--) { + rm(removed[l]); + } + // delete sizeInfo cache + $.each(Object.keys(changedParents), function() { + var target = files[this]; + if (target && target.sizeInfo) { + delete target.sizeInfo; + } + }); + }, + + /** + * Update file object in files caches + * + * @param Array changed file objects + * @return void + */ + change = function(changed) { + $.each(changed, function(i, file) { + var hash = file.hash; + if (files[hash]) { + $.each(['locked', 'hidden', 'width', 'height'], function(i, v){ + if (files[hash][v] && !file[v]) { + delete files[hash][v]; + } + }); + } + files[hash] = files[hash] ? Object.assign(files[hash], file) : file; + }); + }, + + /** + * Delete cache data of files, ownFiles and self.optionsByHashes + * + * @param Object file + * @param Boolean update + * @return void + */ + deleteCache = function(file, update) { + var hash = file.hash, + phash = file.phash; + + if (phash && ownFiles[phash]) { + delete ownFiles[phash][hash]; + } + if (!update) { + ownFiles[hash] && delete ownFiles[hash]; + self.optionsByHashes[hash] && delete self.optionsByHashes[hash]; + } + delete files[hash]; + }, + + /** + * Maximum number of concurrent connections on request + * + * @type Number + */ + requestMaxConn, + + /** + * Current number of connections + * + * @type Number + */ + requestCnt = 0, + + /** + * Queue waiting for connection + * + * @type Array + */ + requestQueue = [], + + /** + * Flag to cancel the `open` command waiting for connection + * + * @type Boolean + */ + requestQueueSkipOpen = false, + + /** + * Exec shortcut + * + * @param jQuery.Event keydown/keypress event + * @return void + */ + execShortcut = function(e) { + var code = e.keyCode, + ctrlKey = !!(e.ctrlKey || e.metaKey), + ddm; + + if (enabled) { + + $.each(shortcuts, function(i, shortcut) { + if (shortcut.type == e.type + && shortcut.keyCode == code + && shortcut.shiftKey == e.shiftKey + && shortcut.ctrlKey == ctrlKey + && shortcut.altKey == e.altKey) { + e.preventDefault(); + e.stopPropagation(); + shortcut.callback(e, self); + self.debug('shortcut-exec', i+' : '+shortcut.description); + } + }); + + // prevent tab out of elfinder + if (code == $.ui.keyCode.TAB && !$(e.target).is(':input')) { + e.preventDefault(); + } + + // cancel any actions by [Esc] key + if (e.type === 'keydown' && code == $.ui.keyCode.ESCAPE) { + // copy or cut + if (! node.find('.ui-widget:visible').length) { + self.clipboard().length && self.clipboard([]); + } + // dragging + if ($.ui.ddmanager) { + ddm = $.ui.ddmanager.current; + ddm && ddm.helper && ddm.cancel(); + } + // button menus + node.find('.ui-widget.elfinder-button-menu').hide(); + // trigger keydownEsc + self.trigger('keydownEsc', e); + } + + } + }, + date = new Date(), + utc, + i18n, + inFrame = (window.parent !== window), + parentIframe = (function() { + var pifm, ifms; + if (inFrame) { + try { + ifms = $('iframe', window.parent.document); + if (ifms.length) { + $.each(ifms, function(i, ifm) { + if (ifm.contentWindow === window) { + pifm = $(ifm); + return false; + } + }); + } + } catch(e) {} + } + return pifm; + })(), + /** + * elFinder boot up function + * + * @type Function + */ + bootUp, + /** + * Original function of XMLHttpRequest.prototype.send + * + * @type Function + */ + savedXhrSend; + + // check opt.bootCallback + if (opts.bootCallback && typeof opts.bootCallback === 'function') { + (function() { + var func = bootCallback, + opFunc = opts.bootCallback; + bootCallback = function(fm, extraObj) { + func && typeof func === 'function' && func.call(this, fm, extraObj); + opFunc.call(this, fm, extraObj); + } + })(); + } + delete opts.bootCallback; + + /** + * Protocol version + * + * @type String + **/ + this.api = null; + + /** + * elFinder use new api + * + * @type Boolean + **/ + this.newAPI = false; + + /** + * elFinder use old api + * + * @type Boolean + **/ + this.oldAPI = false; + + /** + * Net drivers names + * + * @type Array + **/ + this.netDrivers = []; + + /** + * Base URL of elfFinder library starting from Manager HTML + * + * @type String + */ + this.baseUrl = ''; + + /** + * Is elFinder CSS loaded + * + * @type Boolean + */ + this.cssloaded = false; + + /** + * Callback function at boot up that option specified at elFinder starting + * + * @type Function + */ + this.bootCallback; + + /** + * Configuration options + * + * @type Object + **/ + this.options = $.extend(true, {}, this._options, opts||{}); + + // set fm.baseUrl + this.baseUrl = (function() { + var myTag, myCss, base, baseUrl; + + if (self.options.baseUrl) { + return self.options.baseUrl; + } else { + baseUrl = ''; + myTag = $('head > script[src$="js/elfinder.min.js"],script[src$="js/elfinder.full.js"]:first'); + if (myTag.length) { + myCss = $('head > link[href$="css/elfinder.min.css"],link[href$="css/elfinder.full.css"]:first').length; + if (! myCss) { + // to request CSS auto loading + self.cssloaded = null; + } + baseUrl = myTag.attr('src').replace(/js\/[^\/]+$/, ''); + if (! baseUrl.match(/^(https?\/\/|\/)/)) { + // check tag + if (base = $('head > base[href]').attr('href')) { + baseUrl = base.replace(/\/$/, '') + '/' + baseUrl; + } + } + } + if (baseUrl !== '') { + self.options.baseUrl = baseUrl; + } else { + if (! self.options.baseUrl) { + self.options.baseUrl = './'; + } + baseUrl = self.options.baseUrl; + } + return baseUrl; + } + })(); + + // set dispInlineRegex + cwdOptionsDefault['dispInlineRegex'] = this.options.dispInlineRegex; + + // auto load required CSS + if (this.options.cssAutoLoad) { + (function() { + var baseUrl = self.baseUrl; + + if (self.cssloaded === null) { + // hide elFinder node while css loading + node.data('cssautoloadHide', $('')); + $('head').append(node.data('cssautoloadHide')); + + // load CSS + self.loadCss([baseUrl+'css/elfinder.min.css', baseUrl+'css/theme.css']); + + // additional CSS files + if (Array.isArray(self.options.cssAutoLoad)) { + self.loadCss(self.options.cssAutoLoad); + } + } + self.options.cssAutoLoad = false; + })(); + } + + /** + * Volume option to set the properties of the root Stat + * + * @type Object + */ + this.optionProperties = { + icon: void(0), + csscls: void(0), + tmbUrl: void(0), + uiCmdMap: {}, + netkey: void(0), + disabled: [] + }; + + if (opts.ui) { + this.options.ui = opts.ui; + } + + if (opts.commands) { + this.options.commands = opts.commands; + } + + if (opts.uiOptions) { + if (opts.uiOptions.toolbar && Array.isArray(opts.uiOptions.toolbar)) { + if ($.isPlainObject(opts.uiOptions.toolbar[opts.uiOptions.toolbar.length - 1])) { + Object.assign(this.options.uiOptions.toolbarExtra, opts.uiOptions.toolbar.pop()); + } + this.options.uiOptions.toolbar = opts.uiOptions.toolbar; + } + if (opts.uiOptions.toolbarExtra && $.isPlainObject(opts.uiOptions.toolbarExtra)) { + Object.assign(this.options.uiOptions.toolbarExtra, opts.uiOptions.toolbarExtra); + } + + if (opts.uiOptions.cwd && opts.uiOptions.cwd.listView) { + if (opts.uiOptions.cwd.listView.columns) { + this.options.uiOptions.cwd.listView.columns = opts.uiOptions.cwd.listView.columns; + } + if (opts.uiOptions.cwd.listView.columnsCustomName) { + this.options.uiOptions.cwd.listView.columnsCustomName = opts.uiOptions.cwd.listView.columnsCustomName; + } + } + } + // join toolbarExtra to toolbar + this.options.uiOptions.toolbar.push(this.options.uiOptions.toolbarExtra); + delete this.options.uiOptions.toolbarExtra; + + if (opts.contextmenu) { + Object.assign(this.options.contextmenu, opts.contextmenu); + } + + if (! inFrame && ! this.options.enableAlways && $('body').children().length === 2) { // only node and beeper + this.options.enableAlways = true; + } + + if (this.baseUrl === '') { + this.baseUrl = this.options.baseUrl? this.options.baseUrl : ''; + } + + // make options.debug + if (this.options.debug === true) { + this.options.debug = 'all'; + } else if (Array.isArray(this.options.debug)) { + (function() { + var d = {}; + $.each(self.options.debug, function() { + d[this] = true; + }); + self.options.debug = d; + })(); + } else { + this.options.debug = false; + } + + /** + * Original functions evacuated by conflict check + * + * @type Object + */ + this.noConflicts = {}; + + /** + * Check and save conflicts with bootstrap etc + * + * @type Function + */ + this.noConflict = function() { + $.each(conflictChecks, function(i, p) { + if ($.fn[p] && typeof $.fn[p].noConflict === 'function') { + self.noConflicts[p] = $.fn[p].noConflict(); + } + }); + } + // do check conflict + this.noConflict(); + + /** + * Is elFinder over CORS + * + * @type Boolean + **/ + this.isCORS = false; + + // configure for CORS + (function(){ + var parseUrl = document.createElement('a'), + parseUploadUrl; + parseUrl.href = opts.url; + if (opts.urlUpload && (opts.urlUpload !== opts.url)) { + parseUploadUrl = document.createElement('a'); + parseUploadUrl.href = opts.urlUpload; + } + if (window.location.host !== parseUrl.host || (parseUploadUrl && (window.location.host !== parseUploadUrl.host))) { + self.isCORS = true; + if (!$.isPlainObject(self.options.customHeaders)) { + self.options.customHeaders = {}; + } + if (!$.isPlainObject(self.options.xhrFields)) { + self.options.xhrFields = {}; + } + self.options.requestType = 'post'; + self.options.customHeaders['X-Requested-With'] = 'XMLHttpRequest'; + self.options.xhrFields['withCredentials'] = true; + } + })(); + + /** + * Ajax request type + * + * @type String + * @default "get" + **/ + this.requestType = /^(get|post)$/i.test(this.options.requestType) ? this.options.requestType.toLowerCase() : 'get'; + + // set `requestMaxConn` by option + requestMaxConn = Math.max(parseInt(this.options.requestMaxConn), 1); + + /** + * Any data to send across every ajax request + * + * @type Object + * @default {} + **/ + this.customData = $.isPlainObject(this.options.customData) ? this.options.customData : {}; + + /** + * Any custom headers to send across every ajax request + * + * @type Object + * @default {} + */ + this.customHeaders = $.isPlainObject(this.options.customHeaders) ? this.options.customHeaders : {}; + + /** + * Any custom xhrFields to send across every ajax request + * + * @type Object + * @default {} + */ + this.xhrFields = $.isPlainObject(this.options.xhrFields) ? this.options.xhrFields : {}; + + /** + * Replace XMLHttpRequest.prototype.send to extended function for 3rd party libs XHR request etc. + * + * @type Function + */ + this.replaceXhrSend = function() { + if (! savedXhrSend) { + savedXhrSend = XMLHttpRequest.prototype.send; + } + XMLHttpRequest.prototype.send = function() { + var xhr = this; + // set request headers + if (self.customHeaders) { + $.each(self.customHeaders, function(key) { + xhr.setRequestHeader(key, this); + }); + } + // set xhrFields + if (self.xhrFields) { + $.each(self.xhrFields, function(key) { + if (key in xhr) { + xhr[key] = this; + } + }); + } + return savedXhrSend.apply(this, arguments); + } + }; + + /** + * Restore saved original XMLHttpRequest.prototype.send + * + * @type Function + */ + this.restoreXhrSend = function() { + XMLHttpRequest.prototype.send = savedXhrSend; + }; + + /** + * command names for into queue for only cwd requests + * these commands aborts before `open` request + * + * @type Array + * @default ['tmb', 'parents'] + */ + this.abortCmdsOnOpen = this.options.abortCmdsOnOpen || ['tmb', 'parents']; + + /** + * ID. Required to create unique cookie name + * + * @type String + **/ + this.id = id; + + /** + * ui.nav id prefix + * + * @type String + */ + this.navPrefix = 'nav' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-'; + + /** + * ui.cwd id prefix + * + * @type String + */ + this.cwdPrefix = elFinder.prototype.uniqueid? ('cwd' + elFinder.prototype.uniqueid + '-') : ''; + + // Increment elFinder.prototype.uniqueid + ++elFinder.prototype.uniqueid; + + /** + * URL to upload files + * + * @type String + **/ + this.uploadURL = opts.urlUpload || opts.url; + + /** + * Events namespace + * + * @type String + **/ + this.namespace = namespace; + + /** + * Today timestamp + * + * @type Number + **/ + this.today = (new Date(date.getFullYear(), date.getMonth(), date.getDate())).getTime()/1000; + + /** + * Yesterday timestamp + * + * @type Number + **/ + this.yesterday = this.today - 86400; + + utc = this.options.UTCDate ? 'UTC' : ''; + + this.getHours = 'get'+utc+'Hours'; + this.getMinutes = 'get'+utc+'Minutes'; + this.getSeconds = 'get'+utc+'Seconds'; + this.getDate = 'get'+utc+'Date'; + this.getDay = 'get'+utc+'Day'; + this.getMonth = 'get'+utc+'Month'; + this.getFullYear = 'get'+utc+'FullYear'; + + /** + * elFinder node z-index (auto detect on elFinder load) + * + * @type null | Number + **/ + this.zIndex; + + /** + * Current search status + * + * @type Object + */ + this.searchStatus = { + state : 0, // 0: search ended, 1: search started, 2: in search result + query : '', + target : '', + mime : '', + mixed : false, // in multi volumes search: false or Array that target volume ids + ininc : false // in incremental search + }; + + /** + * Method to store/fetch data + * + * @type Function + **/ + this.storage = (function() { + try { + if ('localStorage' in window && window['localStorage'] !== null) { + if (self.UA.Safari) { + // check for Mac/iOS safari private browsing mode + window.localStorage.setItem('elfstoragecheck', 1); + window.localStorage.removeItem('elfstoragecheck'); + } + return self.localStorage; + } else { + return self.cookie; + } + } catch (e) { + return self.cookie; + } + })(); + + /** + * Interface language + * + * @type String + * @default "en" + **/ + this.lang = this.storage('lang') || this.options.lang; + + this.viewType = this.storage('view') || this.options.defaultView || 'icons'; + + this.sortType = this.storage('sortType') || this.options.sortType || 'name'; + + this.sortOrder = this.storage('sortOrder') || this.options.sortOrder || 'asc'; + + this.sortStickFolders = this.storage('sortStickFolders'); + if (this.sortStickFolders === null) { + this.sortStickFolders = !!this.options.sortStickFolders; + } else { + this.sortStickFolders = !!this.sortStickFolders + } + + this.sortAlsoTreeview = this.storage('sortAlsoTreeview'); + if (this.sortAlsoTreeview === null) { + this.sortAlsoTreeview = !!this.options.sortAlsoTreeview; + } else { + this.sortAlsoTreeview = !!this.sortAlsoTreeview + } + + this.sortRules = $.extend(true, {}, this._sortRules, this.options.sortRules); + + $.each(this.sortRules, function(name, method) { + if (typeof method != 'function') { + delete self.sortRules[name]; + } + }); + + this.compare = $.proxy(this.compare, this); + + /** + * Delay in ms before open notification dialog + * + * @type Number + * @default 500 + **/ + this.notifyDelay = this.options.notifyDelay > 0 ? parseInt(this.options.notifyDelay) : 500; + + /** + * Dragging UI Helper object + * + * @type jQuery | null + **/ + this.draggingUiHelper = null; + + /** + * Base droppable options + * + * @type Object + **/ + this.droppable = { + greedy : true, + tolerance : 'pointer', + accept : '.elfinder-cwd-file-wrapper,.elfinder-navbar-dir,.elfinder-cwd-file,.elfinder-cwd-filename', + hoverClass : this.res('class', 'adroppable'), + classes : { // Deprecated hoverClass jQueryUI>=1.12.0 + 'ui-droppable-hover': this.res('class', 'adroppable') + }, + autoDisable: true, // elFinder original, see jquery.elfinder.js + drop : function(e, ui) { + var dst = $(this), + targets = $.map(ui.helper.data('files')||[], function(h) { return h || null }), + result = [], + dups = [], + faults = [], + isCopy = ui.helper.hasClass('elfinder-drag-helper-plus'), + c = 'class', + cnt, hash, i, h; + + if (typeof e.button === 'undefined' || ui.helper.data('namespace') !== namespace || ! self.insideWorkzone(e.pageX, e.pageY)) { + return false; + } + if (dst.hasClass(self.res(c, 'cwdfile'))) { + hash = self.cwdId2Hash(dst.attr('id')); + } else if (dst.hasClass(self.res(c, 'navdir'))) { + hash = self.navId2Hash(dst.attr('id')); + } else { + hash = cwd; + } + + cnt = targets.length; + + while (cnt--) { + h = targets[cnt]; + // ignore drop into itself or in own location + if (h != hash && files[h].phash != hash) { + result.push(h); + } else { + ((isCopy && h !== hash && files[hash].write)? dups : faults).push(h); + } + } + + if (faults.length) { + return false; + } + + ui.helper.data('droped', true); + + if (dups.length) { + ui.helper.hide(); + self.exec('duplicate', dups, {_userAction: true}); + } + + if (result.length) { + ui.helper.hide(); + self.clipboard(result, !isCopy); + self.exec('paste', hash, {_userAction: true}, hash).always(function(){ + self.clipboard([]); + self.trigger('unlockfiles', {files : targets}); + }); + self.trigger('drop', {files : targets}); + } + } + }; + + /** + * Return true if filemanager is active + * + * @return Boolean + **/ + this.enabled = function() { + return enabled && this.visible(); + }; + + /** + * Return true if filemanager is visible + * + * @return Boolean + **/ + this.visible = function() { + return node[0].elfinder && node.is(':visible'); + }; + + /** + * Return file is root? + * + * @param Object target file object + * @return Boolean + */ + this.isRoot = function(file) { + return (file.isroot || ! file.phash)? true : false; + } + + /** + * Return root dir hash for current working directory + * + * @param String target hash + * @param Boolean include fake parent (optional) + * @return String + */ + this.root = function(hash, fake) { + hash = hash || cwd; + var dir, i; + + if (! fake) { + $.each(self.roots, function(id, rhash) { + if (hash.indexOf(id) === 0) { + dir = rhash; + return false; + } + }); + if (dir) { + return dir; + } + } + + dir = files[hash]; + while (dir && dir.phash && (fake || ! dir.isroot)) { + dir = files[dir.phash] + } + if (dir) { + return dir.hash; + } + + while (i in files && files.hasOwnProperty(i)) { + dir = files[i] + if (!dir.phash && !dir.mime == 'directory' && dir.read) { + return dir.hash; + } + } + + return ''; + }; + + /** + * Return current working directory info + * + * @return Object + */ + this.cwd = function() { + return files[cwd] || {}; + }; + + /** + * Return required cwd option + * + * @param String option name + * @param String target hash (optional) + * @return mixed + */ + this.option = function(name, target) { + var res; + target = target || cwd; + if (self.optionsByHashes[target] && typeof self.optionsByHashes[target][name] !== 'undefined') { + return self.optionsByHashes[target][name]; + } + if (cwd !== target) { + res = ''; + $.each(self.volOptions, function(id, opt) { + if (target.indexOf(id) === 0) { + res = opt[name] || ''; + return false; + } + }); + return res; + } else { + return cwdOptions[name] || ''; + } + }; + + /** + * Return disabled commands by each folder + * + * @param Array target hashes + * @return Array + */ + this.getDisabledCmds = function(targets) { + var disabled = ['hidden']; + if (! Array.isArray(targets)) { + targets = [ targets ]; + } + $.each(targets, function(i, h) { + var disCmds = self.option('disabled', h); + if (disCmds) { + $.each(disCmds, function(i, cmd) { + if ($.inArray(cmd, disabled) === -1) { + disabled.push(cmd); + } + }); + } + }); + return disabled; + } + + /** + * Return file data from current dir or tree by it's hash + * + * @param String file hash + * @return Object + */ + this.file = function(hash) { + return hash? files[hash] : void(0); + }; + + /** + * Return all cached files + * + * @param String parent hash + * @return Object + */ + this.files = function(phash) { + var items = {}; + if (phash) { + if (!ownFiles[phash]) { + return {}; + } + $.each(ownFiles[phash], function(h) { + if (files[h]) { + items[h] = files[h]; + } else { + delete ownFiles[phash][h]; + } + }); + return Object.assign({}, items); + } + return Object.assign({}, files); + }; + + /** + * Return list of file parents hashes include file hash + * + * @param String file hash + * @return Array + */ + this.parents = function(hash) { + var parents = [], + dir; + + while ((dir = this.file(hash))) { + parents.unshift(dir.hash); + hash = dir.phash; + } + return parents; + }; + + this.path2array = function(hash, i18) { + var file, + path = []; + + while (hash) { + if ((file = files[hash]) && file.hash) { + path.unshift(i18 && file.i18 ? file.i18 : file.name); + hash = file.isroot? null : file.phash; + } else { + path = []; + break; + } + } + + return path; + }; + + /** + * Return file path or Get path async with jQuery.Deferred + * + * @param Object file + * @param Boolean i18 + * @param Object asyncOpt + * @return String|jQuery.Deferred + */ + this.path = function(hash, i18, asyncOpt) { + var path = files[hash] && files[hash].path + ? files[hash].path + : this.path2array(hash, i18).join(cwdOptions.separator); + if (! asyncOpt || ! files[hash]) { + return path; + } else { + asyncOpt = Object.assign({notify: {type : 'parents', cnt : 1, hideCnt : true}}, asyncOpt); + + var dfd = $.Deferred(), + notify = asyncOpt.notify, + noreq = false, + req = function() { + self.request({ + data : {cmd : 'parents', target : files[hash].phash}, + notify : notify, + preventFail : true + }) + .done(done) + .fail(function() { + dfd.reject(); + }); + }, + done = function() { + self.one('parentsdone', function() { + path = self.path(hash, i18); + if (path === '' && noreq) { + //retry with request + noreq = false; + req(); + } else { + if (notify) { + clearTimeout(ntftm); + notify.cnt = -(parseInt(notify.cnt || 0)); + self.notify(notify); + } + dfd.resolve(path); + } + }); + }, + ntftm; + + if (path) { + return dfd.resolve(path); + } else { + if (self.ui['tree']) { + // try as no request + if (notify) { + ntftm = setTimeout(function() { + self.notify(notify); + }, self.notifyDelay); + } + noreq = true; + done(true); + } else { + req(); + } + return dfd; + } + } + }; + + /** + * Return file url if set + * + * @param String file hash + * @param Object Options + * @return String + */ + this.url = function(hash, opts) { + var file = files[hash], + opts = opts || {}, + async = opts.async || false, + temp = opts.temporary || false, + dfrd = async? $.Deferred() : null, + getUrl = function(url) { + if (url) { + return url; + } + if (file.url) { + return file.url; + } + + baseUrl = (file.hash.indexOf(self.cwd().volumeid) === 0)? cwdOptions.url : self.option('url', file.hash); + + if (baseUrl) { + return baseUrl + $.map(self.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/') + } + + var params = Object.assign({}, self.customData, { + cmd: 'file', + target: file.hash + }); + if (self.oldAPI) { + params.cmd = 'open'; + params.current = file.phash; + } + return self.options.url + (self.options.url.indexOf('?') === -1 ? '?' : '&') + $.param(params, true); + }, + baseUrl, res; + + if (!file || !file.read) { + return async? dfrd.resolve('') : ''; + } + + if (file.url == '1') { + this.request({ + data : { cmd : 'url', target : hash, options : { temporary: temp? 1 : 0 } }, + preventDefault : true, + options: {async: async}, + notify: async? {type : temp? 'file' : 'url', cnt : 1, hideCnt : true} : {} + }) + .done(function(data) { + file.url = data.url || ''; + }) + .fail(function() { + file.url = ''; + }) + .always(function() { + var url; + if (file.url && temp) { + url = file.url; + file.url = '1'; // restore + } + if (async) { + dfrd.resolve(getUrl(url)); + } else { + return getUrl(url); + } + }); + } else { + if (async) { + dfrd.resolve(getUrl()); + } else { + return getUrl(); + } + } + + if (async) { + return dfrd; + } + }; + + /** + * Return file url for open in elFinder + * + * @param String file hash + * @param Boolean for download link + * @return String + */ + this.openUrl = function(hash, download) { + var file = files[hash], + url = ''; + + if (!file || !file.read) { + return ''; + } + + if (!download) { + if (file.url) { + if (file.url != 1) { + url = file.url; + } + } else if (cwdOptions.url && file.hash.indexOf(self.cwd().volumeid) === 0) { + url = cwdOptions.url + $.map(this.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/'); + } + if (url) { + url += (url.match(/\?/)? '&' : '?') + '_'.repeat((url.match(/[\?&](_+)t=/g) || ['&t=']).sort().shift().match(/[\?&](_*)t=/)[1].length + 1) + 't=' + (file.ts || parseInt(+new Date/1000)); + return url; + } + } + + url = this.options.url; + url = url + (url.indexOf('?') === -1 ? '?' : '&') + + (this.oldAPI ? 'cmd=open¤t='+file.phash : 'cmd=file') + + '&target=' + file.hash + + '&_t=' + (file.ts || parseInt(+new Date/1000)); + + if (download) { + url += '&download=1'; + } + + $.each(this.options.customData, function(key, val) { + url += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val); + }); + + return url; + }; + + /** + * Return thumbnail url + * + * @param Object file object + * @return String + */ + this.tmb = function(file) { + var tmbUrl, tmbCrop, + cls = 'elfinder-cwd-bgurl', + url = ''; + + if ($.isPlainObject(file)) { + if (self.searchStatus.state && file.hash.indexOf(self.cwd().volumeid) !== 0) { + tmbUrl = self.option('tmbUrl', file.hash); + tmbCrop = self.option('tmbCrop', file.hash); + } else { + tmbUrl = cwdOptions['tmbUrl']; + tmbCrop = cwdOptions['tmbCrop']; + } + if (tmbCrop) { + cls += ' elfinder-cwd-bgurl-crop'; + } + if (tmbUrl === 'self' && file.mime.indexOf('image/') === 0) { + url = self.openUrl(file.hash); + cls += ' elfinder-cwd-bgself'; + } else if ((self.oldAPI || tmbUrl) && file && file.tmb && file.tmb != 1) { + url = tmbUrl + file.tmb; + } + if (url) { + if (file.ts) { + url += (url.match(/\?/)? '&' : '?') + '_t=' + file.ts; + } + return { url: url, className: cls }; + } + } + + return false; + }; + + /** + * Return selected files hashes + * + * @return Array + **/ + this.selected = function() { + return selected.slice(0); + }; + + /** + * Return selected files info + * + * @return Array + */ + this.selectedFiles = function() { + return $.map(selected, function(hash) { return files[hash] ? Object.assign({}, files[hash]) : null }); + }; + + /** + * Return true if file with required name existsin required folder + * + * @param String file name + * @param String parent folder hash + * @return Boolean + */ + this.fileByName = function(name, phash) { + var hash; + + for (hash in files) { + if (files.hasOwnProperty(hash) && files[hash].phash == phash && files[hash].name == name) { + return files[hash]; + } + } + }; + + /** + * Valid data for required command based on rules + * + * @param String command name + * @param Object cammand's data + * @return Boolean + */ + this.validResponse = function(cmd, data) { + return data.error || this.rules[this.rules[cmd] ? cmd : 'defaults'](data); + }; + + /** + * Return bytes from ini formated size + * + * @param String ini formated size + * @return Integer + */ + this.returnBytes = function(val) { + var last; + if (isNaN(val)) { + if (! val) { + val = ''; + } + // for ex. 1mb, 1KB + val = val.replace(/b$/i, ''); + last = val.charAt(val.length - 1).toLowerCase(); + val = val.replace(/[tgmk]$/i, ''); + if (last == 't') { + val = val * 1024 * 1024 * 1024 * 1024; + } else if (last == 'g') { + val = val * 1024 * 1024 * 1024; + } else if (last == 'm') { + val = val * 1024 * 1024; + } else if (last == 'k') { + val = val * 1024; + } + val = isNaN(val)? 0 : parseInt(val); + } else { + val = parseInt(val); + if (val < 1) val = 0; + } + return val; + }; + + /** + * Proccess ajax request. + * Fired events : + * @todo + * @example + * @todo + * @return $.Deferred + */ + this.request = function(opts) { + var self = this, + o = this.options, + dfrd = $.Deferred(), + // request ID + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16), + // request data + data = Object.assign({}, o.customData, {mimes : o.onlyMimes}, opts.data || opts), + // command name + cmd = data.cmd, + // current cmd is "open" + isOpen = (!opts.asNotOpen && cmd === 'open'), + // call default fail callback (display error dialog) ? + deffail = !(opts.preventDefault || opts.preventFail), + // call default success callback ? + defdone = !(opts.preventDefault || opts.preventDone), + // options for notify dialog + notify = Object.assign({}, opts.notify), + // make cancel button + cancel = !!opts.cancel, + // do not normalize data - return as is + raw = !!opts.raw, + // sync files on request fail + syncOnFail = opts.syncOnFail, + // use lazy() + lazy = !!opts.lazy, + // prepare function before done() + prepare = opts.prepare, + // navigate option object when cmd done + navigate = opts.navigate, + // open notify dialog timeout + timeout, + // request options + options = Object.assign({ + url : o.url, + async : true, + type : this.requestType, + dataType : 'json', + cache : (self.api >= 2.1029), // api >= 2.1029 has unique request ID + data : data, + headers : this.customHeaders, + xhrFields: this.xhrFields + }, opts.options || {}), + /** + * Default success handler. + * Call default data handlers and fire event with command name. + * + * @param Object normalized response data + * @return void + **/ + done = function(data) { + data.warning && self.error(data.warning); + + if (isOpen) { + open(data); + } else { + self.updateCache(data); + } + + data.changed && data.changed.length && change(data.changed); + + self.lazy(function() { + // fire some event to update cache/ui + data.removed && data.removed.length && self.remove(data); + data.added && data.added.length && self.add(data); + data.changed && data.changed.length && self.change(data); + }).then(function() { + // fire event with command name + return self.lazy(function() { + self.trigger(cmd, data, false); + }); + }).then(function() { + // fire event with command name + 'done' + return self.lazy(function() { + self.trigger(cmd + 'done'); + }); + }).then(function() { + // force update content + data.sync && self.sync(); + }); + }, + /** + * Request error handler. Reject dfrd with correct error message. + * + * @param jqxhr request object + * @param String request status + * @return void + **/ + error = function(xhr, status) { + var error, data, + d = self.options.debug; + + switch (status) { + case 'abort': + error = xhr.quiet ? '' : ['errConnect', 'errAbort']; + break; + case 'timeout': + error = ['errConnect', 'errTimeout']; + break; + case 'parsererror': + error = ['errResponse', 'errDataNotJSON']; + if (xhr.responseText) { + if (! cwd || (d && (d === 'all' || d['backend-error']))) { + error.push(xhr.responseText); + } + } + break; + default: + if (xhr.responseText) { + // check responseText, Is that JSON? + try { + data = JSON.parse(xhr.responseText); + if (data && data.error) { + error = data.error; + } + } catch(e) {} + } + if (! error) { + if (xhr.status == 403) { + error = ['errConnect', 'errAccess', 'HTTP error ' + xhr.status]; + } else if (xhr.status == 404) { + error = ['errConnect', 'errNotFound', 'HTTP error ' + xhr.status]; + } else if (xhr.status >= 500) { + error = ['errResponse', 'errServerError', 'HTTP error ' + xhr.status]; + } else { + if (xhr.status == 414 && options.type === 'get') { + // retry by POST method + options.type = 'post'; + self.abortXHR(xhr); + dfrd.xhr = xhr = self.transport.send(options).fail(error).done(success); + return; + } + error = xhr.quiet ? '' : ['errConnect', 'HTTP error ' + xhr.status]; + } + } + } + + self.trigger(cmd + 'done'); + dfrd.reject(error, xhr, status); + }, + /** + * Request success handler. Valid response data and reject/resolve dfrd. + * + * @param Object response data + * @param String request status + * @return void + **/ + success = function(response) { + var d = self.options.debug; + + // Set currrent request command name + self.currentReqCmd = cmd; + + if (response.debug && (!d || (d !== 'all' && !d['backend-error']))) { + if (!d) { + self.options.debug = {}; + } + self.options.debug['backend-error'] = true + } + + if (raw) { + self.abortXHR(xhr); + response && response.debug && self.debug('backend-debug', response); + return dfrd.resolve(response); + } + + if (!response) { + return dfrd.reject(['errResponse', 'errDataEmpty'], xhr, response); + } else if (!$.isPlainObject(response)) { + return dfrd.reject(['errResponse', 'errDataNotJSON'], xhr, response); + } else if (response.error) { + return dfrd.reject(response.error, xhr, response); + } + + var resolve = function() { + var pushLeafRoots = function(name) { + if (self.leafRoots[data.target] && response[name]) { + $.each(self.leafRoots[data.target], function(i, h) { + var root; + if (root = self.file(h)) { + response[name].push(root); + } + }); + } + }, + setTextMimes = function() { + self.textMimes = {}; + $.each(self.resources.mimes.text, function() { + self.textMimes[this] = true; + }); + }, + actionTarget; + + if (isOpen) { + pushLeafRoots('files'); + } else if (cmd === 'tree') { + pushLeafRoots('tree'); + } + + response = self.normalize(response); + + if (!self.validResponse(cmd, response)) { + return dfrd.reject((response.norError || 'errResponse'), xhr, response); + } + + if (!self.api) { + self.api = response.api || 1; + if (self.api == '2.0' && typeof response.options.uploadMaxSize !== 'undefined') { + self.api = '2.1'; + } + self.newAPI = self.api >= 2; + self.oldAPI = !self.newAPI; + } + + if (response.textMimes && Array.isArray(response.textMimes)) { + self.resources.mimes.text = response.textMimes; + setTextMimes(); + } + !self.textMimes && setTextMimes(); + + if (response.options) { + cwdOptions = Object.assign({}, cwdOptionsDefault, response.options); + } + + if (response.netDrivers) { + self.netDrivers = response.netDrivers; + } + + if (response.maxTargets) { + self.maxTargets = response.maxTargets; + } + + if (isOpen && !!data.init) { + self.uplMaxSize = self.returnBytes(response.uplMaxSize); + self.uplMaxFile = !!response.uplMaxFile? parseInt(response.uplMaxFile) : 20; + } + + if (typeof prepare === 'function') { + prepare(response); + } + + if (navigate) { + actionTarget = navigate.target || 'added'; + if (response[actionTarget] && response[actionTarget].length) { + self.one(cmd + 'done', function() { + var targets = response[actionTarget], + newItems = self.findCwdNodes(targets), + inCwdHashes = function() { + var cwdHash = self.cwd().hash; + return $.map(targets, function(f) { return (f.phash && cwdHash === f.phash)? f.hash : null; }); + }, + hashes = inCwdHashes(), + makeToast = function(t) { + var node = void(0), + data = t.action? t.action.data : void(0), + cmd, msg, done; + if ((data || hashes.length) && t.action && (msg = t.action.msg) && (cmd = t.action.cmd) && (!t.action.cwdNot || t.action.cwdNot !== self.cwd().hash)) { + done = t.action.done; + data = t.action.data; + node = $('

') + .append( + $('') + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass('ui-state-hover', e.type == 'mouseenter'); + }) + .on('click', function() { + self.exec(cmd, data || hashes, {_userAction: true, _currentType: 'toast', _currentNode: $(this) }); + if (done) { + self.one(cmd+'done', function() { + if (typeof done === 'function') { + done(); + } else if (done === 'select') { + self.trigger('selectfiles', {files : inCwdHashes()}); + } + }); + } + }) + ); + } + delete t.action; + t.extNode = node; + return t; + }; + + if (! navigate.toast) { + navigate.toast = {}; + } + + !navigate.noselect && self.trigger('selectfiles', {files : self.searchStatus.state > 1 ? $.map(targets, function(f) { return f.hash; }) : hashes}); + + if (newItems.length) { + if (!navigate.noscroll) { + newItems.first().trigger('scrolltoview', {blink : false}); + self.resources.blink(newItems, 'lookme'); + } + if ($.isPlainObject(navigate.toast.incwd)) { + self.toast(makeToast(navigate.toast.incwd)); + } + } else { + if ($.isPlainObject(navigate.toast.inbuffer)) { + self.toast(makeToast(navigate.toast.inbuffer)); + } + } + }); + } + } + + dfrd.resolve(response); + + response.debug && self.debug('backend-debug', response); + }; + self.abortXHR(xhr); + lazy? self.lazy(resolve) : resolve(); + }, + xhr, _xhr, + xhrAbort = function(e) { + if (xhr && xhr.state() === 'pending') { + self.abortXHR(xhr, { quiet: true , abort: true }); + if (!e || (e.type !== 'unload' && e.type !== 'destroy')) { + self.autoSync(); + } + } + }, + abort = function(e){ + self.trigger(cmd + 'done'); + if (e.type == 'autosync') { + if (e.data.action != 'stop') return; + } else if (e.type != 'unload' && e.type != 'destroy' && e.type != 'openxhrabort') { + if (!e.data.added || !e.data.added.length) { + return; + } + } + xhrAbort(e); + }, + request = function(mode) { + var queueAbort = function() { + syncOnFail = false; + dfrd.reject(); + }; + + if (mode) { + if (mode === 'cmd') { + return cmd; + } + } + + if (isOpen) { + if (requestQueueSkipOpen) { + return dfrd.reject(); + } + requestQueueSkipOpen = true; + } + + requestCnt++; + + dfrd.fail(function(error, xhr, response) { + // unset this cmd queue when user canceling + if (error === 0) { + if (requestQueue.length) { + requestQueue = $.map(requestQueue, function(req) { + return (req('cmd') === cmd) ? null : req; + }); + } + } + xhrAbort(); + self.trigger(cmd + 'fail', response); + if (error) { + deffail ? self.error(error) : self.debug('error', self.i18n(error)); + } + syncOnFail && self.sync(); + }) + + if (!cmd) { + syncOnFail = false; + return dfrd.reject('errCmdReq'); + } + + if (self.maxTargets && data.targets && data.targets.length > self.maxTargets) { + syncOnFail = false; + return dfrd.reject(['errMaxTargets', self.maxTargets]); + } + + defdone && dfrd.done(done); + + // quiet abort not completed "open" requests + if (isOpen) { + while ((_xhr = queue.pop())) { + _xhr.queueAbort(); + } + if (cwd !== data.target) { + while ((_xhr = cwdQueue.pop())) { + _xhr.queueAbort(); + } + } + } + + // trigger abort autoSync for commands to add the item + if ($.inArray(cmd, (self.cmdsToAdd + ' autosync').split(' ')) !== -1) { + if (cmd !== 'autosync') { + self.autoSync('stop'); + dfrd.always(function() { + self.autoSync(); + }); + } + self.trigger('openxhrabort'); + } + + delete options.preventFail + + if (self.api >= 2.1029) { + Object.assign(options.data, { reqid : reqId }); + } + + dfrd.xhr = xhr = self.transport.send(options).always(function() { + --requestCnt; + if (requestQueue.length) { + requestQueue.shift()(); + } else { + requestQueueSkipOpen = false; + } + }).fail(error).done(success); + + if (self.api >= 2.1029) { + xhr._requestId = reqId; + } + + // function for set value of this syncOnFail + dfrd.syncOnFail = function(state) { + syncOnFail = !!state; + } + + if (isOpen || (data.compare && cmd === 'info')) { + // regist function queueAbort + xhr.queueAbort = queueAbort; + // add autoSync xhr into queue + queue.unshift(xhr); + // bind abort() + data.compare && self.bind(self.cmdsToAdd + ' autosync openxhrabort', abort); + dfrd.always(function() { + var ndx = $.inArray(xhr, queue); + data.compare && self.unbind(self.cmdsToAdd + ' autosync openxhrabort', abort); + ndx !== -1 && queue.splice(ndx, 1); + }); + } else if ($.inArray(cmd, self.abortCmdsOnOpen) !== -1) { + // regist function queueAbort + xhr.queueAbort = queueAbort; + // add "open" xhr, only cwd xhr into queue + cwdQueue.unshift(xhr); + dfrd.always(function() { + var ndx = $.inArray(xhr, cwdQueue); + ndx !== -1 && cwdQueue.splice(ndx, 1); + }); + } + + // abort pending xhr on window unload or elFinder destroy + self.bind('unload destroy', abort); + dfrd.always(function() { + self.unbind('unload destroy', abort); + }); + + return dfrd; + }, + queueingRequest = function() { + // show notify + if (notify.type && notify.cnt) { + if (cancel) { + notify.cancel = dfrd; + } + timeout = setTimeout(function() { + self.notify(notify); + dfrd.always(function() { + notify.cnt = -(parseInt(notify.cnt)||0); + self.notify(notify); + }) + }, self.notifyDelay) + + dfrd.always(function() { + clearTimeout(timeout); + }); + } + // queueing + if (isOpen) { + requestQueueSkipOpen = false; + } + if (requestCnt < requestMaxConn) { + // do request + return request(); + } else { + if (isOpen) { + requestQueue.unshift(request); + } else { + requestQueue.push(request); + } + return dfrd; + } + }, + bindData = {opts: opts, result: true}; + + // trigger "request.cmd" that callback be able to cancel request by substituting "false" for "event.data.result" + self.trigger('request.' + cmd, bindData, true); + + if (! bindData.result) { + self.trigger(cmd + 'done'); + return dfrd.reject(); + } else if (typeof bindData.result === 'object' && bindData.result.promise) { + bindData.result + .done(queueingRequest) + .fail(function() { + self.trigger(cmd + 'done'); + dfrd.reject(); + }); + return dfrd; + } + + return queueingRequest(); + }; + + /** + * Call cache() + * Store info about files/dirs in "files" object. + * + * @param Array files + * @return void + */ + this.cache = function(dataArray) { + if (! Array.isArray(dataArray)) { + dataArray = [ dataArray ]; + } + cache(dataArray); + }; + + /** + * Update file object caches by respose data object + * + * @param Object respose data object + * @return void + */ + this.updateCache = function(data) { + if ($.isPlainObject(data)) { + data.files && data.files.length && cache(data.files, 'files'); + data.tree && data.tree.length && cache(data.tree, 'tree'); + data.removed && data.removed.length && remove(data.removed); + data.added && data.added.length && cache(data.added, 'add'); + data.changed && data.changed.length && change(data.changed, 'change'); + } + }; + + /** + * Compare current files cache with new files and return diff + * + * @param Array new files + * @param String target folder hash + * @param Array exclude properties to compare + * @return Object + */ + this.diff = function(incoming, onlydir, excludeProps) { + var raw = {}, + added = [], + removed = [], + changed = [], + excludes = null, + isChanged = function(hash) { + var l = changed.length; + + while (l--) { + if (changed[l].hash == hash) { + return true; + } + } + }; + + $.each(incoming, function(i, f) { + raw[f.hash] = f; + }); + + // make excludes object + if (excludeProps && excludeProps.length) { + excludes = {}; + $.each(excludeProps, function() { + excludes[this] = true; + }); + } + + // find removed + $.each(files, function(hash, f) { + if (! raw[hash] && (! onlydir || f.phash === onlydir)) { + removed.push(hash); + } + }); + + // compare files + $.each(raw, function(hash, file) { + var origin = files[hash], + orgKeys = {}, + chkKeyLen; + + if (!origin) { + added.push(file); + } else { + // make orgKeys object + $.each(Object.keys(origin), function() { + orgKeys[this] = true; + }); + $.each(file, function(prop) { + delete orgKeys[prop]; + if (! excludes || ! excludes[prop]) { + if (file[prop] !== origin[prop]) { + changed.push(file); + orgKeys = {}; + return false; + } + } + }); + chkKeyLen = Object.keys(orgKeys).length; + if (chkKeyLen !== 0) { + if (excludes) { + $.each(orgKeys, function(prop) { + if (excludes[prop]) { + --chkKeyLen; + } + }); + } + (chkKeyLen !== 0) && changed.push(file); + } + } + }); + + // parents of removed dirs mark as changed (required for tree correct work) + $.each(removed, function(i, hash) { + var file = files[hash], + phash = file.phash; + + if (phash + && file.mime == 'directory' + && $.inArray(phash, removed) === -1 + && raw[phash] + && !isChanged(phash)) { + changed.push(raw[phash]); + } + }); + + return { + added : added, + removed : removed, + changed : changed + }; + }; + + /** + * Sync content + * + * @return jQuery.Deferred + */ + this.sync = function(onlydir, polling) { + this.autoSync('stop'); + var self = this, + compare = function(){ + var c = '', cnt = 0, mtime = 0; + if (onlydir && polling) { + $.each(files, function(h, f) { + if (f.phash && f.phash === onlydir) { + ++cnt; + mtime = Math.max(mtime, f.ts); + } + c = cnt+':'+mtime; + }); + } + return c; + }, + comp = compare(), + dfrd = $.Deferred().done(function() { self.trigger('sync'); }), + opts = [this.request({ + data : {cmd : 'open', reload : 1, target : cwd, tree : (! onlydir && this.ui.tree) ? 1 : 0, compare : comp}, + preventDefault : true + })], + exParents = function() { + var parents = [], + curRoot = self.file(self.root(cwd)), + curId = curRoot? curRoot.volumeid : null, + phash = self.cwd().phash, + isroot,pdir; + + while(phash) { + if (pdir = self.file(phash)) { + if (phash.indexOf(curId) !== 0) { + parents.push( {target: phash, cmd: 'tree'} ); + if (! self.isRoot(pdir)) { + parents.push( {target: phash, cmd: 'parents'} ); + } + curRoot = self.file(self.root(phash)); + curId = curRoot? curRoot.volumeid : null; + } + phash = pdir.phash; + } else { + phash = null; + } + } + return parents; + }; + + if (! onlydir && self.api >= 2) { + (cwd !== this.root()) && opts.push(this.request({ + data : {cmd : 'parents', target : cwd}, + preventDefault : true + })); + $.each(exParents(), function(i, data) { + opts.push(self.request({ + data : {cmd : data.cmd, target : data.target}, + preventDefault : true + })); + }); + } + $.when.apply($, opts) + .fail(function(error, xhr) { + if (! polling || $.inArray('errOpen', error) !== -1) { + dfrd.reject(error); + error && self.request({ + data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true} + }); + } else { + dfrd.reject((error && xhr.status != 0)? error : void 0); + } + }) + .done(function(odata) { + var pdata, argLen, i; + + if (odata.cwd.compare) { + if (comp === odata.cwd.compare) { + return dfrd.reject(); + } + } + + // for 2nd and more requests + pdata = {tree : []}; + + // results marge of 2nd and more requests + argLen = arguments.length; + if (argLen > 1) { + for(i = 1; i < argLen; i++) { + if (arguments[i].tree && arguments[i].tree.length) { + pdata.tree.push.apply(pdata.tree, arguments[i].tree); + } + } + } + + if (self.api < 2.1) { + if (! pdata.tree) { + pdata.tree = []; + } + pdata.tree.push(odata.cwd); + } + + // data normalize + odata = self.normalize(odata); + if (!self.validResponse('open', odata)) { + return dfrd.reject((odata.norError || 'errResponse')); + } + pdata = self.normalize(pdata); + if (!self.validResponse('tree', pdata)) { + return dfrd.reject((pdata.norError || 'errResponse')); + } + + var diff = self.diff(odata.files.concat(pdata && pdata.tree ? pdata.tree : []), onlydir); + + diff.added.push(odata.cwd); + + self.updateCache(diff); + + // trigger events + diff.removed.length && self.remove(diff); + diff.added.length && self.add(diff); + diff.changed.length && self.change(diff); + return dfrd.resolve(diff); + }) + .always(function() { + self.autoSync(); + }); + + return dfrd; + }; + + this.upload = function(files) { + return this.transport.upload(files, this); + }; + + /** + * Arrays that has to unbind events + * + * @type Object + */ + this.toUnbindEvents = {}; + + /** + * Attach listener to events + * To bind to multiply events at once, separate events names by space + * + * @param String event(s) name(s) + * @param Object event handler + * @return elFinder + */ + this.bind = function(event, callback) { + var i, len; + + if (typeof(callback) == 'function') { + event = ('' + event).toLowerCase().replace(/^\s+|\s+$/g, '').split(/\s+/); + + len = event.length; + for (i = 0; i < len; i++) { + if (listeners[event[i]] === void(0)) { + listeners[event[i]] = []; + } + listeners[event[i]].push(callback); + } + } + return this; + }; + + /** + * Remove event listener if exists + * To un-bind to multiply events at once, separate events names by space + * + * @param String event(s) name(s) + * @param Function callback + * @return elFinder + */ + this.unbind = function(event, callback) { + var i, len, l, ci; + + event = ('' + event).toLowerCase().split(/\s+/); + + len = event.length; + for (i = 0; i < len; i++) { + if (l = listeners[event[i]]) { + ci = $.inArray(callback, l); + ci > -1 && l.splice(ci, 1); + } + } + + callback = null; + return this; + }; + + /** + * Fire event - send notification to all event listeners + * In the callback `this` becames an event object + * + * @param String event type + * @param Object data to send across event + * @param Boolean allow modify data (call by reference of data) default: true + * @return elFinder + */ + this.trigger = function(type, data, allowModify) { + var type = type.toLowerCase(), + isopen = (type === 'open'), + dataIsObj = (typeof data === 'object'), + handlers = listeners[type] || [], i, l, jst, event; + + this.debug('event-'+type, data); + + if (! dataIsObj || typeof allowModify === 'undefined') { + allowModify = true; + } + if (l = handlers.length) { + event = $.Event(type); + if (allowModify) { + event.data = data; + } + + for (i = 0; i < l; i++) { + if (! handlers[i]) { + // probably un-binded this handler + continue; + } + // set `event.data` only callback has argument + if (handlers[i].length) { + if (!allowModify) { + // to avoid data modifications. remember about "sharing" passing arguments in js :) + if (typeof jst === 'undefined') { + try { + jst = JSON.stringify(data); + } catch(e) { + jst = false; + } + } + event.data = jst? JSON.parse(jst) : data; + } + } + + try { + if (handlers[i].call(event, event, this) === false + || event.isDefaultPrevented()) { + this.debug('event-stoped', event.type); + break; + } + } catch (ex) { + window.console && window.console.log && window.console.log(ex); + } + + } + + if (this.toUnbindEvents[type] && this.toUnbindEvents[type].length) { + $.each(this.toUnbindEvents[type], function(i, v) { + self.unbind(v.type, v.callback); + }); + delete this.toUnbindEvents[type]; + } + } + return this; + }; + + /** + * Get event listeners + * + * @param String event type + * @return Array listed event functions + */ + this.getListeners = function(event) { + return event? listeners[event.toLowerCase()] : listeners; + }; + + /** + * Bind keybord shortcut to keydown event + * + * @example + * elfinder.shortcut({ + * pattern : 'ctrl+a', + * description : 'Select all files', + * callback : function(e) { ... }, + * keypress : true|false (bind to keypress instead of keydown) + * }) + * + * @param Object shortcut config + * @return elFinder + */ + this.shortcut = function(s) { + var patterns, pattern, code, i, parts; + + if (this.options.allowShortcuts && s.pattern && $.isFunction(s.callback)) { + patterns = s.pattern.toUpperCase().split(/\s+/); + + for (i= 0; i < patterns.length; i++) { + pattern = patterns[i] + parts = pattern.split('+'); + code = (code = parts.pop()).length == 1 + ? code > 0 ? code : code.charCodeAt(0) + : (code > 0 ? code : $.ui.keyCode[code]); + + if (code && !shortcuts[pattern]) { + shortcuts[pattern] = { + keyCode : code, + altKey : $.inArray('ALT', parts) != -1, + ctrlKey : $.inArray('CTRL', parts) != -1, + shiftKey : $.inArray('SHIFT', parts) != -1, + type : s.type || 'keydown', + callback : s.callback, + description : s.description, + pattern : pattern + }; + } + } + } + return this; + }; + + /** + * Registered shortcuts + * + * @type Object + **/ + this.shortcuts = function() { + var ret = []; + + $.each(shortcuts, function(i, s) { + ret.push([s.pattern, self.i18n(s.description)]); + }); + return ret; + }; + + /** + * Get/set clipboard content. + * Return new clipboard content. + * + * @example + * this.clipboard([]) - clean clipboard + * this.clipboard([{...}, {...}], true) - put 2 files in clipboard and mark it as cutted + * + * @param Array new files hashes + * @param Boolean cut files? + * @return Array + */ + this.clipboard = function(hashes, cut) { + var map = function() { return $.map(clipboard, function(f) { return f.hash }); }; + + if (hashes !== void(0)) { + clipboard.length && this.trigger('unlockfiles', {files : map()}); + remember = {}; + + clipboard = $.map(hashes||[], function(hash) { + var file = files[hash]; + if (file) { + + remember[hash] = true; + + return { + hash : hash, + phash : file.phash, + name : file.name, + mime : file.mime, + read : file.read, + locked : file.locked, + cut : !!cut + } + } + return null; + }); + this.trigger('changeclipboard', {clipboard : clipboard.slice(0, clipboard.length)}); + cut && this.trigger('lockfiles', {files : map()}); + } + + // return copy of clipboard instead of refrence + return clipboard.slice(0, clipboard.length); + }; + + /** + * Return true if command enabled + * + * @param String command name + * @param String|void hash for check of own volume's disabled cmds + * @return Boolean + */ + this.isCommandEnabled = function(name, dstHash) { + var disabled, + cvid = self.cwd().volumeid || ''; + + // In serach results use selected item hash to check + if (!dstHash && self.searchStatus.state > 1 && self.selected().length) { + dstHash = self.selected()[0]; + } + if (dstHash && (! cvid || dstHash.indexOf(cvid) !== 0)) { + disabled = self.option('disabled', dstHash); + if (! disabled) { + disabled = []; + } + } else { + disabled = cwdOptions.disabled; + } + return this._commands[name] ? $.inArray(name, disabled) === -1 : false; + }; + + /** + * Exec command and return result; + * + * @param String command name + * @param String|Array usualy files hashes + * @param String|Array command options + * @param String|void hash for enabled check of own volume's disabled cmds + * @return $.Deferred + */ + this.exec = function(cmd, files, opts, dstHash) { + var dfrd, resType; + + if (cmd === 'open') { + if (this.searchStatus.state || this.searchStatus.ininc) { + this.trigger('searchend', { noupdate: true }); + } + this.autoSync('stop'); + } + if (!dstHash && files) { + if ($.isArray(files)) { + if (files.length) { + dstHash = files[0]; + } + } else { + dstHash = files; + } + } + dfrd = this._commands[cmd] && this.isCommandEnabled(cmd, dstHash) + ? this._commands[cmd].exec(files, opts) + : $.Deferred().reject('No such command'); + + resType = typeof dfrd; + if (resType !== 'object' || ! dfrd instanceof $.Deferred) { + self.debug('warning', '"cmd.exec()" should be returned "$.Deferred" but cmd "' + cmd + '" returned "' + resType + '"'); + dfrd = $.Deferred().resolve(); + } + + this.trigger('exec', { dfrd : dfrd, cmd : cmd, files : files, opts : opts, dstHash : dstHash }); + return dfrd; + }; + + /** + * Create and return dialog. + * + * @param String|DOMElement dialog content + * @param Object dialog options + * @return jQuery + */ + this.dialog = function(content, options) { + var dialog = $('
').append(content).appendTo(node).elfinderdialog(options, this), + dnode = dialog.closest('.ui-dialog'), + resize = function(){ + ! dialog.data('draged') && dialog.is(':visible') && dialog.elfinderdialog('posInit'); + }; + if (dnode.length) { + self.bind('resize', resize); + dnode.on('remove', function() { + self.unbind('resize', resize); + }); + } + return dialog; + }; + + /** + * Create and return toast. + * + * @param Object toast options - see ui/toast.js + * @return jQuery + */ + this.toast = function(options) { + return $('
').appendTo(this.ui.toast).elfindertoast(options || {}, this); + }; + + /** + * Return UI widget or node + * + * @param String ui name + * @return jQuery + */ + this.getUI = function(ui) { + return this.ui[ui] || (ui? $() : node); + }; + + /** + * Return elFinder.command instance or instances array + * + * @param String command name + * @return Object | Array + */ + this.getCommand = function(name) { + return name === void(0) ? this._commands : this._commands[name]; + }; + + /** + * Resize elfinder node + * + * @param String|Number width + * @param String|Number height + * @return void + */ + this.resize = function(w, h) { + var getMargin = function() { + var m = node.outerHeight(true) - node.innerHeight(), + p = node; + + while(p.get(0) !== heightBase.get(0)) { + p = p.parent(); + m += p.outerHeight(true) - p.innerHeight(); + if (! p.parent().length) { + // reached the document + break; + } + } + return m; + }, + fit = ! node.hasClass('ui-resizable'), + prv = node.data('resizeSize') || {w: 0, h: 0}, + mt, size = {}; + + if (heightBase && heightBase.data('resizeTm')) { + clearTimeout(heightBase.data('resizeTm')); + // heightBase.off('resize.' + self.namespace, fitToBase); + } + + if (typeof h === 'string') { + if (mt = h.match(/^([0-9.]+)%$/)) { + // setup heightBase + if (! heightBase || ! heightBase.length) { + heightBase = $(window); + } + if (! heightBase.data('marginToMyNode')) { + heightBase.data('marginToMyNode', getMargin()); + } + if (! heightBase.data('fitToBaseFunc')) { + heightBase.data('fitToBaseFunc', function(e) { + var tm = heightBase.data('resizeTm'); + e.preventDefault(); + e.stopPropagation(); + tm && clearTimeout(tm); + if (! node.hasClass('elfinder-fullscreen')) { + heightBase.data('resizeTm', setTimeout(function() { + self.restoreSize(); + }, 50)); + } + }); + } + h = heightBase.height() * (mt[1] / 100) - heightBase.data('marginToMyNode'); + + heightBase.off('resize.' + self.namespace, heightBase.data('fitToBaseFunc')); + fit && heightBase.on('resize.' + self.namespace, heightBase.data('fitToBaseFunc')); + } + } + + node.css({ width : w, height : parseInt(h) }); + size.w = node.width(); + size.h = node.height(); + node.data('resizeSize', size); + if (size.w !== prv.w || size.h !== prv.h) { + node.trigger('resize'); + this.trigger('resize', {width : size.w, height : size.h}); + } + }; + + /** + * Restore elfinder node size + * + * @return elFinder + */ + this.restoreSize = function() { + this.resize(width, height); + }; + + this.show = function() { + node.show(); + this.enable().trigger('show'); + }; + + this.hide = function() { + if (this.options.enableAlways) { + prevEnabled = enabled; + enabled = false; + } + this.disable().trigger('hide'); + node.hide(); + }; + + /** + * Lazy execution function + * + * @param Object function + * @param Number delay + * @param Object options + * @return Object jQuery.Deferred + */ + this.lazy = function(func, delay, opts) { + var busy = function(state) { + var cnt = node.data('lazycnt'), + repaint; + + if (state) { + repaint = node.data('lazyrepaint')? false : opts.repaint; + if (! cnt) { + node.data('lazycnt', 1) + .addClass('elfinder-processing'); + } else { + node.data('lazycnt', ++cnt); + } + if (repaint) { + node.data('lazyrepaint', true).css('display'); // force repaint + } + } else { + if (cnt && cnt > 1) { + node.data('lazycnt', --cnt); + } else { + repaint = node.data('lazyrepaint'); + node.data('lazycnt', 0) + .removeData('lazyrepaint') + .removeClass('elfinder-processing'); + repaint && node.css('display'); // force repaint; + self.trigger('lazydone'); + } + } + }, + dfd = $.Deferred(); + + delay = delay || 0; + opts = opts || {}; + busy(true); + + setTimeout(function() { + dfd.resolve(func.call(dfd)); + busy(false); + }, delay); + + return dfd; + } + + /** + * Destroy this elFinder instance + * + * @return void + **/ + this.destroy = function() { + if (node && node[0].elfinder) { + node.hasClass('elfinder-fullscreen') && self.toggleFullscreen(node); + this.options.syncStart = false; + this.autoSync('forcestop'); + this.trigger('destroy').disable(); + clipboard = []; + selected = []; + listeners = {}; + shortcuts = {}; + $(window).off('.' + namespace); + $(document).off('.' + namespace); + self.trigger = function(){} + $(beeper).remove(); + node.off() + .removeData() + .empty() + .append(prevContent.contents()) + .attr('class', prevContent.attr('class')) + .attr('style', prevContent.attr('style')); + delete node[0].elfinder; + // restore kept events + $.each(prevEvents, function(n, arr) { + $.each(arr, function(i, o) { + node.on(o.type + (o.namespace? '.'+o.namespace : ''), o.selector, o.handler); + }); + }); + } + }; + + /** + * Start or stop auto sync + * + * @param String|Bool stop + * @return void + */ + this.autoSync = function(mode) { + var sync; + if (self.options.sync >= 1000) { + if (syncInterval) { + clearTimeout(syncInterval); + syncInterval = null; + self.trigger('autosync', {action : 'stop'}); + } + + if (mode === 'stop') { + ++autoSyncStop; + } else { + autoSyncStop = Math.max(0, --autoSyncStop); + } + + if (autoSyncStop || mode === 'forcestop' || ! self.options.syncStart) { + return; + } + + // run interval sync + sync = function(start){ + var timeout; + if (cwdOptions.syncMinMs && (start || syncInterval)) { + start && self.trigger('autosync', {action : 'start'}); + timeout = Math.max(self.options.sync, cwdOptions.syncMinMs); + syncInterval && clearTimeout(syncInterval); + syncInterval = setTimeout(function() { + var dosync = true, hash = cwd, cts; + if (cwdOptions.syncChkAsTs && files[hash] && (cts = files[hash].ts)) { + self.request({ + data : {cmd : 'info', targets : [hash], compare : cts, reload : 1}, + preventDefault : true + }) + .done(function(data){ + var ts; + dosync = true; + if (data.compare) { + ts = data.compare; + if (ts == cts) { + dosync = false; + } + } + if (dosync) { + self.sync(hash).always(function(){ + if (ts) { + // update ts for cache clear etc. + files[hash].ts = ts; + } + sync(); + }); + } else { + sync(); + } + }) + .fail(function(error, xhr){ + if (error && xhr.status != 0) { + self.error(error); + if ($.inArray('errOpen', error) !== -1) { + self.request({ + data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true} + }); + } + } else { + syncInterval = setTimeout(function() { + sync(); + }, timeout); + } + }); + } else { + self.sync(cwd, true).always(function(){ + sync(); + }); + } + }, timeout); + } + }; + sync(true); + } + }; + + /** + * Return bool is inside work zone of specific point + * + * @param Number event.pageX + * @param Number event.pageY + * @return Bool + */ + this.insideWorkzone = function(x, y, margin) { + var rectangle = this.getUI('workzone').data('rectangle'); + + margin = margin || 1; + if (x < rectangle.left + margin + || x > rectangle.left + rectangle.width + margin + || y < rectangle.top + margin + || y > rectangle.top + rectangle.height + margin) { + return false; + } + return true; + }; + + /** + * Target ui node move to last of children of elFinder node fot to show front + * + * @param Object target Target jQuery node object + */ + this.toFront = function(target) { + var lastnode = node.children(':last'); + target = $(target); + if (lastnode.get(0) !== target.get(0)) { + target.trigger('beforedommove') + .insertAfter(lastnode) + .trigger('dommove'); + } + }; + + /** + * Return css object for maximize + * + * @return Object + */ + this.getMaximizeCss = function() { + return { + width : '100%', + height : '100%', + margin : 0, + padding : 0, + top : 0, + left : 0, + display : 'block', + position: 'fixed', + zIndex : Math.max(self.zIndex? (self.zIndex + 1) : 0 , 1000), + maxWidth : '', + maxHeight: '' + }; + }; + + // Closure for togglefullscreen + (function() { + // check is in iframe + if (inFrame && self.UA.Fullscreen) { + self.UA.Fullscreen = false; + if (parentIframe && typeof parentIframe.attr('allowfullscreen') !== 'undefined') { + self.UA.Fullscreen = true; + } + } + + var orgStyle, bodyOvf, resizeTm, fullElm, exitFull, toFull, + cls = 'elfinder-fullscreen', + clsN = 'elfinder-fullscreen-native', + checkDialog = function() { + var t = 0, + l = 0; + $.each(node.children('.ui-dialog,.ui-draggable'), function(i, d) { + var $d = $(d), + pos = $d.position(); + + if (pos.top < 0) { + $d.css('top', t); + t += 20; + } + if (pos.left < 0) { + $d.css('left', l); + l += 20; + } + }); + }, + funcObj = self.UA.Fullscreen? { + // native full screen mode + + fullElm: function() { + return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null; + }, + + exitFull: function() { + if (document.exitFullscreen) { + return document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + return document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + return document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + return document.msExitFullscreen(); + } + }, + + toFull: function(elem) { + if (elem.requestFullscreen) { + return elem.requestFullscreen(); + } else if (elem.webkitRequestFullscreen) { + return elem.webkitRequestFullscreen(); + } else if (elem.mozRequestFullScreen) { + return elem.mozRequestFullScreen(); + } else if (elem.msRequestFullscreen) { + return elem.msRequestFullscreen(); + } + return false; + } + } : { + // node element maximize mode + + fullElm: function() { + var full; + if (node.hasClass(cls)) { + return node.get(0); + } else { + full = node.find('.' + cls); + if (full.length) { + return full.get(0); + } + } + return null; + }, + + exitFull: function() { + var elm; + + $(window).off('resize.' + namespace, resize); + if (bodyOvf !== void(0)) { + $('body').css('overflow', bodyOvf); + } + bodyOvf = void(0); + + if (orgStyle) { + elm = orgStyle.elm; + restoreStyle(elm); + $(elm).trigger('resize', {fullscreen: 'off'}); + } + + $(window).trigger('resize'); + }, + + toFull: function(elem) { + bodyOvf = $('body').css('overflow') || ''; + $('body').css('overflow', 'hidden'); + + $(elem).css(self.getMaximizeCss()) + .addClass(cls) + .trigger('resize', {fullscreen: 'on'}); + + checkDialog(); + + $(window).on('resize.' + namespace, resize).trigger('resize'); + + return true; + } + }, + restoreStyle = function(elem) { + if (orgStyle && orgStyle.elm == elem) { + $(elem).removeClass(cls + ' ' + clsN).attr('style', orgStyle.style); + orgStyle = null; + } + }, + resize = function(e) { + var elm; + if (e.target === window) { + resizeTm && clearTimeout(resizeTm); + resizeTm = setTimeout(function() { + if (elm = funcObj.fullElm()) { + $(elm).trigger('resize', {fullscreen: 'on'}); + } + }, 100); + } + }; + + $(document).on('fullscreenchange.' + namespace + ' webkitfullscreenchange.' + namespace + ' mozfullscreenchange.' + namespace + ' MSFullscreenChange.' + namespace, function(e){ + if (self.UA.Fullscreen) { + var elm = funcObj.fullElm(), + win = $(window); + + resizeTm && clearTimeout(resizeTm); + if (elm === null) { + win.off('resize.' + namespace, resize); + if (orgStyle) { + elm = orgStyle.elm; + restoreStyle(elm); + $(elm).trigger('resize', {fullscreen: 'off'}); + } + } else { + $(elm).addClass(cls + ' ' + clsN) + .attr('style', 'width:100%; height:100%; margin:0; padding:0;') + .trigger('resize', {fullscreen: 'on'}); + win.on('resize.' + namespace, resize); + checkDialog(); + } + win.trigger('resize'); + } + }); + + /** + * Toggle Full Scrren Mode + * + * @param Object target + * @param Bool full + * @return Object | Null DOM node object of current full scrren + */ + self.toggleFullscreen = function(target, full) { + var elm = $(target).get(0), + curElm = null; + + curElm = funcObj.fullElm(); + if (curElm) { + if (curElm == elm) { + if (full === true) { + return curElm; + } + } else { + if (full === false) { + return curElm; + } + } + funcObj.exitFull(); + return null; + } else { + if (full === false) { + return null; + } + } + + orgStyle = {elm: elm, style: $(elm).attr('style')}; + if (funcObj.toFull(elm) !== false) { + return elm; + } else { + orgStyle = null; + return null; + } + }; + })(); + + // Closure for toggleMaximize + (function(){ + var cls = 'elfinder-maximized', + resizeTm, + resize = function(e) { + if (e.target === window && e.data && e.data.elm) { + var elm = e.data.elm; + resizeTm && clearTimeout(resizeTm); + resizeTm = setTimeout(function() { + elm.trigger('resize', {maximize: 'on'}); + }, 100); + } + }, + exitMax = function(elm) { + $(window).off('resize.' + namespace, resize); + $('body').css('overflow', elm.data('bodyOvf')); + elm.removeClass(cls) + .attr('style', elm.data('orgStyle')) + .removeData('bodyOvf') + .removeData('orgStyle'); + elm.trigger('resize', {maximize: 'off'}); + }, + toMax = function(elm) { + elm.data('bodyOvf', $('body').css('overflow') || '') + .data('orgStyle', elm.attr('style')) + .addClass(cls) + .css(self.getMaximizeCss()); + $('body').css('overflow', 'hidden'); + $(window).on('resize.' + namespace, {elm: elm}, resize); + elm.trigger('resize', {maximize: 'on'}); + }; + + /** + * Toggle Maximize target node + * + * @param Object target + * @param Bool max + * @return void + */ + self.toggleMaximize = function(target, max) { + var elm = $(target), + maximized = elm.hasClass(cls); + + if (maximized) { + if (max === true) { + return; + } + exitMax(elm); + } else { + if (max === false) { + return; + } + toMax(elm); + } + }; + })(); + + /************* init stuffs ****************/ + + // check jquery ui + if (!($.fn.selectable && $.fn.draggable && $.fn.droppable && $.fn.resizable)) { + return alert(this.i18n('errJqui')); + } + + // check node + if (!node.length) { + return alert(this.i18n('errNode')); + } + // check connector url + if (!this.options.url) { + return alert(this.i18n('errURL')); + } + + Object.assign($.ui.keyCode, { + 'F1' : 112, + 'F2' : 113, + 'F3' : 114, + 'F4' : 115, + 'F5' : 116, + 'F6' : 117, + 'F7' : 118, + 'F8' : 119, + 'F9' : 120, + 'F10' : 121, + 'F11' : 122, + 'F12' : 123, + 'DIG0' : 48, + 'DIG1' : 49, + 'DIG2' : 50, + 'DIG3' : 51, + 'DIG4' : 52, + 'DIG5' : 53, + 'DIG6' : 54, + 'DIG7' : 55, + 'DIG8' : 56, + 'DIG9' : 57, + 'NUM0' : 96, + 'NUM1' : 97, + 'NUM2' : 98, + 'NUM3' : 99, + 'NUM4' : 100, + 'NUM5' : 101, + 'NUM6' : 102, + 'NUM7' : 103, + 'NUM8' : 104, + 'NUM9' : 105, + 'CONTEXTMENU' : 93 + }); + + this.dragUpload = false; + this.xhrUpload = (typeof XMLHttpRequestUpload != 'undefined' || typeof XMLHttpRequestEventTarget != 'undefined') && typeof File != 'undefined' && typeof FormData != 'undefined'; + + // configure transport object + this.transport = {}; + + if (typeof(this.options.transport) == 'object') { + this.transport = this.options.transport; + if (typeof(this.transport.init) == 'function') { + this.transport.init(this) + } + } + + if (typeof(this.transport.send) != 'function') { + this.transport.send = function(opts) { return $.ajax(opts); } + } + + if (this.transport.upload == 'iframe') { + this.transport.upload = $.proxy(this.uploads.iframe, this); + } else if (typeof(this.transport.upload) == 'function') { + this.dragUpload = !!this.options.dragUploadAllow; + } else if (this.xhrUpload && !!this.options.dragUploadAllow) { + this.transport.upload = $.proxy(this.uploads.xhr, this); + this.dragUpload = true; + } else { + this.transport.upload = $.proxy(this.uploads.iframe, this); + } + + /** + * Decoding 'raw' string converted to unicode + * + * @param String str + * @return String + */ + this.decodeRawString = $.isFunction(this.options.rawStringDecoder)? this.options.rawStringDecoder : function(str) { + var charCodes = function(str) { + var i, len, arr; + for (i=0,len=str.length,arr=[]; i= 0xd800 && c <= 0xdbff) { + scalars.push((c & 1023) + 64 << 10 | arr[++i] & 1023); + } else { + scalars.push(c); + } + } + return scalars; + }, + decodeUTF8 = function(arr) { + var i, len, c, str, char = String.fromCharCode; + for (i=0,len=arr.length,str=""; c=arr[i],i= 0xc2) { + str += char((c&31)<<6 | arr[++i]&63); + } else if (c <= 0xef && c >= 0xe0) { + str += char((c&15)<<12 | (arr[++i]&63)<<6 | arr[++i]&63); + } else if (c <= 0xf7 && c >= 0xf0) { + str += char( + 0xd800 | ((c&7)<<8 | (arr[++i]&63)<<2 | arr[++i]>>>4&3) - 64, + 0xdc00 | (arr[i++]&15)<<6 | arr[i]&63 + ); + } else { + str += char(0xfffd); + } + } + return str; + }; + + return decodeUTF8(scalarValues(str)); + }; + + /** + * Alias for this.trigger('error', {error : 'message'}) + * + * @param String error message + * @return elFinder + **/ + this.error = function() { + var arg = arguments[0], + opts = arguments[1] || null; + return arguments.length == 1 && typeof(arg) == 'function' + ? self.bind('error', arg) + : (arg === true? this : self.trigger('error', {error : arg, opts : opts})); + }; + + // create bind/trigger aliases for build-in events + $.each(events, function(i, name) { + self[name] = function() { + var arg = arguments[0]; + return arguments.length == 1 && typeof(arg) == 'function' + ? self.bind(name, arg) + : self.trigger(name, $.isPlainObject(arg) ? arg : {}); + } + }); + + // bind core event handlers + this + .enable(function() { + if (!enabled && self.visible() && self.ui.overlay.is(':hidden') && ! node.children('.elfinder-dialog').find('.'+self.res('class', 'editing')).length) { + enabled = true; + document.activeElement && document.activeElement.blur(); + node.removeClass('elfinder-disabled'); + } + }) + .disable(function() { + prevEnabled = enabled; + enabled = false; + node.addClass('elfinder-disabled'); + }) + .open(function() { + selected = []; + }) + .select(function(e) { + var cnt = 0, + unselects = []; + selected = $.map(e.data.selected || e.data.value|| [], function(hash) { + if (unselects.length || (self.maxTargets && ++cnt > self.maxTargets)) { + unselects.push(hash); + return null; + } else { + return files[hash] ? hash : null; + } + }); + if (unselects.length) { + self.trigger('unselectfiles', {files: unselects, inselect: true}); + self.toast({mode: 'warning', msg: self.i18n(['errMaxTargets', self.maxTargets])}); + } + }) + .error(function(e) { + var opts = { + cssClass : 'elfinder-dialog-error', + title : self.i18n(self.i18n('error')), + resizable : false, + destroyOnClose : true, + buttons : {} + }; + + opts.buttons[self.i18n(self.i18n('btnClose'))] = function() { $(this).elfinderdialog('close'); }; + + if (e.data.opts && $.isPlainObject(e.data.opts)) { + Object.assign(opts, e.data.opts); + } + + self.dialog(''+self.i18n(e.data.error), opts); + }) + .bind('tmb', function(e) { + $.each(e.data.images||[], function(hash, tmb) { + if (files[hash]) { + files[hash].tmb = tmb; + } + }) + }) + .bind('searchstart', function(e) { + Object.assign(self.searchStatus, e.data); + self.searchStatus.state = 1; + }) + .bind('search', function(e) { + self.searchStatus.state = 2; + }) + .bind('searchend', function() { + self.searchStatus.state = 0; + self.searchStatus.ininc = false; + self.searchStatus.mixed = false; + }) + + ; + + // We listen and emit a sound on delete according to option + if (true === this.options.sound) { + this.bind('playsound', function(e) { + var play = beeper.canPlayType && beeper.canPlayType('audio/wav; codecs="1"'), + file = e.data && e.data.soundFile; + + play && file && play != '' && play != 'no' && $(beeper).html('')[0].play(); + }); + } + + // bind external event handlers + $.each(this.options.handlers, function(event, callback) { + self.bind(event, callback); + }); + + /** + * History object. Store visited folders + * + * @type Object + **/ + this.history = new this.history(this); + + /** + * Root hashed + * + * @type Object + */ + this.roots = {}; + + /** + * leaf roots + * + * @type Object + */ + this.leafRoots = {}; + + /** + * Loaded commands + * + * @type Object + **/ + this._commands = {}; + + if (!Array.isArray(this.options.commands)) { + this.options.commands = []; + } + + if ($.inArray('*', this.options.commands) !== -1) { + this.options.commands = Object.keys(this.commands); + } + + /** + * UI command map of cwd volume ( That volume driver option `uiCmdMap` ) + * + * @type Object + **/ + this.commandMap = {}; + + /** + * cwd options of each volume + * key: volumeid + * val: options object + * + * @type Object + */ + this.volOptions = {}; + + /** + * Hash of trash holders + * key: trash folder hash + * val: source volume hash + * + * @type Object + */ + this.trashes = {}; + + /** + * cwd options of each folder/file + * key: hash + * val: options object + * + * @type Object + */ + this.optionsByHashes = {}; + + /** + * UI Auto Hide Functions + * Each auto hide function mast be call to `fm.trigger('uiautohide')` at end of process + * + * @type Array + **/ + this.uiAutoHide = []; + + // trigger `uiautohide` + this.one('open', function() { + if (self.uiAutoHide.length) { + setTimeout(function() { + self.trigger('uiautohide'); + }, 500); + } + }); + + // Auto Hide Functions sequential processing start + this.bind('uiautohide', function() { + if (self.uiAutoHide.length) { + self.uiAutoHide.shift()(); + } + }); + + if (this.options.width) { + width = this.options.width; + } + + if (this.options.height) { + height = this.options.height; + } + + if (this.options.heightBase) { + heightBase = $(this.options.heightBase); + } + + if (this.options.soundPath) { + soundPath = this.options.soundPath.replace(/\/+$/, '') + '/'; + } + + // attach events to document + $(document) + // disable elfinder on click outside elfinder + .on('click.'+namespace, function(e) { enabled && ! self.options.enableAlways && !$(e.target).closest(node).length && self.disable(); }) + // exec shortcuts + .on(keydown+' '+keypress, execShortcut); + + // attach events to window + self.options.useBrowserHistory && $(window) + .on('popstate.' + namespace, function(ev) { + var target = ev.originalEvent.state && ev.originalEvent.state.thash; + target && !$.isEmptyObject(self.files()) && self.request({ + data : {cmd : 'open', target : target, onhistory : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true}, + syncOnFail : true + }); + }); + + (function(){ + var tm; + $(window).on('resize.' + namespace, function(e){ + if (e.target === this) { + tm && clearTimeout(tm); + tm = setTimeout(function() { + self.trigger('resize', {width : node.width(), height : node.height()}); + }, 100); + } + }) + .on('beforeunload.' + namespace,function(e){ + var msg, cnt; + if (node.is(':visible')) { + if (self.ui.notify.children().length && $.inArray('hasNotifyDialog', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('ntfsmth'); + } else if (node.find('.'+self.res('class', 'editing')).length && $.inArray('editingFile', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('editingFile'); + } else if ((cnt = Object.keys(self.selected()).length) && $.inArray('hasSelectedItem', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('hasSelected', ''+cnt); + } else if ((cnt = Object.keys(self.clipboard()).length) && $.inArray('hasClipboardData', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('hasClipboard', ''+cnt); + } + if (msg) { + e.returnValue = msg; + return msg; + } + } + self.trigger('unload'); + }); + })(); + + // bind window onmessage for CORS + $(window).on('message.' + namespace, function(e){ + var res = e.originalEvent || null, + obj, data; + if (res && self.uploadURL.indexOf(res.origin) === 0) { + try { + obj = JSON.parse(res.data); + data = obj.data || null; + if (data) { + if (data.error) { + if (obj.bind) { + self.trigger(obj.bind+'fail', data); + } + self.error(data.error); + } else { + data.warning && self.error(data.warning); + self.updateCache(data); + data.removed && data.removed.length && self.remove(data); + data.added && data.added.length && self.add(data); + data.changed && data.changed.length && self.change(data); + if (obj.bind) { + self.trigger(obj.bind, data); + self.trigger(obj.bind+'done'); + } + data.sync && self.sync(); + } + } + } catch (e) { + self.sync(); + } + } + }); + + // elFinder enable always + if (self.options.enableAlways) { + $(window).on('focus.' + namespace, function(e){ + (e.target === this) && self.enable(); + }); + if (inFrame) { + $(window.top).on('focus.' + namespace, function() { + if (self.enable() && (! parentIframe || parentIframe.is(':visible'))) { + setTimeout(function() { + $(window).focus(); + }, 10); + } + }); + } + } else if (inFrame) { + $(window).on('blur.' + namespace, function(e){ + enabled && e.target === this && self.disable(); + }); + } + + // return focus to the window on click (elFInder in the frame) + if (inFrame) { + node.on('click', function(e) { + $(window).focus(); + }); + } + + // elFinder to enable by mouse over + if (this.options.enableByMouseOver) { + node.on('mouseenter', function(e) { + (inFrame) && $(window).focus(); + ! self.enabled() && self.enable(); + }); + } + + // store instance in node + node[0].elfinder = this; + + // auto load language file + dfrdsBeforeBootup.push((function() { + var lang = self.lang, + langJs = self.baseUrl + 'js/i18n/elfinder.' + lang + '.js', + dfd = $.Deferred().done(function() { + if (self.i18[lang]) { + self.lang = lang; + } + self.trigger('i18load'); + i18n = self.lang === 'en' + ? self.i18['en'] + : $.extend(true, {}, self.i18['en'], self.i18[self.lang]); + }); + + if (!self.i18[lang]) { + self.lang = 'en'; + if (typeof define === 'function' && define.amd) { + require([langJs], function() { + dfd.resolve(); + }, function() { + dfd.resolve(); + }); + } else { + self.loadScript([langJs], function() { + dfd.resolve(); + }, { + loadType: 'tag', + error : function() { + dfd.resolve(); + } + }); + } + } else { + dfd.resolve(); + } + return dfd; + })()); + + // elFinder boot up function + bootUp = function() { + /** + * Interface direction + * + * @type String + * @default "ltr" + **/ + self.direction = i18n.direction; + + /** + * i18 messages + * + * @type Object + **/ + self.messages = i18n.messages; + + /** + * Date/time format + * + * @type String + * @default "m.d.Y" + **/ + self.dateFormat = self.options.dateFormat || i18n.dateFormat; + + /** + * Date format like "Yesterday 10:20:12" + * + * @type String + * @default "{day} {time}" + **/ + self.fancyFormat = self.options.fancyDateFormat || i18n.fancyDateFormat; + + /** + * Date format for if upload file has not original unique name + * e.g. Clipboard image data, Image data taken with iOS + * + * @type String + * @default "ymd-His" + **/ + self.nonameDateFormat = (self.options.nonameDateFormat || i18n.nonameDateFormat).replace(/[\/\\]/g, '_'); + + /** + * Css classes + * + * @type String + **/ + self.cssClass = 'ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-' + +(self.direction == 'rtl' ? 'rtl' : 'ltr') + +(self.UA.Touch? (' elfinder-touch' + (self.options.resizable ? ' touch-punch' : '')) : '') + +(self.UA.Mobile? ' elfinder-mobile' : '') + +' '+self.options.cssClass; + + // prepare node + node.addClass(self.cssClass) + .on(mousedown, function() { + !enabled && self.enable(); + }); + + // draggable closure + (function() { + var ltr, wzRect, wzBottom, wzBottom2, nodeStyle, + keyEvt = keydown + 'draggable' + ' keyup.' + namespace + 'draggable'; + + /** + * Base draggable options + * + * @type Object + **/ + self.draggable = { + appendTo : node, + addClasses : false, + distance : 4, + revert : true, + refreshPositions : false, + cursor : 'crosshair', + cursorAt : {left : 50, top : 47}, + scroll : false, + start : function(e, ui) { + var helper = ui.helper, + targets = $.map(helper.data('files')||[], function(h) { + if (h) { + remember[h] = true; + return h; + } + return null; + }), + locked = false, + cnt, h; + + // fix node size + nodeStyle = node.attr('style'); + node.width(node.width()).height(node.height()); + + // set var for drag() + ltr = (self.direction === 'ltr'); + wzRect = self.getUI('workzone').data('rectangle'); + wzBottom = wzRect.top + wzRect.height; + wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true); + + self.draggingUiHelper = helper; + cnt = targets.length; + while (cnt--) { + h = targets[cnt]; + if (files[h].locked) { + locked = true; + helper.data('locked', true); + break; + } + } + !locked && self.trigger('lockfiles', {files : targets}); + + helper.data('autoScrTm', setInterval(function() { + if (helper.data('autoScr')) { + self.autoScroll[helper.data('autoScr')](helper.data('autoScrVal')); + } + }, 50)); + }, + drag : function(e, ui) { + var helper = ui.helper, + autoScr, autoUp, bottom; + + if ((autoUp = wzRect.top > e.pageY) || wzBottom2 < e.pageY) { + if (wzRect.cwdEdge > e.pageX) { + autoScr = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down'); + } else { + autoScr = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down'); + } + if (!autoUp) { + if (autoScr.substr(0, 3) === 'cwd') { + if (wzBottom < e.pageY) { + bottom = wzBottom; + } else { + autoScr = null; + } + } else { + bottom = wzBottom2; + } + } + if (autoScr) { + helper.data('autoScr', autoScr); + helper.data('autoScrVal', Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - bottom), 1.3)); + } + } + if (! autoScr) { + if (helper.data('autoScr')) { + helper.data('refreshPositions', 1).data('autoScr', null); + } + } + if (helper.data('refreshPositions') && $(this).elfUiWidgetInstance('draggable')) { + if (helper.data('refreshPositions') > 0) { + $(this).draggable('option', { refreshPositions : true, elfRefresh : true }); + helper.data('refreshPositions', -1); + } else { + $(this).draggable('option', { refreshPositions : false, elfRefresh : false }); + helper.data('refreshPositions', null); + } + } + }, + stop : function(e, ui) { + var helper = ui.helper, + files; + + $(document).off(keyEvt); + $(this).elfUiWidgetInstance('draggable') && $(this).draggable('option', { refreshPositions : false }); + self.draggingUiHelper = null; + self.trigger('focus').trigger('dragstop'); + if (! helper.data('droped')) { + files = $.map(helper.data('files')||[], function(h) { return h || null ;}); + self.trigger('unlockfiles', {files : files}); + self.trigger('selectfiles', {files : files}); + } + self.enable(); + + // restore node style + node.attr('style', nodeStyle); + + helper.data('autoScrTm') && clearInterval(helper.data('autoScrTm')); + }, + helper : function(e, ui) { + var element = this.id ? $(this) : $(this).parents('[id]:first'), + helper = $('
'), + icon = function(f) { + var mime = f.mime, i, tmb = self.tmb(f); + i = '
'; + if (tmb) { + i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML; + } + return i; + }, + hashes, l, ctr; + + self.draggingUiHelper && self.draggingUiHelper.stop(true, true); + + self.trigger('dragstart', {target : element[0], originalEvent : e}, true); + + hashes = element.hasClass(self.res('class', 'cwdfile')) + ? self.selected() + : [self.navId2Hash(element.attr('id'))]; + + helper.append(icon(files[hashes[0]])).data('files', hashes).data('locked', false).data('droped', false).data('namespace', namespace).data('dropover', 0); + + if ((l = hashes.length) > 1) { + helper.append(icon(files[hashes[l-1]]) + ''+l+''); + } + + $(document).on(keyEvt, function(e){ + var chk = (e.shiftKey||e.ctrlKey||e.metaKey); + if (ctr !== chk) { + ctr = chk; + if (helper.is(':visible') && helper.data('dropover') && ! helper.data('droped')) { + helper.toggleClass('elfinder-drag-helper-plus', helper.data('locked')? true : ctr); + self.trigger(ctr? 'unlockfiles' : 'lockfiles', {files : hashes, helper: helper}); + } + } + }); + + return helper; + } + }; + })(); + + // in getFileCallback set - change default actions on double click/enter/ctrl+enter + if (self.commands.getfile) { + if (typeof(self.options.getFileCallback) == 'function') { + self.bind('dblclick', function(e) { + e.preventDefault(); + self.exec('getfile').fail(function() { + self.exec('open', e.data && e.data.file? [ e.data.file ]: void(0)); + }); + }); + self.shortcut({ + pattern : 'enter', + description : self.i18n('cmdgetfile'), + callback : function() { self.exec('getfile').fail(function() { self.exec(self.OS == 'mac' ? 'rename' : 'open') }) } + }) + .shortcut({ + pattern : 'ctrl+enter', + description : self.i18n(self.OS == 'mac' ? 'cmdrename' : 'cmdopen'), + callback : function() { self.exec(self.OS == 'mac' ? 'rename' : 'open') } + }); + } else { + self.options.getFileCallback = null; + } + } + + // load commands + $.each(self.commands, function(name, cmd) { + var proto = Object.assign({}, cmd.prototype), + extendsCmd, opts; + if ($.isFunction(cmd) && !self._commands[name] && (cmd.prototype.forceLoad || $.inArray(name, self.options.commands) !== -1)) { + extendsCmd = cmd.prototype.extendsCmd || ''; + if (extendsCmd) { + if ($.isFunction(self.commands[extendsCmd])) { + cmd.prototype = Object.assign({}, base, new self.commands[extendsCmd](), cmd.prototype); + } else { + return true; + } + } else { + cmd.prototype = Object.assign({}, base, cmd.prototype); + } + self._commands[name] = new cmd(); + cmd.prototype = proto; + opts = self.options.commandsOptions[name] || {}; + if (extendsCmd && self.options.commandsOptions[extendsCmd]) { + opts = $.extend(true, {}, self.options.commandsOptions[extendsCmd], opts); + } + self._commands[name].setup(name, opts); + // setup linked commands + if (self._commands[name].linkedCmds.length) { + $.each(self._commands[name].linkedCmds, function(i, n) { + var lcmd = self.commands[n]; + if ($.isFunction(lcmd) && !self._commands[n]) { + lcmd.prototype = base; + self._commands[n] = new lcmd(); + self._commands[n].setup(n, self.options.commandsOptions[n]||{}); + } + }); + } + } + }); + + /** + * UI nodes + * + * @type Object + **/ + self.ui = { + // container for nav panel and current folder container + workzone : $('
').appendTo(node).elfinderworkzone(self), + // container for folders tree / places + navbar : $('
').appendTo(node).elfindernavbar(self, self.options.uiOptions.navbar || {}), + // container for for preview etc at below the navbar + navdock : $('
').appendTo(node).elfindernavdock(self, self.options.uiOptions.navdock || {}), + // contextmenu + contextmenu : $('
').appendTo(node).elfindercontextmenu(self), + // overlay + overlay : $('
').appendTo(node).elfinderoverlay({ + show : function() { self.disable(); }, + hide : function() { prevEnabled && self.enable(); } + }), + // current folder container + cwd : $('
').appendTo(node).elfindercwd(self, self.options.uiOptions.cwd || {}), + // notification dialog window + notify : self.dialog('', { + cssClass : 'elfinder-dialog-notify', + position : self.options.notifyDialog.position, + absolute : true, + resizable : false, + autoOpen : false, + closeOnEscape : false, + title : ' ', + width : parseInt(self.options.notifyDialog.width) + }), + statusbar : $('
').hide().appendTo(node), + toast : $('
').appendTo(node), + bottomtray : $('
').appendTo(node) + }; + + // load required ui + $.each(self.options.ui || [], function(i, ui) { + var name = 'elfinder'+ui, + opts = self.options.uiOptions[ui] || {}; + + if (!self.ui[ui] && $.fn[name]) { + // regist to self.ui before make instance + self.ui[ui] = $('<'+(opts.tag || 'div')+'/>').appendTo(node); + self.ui[ui][name](self, opts); + } + }); + + // update size + self.resize(width, height); + + // make node resizable + if (self.options.resizable) { + node.resizable({ + resize : function(e, ui) { + self.resize(ui.size.width, ui.size.height); + }, + handles : 'se', + minWidth : 300, + minHeight : 200 + }); + if (self.UA.Touch) { + node.addClass('touch-punch'); + } + } + + (function() { + var navbar = self.getUI('navbar'), + cwd = self.getUI('cwd').parent(); + + self.autoScroll = { + navbarUp : function(v) { + navbar.scrollTop(Math.max(0, navbar.scrollTop() - v)); + }, + navbarDown : function(v) { + navbar.scrollTop(navbar.scrollTop() + v); + }, + cwdUp : function(v) { + cwd.scrollTop(Math.max(0, cwd.scrollTop() - v)); + }, + cwdDown : function(v) { + cwd.scrollTop(cwd.scrollTop() + v); + } + }; + })(); + + // Swipe on the touch devices to show/hide of toolbar or navbar + if (self.UA.Touch) { + (function() { + var lastX, lastY, nodeOffset, nodeWidth, nodeTop, navbarW, toolbarH, + navbar = self.getUI('navbar'), + toolbar = self.getUI('toolbar'), + moveEv = 'touchmove.stopscroll', + moveTm, + moveOn = function(e) { + e.preventDefault(); + moveTm && clearTimeout(moveTm); + }, + moveOff = function() { + moveTm = setTimeout(function() { + node.off(moveEv); + }, 100); + }, + handleW, handleH = 50; + + navbar = navbar.children().length? navbar : null; + toolbar = toolbar.length? toolbar : null; + node.on('touchstart touchmove touchend', function(e) { + if (e.type === 'touchend') { + lastX = false; + lastY = false; + moveOff(); + return; + } + + var touches = e.originalEvent.touches || [{}], + x = touches[0].pageX || null, + y = touches[0].pageY || null, + ltr = (self.direction === 'ltr'), + navbarMode, treeWidth, swipeX, moveX, toolbarT, mode; + + if (x === null || y === null || (e.type === 'touchstart' && touches.length > 1)) { + return; + } + + if (e.type === 'touchstart') { + nodeOffset = node.offset(); + nodeWidth = node.width(); + if (navbar) { + lastX = false; + if (navbar.is(':hidden')) { + if (! handleW) { + handleW = Math.max(50, nodeWidth / 10) + } + if ((ltr? (x - nodeOffset.left) : (nodeWidth + nodeOffset.left - x)) < handleW) { + lastX = x; + } + } else if (! e.originalEvent._preventSwipeX) { + navbarW = navbar.width(); + if (ltr) { + swipeX = (x < nodeOffset.left + navbarW); + } else { + swipeX = (x > nodeOffset.left + nodeWidth - navbarW); + } + if (swipeX) { + handleW = Math.max(50, nodeWidth / 10); + lastX = x; + } else { + lastX = false; + } + } + } + if (toolbar) { + toolbarH = toolbar.height(); + nodeTop = nodeOffset.top; + if (y - nodeTop < (toolbar.is(':hidden')? handleH : (toolbarH + 30))) { + lastY = y; + node.on(moveEv, moveOn); + moveOff(); + } else { + lastY = false; + } + } + } else { + if (navbar && lastX !== false) { + navbarMode = (ltr? (lastX > x) : (lastX < x))? 'navhide' : 'navshow'; + moveX = Math.abs(lastX - x); + if (navbarMode === 'navhide' && moveX > navbarW * .6 + || (moveX > (navbarMode === 'navhide'? navbarW / 3 : 45) + && (navbarMode === 'navshow' + || (ltr? x < nodeOffset.left + 20 : x > nodeOffset.left + nodeWidth - 20) + )) + ) { + self.getUI('navbar').trigger(navbarMode, {handleW: handleW}); + lastX = false; + } + } + if (toolbar && lastY !== false ) { + toolbarT = toolbar.offset().top; + if (Math.abs(lastY - y) > Math.min(45, toolbarH / 3)) { + mode = (lastY > y)? 'slideUp' : 'slideDown'; + if (mode === 'slideDown' || toolbarT + 20 > y) { + if (toolbar.is(mode === 'slideDown' ? ':hidden' : ':visible')) { + toolbar.stop(true, true).trigger('toggle', {duration: 100, handleH: handleH}); + moveOff(); + } + lastY = false; + } + } + } + } + }); + })(); + } + + if (self.dragUpload) { + // add event listener for HTML5 DnD upload + (function() { + var isin = function(e) { + return (e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && $(e.target).closest('div.ui-dialog-content').length === 0); + }, + ent = 'native-drag-enter', + disable = 'native-drag-disable', + c = 'class', + navdir = self.res(c, 'navdir'), + droppable = self.res(c, 'droppable'), + dropover = self.res(c, 'adroppable'), + arrow = self.res(c, 'navarrow'), + clDropActive = self.res(c, 'adroppable'), + wz = self.getUI('workzone'), + ltr = (self.direction === 'ltr'), + clearTm = function() { + autoScrTm && clearTimeout(autoScrTm); + autoScrTm = null; + }, + wzRect, autoScrFn, autoScrTm; + + node.on('dragenter', function(e) { + clearTm(); + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + wzRect = wz.data('rectangle'); + } + }) + .on('dragleave', function(e) { + clearTm(); + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + } + }) + .on('dragover', function(e) { + var autoUp; + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + e.originalEvent.dataTransfer.dropEffect = 'none'; + if (! autoScrTm) { + autoScrTm = setTimeout(function() { + var wzBottom = wzRect.top + wzRect.height, + wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true), + fn; + if ((autoUp = e.pageY < wzRect.top) || e.pageY > wzBottom2 ) { + if (wzRect.cwdEdge > e.pageX) { + fn = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down'); + } else { + fn = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down'); + } + if (!autoUp) { + if (fn.substr(0, 3) === 'cwd') { + if (wzBottom < e.pageY) { + wzBottom2 = wzBottom; + } else { + fn = ''; + } + } + } + fn && self.autoScroll[fn](Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - wzBottom2), 1.3)); + } + autoScrTm = null; + }, 20); + } + } else { + clearTm(); + } + }) + .on('drop', function(e) { + clearTm(); + if (isin(e)) { + e.stopPropagation(); + e.preventDefault(); + } + }); + + node.on('dragenter', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget), + id = e.currentTarget.id || null, + cwd = null, + elfFrom; + if (!id) { // target is cwd + cwd = self.cwd(); + $elm.data(disable, false); + try { + $.each(e.originalEvent.dataTransfer.types, function(i, v){ + if (v.substr(0, 13) === 'elfinderfrom:') { + elfFrom = v.substr(13).toLowerCase(); + } + }); + } catch(e) {} + } + if (!cwd || (cwd.write && (!elfFrom || elfFrom !== (window.location.href + cwd.hash).toLowerCase()))) { + e.preventDefault(); + e.stopPropagation(); + $elm.data(ent, true); + $elm.addClass(clDropActive); + } else { + $elm.data(disable, true); + } + } + }) + .on('dragleave', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget); + e.preventDefault(); + e.stopPropagation(); + if ($elm.data(ent)) { + $elm.data(ent, false); + } else { + $elm.removeClass(clDropActive); + } + } + }) + .on('dragover', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget); + e.preventDefault(); + e.stopPropagation(); + e.originalEvent.dataTransfer.dropEffect = $elm.data(disable)? 'none' : 'copy'; + $elm.data(ent, false); + } + }) + .on('drop', '.native-droppable', function(e){ + if (e.originalEvent && e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget) + id; + e.preventDefault(); + e.stopPropagation(); + $elm.removeClass(clDropActive); + if (e.currentTarget.id) { + id = $elm.hasClass(navdir)? self.navId2Hash(e.currentTarget.id) : self.cwdId2Hash(e.currentTarget.id); + } else { + id = self.cwd().hash; + } + e.originalEvent._target = id; + self.exec('upload', {dropEvt: e.originalEvent, target: id}, void 0, id); + } + }); + })(); + } + + // trigger event cssloaded if cddAutoLoad disabled + if (self.cssloaded === null) { + // check css loaded and remove hide + (function() { + var loaded = function() { + node.data('cssautoloadHide').remove(); + node.removeData('cssautoloadHide'); + self.cssloaded = true; + self.trigger('cssloaded'); + }, + cnt, fi; + if (node.css('visibility') === 'hidden') { + cnt = 1000; // timeout 10 secs + fi = setInterval(function() { + if (--cnt < 0 || node.css('visibility') !== 'hidden') { + clearInterval(fi); + loaded(); + } + }, 10); + } else { + loaded(); + } + })(); + } else { + self.cssloaded = true; + self.trigger('cssloaded'); + } + + // calculate elFinder node z-index + self.zIndexCalc(); + + // send initial request and start to pray >_< + self.trigger('init') + .request({ + data : {cmd : 'open', target : self.startDir(), init : 1, tree : 1}, + preventDone : true, + notify : {type : 'open', cnt : 1, hideCnt : true}, + freeze : true + }) + .fail(function() { + self.trigger('fail').disable().lastDir(''); + listeners = {}; + shortcuts = {}; + $(document).add(node).off('.'+namespace); + self.trigger = function() { }; + }) + .done(function(data) { + var trashDisable = function(th) { + var src = self.file(self.trashes[th]), + d = self.options.debug, + error; + + if (src && src.volumeid) { + delete self.volOptions[src.volumeid].trashHash; + } + self.trashes[th] = false; + self.debug('backend-error', 'Trash hash "'+th+'" was not found or not writable.'); + }, + toChkTh = {}; + + // re-calculate elFinder node z-index + self.zIndexCalc(); + + self.load().debug('api', self.api); + // update ui's size after init + node.trigger('resize'); + // initial open + open(data); + self.trigger('open', data, false); + self.trigger('opendone'); + + if (inFrame && self.options.enableAlways) { + $(window).focus(); + } + + // check self.trashes + $.each(self.trashes, function(th) { + var dir = self.file(th), + src; + if (! dir) { + toChkTh[th] = true; + } else if (dir.mime !== 'directory' || ! dir.write) { + trashDisable(th); + } + }); + if (Object.keys(toChkTh).length) { + self.request({ + data : {cmd : 'info', targets : Object.keys(toChkTh)}, + preventDefault : true + }).done(function(data) { + if (data && data.files) { + $.each(data.files, function(i, dir) { + if (dir.mime === 'directory' && dir.write) { + delete toChkTh[dir.hash]; + } + }); + } + }).always(function() { + $.each(toChkTh, trashDisable); + }) + } + + }); + // self.timeEnd('load'); + // End of bootUp() + }; + + // call bootCallback function with elFinder instance, extraObject - { dfrdsBeforeBootup: dfrdsBeforeBootup } + if (bootCallback && typeof bootCallback === 'function') { + self.bootCallback = bootCallback; + bootCallback.call(node.get(0), self, { dfrdsBeforeBootup: dfrdsBeforeBootup }); + } + + // call dfrdsBeforeBootup functions then boot up elFinder + $.when.apply(null, dfrdsBeforeBootup).done(function() { + bootUp(); + }).fail(function(error) { + self.error(error); + }); +}; + +//register elFinder to global scope +if (typeof toGlobal === 'undefined' || toGlobal) { + window.elFinder = elFinder; +} + +/** + * Prototype + * + * @type Object + */ +elFinder.prototype = { + + uniqueid : 0, + + res : function(type, id) { + return this.resources[type] && this.resources[type][id]; + }, + + /** + * User os. Required to bind native shortcuts for open/rename + * + * @type String + **/ + OS : navigator.userAgent.indexOf('Mac') !== -1 ? 'mac' : navigator.userAgent.indexOf('Win') !== -1 ? 'win' : 'other', + + /** + * User browser UA. + * jQuery.browser: version deprecated: 1.3, removed: 1.9 + * + * @type Object + **/ + UA : (function(){ + var webkit = !document.uniqueID && !window.opera && !window.sidebar && window.localStorage && 'WebkitAppearance' in document.documentElement.style; + return { + // Browser IE <= IE 6 + ltIE6 : typeof window.addEventListener == "undefined" && typeof document.documentElement.style.maxHeight == "undefined", + // Browser IE <= IE 7 + ltIE7 : typeof window.addEventListener == "undefined" && typeof document.querySelectorAll == "undefined", + // Browser IE <= IE 8 + ltIE8 : typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined", + // Browser IE <= IE 9 + ltIE9 : document.uniqueID && document.documentMode <= 9, + // Browser IE <= IE 10 + ltIE10 : document.uniqueID && document.documentMode <= 10, + // Browser IE >= IE 11 + gtIE11 : document.uniqueID && document.documentMode >= 11, + IE : document.uniqueID, + Firefox : window.sidebar, + Opera : window.opera, + Webkit : webkit, + Chrome : webkit && window.chrome, + Safari : webkit && !window.chrome, + Mobile : typeof window.orientation != "undefined", + Touch : typeof window.ontouchstart != "undefined", + iOS : navigator.platform.match(/^iP(?:[ao]d|hone)/), + Fullscreen : (typeof (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen) !== 'undefined') + }; + })(), + + /** + * Current request command + * + * @type String + */ + currentReqCmd : '', + + /** + * Internationalization object + * + * @type Object + */ + i18 : { + en : { + translator : '', + language : 'English', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', + fancyDateFormat : '$1 H:i', + nonameDateFormat : 'ymd-His', + messages : {} + }, + months : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort : ['msJan', 'msFeb', 'msMar', 'msApr', 'msMay', 'msJun', 'msJul', 'msAug', 'msSep', 'msOct', 'msNov', 'msDec'], + + days : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + daysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + }, + + /** + * File mimetype to kind mapping + * + * @type Object + */ + kinds : { + 'unknown' : 'Unknown', + 'directory' : 'Folder', + 'group' : 'Selects', + 'symlink' : 'Alias', + 'symlink-broken' : 'AliasBroken', + 'application/x-empty' : 'TextPlain', + 'application/postscript' : 'Postscript', + 'application/vnd.ms-office' : 'MsOffice', + 'application/msword' : 'MsWord', + 'application/vnd.ms-word' : 'MsWord', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'MsWord', + 'application/vnd.ms-word.document.macroEnabled.12' : 'MsWord', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' : 'MsWord', + 'application/vnd.ms-word.template.macroEnabled.12' : 'MsWord', + 'application/vnd.ms-excel' : 'MsExcel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'MsExcel', + 'application/vnd.ms-excel.sheet.macroEnabled.12' : 'MsExcel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' : 'MsExcel', + 'application/vnd.ms-excel.template.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-excel.addin.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-powerpoint' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' : 'MsPP', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' : 'MsPP', + 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.template' : 'MsPP', + 'application/vnd.ms-powerpoint.template.macroEnabled.12' : 'MsPP', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.slide' : 'MsPP', + 'application/vnd.ms-powerpoint.slide.macroEnabled.12' : 'MsPP', + 'application/pdf' : 'PDF', + 'application/xml' : 'XML', + 'application/vnd.oasis.opendocument.text' : 'OO', + 'application/vnd.oasis.opendocument.text-template' : 'OO', + 'application/vnd.oasis.opendocument.text-web' : 'OO', + 'application/vnd.oasis.opendocument.text-master' : 'OO', + 'application/vnd.oasis.opendocument.graphics' : 'OO', + 'application/vnd.oasis.opendocument.graphics-template' : 'OO', + 'application/vnd.oasis.opendocument.presentation' : 'OO', + 'application/vnd.oasis.opendocument.presentation-template' : 'OO', + 'application/vnd.oasis.opendocument.spreadsheet' : 'OO', + 'application/vnd.oasis.opendocument.spreadsheet-template' : 'OO', + 'application/vnd.oasis.opendocument.chart' : 'OO', + 'application/vnd.oasis.opendocument.formula' : 'OO', + 'application/vnd.oasis.opendocument.database' : 'OO', + 'application/vnd.oasis.opendocument.image' : 'OO', + 'application/vnd.openofficeorg.extension' : 'OO', + 'application/x-shockwave-flash' : 'AppFlash', + 'application/flash-video' : 'Flash video', + 'application/x-bittorrent' : 'Torrent', + 'application/javascript' : 'JS', + 'application/rtf' : 'RTF', + 'application/rtfd' : 'RTF', + 'application/x-font-ttf' : 'TTF', + 'application/x-font-otf' : 'OTF', + 'application/x-rpm' : 'RPM', + 'application/x-web-config' : 'TextPlain', + 'application/xhtml+xml' : 'HTML', + 'application/docbook+xml' : 'DOCBOOK', + 'application/x-awk' : 'AWK', + 'application/x-gzip' : 'GZIP', + 'application/x-bzip2' : 'BZIP', + 'application/x-xz' : 'XZ', + 'application/zip' : 'ZIP', + 'application/x-zip' : 'ZIP', + 'application/x-rar' : 'RAR', + 'application/x-tar' : 'TAR', + 'application/x-7z-compressed' : '7z', + 'application/x-jar' : 'JAR', + 'text/plain' : 'TextPlain', + 'text/x-php' : 'PHP', + 'text/html' : 'HTML', + 'text/javascript' : 'JS', + 'text/css' : 'CSS', + 'text/rtf' : 'RTF', + 'text/rtfd' : 'RTF', + 'text/x-c' : 'C', + 'text/x-csrc' : 'C', + 'text/x-chdr' : 'CHeader', + 'text/x-c++' : 'CPP', + 'text/x-c++src' : 'CPP', + 'text/x-c++hdr' : 'CPPHeader', + 'text/x-shellscript' : 'Shell', + 'application/x-csh' : 'Shell', + 'text/x-python' : 'Python', + 'text/x-java' : 'Java', + 'text/x-java-source' : 'Java', + 'text/x-ruby' : 'Ruby', + 'text/x-perl' : 'Perl', + 'text/x-sql' : 'SQL', + 'text/xml' : 'XML', + 'text/x-comma-separated-values' : 'CSV', + 'text/x-markdown' : 'Markdown', + 'image/x-ms-bmp' : 'BMP', + 'image/jpeg' : 'JPEG', + 'image/gif' : 'GIF', + 'image/png' : 'PNG', + 'image/tiff' : 'TIFF', + 'image/x-targa' : 'TGA', + 'image/vnd.adobe.photoshop' : 'PSD', + 'image/xbm' : 'XBITMAP', + 'image/pxm' : 'PXM', + 'audio/mpeg' : 'AudioMPEG', + 'audio/midi' : 'AudioMIDI', + 'audio/ogg' : 'AudioOGG', + 'audio/mp4' : 'AudioMPEG4', + 'audio/x-m4a' : 'AudioMPEG4', + 'audio/wav' : 'AudioWAV', + 'audio/x-mp3-playlist' : 'AudioPlaylist', + 'video/x-dv' : 'VideoDV', + 'video/mp4' : 'VideoMPEG4', + 'video/mpeg' : 'VideoMPEG', + 'video/x-msvideo' : 'VideoAVI', + 'video/quicktime' : 'VideoMOV', + 'video/x-ms-wmv' : 'VideoWM', + 'video/x-flv' : 'VideoFlash', + 'video/x-matroska' : 'VideoMKV', + 'video/ogg' : 'VideoOGG' + }, + + /** + * File mimetype to file extention mapping + * + * @type Object + * @see elFinder.mimetypes.js + */ + mimeTypes : {}, + + /** + * Ajax request data validation rules + * + * @type Object + */ + rules : { + defaults : function(data) { + if (!data + || (data.added && !Array.isArray(data.added)) + || (data.removed && !Array.isArray(data.removed)) + || (data.changed && !Array.isArray(data.changed))) { + return false; + } + return true; + }, + open : function(data) { return data && data.cwd && data.files && $.isPlainObject(data.cwd) && Array.isArray(data.files); }, + tree : function(data) { return data && data.tree && Array.isArray(data.tree); }, + parents : function(data) { return data && data.tree && Array.isArray(data.tree); }, + tmb : function(data) { return data && data.images && ($.isPlainObject(data.images) || Array.isArray(data.images)); }, + upload : function(data) { return data && ($.isPlainObject(data.added) || Array.isArray(data.added));}, + search : function(data) { return data && data.files && Array.isArray(data.files)} + }, + + /** + * Commands costructors + * + * @type Object + */ + commands : {}, + + /** + * Commands to add the item (space delimited) + * + * @type String + */ + cmdsToAdd : 'archive duplicate extract mkdir mkfile paste rm upload', + + parseUploadData : function(text) { + var data; + + if (!$.trim(text)) { + return {error : ['errResponse', 'errDataEmpty']}; + } + + try { + data = JSON.parse(text); + } catch (e) { + return {error : ['errResponse', 'errDataNotJSON']}; + } + + data = this.normalize(data); + if (!this.validResponse('upload', data)) { + return {error : (response.norError || ['errResponse'])}; + } + data.removed = $.merge((data.removed || []), $.map(data.added||[], function(f) { return f.hash; })); + return data; + + }, + + iframeCnt : 0, + + uploads : { + // xhr muiti uploading flag + xhrUploading: false, + + // Timer of request fail to sync + failSyncTm: null, + + // current chunkfail requesting chunk + chunkfailReq: {}, + + // check file/dir exists + checkExists: function(files, target, fm, isDir) { + var dfrd = $.Deferred(), + names, renames = [], hashes = {}, chkFiles = [], + cancel = function() { + var i = files.length; + while (--i > -1) { + files[i]._remove = true; + } + }, + resolve = function() { + dfrd.resolve(renames, hashes); + }, + check = function() { + var existed = [], exists = [], i, c, + pathStr = target !== fm.cwd().hash? fm.path(target, true) + fm.option('separator', target) : '', + confirm = function(ndx) { + var last = ndx == exists.length-1, + opts = { + title : fm.i18n('cmdupload'), + text : ['errExists', pathStr + exists[ndx].name, 'confirmRepl'], + all : !last, + accept : { + label : 'btnYes', + callback : function(all) { + !last && !all + ? confirm(++ndx) + : resolve(); + } + }, + reject : { + label : 'btnNo', + callback : function(all) { + var i; + + if (all) { + i = exists.length; + while (ndx < i--) { + files[exists[i].i]._remove = true; + } + } else { + files[exists[ndx].i]._remove = true; + } + + !last && !all + ? confirm(++ndx) + : resolve(); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { + cancel(); + resolve(); + } + }, + buttons : [ + { + label : 'btnBackup', + callback : function(all) { + var i; + if (all) { + i = exists.length; + while (ndx < i--) { + renames.push(exists[i].name); + } + } else { + renames.push(exists[ndx].name); + } + !last && !all + ? confirm(++ndx) + : resolve(); + } + } + ] + }; + + if (!isDir) { + opts.buttons.push({ + label : 'btnRename' + (last? '' : 'All'), + callback : function() { + renames = null; + resolve(); + } + }); + } + if (fm.iframeCnt > 0) { + delete opts.reject; + } + fm.confirm(opts); + }; + + if (! fm.file(target).read) { + // for dropbox type + resolve(); + return; + } + + names = $.map(files, function(file, i) { return file.name && (!fm.UA.iOS || file.name !== 'image.jpg')? {i: i, name: file.name} : null ;}); + + fm.request({ + data : {cmd : 'ls', target : target, intersect : $.map(names, function(item) { return item.name;})}, + notify : {type : 'preupload', cnt : 1, hideCnt : true}, + preventFail : true + }) + .done(function(data) { + var existedArr, cwdItems; + if (data) { + if (data.error) { + cancel(); + } else { + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + if (data.list) { + if (Array.isArray(data.list)) { + existed = data.list || []; + } else { + existedArr = []; + existed = $.map(data.list, function(n) { + if (typeof n === 'string') { + return n; + } else { + // support to >=2.1.11 plugin Normalizer, Sanitizer + existedArr = existedArr.concat(n); + return null; + } + }); + if (existedArr.length) { + existed = existed.concat(existedArr); + } + hashes = data.list; + } + exists = $.map(names, function(name){ + return $.inArray(name.name, existed) !== -1 ? name : null ; + }); + if (exists.length && existed.length && target == fm.cwd().hash) { + cwdItems = $.map(fm.files(target), function(file) { return file.name; } ); + if ($.map(existed, function(n) { + return $.inArray(n, cwdItems) === -1? true : null; + }).length){ + fm.sync(); + } + } + } + } + } + } + if (exists.length > 0) { + confirm(0); + } else { + resolve(); + } + }) + .fail(function(error) { + cancel(); + resolve(); + error && fm.error(error); + }); + }; + if (fm.api >= 2.1 && typeof files[0] == 'object') { + check(); + } else { + resolve(); + } + return dfrd; + }, + + // check droped contents + checkFile : function(data, fm, target) { + if (!!data.checked || data.type == 'files') { + return data.files; + } else if (data.type == 'data') { + var dfrd = $.Deferred(), + files = [], + paths = [], + dirctorys = [], + entries = [], + processing = 0, + items, + mkdirs = [], + + readEntries = function(dirReader) { + var toArray = function(list) { + return Array.prototype.slice.call(list || []); + }; + }, + + doScan = function(items) { + var dirReader, entry, length, + entries = [], + toArray = function(list) { + return Array.prototype.slice.call(list || [], 0); + }, + excludes = fm.options.folderUploadExclude[fm.OS] || null; + length = items.length; + for (var i = 0; i < length; i++) { + entry = items[i]; + if (entry) { + if (entry.isFile) { + processing++; + entry.file(function (file) { + if (! excludes || ! file.name.match(excludes)) { + paths.push(entry.fullPath || ''); + files.push(file); + } + processing--; + }); + } else if (entry.isDirectory) { + if (fm.api >= 2.1) { + processing++; + mkdirs.push(entry.fullPath); + dirReader = entry.createReader(); + var entries = []; + // Call the reader.readEntries() until no more results are returned. + var readEntries = function() { + dirReader.readEntries (function(results) { + if (!results.length) { + for (var i = 0; i < entries.length; i++) { + doScan([entries[i]]); + } + processing--; + } else { + entries = entries.concat(toArray(results)); + readEntries(); + } + }, function(){ + processing--; + }); + }; + readEntries(); // Start reading dirs. + } + } + } + } + }, hasDirs; + + items = $.map(data.files.items, function(item){ + return item.getAsEntry? item.getAsEntry() : item.webkitGetAsEntry(); + }); + $.each(items, function(i, item) { + if (item.isDirectory) { + hasDirs = true; + return false; + } + }); + if (items.length > 0) { + fm.uploads.checkExists(items, target, fm, hasDirs).done(function(renames, hashes){ + var notifyto, dfds = []; + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + if (renames === null) { + data.overwrite = 0; + renames = []; + } + items = $.map(items, function(item){ + var i, bak, hash, dfd, hi; + if (item.isDirectory && renames.length) { + i = $.inArray(item.name, renames); + if (i !== -1) { + renames.splice(i, 1); + bak = fm.uniqueName(item.name + fm.options.backupSuffix , null, ''); + $.each(hashes, function(h, name) { + if (item.name == name) { + hash = h; + return false; + } + }); + if (! hash) { + hash = fm.fileByName(item.name, target).hash; + } + fm.lockfiles({files : [hash]}); + dfd = fm.request({ + data : {cmd : 'rename', target : hash, name : bak}, + notify : {type : 'rename', cnt : 1} + }) + .fail(function(error) { + item._remove = true; + fm.sync(); + }) + .always(function() { + fm.unlockfiles({files : [hash]}) + }); + dfds.push(dfd); + } + } + return !item._remove? item : null; + }); + } + $.when.apply($, dfds).done(function(){ + if (items.length > 0) { + notifyto = setTimeout(function() { + fm.notify({type : 'readdir', cnt : 1, hideCnt: true}); + }, fm.options.notifyDelay); + doScan(items); + setTimeout(function wait() { + if (processing > 0) { + setTimeout(wait, 10); + } else { + notifyto && clearTimeout(notifyto); + fm.notify({type : 'readdir', cnt : -1}); + dfrd.resolve([files, paths, renames, hashes, mkdirs]); + } + }, 10); + } else { + dfrd.reject(); + } + }); + }); + return dfrd.promise(); + } else { + return dfrd.reject(); + } + } else { + var ret = []; + var check = []; + var str = data.files[0]; + if (data.type == 'html') { + var tmp = $("").append($.parseHTML(str.replace(/ src=/ig, ' _elfsrc='))), + atag; + $('img[_elfsrc]', tmp).each(function(){ + var url, purl, + self = $(this), + pa = self.closest('a'); + if (pa && pa.attr('href') && pa.attr('href').match(/\.(?:jpe?g|gif|bmp|png)/i)) { + purl = pa.attr('href'); + } + url = self.attr('_elfsrc'); + if (url) { + if (purl) { + $.inArray(purl, ret) == -1 && ret.push(purl); + $.inArray(url, check) == -1 && check.push(url); + } else { + $.inArray(url, ret) == -1 && ret.push(url); + } + } + // Probably it's clipboard data + if (ret.length === 1 && ret[0].match(/^data:image\/png/)) { + data.clipdata = true; + } + }); + atag = $('a[href]', tmp); + atag.each(function(){ + var loc, + parseUrl = function(url) { + var a = document.createElement('a'); + a.href = url; + return a; + }; + if ($(this).text()) { + loc = parseUrl($(this).attr('href')); + if (loc.href && (atag.length === 1 || ! loc.pathname.match(/(?:\.html?|\/[^\/.]*)$/i))) { + if ($.inArray(loc.href, ret) == -1 && $.inArray(loc.href, check) == -1) ret.push(loc.href); + } + } + }); + } else { + var regex, m, url; + regex = /(http[^<>"{}|\\^\[\]`\s]+)/ig; + while (m = regex.exec(str)) { + url = m[1].replace(/&/g, '&'); + if ($.inArray(url, ret) == -1) ret.push(url); + } + } + return ret; + } + }, + + // upload transport using XMLHttpRequest + xhr : function(data, fm) { + var self = fm ? fm : this, + node = self.getUI(), + xhr = new XMLHttpRequest(), + notifyto = null, notifyto2 = null, + dataChecked = data.checked, + isDataType = (data.isDataType || data.type == 'data'), + target = (data.target || self.cwd().hash), + dropEvt = (data.dropEvt || null), + chunkEnable = (self.option('uploadMaxConn', target) != -1), + multiMax = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))), + retryWait = 10000, // 10 sec + retryMax = 30, // 10 sec * 30 = 300 secs (Max 5 mins) + retry = 0, + getFile = function(files) { + var dfd = $.Deferred(), + file; + if (files.promise) { + files.always(function(f) { + dfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {}); + }); + } else { + dfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {}); + } + return dfd; + }, + dfrd = $.Deferred() + .fail(function(error) { + var userAbort; + if (error === 'userabort') { + userAbort = true; + error = void 0; + } + if (files && (self.uploads.xhrUploading || userAbort)) { + // send request om fail + getFile(files).done(function(file) { + if (! file._cid) { + // send sync request + self.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm); + self.uploads.failSyncTm = setTimeout(function() { + self.sync(target); + }, 1000); + } else if (! self.uploads.chunkfailReq[file._cid]) { + // send chunkfail request + self.uploads.chunkfailReq[file._cid] = true; + setTimeout(function() { + fm.request({ + data : { + cmd: 'upload', + target: target, + chunk: file._chunk, + cid: file._cid, + upload: ['chunkfail'], + mimes: 'chunkfail' + }, + options : { + type: 'post', + url: self.uploadURL + }, + preventDefault: true + }).always(function() { + delete self.uploads.chunkfailReq[file._chunk]; + }); + }, 1000); + } + }); + } + !userAbort && self.sync(); + self.uploads.xhrUploading = false; + files = null; + error && self.error(error); + }) + .done(function(data) { + self.uploads.xhrUploading = false; + files = null; + if (data) { + self.currentReqCmd = 'upload'; + data.warning && self.error(data.warning); + self.updateCache(data); + data.removed && self.remove(data); + data.added && self.add(data); + data.changed && self.change(data); + self.trigger('upload', data, false); + self.trigger('uploaddone'); + data.sync && self.sync(); + data.debug && fm.debug('backend-debug', data); + } + }) + .always(function() { + self.abortXHR(xhr); + // unregist fnAbort function + node.off('uploadabort', fnAbort); + $(window).off('unload', fnAbort); + notifyto && clearTimeout(notifyto); + notifyto2 && clearTimeout(notifyto2); + dataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + chunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1}); + }), + formData = new FormData(), + files = data.input ? data.input.files : self.uploads.checkFile(data, self, target), + cnt = data.checked? (isDataType? files[0].length : files.length) : files.length, + loaded = 0, + prev = 0, + filesize = 0, + notify = false, + notifyElm = self.ui.notify, + cancelBtn = true, + abort = false, + checkNotify = function() { + return notify = (notify || notifyElm.children('.elfinder-notify-upload').length); + }, + fnAbort = function(e, error) { + abort = true; + self.abortXHR(xhr, { quiet: true, abort: true }); + dfrd.reject(error); + if (checkNotify()) { + self.notify({type : 'upload', cnt : notifyElm.children('.elfinder-notify-upload').data('cnt') * -1, progress : 0, size : 0}); + } + }, + cancelToggle = function(show) { + notifyElm.children('.elfinder-notify-upload').children('.elfinder-notify-cancel')[show? 'show':'hide'](); + }, + startNotify = function(size) { + if (!size) size = filesize; + return setTimeout(function() { + notify = true; + self.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size, + cancel: function() { + node.trigger('uploadabort', 'userabort'); + } + }); + prev = loaded; + if (data.multiupload) { + cancelBtn && cancelToggle(true); + } else { + cancelToggle(cancelBtn && loaded < size); + } + }, self.options.notifyDelay); + }, + doRetry = function() { + if (retry++ <= retryMax) { + if (checkNotify() && prev) { + self.notify({type : 'upload', cnt : 0, progress : 0, size : prev}); + } + self.abortXHR(xhr, { quiet: true }); + prev = loaded = 0; + setTimeout(function() { + var reqId; + if (! abort) { + xhr.open('POST', self.uploadURL, true); + if (self.api >= 2.1029) { + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16); + (typeof formData['delete'] === 'function') && formData['delete']('reqid'); + formData.append('reqid', reqId); + xhr._requestId = reqId; + } + xhr.send(formData); + } + }, retryWait); + } else { + node.trigger('uploadabort', ['errAbort', 'errTimeout']); + } + }, + renames = (data.renames || null), + hashes = (data.hashes || null), + chunkMerge = false; + + // regist fnAbort function + node.one('uploadabort', fnAbort); + $(window).one('unload.' + fm.namespace, fnAbort); + + !chunkMerge && (prev = loaded); + + if (!isDataType && !cnt) { + return dfrd.reject(['errUploadNoFiles']); + } + + xhr.addEventListener('error', function() { + if (xhr.status == 0) { + if (abort) { + dfrd.reject(); + } else { + // ff bug while send zero sized file + // for safari - send directory + if (!isDataType && data.files && $.map(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? f : null;}).length) { + errors.push('errFolderUpload'); + dfrd.reject(['errAbort', 'errFolderUpload']); + } else if (data.input && $.map(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? f : null;}).length) { + dfrd.reject(['errUploadNoFiles']); + } else { + doRetry(); + } + } + } else { + node.trigger('uploadabort', 'errConnect'); + } + }, false); + + xhr.addEventListener('load', function(e) { + var status = xhr.status, res, curr = 0, error = ''; + + if (status >= 400) { + if (status > 500) { + error = 'errResponse'; + } else { + error = ['errResponse', 'errServerError']; + } + } else { + if (!xhr.responseText) { + error = ['errResponse', 'errDataEmpty']; + } + } + + if (error) { + node.trigger('uploadabort'); + getFile(files).done(function(file) { + return dfrd.reject(file._cid? null : error); + }); + } + + loaded = filesize; + + if (checkNotify() && (curr = loaded - prev)) { + self.notify({type : 'upload', cnt : 0, progress : curr, size : 0}); + } + + res = self.parseUploadData(xhr.responseText); + + // chunked upload commit + if (res._chunkmerged) { + formData = new FormData(); + var _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}]; + chunkMerge = true; + node.off('uploadabort', fnAbort); + notifyto2 = setTimeout(function() { + self.notify({type : 'chunkmerge', cnt : 1}); + }, self.options.notifyDelay); + isDataType? send(_file, files[1]) : send(_file); + return; + } + + res._multiupload = data.multiupload? true : false; + if (res.error) { + self.trigger('uploadfail', res); + if (res._chunkfailure || res._multiupload) { + abort = true; + self.uploads.xhrUploading = false; + notifyto && clearTimeout(notifyto); + if (notifyElm.children('.elfinder-notify-upload').length) { + self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + dfrd.reject(res.error); + } else { + // for multi connection + dfrd.reject(); + } + } else { + dfrd.reject(res.error); + } + } else { + dfrd.resolve(res); + } + }, false); + + xhr.upload.addEventListener('loadstart', function(e) { + if (!chunkMerge && e.lengthComputable) { + loaded = e.loaded; + retry && (loaded = 0); + filesize = e.total; + if (!loaded) { + loaded = parseInt(filesize * 0.05); + } + if (checkNotify()) { + self.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize}); + prev = loaded; + } + } + }, false); + + xhr.upload.addEventListener('progress', function(e) { + var curr; + + if (e.lengthComputable && !chunkMerge && xhr.readyState < 2) { + + loaded = e.loaded; + + // to avoid strange bug in safari (not in chrome) with drag&drop. + // bug: macos finder opened in any folder, + // reset safari cache (option+command+e), reload elfinder page, + // drop file from finder + // on first attempt request starts (progress callback called ones) but never ends. + // any next drop - successfull. + if (!data.checked && loaded > 0 && !notifyto) { + notifyto = startNotify(xhr._totalSize - loaded); + } + + if (!filesize) { + filesize = e.total; + if (!loaded) { + loaded = parseInt(filesize * 0.05); + } + } + + curr = loaded - prev; + if (checkNotify() && (curr/e.total) >= 0.05) { + self.notify({type : 'upload', cnt : 0, progress : curr, size : 0}); + prev = loaded; + } + + if (! data.multiupload && loaded >= filesize) { + cancelBtn = false; + cancelToggle(false); + } + } + }, false); + + var send = function(files, paths){ + var size = 0, + fcnt = 1, + sfiles = [], + c = 0, + total = cnt, + maxFileSize, + totalSize = 0, + chunked = [], + chunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system + BYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize + blobSlice = chunkEnable? false : '', + blobSize, blobMtime, i, start, end, chunks, blob, chunk, added, done, last, failChunk, + multi = function(files, num){ + var sfiles = [], cid, sfilesLen = 0, cancelChk; + if (!abort) { + while(files.length && sfiles.length < num) { + sfiles.push(files.shift()); + } + sfilesLen = sfiles.length; + if (sfilesLen) { + cancelChk = sfilesLen; + for (var i=0; i < sfilesLen; i++) { + if (abort) { + break; + } + cid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null); + if (!!failChunk[cid]) { + last--; + continue; + } + fm.exec('upload', { + type: data.type, + isDataType: isDataType, + files: sfiles[i], + checked: true, + target: target, + dropEvt: dropEvt, + renames: renames, + hashes: hashes, + multiupload: true, + overwrite: data.overwrite === 0? 0 : void 0 + }, void 0, target) + .fail(function(error) { + if (error && error === 'No such command') { + abort = true; + fm.error(['errUpload', 'errPerm']); + } + if (cid) { + failChunk[cid] = true; + } + }) + .always(function(e) { + if (e && e.added) added = $.merge(added, e.added); + if (last <= ++done) { + fm.trigger('multiupload', {added: added}); + notifyto && clearTimeout(notifyto); + if (checkNotify()) { + self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + } + } + if (files.length) { + multi(files, 1); // Next one + } else { + if (--cancelChk <= 1) { + cancelBtn = false; + cancelToggle(false); + } + } + }); + } + } + } + if (sfiles.length < 1 || abort) { + if (abort) { + notifyto && clearTimeout(notifyto); + if (cid) { + failChunk[cid] = true; + } + dfrd.reject(); + } else { + dfrd.resolve(); + self.uploads.xhrUploading = false; + } + } + }, + check = function(){ + if (!self.uploads.xhrUploading) { + self.uploads.xhrUploading = true; + multi(sfiles, multiMax); // Max connection: 3 + } else { + setTimeout(function(){ check(); }, 100); + } + }, + reqId; + + if (! dataChecked && (isDataType || data.type == 'files')) { + if (! (maxFileSize = fm.option('uploadMaxSize', target))) { + maxFileSize = 0; + } + for (i=0; i < files.length; i++) { + try { + blob = files[i]; + blobSize = blob.size; + if (blobSlice === false) { + blobSlice = ''; + if (self.api >= 2.1) { + if ('slice' in blob) { + blobSlice = 'slice'; + } else if ('mozSlice' in blob) { + blobSlice = 'mozSlice'; + } else if ('webkitSlice' in blob) { + blobSlice = 'webkitSlice'; + } + } + } + } catch(e) { + cnt--; + total--; + continue; + } + + // file size check + if ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) { + self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadFileSize')); + cnt--; + total--; + continue; + } + + // file mime check + if (blob.type && ! self.uploadMimeCheck(blob.type, target)) { + self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadMime') + ' (' + self.escape(blob.type) + ')'); + cnt--; + total--; + continue; + } + + if (blobSlice && blobSize > BYTES_PER_CHUNK) { + start = 0; + end = BYTES_PER_CHUNK; + chunks = -1; + total = Math.floor(blobSize / BYTES_PER_CHUNK); + blobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0; + + totalSize += blobSize; + chunked[chunkID] = 0; + while(start <= blobSize) { + chunk = blob[blobSlice](start, end); + chunk._chunk = blob.name + '.' + (++chunks) + '_' + total + '.part'; + chunk._cid = chunkID; + chunk._range = start + ',' + chunk.size + ',' + blobSize; + chunk._mtime = blobMtime; + chunked[chunkID]++; + + if (size) { + c++; + } + if (typeof sfiles[c] == 'undefined') { + sfiles[c] = []; + if (isDataType) { + sfiles[c][0] = []; + sfiles[c][1] = []; + } + } + size = BYTES_PER_CHUNK; + fcnt = 1; + if (isDataType) { + sfiles[c][0].push(chunk); + sfiles[c][1].push(paths[i]); + } else { + sfiles[c].push(chunk); + } + + start = end; + end = start + BYTES_PER_CHUNK; + } + if (chunk == null) { + self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadFileSize')); + cnt--; + total--; + } else { + total += chunks; + size = 0; + fcnt = 1; + c++; + } + continue; + } + if ((fm.uplMaxSize && size + blobSize >= fm.uplMaxSize) || fcnt > fm.uplMaxFile) { + size = 0; + fcnt = 1; + c++; + } + if (typeof sfiles[c] == 'undefined') { + sfiles[c] = []; + if (isDataType) { + sfiles[c][0] = []; + sfiles[c][1] = []; + } + } + if (isDataType) { + sfiles[c][0].push(blob); + sfiles[c][1].push(paths[i]); + } else { + sfiles[c].push(blob); + } + size += blobSize; + totalSize += blobSize; + fcnt++; + } + + if (sfiles.length == 0) { + // no data + data.checked = true; + return false; + } + + if (sfiles.length > 1) { + // multi upload + notifyto = startNotify(totalSize); + added = []; + done = 0; + last = sfiles.length; + failChunk = []; + check(); + return true; + } + + // single upload + if (isDataType) { + files = sfiles[0][0]; + paths = sfiles[0][1]; + } else { + files = sfiles[0]; + } + } + + if (!dataChecked) { + if (!fm.UA.Safari || !data.files) { + notifyto = startNotify(totalSize); + } else { + xhr._totalSize = totalSize; + } + } + + dataChecked = true; + + if (! files.length) { + dfrd.reject(['errUploadNoFiles']); + } + + xhr.open('POST', self.uploadURL, true); + + // set request headers + if (fm.customHeaders) { + $.each(fm.customHeaders, function(key) { + xhr.setRequestHeader(key, this); + }); + } + + // set xhrFields + if (fm.xhrFields) { + $.each(fm.xhrFields, function(key) { + if (key in xhr) { + xhr[key] = this; + } + }); + } + + if (self.api >= 2.1029) { + // request ID + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16); + formData.append('reqid', reqId); + xhr._requestId = reqId; + } + formData.append('cmd', 'upload'); + formData.append(self.newAPI ? 'target' : 'current', target); + if (renames && renames.length) { + $.each(renames, function(i, v) { + formData.append('renames[]', v); + }); + formData.append('suffix', fm.options.backupSuffix); + } + if (hashes) { + $.each(hashes, function(i, v) { + formData.append('hashes['+ i +']', v); + }); + } + $.each(self.options.customData, function(key, val) { + formData.append(key, val); + }); + $.each(self.options.onlyMimes, function(i, mime) { + formData.append('mimes[]', mime); + }); + + $.each(files, function(i, file) { + if (file._chunkmerged) { + formData.append('chunk', file._chunkmerged); + formData.append('upload[]', file._name); + formData.append('mtime[]', file._mtime); + } else { + if (file._chunkfail) { + formData.append('upload[]', 'chunkfail'); + formData.append('mimes', 'chunkfail'); + } else { + formData.append('upload[]', file); + if (data.clipdata) { + data.overwrite = 0; + formData.append('name[]', fm.date(fm.nonameDateFormat) + '.png'); + } + if (fm.UA.iOS && file.name === 'image.jpg') { + data.overwrite = 0; + formData.append('name[]', fm.date(fm.nonameDateFormat) + '.jpg'); + } + } + if (file._chunk) { + formData.append('chunk', file._chunk); + formData.append('cid' , file._cid); + formData.append('range', file._range); + formData.append('mtime[]', file._mtime); + } else { + formData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0); + } + } + }); + + if (isDataType) { + $.each(paths, function(i, path) { + formData.append('upload_path[]', path); + }); + } + + if (data.overwrite === 0) { + formData.append('overwrite', 0); + } + + // send int value that which meta key was pressed when dropped as `dropWith` + if (dropEvt) { + formData.append('dropWith', parseInt( + (dropEvt.altKey ? '1' : '0')+ + (dropEvt.ctrlKey ? '1' : '0')+ + (dropEvt.metaKey ? '1' : '0')+ + (dropEvt.shiftKey? '1' : '0'), 2)); + } + + xhr.send(formData); + + return true; + }; + + if (! isDataType) { + if (files.length > 0) { + if (! data.clipdata && renames == null) { + var mkdirs = [], + paths = [], + excludes = fm.options.folderUploadExclude[fm.OS] || null; + $.each(files, function(i, file) { + var relPath = file.webkitRelativePath || file.relativePath || ''; + if (! relPath) { + return false; + } + if (excludes && file.name.match(excludes)) { + file._remove = true; + relPath = void(0); + } else { + relPath = relPath.replace(/\/[^\/]*$/, ''); + if (relPath && $.inArray(relPath, mkdirs) === -1) { + mkdirs.push(relPath); + } + } + paths.push(relPath); + }); + renames = []; + hashes = {}; + if (mkdirs.length) { + (function() { + var checkDirs = $.map(mkdirs, function(name) { return name.indexOf('/') === -1 ? {name: name} : null;}), + cancelDirs = []; + fm.uploads.checkExists(checkDirs, target, fm, true).done( + function(res, res2) { + var dfds = [], dfd, bak, hash; + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + cancelDirs = $.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} ); + checkDirs = $.map(checkDirs, function(dir) { return !dir._remove? dir : null ;} ); + } + if (cancelDirs.length) { + $.each(paths.concat(), function(i, path) { + if ($.inArray(path, cancelDirs) === 0) { + files[i]._remove = true; + delete paths[i]; + } + }); + } + files = $.map(files, function(file) { return file._remove? null : file; }); + paths = $.map(paths, function(path) { return path === void 0 ? null : path; }); + if (checkDirs.length) { + dfd = $.Deferred(); + if (res.length) { + $.each(res, function(i, existName) { + // backup + bak = fm.uniqueName(existName + fm.options.backupSuffix , null, ''); + $.each(res2, function(h, name) { + if (res[0] == name) { + hash = h; + return false; + } + }); + if (! hash) { + hash = fm.fileByName(res[0], target).hash; + } + fm.lockfiles({files : [hash]}); + dfds.push( + fm.request({ + data : {cmd : 'rename', target : hash, name : bak}, + notify : {type : 'rename', cnt : 1} + }) + .fail(function(error) { + dfrd.reject(error); + fm.sync(); + }) + .always(function() { + fm.unlockfiles({files : [hash]}) + }) + ); + }); + } else { + dfds.push(null); + } + + $.when.apply($, dfds).done(function() { + // ensure directories + fm.request({ + data : {cmd : 'mkdir', target : target, dirs : mkdirs}, + notify : {type : 'mkdir', cnt : mkdirs.length}, + preventFail: true + }) + .fail(function(error) { + error = error || ['errUnknown']; + if (error[0] === 'errCmdParams') { + multiMax = 1; + } else { + multiMax = 0; + dfrd.reject(error); + } + }) + .done(function(data) { + if (data.hashes) { + paths = $.map(paths.concat(), function(p) { + if (p === '') { + return target; + } else { + return data.hashes['/' + p]; + } + }); + } + }) + .always(function(data) { + if (multiMax) { + isDataType = true; + if (! send(files, paths)) { + dfrd.reject(); + } + } + }); + }); + } else { + dfrd.reject(); + } + } + ); + })(); + } else { + fm.uploads.checkExists(files, target, fm).done( + function(res, res2){ + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + if (res === null) { + data.overwrite = 0; + } else { + renames = res; + hashes = res2; + } + files = $.map(files, function(file){return !file._remove? file : null ;}); + } + cnt = files.length; + if (cnt > 0) { + if (! send(files)) { + dfrd.reject(); + } + } else { + dfrd.reject(); + } + } + ); + } + } else { + if (! send(files)) { + dfrd.reject(); + } + } + } else { + dfrd.reject(); + } + } else { + if (dataChecked) { + send(files[0], files[1]); + } else { + files.done(function(result) { // result: [files, paths, renames, hashes, mkdirs] + renames = []; + cnt = result[0].length; + if (cnt) { + if (result[4] && result[4].length) { + // ensure directories + fm.request({ + data : {cmd : 'mkdir', target : target, dirs : result[4]}, + notify : {type : 'mkdir', cnt : result[4].length}, + preventFail: true + }) + .fail(function(error) { + error = error || ['errUnknown']; + if (error[0] === 'errCmdParams') { + multiMax = 1; + } else { + multiMax = 0; + dfrd.reject(error); + } + }) + .done(function(data) { + if (data.hashes) { + result[1] = $.map(result[1], function(p) { + p = p.replace(/\/[^\/]*$/, ''); + if (p === '') { + return target; + } else { + return data.hashes[p]; + } + }); + } + }) + .always(function(data) { + if (multiMax) { + renames = result[2]; + hashes = result[3]; + send(result[0], result[1]); + } + }); + return; + } else { + result[1] = $.map(result[1], function() { return target; }); + } + renames = result[2]; + hashes = result[3]; + send(result[0], result[1]); + } else { + dfrd.reject(['errUploadNoFiles']); + } + }).fail(function(){ + dfrd.reject(); + }); + } + } + + return dfrd; + }, + + // upload transport using iframe + iframe : function(data, fm) { + var self = fm ? fm : this, + input = data.input? data.input : false, + files = !input ? self.uploads.checkFile(data, self) : false, + dfrd = $.Deferred() + .fail(function(error) { + error && self.error(error); + }), + name = 'iframe-'+fm.namespace+(++self.iframeCnt), + form = $('
'), + msie = this.UA.IE, + // clear timeouts, close notification dialog, remove form/iframe + onload = function() { + abortto && clearTimeout(abortto); + notifyto && clearTimeout(notifyto); + notify && self.notify({type : 'upload', cnt : -cnt}); + + setTimeout(function() { + msie && $('