PK SPKK}&~ ~ main.default.jsnu W+A "use strict";
/**
* elFinder client options and main script for RequireJS
*
* Rename "main.default.js" to "main.js" and edit it if you need configure elFInder options or any things. And use that in elfinder.html.
* e.g. ``
**/
(function(){
var // jQuery and jQueryUI version
jqver = '3.2.1',
uiver = '1.12.1',
// Detect language (optional)
lang = (function() {
var locq = window.location.search,
fullLang, locm, lang;
if (locq && (locm = locq.match(/lang=([a-zA-Z_-]+)/))) {
// detection by url query (?lang=xx)
fullLang = locm[1];
} else {
// detection by browser language
fullLang = (navigator.browserLanguage || navigator.language || navigator.userLanguage);
}
lang = fullLang.substr(0,2);
if (lang === 'ja') lang = 'jp';
else if (lang === 'pt') lang = 'pt_BR';
else if (lang === 'ug') lang = 'ug_CN';
else if (lang === 'zh') lang = (fullLang.substr(0,5).toLowerCase() === 'zh-tw')? 'zh_TW' : 'zh_CN';
return lang;
})(),
// Start elFinder (REQUIRED)
start = function(elFinder, editors, config) {
// load jQueryUI CSS
elFinder.prototype.loadCss('//cdnjs.cloudflare.com/ajax/libs/jqueryui/'+uiver+'/themes/smoothness/jquery-ui.css');
$(function() {
var optEditors = {
commandsOptions: {
edit: {
editors: Array.isArray(editors)? editors : []
}
}
},
opts = {};
// Interpretation of "elFinderConfig"
if (config && config.managers) {
$.each(config.managers, function(id, mOpts) {
opts = Object.assign(opts, config.defaultOpts || {});
// editors marges to opts.commandOptions.edit
try {
mOpts.commandsOptions.edit.editors = mOpts.commandsOptions.edit.editors.concat(editors || []);
} catch(e) {
Object.assign(mOpts, optEditors);
}
// Make elFinder
$('#' + id).elfinder(
// 1st Arg - options
$.extend(true, { lang: lang }, opts, mOpts || {}),
// 2nd Arg - before boot up function
function(fm, extraObj) {
// `init` event callback function
fm.bind('init', function() {
// Optional for Japanese decoder "extras/encoding-japanese.min"
delete fm.options.rawStringDecoder;
if (fm.lang === 'jp') {
require(
[ 'extras/encoding-japanese.min' ],
function(Encoding) {
if (Encoding.convert) {
fm.options.rawStringDecoder = function(s) {
return Encoding.convert(s,{to:'UNICODE',type:'string'});
};
}
}
);
}
});
}
);
});
} else {
alert('"elFinderConfig" object is wrong.');
}
});
},
// JavaScript loader (REQUIRED)
load = function() {
require(
[
'elfinder'
, 'extras/editors.default.min' // load text, image editors
, 'elFinderConfig'
// , 'extras/quicklook.googledocs.min' // optional preview for GoogleApps contents on the GoogleDrive volume
],
start,
function(error) {
alert(error.message);
}
);
},
// is IE8? for determine the jQuery version to use (optional)
ie8 = (typeof window.addEventListener === 'undefined' && typeof document.getElementsByClassName === 'undefined');
// config of RequireJS (REQUIRED)
require.config({
baseUrl : 'js',
paths : {
'jquery' : '//cdnjs.cloudflare.com/ajax/libs/jquery/'+(ie8? '1.12.4' : jqver)+'/jquery.min',
'jquery-ui': '//cdnjs.cloudflare.com/ajax/libs/jqueryui/'+uiver+'/jquery-ui.min',
'elfinder' : 'elfinder.min'
},
waitSeconds : 10 // optional
});
// check elFinderConfig and fallback
if (! require.defined('elFinderConfig')) {
define('elFinderConfig', {
// elFinder options (REQUIRED)
// Documentation for client options:
// https://github.com/Studio-42/elFinder/wiki/Client-configuration-options
defaultOpts : {
url : 'php/connector.minimal.php' // connector URL (REQUIRED)
,commandsOptions : {
edit : {
extraOptions : {
// set API key to enable Creative Cloud image editor
// see https://console.adobe.io/
creativeCloudApiKey : '',
// browsing manager URL for CKEditor, TinyMCE
// uses self location with the empty value
managerUrl : ''
}
}
,quicklook : {
// to enable preview with Google Docs Viewer
googleDocsMimes : ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation']
}
}
},
managers : {
'elfinder': {},
}
});
}
// load JavaScripts (REQUIRED)
load();
})();
PK SPK;E elfinder.src.htmlnu W+A
elFinder 2.1.x source version with PHP connector
PK SPK
.
LICENSE.mdnu W+A elFinder is issued under a 3-clauses BSD license.
Copyright (c) 2009-2016, Studio 42
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the Studio 42 Ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL "STUDIO 42" OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK SPK]P[ [
elfinder.htmlnu W+A
elFinder 2.1.x source version with PHP connector
PK SPKL\1 1 Changelognu W+A 2017-10-07 Naoki Sawada
* elFinder (2.1.29):
- [cmd:quicklook.plugins] Fixed #2149 support Data URI scheme contents of the text file
- [cmd:quicklook] Fixed #2151 tmb icon don't appear at file addition
- [ui:cwd] Fixed #2152 table header position unmatch in the rtl language
- [jquery.elfinder] add jQuery function `$.fn.scrollRight()`
- [ui:navbar] correction position of navbar resize handle in
- [js:core] Fixed #2153 correction of `mime2class()` also give sub-type of "image/*"
- [ui:cwd] Fixed #2158 add file type badge in icons view with CSS
- [VD:abstract,plugin] Fixed #2160 animation of apng is lost
- [php:core] bugfix of passing tagetHash to callback 'upload.presave'
- [api] configurable MIME-types to handle as text on the connector side
- [VD:MySQL] Fixed #2164, Fixed #2166 problem with MySQL > 5.6
- [ui:navbar,cmd:quicklook] Fixed #2171 allow to display the preview on the navbar
- [js:options] add an option `fileFilter` cf. #2176, #2178
- [ui:contextmenu] Fixed #2183 problem of selecting submenu on touch devices
- [js:core] add a unique query param to thumbnail url
- [cmd:quicklook] Fixed #2191 add an option `commandsOptions.quicklook.contain`
- [cmd:quicklook] Fixed #2192 show cwd info when unselect item
- [cmd:quicklook] add PSD preview plugin
- [VD:FTP] Fixed the permissions when the ftp deamon uses a Virtual User that it isn't a passwd user
- [php:plugins] Fixed #2198 AutoResize/AutoRotate/Watermark fail if php fileinfo module not loaded
- [php:core,VD:abstarct] Fixed #2199 remove `create_function()` for PHP>=7.2
- [js:core] Fixed #2201 bugfix that language setting of options stores in browser
- [ui:dialog] Fixed #2203 option `dialogContained` to contained in the elFinder node
- [js:core] Fixed #2210 send `mimes` as Array (not Object) on upload
- [VD:FTP] Fixed Using epsv4 off with Pure-ftpd servers creates a timeout
- [js:core] Fixed #2216 to destruction completely of used XHR objects
- [cmd:quicklook,rm] Fixed #2221 show folder size info into the each
- [api] Fixed #2222 abort on the client side then notify it to the connector side
- [js:cwd] Fixed #2224 problems that cause discrepancies on displaying
- [VD:LocalFileSystem] Fixed #2226 problem on save empty file
- [i18n:LANG] add "Sum" for the caption of recursive folder size
- [cmd:download] bugfix of non-alphabetic characters in download filename
- [php:core] add a main option `connectionFlagsPath`
- [i18n:LANG] add "Sum" for the caption of recursive folder size
- [js:core] Fixed #2236 show target path in upload confirm dialog at non-cwd
- And some minor bug fixes
2017-08-16 Naoki Sawada
* elFinder (2.1.28):
- [ui:cwd] Fixed #2140 sync problem of col-width of table header when item add/remove
- [cmd] Fixed #2144 add cmds `select(all|none|invert)`
- [php:core] Fixed #2143 locale dependent version number problem
- And some minor bug fixes
2017-08-10 Naoki Sawada
* elFinder (2.1.27):
- [php:core] Fixed #2104 notice error in `getIniBytes()` with php 7.1
- [cmd:download] Fixed #2106 add an option `commandOptions.download.minFilesZipdl`
- [VD:abstract] enable to specify the path of server commands as constant
- [cmd:quicklook] Fixed #2108 support HLS, DASH video preview
- [cmd:open,quicklook] MIME type determination to case incentive
- [cmd:undo,redo] Fixed #2115 implement the Undo/Redo command
- [VD] Fixed #2120 item copy between volumes is incomplete
- [VD:Box,OneDrive] Fixed #2122 to be able to know the access token in debug mode
- [VD:abstract] Fixed #2107 do clearstatcache() in abstract class
- [cmd:help] Fixed #2118 controling to show/hide toolbar icons in preference tab
- [ui:dialog] Fixed #2123 problem in maximaize on fullscreen mode
- [ui:toolbar] add an option `showPreferenceButton`
- [cmd:rm] Fixed #2087 rm command not disable on unselect items
- [ui:dialog] Fixed #2124 missing dialog on fullscreen mode
- [cmd:resize] Fixed #2127 don't show "SaveAs" if new image saving is not allowed
- [VD:OneDrive] Fixed #2131 causes an infinite loop at the copy command
- And some minor bug fixes
2017-07-17 Naoki Sawada
* elFinder (2.1.26):
- [php:core] Fixed #2069 add static method `elFinder::getApiFullVersion()`
- [js:core] Fixed #2073 auto loading of language files implemented in core
- [cmd:help] Fixed #2074 add the Preference tab
- [js:core] Fixed #2079 lost binded user functions with node.elfinder('reload')
- [cmd:help] Fixed #2076 problem of content area height synchronization
- [js:core] Fixed #2081 problem that updating of `uiCmdMap`
- [cmd:resize] Fixed #2085 "Save As" dose not work in 2.1.25
- [cmd:rm] Fixed #2086 problem of cmd mode sync on the item selected
- [js:core] Fixed #2076 cancel full screen mode on `destroy`
- [cmd:rm] Fixed #2087 JavaScript error when hide `rm` icon in toolbar
- [cmd:netmount] Fixed #2088 problem of shows error dialog behind this dialog
- [cmd:rm] Fixed #2087 button icon label is wrong until boot up
- [php:connector] Supports X-Sendfile and similar file-download accelerators
- And some minor bug fixes
2017-06-23 Naoki Sawada
* elFinder (2.1.25):
- [php] Fixed #2014 "Parse error" on PHP < 5.3
- [core,API] Fixed #1431 cmd `edit` supports Data Uri Scheme
- [cmd:edit] Added Pixlr Editor, Pixlr Express, Cleative Cloud Image editor, Ace Editor, CodeMirror, SimpleMDE, CKEditor and TinyMCE as default editors
- [cmd:edit] Fixed #2020 add "Save As" button
- [cmd:resize] Fixed #2016 add Preset size buttons
- [cmd:resize] Fixed #2019 conflict with the bootstrap.js
- [CD:abstract] Fixed #2025 cannot edit any files with `memory_limit` = -1
- [cmd:edit] Fixed #2027 make it selectable from multiple editors
- [VD:abstract,LocalFileSystem] Fixed #2035 support multipart rar extraction
- [VD:abstract] Fixed #2040 Fatal error on create the item with PHP>=7.1
- [cmd:rm] Fixed #2042 add command options `infoCheckWait`, `toTrashMaxItems`
- [cmd:resize] Fixed #2043 add "Save As" button into the resize dialog
- [js:core] Fixed #2050 handling server errors during upload
- [VD:abstract] Fixed #2054 to use the same hash value as Linux on Windows server
- [js:restore] Fixed #2057 problem of empty folder handling
- [cmd:empty] Fixed #2061 add a new command `empty` - "Empty the folder"
- And some minor bug fixes
2017-05-19 Naoki Sawada
* elFinder (2.1.24):
- [js:options] Fixed #1947 add client option `dispInlineRegex` for legacy connectors
- [js:options] Fixed #1948 separate uiOptions.toolbar extra options to uiOptions.toolbarExtra
- [js:core,php:core] Fixed #1951 set name to uploaded items from clipboard data
- [js:core,php:core] Fixed #1951 to IE and correction to Firefox
- [js:core] Fixed #1953 to selectable "Rename" when item name exists on upload
- [VD:abstract] Fixed #1952 urlencode of results file.url on upload
- [VD:abstract] Fixed #1959 add connector roots option `acceptedDirname`
- [js:core] Fixed #1965 add an option `heightBase` to client configuration
- [VD:abstract] Fixed #1974 add an option `driverId` (prefix of volumeid)
- [php:connector] Fixed #1975 possible XSS issue on debug mode of connector
- [VD:FTP] Fixed #1982 problem with connect to Pure-FTPd
- [php:plugin:Normalizer,Sanitizer] Fixed #1983 upload fails due to unnecessary conversion
- [cmd:quicklook] Fixed #1985 seek and volume change disabled in Firefox
- [js:core,cmd:rm,VD:trash] Fixed #1065 add "Trash" feature
- [php:core] Fixed #1990 sometimes in initial request, pass to bind callback `$volume` is empty
- [cmd:rm,trash,restore] Fixed #1991 implementation of restore function
- [js:core] Fixed #1996 pass an event object as `this` into binded callback
- [ui:tree] Fixed #1999 split display of many directories
- [js:core] Fixed #2005 prevent folder switching heavy as folders increase
- [VD:abstract] Fixed #2000 `elFinderVolumeDriver::imageUtil()` is not working properly
- [plugin:normalizer] Fixed #2004 add an option `umlauts
- [VD:LocalFileSystem] Fixed #2009 corrention of an option `keepTimestamp`(upload)`
- [ui:cwd,stat] Fixed #2010 sync problem when deleted any items in search results view
- And some minor bug fixes
2017-03-31 Naoki Sawada
* elFinder (2.1.23):
- [VD:Dropbox2] Fixed #1598 add a driver of Dropbox APIv2
- [js:core] change option `abortCmdsOnOpen` default value to `['tmb', 'parents']
- [php:core,VD:abstract] add a command `subdirs`
- [js:core] add new method `asyncJob`
- [quicklook] optimize of HTML5 audio/video player
- [php:core,VD:abstract] Fixed problem of caching of subdirs
- [ui:tree] trigger `check subdirs()` if necessary of change targets
- [cmd:netmount] Fixed #1925 allow selection of multi-level hierarchy
- [ui,cmd] Fixed #1931 cmd.disabled is not working in multi-volume search
- [VD:GoogleDrive] Fixed #1932 support to auth type "JSON service account credentials"
- [VD:GoogleDrive] Fixed #1933 sometimes infinite loop if root path is other than root on GoogleDrive
- [js:core,ui:cwd,tree] add core method fm.getIconStyle() and use
- [cmd:quicklook,info] Fixed #1926 support i18 name, file.icon
- [Vd:abstract] allow -1 as value of option `checkSubfolders` for check asynchronously
- [ui:cwd] Fixed #1923 first letter search & navigation in cwd
- [VD:LocalFileSystem,FTP] Make success `extract()` by excluding unallowed items
- [ui:cwd] Fixed #1941 performance deterioration of the thumbnail attach process
- [js:core] Supports tag
- And some minor bug fixes
2017-02-25 Naoki Sawada
* elFinder (2.1.22):
- [VD:LocalFileSystem] Fixed #1882 option `copyJoin` does not work on extract
- [cmd:help] Fixed #1898 error ".tabs is not a function" without JqUI tabs widget
- [VD:abstract] Fixed #1899 rotating image breaks itself without exiftran and jpegtran
- [VD:LocalFileSystem] Fixed #1910 `startPath` dose not work currently
- [VD:abstract] Fixed #1911 unable to rename folder
- And some minor bug fixes
2017-02-25 Naoki Sawada
* elFinder (2.0.9):
- [VD:abstract] Fixed #1911 unable to rename folder
2017-02-09 Naoki Sawada
* elFinder (2.0.8):
- [VD:security] Fixed #1891 MIME-type check of unknown item is not execute
2017-02-07 Naoki Sawada
* elFinder (2.1.21):
- [cmd:open] Fixed #1844 make configurable to open into tab(s)
- [php:core] Fixed #1846 target folder may be stay locked by adding items
- [cmd:download] Fixed #1868 fixed up timeouts for bad connection download
- [proxy:v1] Fixed #1880 error on command `paste`
- [v1 support] Fixed #1884 error on command `reload`
- [cmd:upload] Fixed #1885 Error on upload.ui = 'uploadbutton'
- [VD:security] Fixed #1891 MIME-type check of unknown item is not execute
- And some minor bug fixes
2017-01-11 Naoki Sawada
* elFinder (2.1.20):
- [php:core] Fixed #1800 session write before umount of the volume
- [cmd:upload] Fixed #1804 add folder upload button into upload dialog
- [php:plugin] Fixed #1807 enable/disable plugin by pressing meta key on DnD upload
- [cmd:rename] Fixed #1814 trigger event blur of input on item unselect
- [js:core] Fixed #1817 add "execpre.[cmd]" event and make cmd exec cancelable
- [js:core] Fixed #1818 mtime not defined for chunk upload
- [js:core] Fixed #1826 allow command invalidation by each item(folder/file)
- [ui:dialog] Fixed #1824 empty dialog on elfinder load
- [cmd:resize] Fixed #1834 configurable default state of `8px Grid`
- [VD] Fixed #1841 published files security issues
- [js:core] Fixed #1832 allow to set error message on HTTP status code 4/5xx
- [js:cmd] Fixed #1842 disable shortcut that specified to `disabled`
- [php:core] Fixed #1843 security vulnerability fix
2016-12-10 Naoki Sawada
* elFinder (2.1.19):
- [js] Fixed #1000 Wrap compiled code in UMD (for commonJs and AMD support)
- [VD:OneDrive,Box] Fixed #1774 dose not work when PHP has `open_basedir`
- [cmd:edit,php:core] Fixed #1779 save contents with original character encoding
- [ui:toolbar] Fixed #1778 displayTextLabel option not works
- [cmd:edit] add encoding select box rel. #1779
- [cmd:search] Fixed #1782 search by mimetype dose not work (>=2.1.16)
- [ui:dialog] Fixed #1785 trigger resize event with `maximize:on` in minimize element
- [VD:abstract] Fixed #1783 Illegal duplicate data as bind in duplicate command
- [cmd:edit] include elFinder instance as `fm` into `ta.editor` property
- [js:core] Fixed #1791 implement JS, CSS loader and auto load of elFinder CSS
- [cmd:resize] Fixed #1789 bug that crop image size is change while dragging
- [js:core] Fixed #1788 bug that chunked upload timeout processing is invalid
- [VD:abstract] Fixed #1799 uses `link()` in exec `zipdl` to more faster
- And some minor bug fixes
2016-11-21 Naoki Sawada
* elFinder (2.1.18):
- [VD:FTP] Fixed #1757 cause infinite loop with getting stat of second level items from system root
- [js:core] Fixed #1761 problem of chunk merge request on 2.1.17
- [php:core] Fixed #1762 broken backward compatibility of PHP < 5.4 on 2.1.17
- And some minor bug fixes
2016-11-19 Naoki Sawada
* elFinder (2.1.17):
- [cmd:upload] Fixed #1695 disabled check doesn't work in other than CWD volume
- [js:core] Fixed #1698 abort the file upload at network error occurs
- [ui:toolbar] Fixed #1699 add an option `displayTextLabel` (default: `false`)
- [css:toolbar] Fixed #1700 correction of button label for touch devices
- [ui:toolbar] add contextmenu to show/hide the text label
- [ui:workzone] Fixed #1702 cwd size fits to the workzone at resize
- [VD:abstract] Fixed #1703 problem of make the video thumbnail
- [core] Fixed #1706 configurable to limit max number of selectable items
- Added an option `maxTargets` of connector main option.
- [ui:cwd] Fixed #1701 No thumbnails after added the item (v 2.1.16)
- [cmd:download] Fixed #1707 allow zip download in multi volume searching
- Added native driver for GoogleDrive, OneDrive and Box (Special thanks to Raja Sharma)
- [cmd:netmount] Fixed #1713 OAuth of procedure is not completed on MS Edge
- [css:quicklook] Fixed #1717 preview html file won't scroll on IOS
- [cmd:upload] Fixed #1718 File upload on paste does not work
- [js:core] Fixed #1724 add client option `enableByMouseOver`
- [js:core] Fixed #1724 disable event `disable` with option `enableAlways=true`
- [js:core] Fixed #1724 optimize switching enable/disable for elf in iframe
- [cmd:getfile] Fixed #1727 wrong path when the tree is not loaded
- [cmd:quicklook] Fixed #1737 select next item after an item deleted
- [cmd:mkdir] Fixed #1739 Add 'new folder' action to tree context menu
- [VD:abstract,LocalFileSystem] Fixed #1744 results `url` must be urlencoded
- [js:core] Fixed #1738 retry uploading only on connection aborted
- [cmd:search] Fixed #1745 "onlyMimes" option invalid in search results
- [js:core] Fixed #1738 bug in the retry function on chunked uploading
- [php:plugin:AutoResize] Fixed #1746 add an option `forceEffect` (default:false)
- [js:core,cmd:quicklook] Fixed #1748 add client option `rawStringDecoder`
- And some minor bug fixes
2016-10-11 Naoki Sawada
* elFinder (2.1.16):
- [cmd:info] Fixed #1652 add CSS class name `file.csscls` to icon
- [ui:cwd] Fixed #1653 JQUI.selectable does not work on items that has been added
- [js:core,cmd:info] Fixed #1652 add the item type `Volume Root`
- [js:core] Fixed #1656 wrong result `fm.convAbsUrl()` with location basename
- [php:core] Fixed #1658 to allow cancel cmd exec by [cmd].pre callback
- [js:code] Fixed #1659 not work in Mac/iOS safari private browsing mode
- [js:core] Fixed #1662 `[cmd]fail` event is fired at fail cmd execution
- [php:core] Fixed #1669 Fatal error in `detectFileExtension()` when URL upload
- [ui:dialog] Fixed #1670 add the minimize button into the editing dialog
- [ui:navbar] Fixed #1684 rtl right-panel resize bug
- [cmd:resize] Fixed #1685 to enable specify bgcolor in the image rotation
- [cmd:resize] Fixed #1686 add "Aspect ratio" button into crop panel
- [cmd:resize] add button "8px Grid" Enabled/Disabled for JPEG image
- [js:core] Fixed #1689 initialized to an undefined property
- [js:core] Fixed #1692 optimize function of swipe to close navbar
- [cmd:quicklook] Fixed #1693 `dispInlineRegex` doesn't reflect in multi volume searching
- And some minor bug fixes
2016-09-12 Naoki Sawada
* elFinder (2.1.15):
- [js:command] inheritable elFinder.command object rel. #1545
- [VD:abstract] Fixed #1550 option `uiCmdMap` dose not work on 2.1.14
- [VD:abstract] Fixed #1553 root stat not refresh when do chmod of root
- [php:core] fix make netkey problem - support multiple array options
- [js:core] Fixed #1554 can not unmount netvolume when done auto sync
- [js:core] Fixed #1555 can not upload to unreadable folder
- [php:core] parent dir sets to changed when upload, paste, rm, mkfile, mkdir etc
- [js:core] Fixed #1560 to possible to apply sort mode in tree in navbar
- [js:ui,cmd:fullscreen] Fixed #1563 add ui command "fullscrren"
- [cmd:edit] Fixed #1561 add to fullscreen button
- [js:core] Fixed #1562 sort with i18 name if exist
- [js:options] ui option `commands` accepts "*" as all of commands
- [VD:LocalFileSystem] Fixed #1565 dose not support volume option `searchTimeout`
- [VD:FTP] Fixed #1571 cause infinite loop during auto-sync of the volume root
- [php:core] Fixed #1572 unable to DnD upload the folder named "0"
- [VD:abstract] Fixed #1575 can not rename "0" to "00", "000"...
- [cmd:rename] Fixed #1573 input text stay in there at rename error in tree view
- [ui:cwd] Fixed #1576 reset the column width may not applied to the header
- [ui:conttextmenu] Fixed #1578 to the contextmenu draggable
- [php,cmd:open] Fixed #1586 RFC7233 violation, add `commandsOptions.open.method`
- [ui:navbar,cwd] Fixed #1590 auto scroll on HTML5 native dragging
- [VD:Dropbox] Fixed #1596 correction of `basename`, `dirname` on the windows server
- [cmd:upload] Fixed #1600 add target folder selector into upload dialog
- [ui] Fixed #1609 toast notification on complete of upload/paste into any folder
- [cmd:getfile] Fixed #1610 getFileCallback to supports the jQuery.Deferred
- [cmd:rename] Fixed #1613 correction of error handling
- [js:core] Fixed #1614 correction of upload mixed chunks and normal file
- [ui:cwd] Fixed #1615 break the lazy rendering when it delete items
- [ui:tree] Fixed #1617 other volumes cmds doesn't work when it disabled in cwd
- [core] Fixed #1622 added an option `phash` to the volume roots for implement feature of volume group
- [ui:toolbar] Fixed #1619 use fm.trigger('toolbarload') instead toolbar.tigger('load')
- [js:options] Fixed #1624 add a new option `overwriteUploadConfirm`
- [cmd:search] Fixed #1635 support parallel requests for multi volumes
- [contextmenu] Fixed #1645 to enable the operation of the keyboard
- [ui:cwd] Fixed #1646 selected targets by ctrl+shift are wrong
- [ui:dialog] Fixed #1647 controlling tabstop by `elfinder-tabstop` css class name
- And some minor bug fixes
2016-07-25 Naoki Sawada
* elFinder (2.1.14):
- [js:core,VD:abstract] Fixed #1525 do MIME check before file upload
- [API] Accept the root options data as an attribute `options` of the root stat
- [ui:cwd] Fixed #1532 can not use the `_` in custom column name
- [js:command] Fixed #1533 update the cmd status at `sync`
- [core] Fixed #1012 support i18n folder name
- [ui:cwd] Fixed #1544 jQuery backward compatibility (fix DnD problem)
- [proxy:APIv1] Fixed #178 correction of command `paste`
- And some minor bug fixes
2016-07-11 Naoki Sawada
* elFinder (2.1.13):
- [ui:cwd] Fixed #1433 create a thumbnail of the video file with ffmpeg
- [js:core] Fixed #1435 bug of getFileCallback on multi instances
- [ui:cwd] Fixed #1440 bug that not become disabled on multi instance
- [cmd:quicklook] Fixed #1441 hide the prev/next button on first/last item
- [js:core] Fixed #1439 show window close confirm dialog while editing file
- [ui:cwd] Fixed #1450 missing contextmenu on touch up on iOS devices
- [js] Fixed #1455 duplicate registration of command change event
- [ui:cwd] Fixed #1461 resizable table column width
- [cmd:sort] Fixed #1464 to enable more sort options
- [cmd:chmod] Fixed #1465 remove unnecessary `this` reference
- [ui:toolbar,navbar] Fixed #1473 memorize state of open/close by swipe
- [ui:cwd] Fixed #1475 make custom column sortable on list view
- [cmd:quicklook] Fixed #1478 preview broken with old jQuery
- [js:core] Fixed #1480 broken compatibility with protocol API v1
- [cmd:opendir] Fixed #1481 broken in elFinder 2.1.12
- [ui:cwd] Fixed #1479 can't be moved to the right edge at column sort
- [ui:cwd] Fixed #1485 add an option of template placeholders replacement rules
- [php:core] Fixed #1490 configurable root options of the network mounting volume
- [js] Fixed #1491 jQuery 3.0 supports
- [cmd:search] Fixed #1499 incremental search from current view items
- [cmd;resize] Fixed #1498 img-edit dialog layout disordered when resizing window
- [VD:abstract] Fixed #1505 configurable duplicate's suffix, unique numbe format
- [VD:abstract] Fixed #1507 add a volume option `dirUrlOwn`
- [VD:abstract] Fixed #1514 security vulnerability in the archive command
- And some minor bug fixes
2016-07-11 Naoki Sawada
* elFinder (2.0.7):
- [VD:abstract] Fixed #1514 security vulnerability in the archive command
2016-05-30 Naoki Sawada
* elFinder (2.1.12):
- Fixed #1321 Not trim white spaces on editing the text file
- Fixed #1320 Supported operation in the modal dialog
- Correction of the context menu (Mobile devices, Right-to-Left Language etc.)
- Correction of Quicklook (Supported 'video/quicktime', improvement of IFRAME, For Mobile devices etc)
- Fixed #1272 Correct detection of timestamp on FTP volume
- Fixed #1315 Implement function for `copyJoin` of the volume root option
- Fixed #1344 Use self image as thumbnail when without `imgLib`
- Fixed #1342 Bugfix of method `getFullPath` that was problems relative path can not be resolved
- Added a volume root option `uploadMaxConn`
- Maximum number of chunked upload connection. `-1` to disable chunked upload.
- Changed default value of volume root option `tmbBgColor` to 'transparent'
- Added a volume root option `bgColorFb`
- Image rotate fallback background color (defalt: #ffffff). Uses this color if it can not specify to transparent.
- Fixed #935 Supports `'convert'`(imagemagick) as `imgLib`
- Fixed #1363 Bugfix of FTP connect from windows localhost to remote server
- Fixed #1367 Bugfix of backward compatible to jQuery UI < 1.11
- Mobile devices friendly
- Swipe to navbar/toolbar show/hide on touch devices
- Hide toolbar on mobile devices at initial view
- A little bigger icons
- Added item select checkboxes
- Path breadcrumbs move to top of workzone when hide navbar
- To enable resizing/cropping by touch events
- UX enhancements
- Fixed #1311 CWD list table with fixed fixed header
- UI path apply text-ellipsis in each holder name
- Fixed #1370 implemented function keep timestamp into LocalFileSystem volume driver
- Added PHP error handler and removed all `@` error-control operator
- Fixed #1391 take care 32bit system of chunked file uploading arg `cid`
- Fixed #1393 Added PHP class auto loader
- Fixed #1412 Enable auto scroll when navbar/cwd drag over
- And some minor bug fixes
2016-04-11 Naoki Sawada
* elFinder (2.1.11):
- Added Archive(zip|gzip|tar) quicklook preview plugin
- DnD upload supports Microsoft Edge
- Fixed problem which directory is not detected in the LocalFileSystem driver (Bug of 2.1.10)
- And some minor bug fixes
2016-04-02 Naoki Sawada
* elFinder (2.1.10):
- Fixed #1061, #1231 Supported controllable folder icons
- Fixed #1240 LocalFileSystem search files it was still follow symlinks
- Added new volume root option `searchExDirReg` for exclusion serach
- Return file.url in result on file upload for 3rd party uploader
- Supported elFinder API version 1
- Added a new volume driver FlysystemGoogleDriveNetmount that based on flysystem-google-drive
- Added a new connector plugin "AutoRotate"
- And some minor bug fixes
2016-03-11 Naoki Sawada
* elFinder (2.1.9):
- Fixed enbug of 2.1.6-2.1.7 PHP error undefind valiable/array to string conversion
- The function to make thumbnail supports more image types when Imagick enabled
- Correction of the problem that Archive / Extract function don't work well under some environment
- Added a quicklook plugin that is the Google docs online viewer
- Default is disabled. Set `commandsOptions.quicklook.googleDocsMimes` to enable this plugin.
```javascript
commandsOptions : {
// "quicklook" command options.
quicklook : {
autoplay : true,
jplayer : 'extensions/jplayer',
// MIME types to use Google Docs online viewer
// Example array value
// ['application/pdf', 'image/tiff', 'application/msword', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
googleDocsMimes : []
}
}
```
- And some minor bug fixes
2016-03-07 Naoki Sawada
* elFinder (2.1.8):
- Added a new volume driver `MsSQL`
- Fixed #1226 problem of sort by clicking on cloumn headers
- Fixed #1229 bug of selection after sorting in list view
- Replaceable session handling wrapper (elFinderSessionInterface)
- Added Connector main config `defaultMimefile` ()
- update mime.types
- Added LocalFileSystem volume root config `followSymLinks` (defailt true)
- And some minor bug fixes
2016-02-21 Naoki Sawada
* elFinder (2.1.7):
- Added connector main options `commonTempPath` and `maxArcFilesSize`
- Fixed #353 It can download files/folders as an archve file
- Fixed #1195 Supported BMP in GD image resize
- Became possible to cancellation while searching
- Supported API protocol version 2.0 for the legacy connector
- Fixed #1206 Configurable places(favorites) (https://github.com/Studio-42/elFinder/issues/1206)
- Fixed #1211 Remove deprecated method jQueryUI.zIndex()
- Supported jQueryUI 1.12.0
- Fixed #1213 infinite loop in PHP connector
- Cmd:mkdir to callable "New Folder with Selected items" as "Into New Folder"
- Supported nao-pon/flysystem-google-drive with barryvdh/elfinder-flysystem-driver
- barryvdh/elfinder-flysystem-driver (https://github.com/barryvdh/elfinder-flysystem-driver)
- nao-pon/flysystem-google-drive (https://github.com/nao-pon/flysystem-google-drive)
- UX improvement of in Touch devices
- And some minor bug fixes
2015-02-21 Naoki Sawada
* elFinder (2.0.6):
- Fixed #1213 infinite loop in PHP connector
2016-01-19 Naoki Sawada
* elFinder (2.1.6):
- Fixed #1074 startPath for multi volumes
- Fixed #1172 enbug-fix of rename command
- Fixed #1174 support for multi-instance on the same connector
- Plugin: AutoResize New option `preserveExif`
- Fixed #179 JPEG quality specifiable
- Fixed #1176 auto-sync check with HTTP long polling/inotifywait
- Fixed #1181 case insensitive search problem of LocalFileSystem driver
- Added an autosync button into contextmenu `Reload`
- Added new client configuration `syncStart`
- Search result view optimization
- Adddd new volume root option `searchTimeout` (default 30s)
- Added new crient command `opendir` - opens selected item's parent folder at search result
- Sortable "Places" (your favorites)
- Fixed #1193 open the file at direct URL if possible
- And some minor bug fixes
2015-12-26 Naoki Sawada
* elFinder (2.1.5):
- Fixed bug that can't in writable with `chmod`
- Show remove item info in confirm dialog on `rm` action
- Fixed #1165, MIME types maintenance (doc, dot, xlt, xla)
- Fixed problem if filename included character that can't be json encode
- Added option `convmap` to Normalizer plugin
- And some minor bug fixes
2015-12-26 Naoki Sawada
* elFinder (2.0.5):
- Fixed problem if filename included character that can't be json encode
2015-12-16 Naoki Sawada
* elFinder (2.1.4):
- Fixed #1163 Dropbox driver supported windows server
- Fixed search problem on Windows server
2015-12-13 Naoki Sawada
* elFinder (2.1.3):
- Auto configure `customHeaders`, `xhrFields` for CORS
- Allow set elFinder::$volumesCnt by HTTP header "X-elFinder-VolumesCntStart"
- Resolved #1145, Configurable keyboard shortcuts of any command
- Force non-overwrite on URL uploading
- Supported Drag out function with [Shift] + Drag of file item (with out IE)
- Drag and Drop copy from elFinder(A) to elFinder(B)
- Make list of download url to Text editor
- Drag and Drop download with Chrome (Single file only)
- etc.
- Choosable "backup" at pasting of same name files
- Show confirm at uploading of same name file exists
- Show URL link icon on Download menu in contextmenu
- This icon is clickable as normal link, shows context menu and drag out
- Added more feedback sign of jQuery DnD drag icon
- Others, some minor bug fixes
2015-11-23 Naoki Sawada
* elFinder (2.1.2):
- [security-fix] vulnerability of the MIME type quarantine
- Multi-line filename editing on icon view
- Auto expands filename editing on list view
- Fixed #1124, Uploading problem exactly 20MiB/30MiB/40MiB...
- Marged #1125, Fix file permissions for MySQL LOAD_FILE command
- Fixed #1127, Supported full path including the drive letter of the Windows server
- Marged #1131, #1132, Complete Romanian(ro) translation
- Fixed symbolic link file stats `mtime`, `size`
- Marged #1133, Complete German(de) translation
- Marged #1139, Complete Türkçe(tr) translation
- Marged #1141, Plugin Normalizer function: make filename lowercase
- Others, some minor bug fixes
2015-11-23 Naoki Sawada
* elFinder (2.0.4):
- [security-fix] vulnerability of the MIME type quarantine
2015-11-10 Naoki Sawada
* elFinder (2.1.1):
- More High performance server backend and light client UI
- Connector plugin
- AutoResize : Auto resize on file upload.
- Normalizer : UTF-8 Normalizer of file-name and file-path etc.
- Sanitizer : Sanitizer of file-name and file-path etc.
- Watermark : Print watermark on file upload.
- Folder upload with Chrome
- Chunked file upload
- Upload directly to the folder
- Creating the archive by specifying the file name
- Direct extraction to the current working directory (you do not want to create a folder)
- Support Dropbox.com© (Configurable & As network volume)
- Supports custom information in info dialog
- Configuable columns of list view
- Supports custom CSS class function of tree view
2015-11-10 Naoki Sawada
* elFinder (2.0.3):
- jQuery 1.9+ support
- 350+ bugs fixed since rc1 version
- Modify translations and some new translations
- Netmount volume function
2012-04-10 Troex Nevelin
* elFinder (2.0 rc1):
- Major code refactor
- 200+ bugs fixed since beta version
- 14 new translations
- FTP volume driver
- Advanced image editing dialog
2011-07-10 Troex Nevelin
* elFinder (2.0 beta):
- New branch 2.x, total rewrite from scratch
- MySQL volume driver support (as file storage)
- Full drag & drop support with HTML5 upload
2011-06-20 Troex Nevelin
* elFinder (1.2):
- jQuery and UI updated
- Python connector improvements
- QuickLook fixed
- CSS fixes
- New icons from http://pixel-mixer.com/
- New languages: Czech, Dutch, German, Greek, French, Hungarian,
Italian, Japanese, Latvian, Polish, Brazilian Portuguese,
Slovak, Thai, Turkish, Vietnamese, Simplified Chinese,
Traditional Chinese
2010-03-11 Troex Nevelin
* elFinder (1.1):
- Total rewrite from scratch.
- New PHP connector.
- Python connector.
- Create/Extract archives.
- QuickLook.
- "Places" for favorites.
- Background thumbnails creation.
- Exteneded configuration options of connector and client.
- Spanish localization.
- JSON API description.
- Full documentation in English, Russian and Spanish.
- No more use of jquery plugins.
- Website update.
- [bugfix] All known bugs fixed.
2009-11-09 Dmitry Levashov
* elFinder (1.0.1):
- In directory tree panel added arrows to open/close directories
without entering in.
- Added shortcut support for copy/cut/paste/delete files and
folders. For Mac users added Command+Backspace support.
- Added context menu to current directory.
- Added help.
- [bugfix] invalid determing files/folders permissions using
"perms" options in php connector
PK SPK%g" g" README.mdnu W+A elFinder
========
**WARNING: IF YOU HAVE OLDER (IN PARTICULAR 2.1.20 OR EARLIER) VERSIONS OF ELFINDER ON PUBLIC SERVERS, IT MAY CAUSE SERIOUS DAMAGE TO YOUR SERVER AND VISITED USER. YOU SHOULD UPDATE TO THE LATEST VERSION OR REMOVE IT FROM THE SERVER.**
_ ______ _ _
| | ____(_) | |
___| | |__ _ _ __ __| | ___ _ __
/ _ \ | __| | | '_ \ / _` |/ _ \ '__|
| __/ | | | | | | | (_| | __/ |
\___|_|_| |_|_| |_|\__,_|\___|_|
elFinder is an open-source file manager for web, written in JavaScript using
jQuery UI. Creation is inspired by simplicity and convenience of Finder program
used in Mac OS X operating system.
[![Download now!](http://studio-42.github.io/elFinder/images/download-icon.png)](https://github.com/Studio-42/elFinder/releases/latest)
[![Packagist License](https://poser.pugx.org/studio-42/elfinder/license.png)](http://choosealicense.com/licenses/bsd-3-clause/)
[![Latest Stable Version](https://poser.pugx.org/studio-42/elfinder/version.png)](https://packagist.org/packages/studio-42/elfinder)
[![Total Downloads](https://poser.pugx.org/studio-42/elfinder/d/total.png)](https://packagist.org/packages/studio-42/elfinder)
[![CDNJS version](https://img.shields.io/cdnjs/v/elfinder.svg)](https://cdnjs.com/libraries/elfinder)
Contents
--------
* [Branches](#branches)
* [Features](#features)
* [Requirements](#requirements)
* [Installation](#installation)
* [Downloads](#downloads)
* [Demo Sites](#demo-sites)
* [FAQs](#faqs)
* [3rd Party Connectors](#3rd-party-connectors)
* [3rd Party Volume Drivers](#3rd-party-volume-drivers)
* [3rd Party Themes](#3rd-party-themes)
* [Support](#support)
* [Authors](#authors)
* [License](#license)
Branches
--------
- [master](https://github.com/Studio-42/elFinder/tree/master) - Main development branch
- [2.1-src](https://github.com/Studio-42/elFinder/tree/2.1-src) - 2.1 development branch, auto build to 2.1 on commit
- [2.1](https://github.com/Studio-42/elFinder/tree/2.1) - 2.1 nightly build branch
Features
--------
* Usability like the MacOS Finder or Windows Explorer
* Mobile friendly view for touch devices
* All operations with files and folders on a remote server (copy, move,
upload, create folder/file, rename, etc.)
* High performance server backend and light client UI
* Multi-root support
* Local file system, MySQL, FTP volume storage drivers
* Cloud storage (Box, Dropbox, GoogleDrive and OneDrive) drivers
* Background file/folder upload with Drag & Drop HTML5 support
* Chunked file upload for large file
* Upload directly to the folder
* Upload form URL (or list)
* List and Icons view
* Keyboard shortcuts
* Standard methods of file/group selection using mouse or keyboard
* Move/Copy files with Drag & Drop
* Drag & Drop to outside by starting drag with alt/option key press
* Archives create/extract (zip, rar, 7z, tar, gzip, bzip2)
* Rich context menu and toolbar
* Quicklook, preview for common file types
* Edit text files and images
* "Places" for your favorites
* Calculate directory sizes
* Thumbnails for image, movie files
* Easy to integrate with web editors (elRTE, CKEditor, TinyMCE)
* Flexible configuration of access rights, upload file types, user interface
and other
* Extensibility by event handling of backend and client side
* Simple client-server API based on JSON
* Supports custom information in info dialog
* Configuable columns of list view
* Supports custom CSS class function for the custom folder icon
* Connector plugin
* [AutoRotate](https://github.com/Studio-42/elFinder/blob/2.1-src/php/plugins/AutoRotate/plugin.php) : Auto rotation on file upload of JPEG file by EXIF Orientation.
* [AutoResize](https://github.com/Studio-42/elFinder/blob/2.1-src/php/plugins/AutoResize/plugin.php) : Auto resize on file upload.
* [Normalizer](https://github.com/Studio-42/elFinder/blob/2.1-src/php/plugins/Normalizer/plugin.php) : UTF-8 Normalizer of file-name and file-path etc.
* [Sanitizer](https://github.com/Studio-42/elFinder/blob/2.1-src/php/plugins/Sanitizer/plugin.php) : Sanitizer of file-name and file-path etc.
* [Watermark](https://github.com/Studio-42/elFinder/blob/2.1-src/php/plugins/Watermark/plugin.php) : Print watermark on file upload.
* For more details, see the [Changelog](https://github.com/Studio-42/elFinder/blob/master/Changelog)
Requirements
------------
### jQuery / jQuery UI
* jQuery 1.8.0+
* jQuery UI 1.9.0+ (require selectable, draggable, droppable and resizable)
**However, we recommend newest version.**
### Client
* Modern browser. elFinder was tested in Internet Explorer 8
and newest Firefox, Chrome, IE, Edge and Opera
### Server
* Any web server
* PHP 5.2+ (Recommend PHP 5.4 or higher) And for thumbnails - GD / Imagick module / convert(imagemagick) require
Installation
------------
### Builds (compressed)
1. Download and unzip one of the [builds](#downloads) below to your PHP server
2. Rename `/php/connector.minimal.php-dist` to `/php/connector.minimal.php`
3. Load `/elfinder.html` in your browser to run elFinder
### Source (uncompressed)
1. Clone this repository to your PHP server
```
$ git clone https://github.com/Studio-42/elFinder.git
```
2. Rename `/php/connector.minimal.php-dist` to `/php/connector.minimal.php`
3. Load `/elfinder.src.html` in your browser to run elFinder
### Installer
- [Setup elFinder 2.1.x nightly with Composer](https://github.com/Studio-42/elFinder/tree/gh-pages/tools/installer/setup_with_composer)
Downloads
------------
**Stable releases** ([Changelog](https://github.com/Studio-42/elFinder/blob/master/Changelog))
+ [elFinder 2.1.29](https://github.com/Studio-42/elFinder/archive/2.1.29.zip)
+ [elFinder 2.0.9](https://github.com/Studio-42/elFinder/archive/2.0.9.zip) (deprecated)
**Nightly builds**
+ [elFinder 2.1.x (Nightly)](https://github.com/Studio-42/elFinder/archive/2.1.zip)
Demo sites
------------
**2.1.x Nightly**
+ https://studio-42.github.io/elFinder/ (with CORS)
+ https://hypweb.net/elFinder-nightly/demo/2.1/
FAQs
------------
### Should I use elFinder builds (compressed) or source (uncompressed)?
For debugging and development, use the [source](#source-uncompressed). For production, use [builds](#builds-compressed).
### How do I integrate elFinder with CKEditor/TinyMCE/elRTE/etc...?
Check out the [wiki](https://github.com/studio-42/elFinder/wiki#howtos) for individual instructions.
### The procedure of language files created or modified?
You can create or modify the language file to use translation tool. Please refer to the pull request the results to the respective branch.
* [2.1 branch translation tool](http://studio-42.github.io/elFinder/tools/langman/#2.1)
3rd party connectors
--------------------
* [ASP.NET](https://github.com/leniel/elFinder.Net)
* [ASP.NET Core](https://github.com/gordon-matt/elFinder.NetCore)
* [Java Servlet](https://github.com/trustsystems/elfinder-java-connector)
* [Python](https://github.com/Studio-42/elfinder-python)
* [Ruby/Rails](https://github.com/phallstrom/el_finder)
* [Django](https://github.com/mikery/django-elfinder)
* [Laravel](https://github.com/barryvdh/laravel-elfinder)
* [JavaScript/Efw](https://github.com/efwGrp/efw3.X/blob/master/help/api_efw_tag.md#elfinder-tag)
* [Symfony](https://github.com/helios-ag/FMElfinderBundle)
3rd party Volume Drivers
--------------------
* [League\Flysystem (PHP)](https://github.com/barryvdh/elfinder-flysystem-driver) (for elFinder 2.1+)
3rd party Themes
--------------------
Hint: [How to load CSS with RequireJS?](https://github.com/Studio-42/elFinder/wiki/How-to-load-CSS-with-RequireJS%3F)
* [lokothodida/elfinder-theme-moono](https://github.com/lokothodida/elfinder-theme-moono)
* [lokothodida/elfinder-theme-windows-10](https://github.com/lokothodida/elfinder-theme-windows-10)
* [StudioJunkyard/elfinder-boostrap-theme](https://github.com/StudioJunkyard/LibreICONS/tree/master/themes/elFinder)
* [RobiNN1/elFinder-Material-Theme](https://github.com/RobiNN1/elFinder-Material-Theme)
Support
-------
* [Homepage](http://elfinder.org)
* [Wiki](https://github.com/Studio-42/elFinder/wiki)
* [Issues](https://github.com/Studio-42/elFinder/issues)
*
Authors
-------
* Chief developer: Dmitry "dio" Levashov
* Maintainer: Troex Nevelin
* Developers: Alexey Sukhotin , Naoki Sawada
* Icons: [PixelMixer](http://pixelmixer.ru), [Yusuke Kamiyamane](http://p.yusukekamiyamane.com)
We hope our tools will be helpful for you.
License
-------
elFinder is issued under a 3-clauses BSD license.
* [License terms](https://github.com/Studio-42/elFinder/blob/master/LICENSE.md)
PK SPK-2 2 Jakefile.jsnu W+A /*
* This is build file for elFinder 2.x
* Build tool: https://github.com/mde/jake
* JS compressor: https://github.com/mishoo/UglifyJS/
* CSS optimizer: https://github.com/css/csso
*/
// if Jake fails to detect need libraries try running before: export NODE_PATH=`npm root`
var fs = require('fs'),
path = require('path'),
util = require('util'),
ugjs = require('uglify-js'),
csso = require('csso');
var dirmode = 0755,
src = __dirname,
version = null,
files = {
'elfinder.full.js':
[
path.join(src, 'js', 'elFinder.js'),
path.join(src, 'js', 'elFinder.version.js'),
path.join(src, 'js', 'jquery.elfinder.js'),
path.join(src, 'js', 'elFinder.mimetypes.js'),
path.join(src, 'js', 'elFinder.options.js'),
path.join(src, 'js', 'elFinder.options.netmount.js'),
path.join(src, 'js', 'elFinder.history.js'),
path.join(src, 'js', 'elFinder.command.js'),
path.join(src, 'js', 'elFinder.resources.js'),
path.join(src, 'js', 'jquery.dialogelfinder.js'),
path.join(src, 'js', 'i18n', 'elfinder.en.js')
]
.concat(grep(path.join(src, 'js', 'ui'), '\\.js$'))
.concat(grep(path.join(src, 'js', 'commands'), '\\.js$')),
'elfinder.full.css': grep(path.join(src, 'css'), '\\.css$', 'elfinder|theme'),
'images': grep(path.join(src, 'img'), '\\.png|\\.gif'),
'sounds': grep(path.join(src, 'sounds'), '\\.wav'),
'i18n': grep(path.join(src, 'js', 'i18n'), '\\.js', 'elfinder.en.js')
.concat(grep(path.join(src, 'js', 'i18n', 'help'), '\\.js')),
'php':
[
path.join(src, 'php', 'autoload.php'),
path.join(src, 'php', 'connector.minimal.php-dist'),
path.join(src, 'php', 'mime.types'),
path.join(src, 'php', 'MySQLStorage.sql'),
path.join(src, 'php', 'elFinderPlugin.php'),
path.join(src, 'php', 'elFinderSession.php'),
path.join(src, 'php', 'elFinderSessionInterface.php'),
path.join(src, 'php', '.tmp', '.htaccess')
]
.concat(grep(path.join(src, 'php'), '\\.class\\.php$'))
.concat(grep(path.join(src, 'php'), 'Netmount\\.php$'))
.concat(grep(path.join(src, 'php', 'libs'), '\\.php$'))
.concat(grep(path.join(src, 'php', 'resources'), '.+\..+$')),
'misc':
[
path.join(src, 'js', 'proxy', 'elFinderSupportVer1.js'),
path.join(src, 'Changelog'),
path.join(src, 'LICENSE.md'),
path.join(src, 'README.md'),
path.join(src, 'composer.json'),
path.join(src, 'elfinder.html'),
path.join(src, 'elfinder.legacy.html'),
path.join(src, 'main.default.js')
]
.concat(grep(path.join(src, 'js', 'extras'), '\\.js$'))
};
// plugins files
var plugins = [];
try {
plugins = fs.readdirSync(path.join(src, 'php', 'plugins'));
} catch (err) { }
if (plugins.length) {
for (var i in plugins) {
files.php = files.php.concat(grep(path.join(src, 'php', 'plugins', plugins[i]), '.+'));
}
}
// custom functions
function grep(prefix, mask, exculde) {
var m = new RegExp(mask);
var e = new RegExp(exculde);
var o = new Array();
var input = new Array();
try {
input = fs.readdirSync(prefix);
} catch (err) { }
for (i in input) {
if ((typeof exculde !== 'undefined') && (input[i].match(e))) {
//console.log('skip ' + input[i]);
continue;
}
if (input[i].match(m)) {
o.push(path.join(prefix, input[i]));
}
}
return o.sort();
}
function copyFile(from, to, overwrite) {
if (!overwrite && fs.existsSync(to)) {
return false;
}
console.log('\t' + from);
var srcs = fs.createReadStream(from);
var dsts = fs.createWriteStream(to);
return srcs.pipe(dsts);
}
function getVersion() {
var ver = fs.readFileSync(path.join(src, 'js', 'elFinder.version.js')).toString();
ver = ver.match(/elFinder.prototype.version = '(.+)';/);
return ver[1];
}
function buildComment() {
var d = new Date();
var buildDate = d.getFullYear() + '-' +
(d.getMonth() >= 9 ? '' : '0') + (d.getMonth() + 1) + '-' +
(d.getDate() >= 10 ? '' : '0') + d.getDate();
var comment =
'/*!\n' +
' * elFinder - file manager for web\n' +
' * Version ' + getVersion() + ' (' + buildDate + ')\n' +
' * http://elfinder.org\n' +
' * \n' +
' * Copyright 2009-' + d.getFullYear() + ', Studio 42\n' +
' * Licensed under a 3-clauses BSD license\n' +
' */\n';
return comment;
}
// tasks
desc('Help');
task('default', function(){
console.log(
"This is elFinder build script, run `jake --tasks` for more info, for a default build run:\n" +
" jake -C ./build elfinder"
);
});
desc('pre build task');
task('prebuild', function(){
console.log('build dir: ' + path.resolve());
console.log('src dir: ' + src);
var dir = ['css', 'js', 'img', 'sounds',
path.join('js', 'i18n'), path.join('js', 'i18n', 'help'), path.join('js', 'extras'), path.join('js', 'proxy'),
'php',
path.join('php', '.tmp'), path.join('php', 'libs'), path.join('php', 'resources'),
'files', path.join('files', '.trash')];
if (plugins.length) {
dir.push(path.join('php', 'plugins'));
for (var i in plugins) {
dir.push(path.join('php', 'plugins', plugins[i]));
}
}
for (d in dir) {
var bd = dir[d];
if (!fs.existsSync(bd)) {
console.log('mkdir ' + bd);
fs.mkdirSync(bd, dirmode);
}
}
//jake.Task['elfinder'].invoke();
});
desc('build elFinder');
task({'elfinder': ['prebuild', 'css/elfinder.min.css', 'js/elfinder.min.js', 'misc', 'js/extras']}, function(){
console.log('elFinder build done');
});
// CSS
desc('concat elfinder.full.css');
file({'css/elfinder.full.css': files['elfinder.full.css']}, function(){
console.log('concat ' + this.name);
var data = '';
for (f in this.prereqs) {
file = this.prereqs[f];
console.log('\t' + file);
data += '\n/* File: ' + file.replace(src, '') + ' */\n';
data += fs.readFileSync(file);
}
fs.writeFileSync(this.name, buildComment() + data);
});
desc('optimize elfinder.min.css');
file({'css/elfinder.min.css': ['css/elfinder.full.css']}, function () {
console.log('optimize elfinder.min.css');
var cssOptimized = csso.minify(fs.readFileSync('css/elfinder.full.css').toString());
fs.writeFileSync(this.name, cssOptimized.css || cssOptimized);
});
// JS
desc('concat elfinder.full.js');
file({'js/elfinder.full.js': files['elfinder.full.js']}, function(){
console.log('concat elfinder.full.js');
var strict = new RegExp('"use strict"\;?\n?');
var elf = files['elfinder.full.js'];
var data = '';
for (f in elf) {
file = elf[f];
console.log('\t' + file);
data += '\n\n/*\n * File: ' + file.replace(src, '') + '\n */\n\n';
data += fs.readFileSync(file);
data = data.replace(strict, '');
}
data = "(function(root, factory) {\n" +
" if (typeof define === 'function' && define.amd) {\n" +
" // AMD\n" +
" define(['jquery','jquery-ui'], factory);\n" +
" } else if (typeof exports !== 'undefined') {\n" +
" // CommonJS\n" +
" var $, ui;\n" +
" try {\n" +
" $ = require('jquery');\n" +
" ui = require('jquery-ui');\n" +
" } catch (e) {}\n" +
" module.exports = factory($, ui);\n" +
" } else {\n" +
" // Browser globals (Note: root is window)\n" +
" factory(root.jQuery, root.jQuery.ui, true);\n" +
" }\n" +
"}(this, function($, _ui, toGlobal) {\n" +
"toGlobal = toGlobal || false;\n" + data + '\nreturn elFinder;\n}));'; // add UMD closure
fs.writeFileSync(this.name, buildComment() + data);
});
desc('uglify elfinder.min.js');
file({'js/elfinder.min.js': ['js/elfinder.full.js']}, function () {
console.log('uglify elfinder.min.js');
var result;
if (typeof ugjs.minify == 'undefined') {
var ugp = ugjs.parser;
var ugu = ugjs.uglify;
var ast = ugp.parse(fs.readFileSync('js/elfinder.full.js').toString()); // parse code and get the initial AST
ast = ugu.ast_mangle(ast); // get a new AST with mangled names
ast = ugu.ast_squeeze(ast); // get an AST with compression optimizations
result = ugu.split_lines(ugu.gen_code(ast), 1024 * 8); // insert new line every 8 kb
} else {
result = ugjs.minify('js/elfinder.full.js').code;
}
fs.writeFileSync(this.name, buildComment() + result);
});
// IMG + SOUNDS + I18N + PHP
desc('copy misc files');
task('misc', function(){
console.log('copy misc files');
var cf = files['images']
.concat(files['sounds'])
.concat(files['i18n'])
.concat(path.join(src, 'css', 'theme.css'))
.concat(files['php'])
.concat(files['misc'])
.concat(path.join(src, 'files', '.gitignore'))
.concat(path.join(src, 'files', '.trash', '.gitignore'));
for (i in cf)
{
var dst = cf[i].replace(src, '').substr(1);
copyFile(cf[i], dst);
}
// elfinder.html
// var hs = path.join(src, 'build', 'elfinder.html');
// var hd = path.join('elfinder.html');
// copyFile(hs, hd);
// connector
//var cs = path.join(src, 'php', 'connector.minimal.php-dist');
//var cd = path.join('php', 'connector.php-dist');
//copyFile(cs, cd);
});
desc('uglify js/extras');
task('js/extras', function(){
var files = grep(path.join(src, 'js', 'extras'), '\\.js$');
var base, name, result;
for (var i in files) {
name = files[i].replace(/^.+\/([^\/]+)$/, '$1');
if (! name.match(/\.min\./)) {
base = name.replace(/\.js$/, '');
name = 'js/extras/' + name;
console.log('uglify ' + name);
if (typeof ugjs.minify == 'undefined') {
var ugp = ugjs.parser;
var ugu = ugjs.uglify;
var ast = ugp.parse(fs.readFileSync(files[i]).toString()); // parse code and get the initial AST
ast = ugu.ast_mangle(ast); // get a new AST with mangled names
ast = ugu.ast_squeeze(ast); // get an AST with compression optimizations
result = ugu.split_lines(ugu.gen_code(ast), 1024 * 8); // insert new line every 8 kb
} else {
result = ugjs.minify(files[i]).code;
}
fs.writeFileSync('js/extras/' + base + '.min.js', result);
}
}
});
// other
desc('clean build dir');
task('clean', function(){
console.log('cleaning the floor');
uf = [path.join('js', 'elfinder.full.js'), path.join('js', 'elfinder.min.js'),
path.join('css', 'elfinder.full.css'), path.join('css', 'elfinder.min.css'),
path.join('files', '.trash', '.gitignore'), path.join('files', '.gitignore')];
// clean images, sounds, js/i18n and php only if we are not in src
if (src != path.resolve()) {
uf = uf
.concat(path.join('css', 'theme.css'))
.concat(grep('img', '\\.png|\\.gif'))
.concat(grep('sounds', '\\.wav'))
.concat(grep(path.join('js', 'i18n', 'help')))
.concat(grep(path.join('js', 'i18n'), '\\.js'))
.concat(grep(path.join('js', 'extras')))
.concat([path.join('js', 'proxy', 'elFinderSupportVer1.js'), 'Changelog', 'README.md', 'elfinder.html', 'composer.json', 'LICENSE.md', 'main.default.js', path.join('files', 'readme.txt')])
.concat(grep('php', '\\.php|\\.sql'))
.concat(path.join('php', 'mime.types'))
.concat(grep(path.join('php', '.tmp')))
.concat(grep(path.join('php', 'libs')))
.concat(grep(path.join('php', 'resources')));
uf = [].concat.apply(uf, grep(path.join('php', 'plugins')).map(function(dir) { return grep(dir); }));
}
for (f in uf) {
var file = uf[f];
if (fs.existsSync(file)) {
console.log('\tunlink ' + file);
fs.unlinkSync(file);
}
}
// if (path.join(src, 'build') != path.resolve()) {
// fs.unlinkSync('elfinder.html');
// }
if (src != path.resolve()) {
var ud = [
'css', 'img', 'sounds', path.join('files', '.trash'), 'files',
path.join('js', 'proxy'), path.join('js', 'i18n', 'help'), path.join('js', 'i18n'), path.join('js', 'extras'), 'js',
path.join('php', '.tmp'), path.join('php', 'libs'), path.join('php', 'resources')]
.concat(grep(path.join('php', 'plugins')))
.concat([path.join('php', 'plugins'), 'php']);
for (d in ud) {
var dir = ud[d];
if (fs.existsSync(dir)) {
console.log('\trmdir ' + dir);
fs.rmdirSync(dir);
}
}
}
});
desc('get current build version from git');
task('version', function(){
version = getVersion();
console.log('Version: ' + version);
complete();
}, {async: true});
desc('create package task');
task('prepack', function(){
new jake.PackageTask('elfinder', version, function(){
var fls = (files['php'].concat(files['images']).concat(files['sounds']).concat(files['i18n']).concat(files['misc'])).map(function(i){
return i.substr(src.length + 1);
});
fls.push(path.join('css', 'elfinder.min.css'));
fls.push(path.join('css', 'theme.css'));
fls.push(path.join('js', 'elfinder.min.js'));
fls.push('files');
console.log('Including next files into release:');
console.log(fls);
this.packageFiles.items = fls;
this.needTarGz = true;
this.needZip = true;
});
});
desc('pack release');
task({'release': ['version']}, function(){
var prePack = jake.Task['prepack'];
prePack.addListener('complete', function() {
var pack = jake.Task['package'];
pack.addListener('complete', function() {
console.log('Created package for elFinder ' + version);
complete();
});
pack.invoke();
});
prePack.invoke();
}, {async: true});
PK SPK˞Ś
js/jquery.dialogelfinder.jsnu W+A "use strict";
/**
* @class dialogelfinder - open elFinder in dialog window
*
* @param Object elFinder options with dialog options
* @example
* $(selector).dialogelfinder({
* // some elfinder options
* title : 'My files', // dialog title, default = "Files"
* width : 850, // dialog width, default 840
* autoOpen : false, // if false - dialog will not be opened after init, default = true
* destroyOnClose : true // destroy elFinder on close dialog, default = false
* })
* @author Dmitry (dio) Levashov
**/
$.fn.dialogelfinder = function(opts) {
var position = 'elfinderPosition',
destroy = 'elfinderDestroyOnClose';
this.not('.elfinder').each(function() {
var doc = $(document),
toolbar = $(''),
button = $(' ')
.appendTo(toolbar)
.click(function(e) {
e.preventDefault();
node.dialogelfinder('close');
}),
node = $(this).addClass('dialogelfinder')
.css('position', 'absolute')
.hide()
.appendTo('body')
.draggable({
handle : '.dialogelfinder-drag',
containment : 'window',
stop : function() {
node.trigger('resize');
elfinder.trigger('resize');
}
})
.elfinder(opts)
.prepend(toolbar),
elfinder = node.elfinder('instance');
node.width(parseInt(node.width()) || 840) // fix width if set to "auto"
.data(destroy, !!opts.destroyOnClose)
.find('.elfinder-toolbar').removeClass('ui-corner-top');
opts.position && node.data(position, opts.position);
opts.autoOpen !== false && $(this).dialogelfinder('open');
});
if (opts == 'open') {
var node = $(this),
pos = node.data(position) || {
top : parseInt($(document).scrollTop() + ($(window).height() < node.height() ? 2 : ($(window).height() - node.height())/2)),
left : parseInt($(document).scrollLeft() + ($(window).width() < node.width() ? 2 : ($(window).width() - node.width())/2))
};
if (node.is(':hidden')) {
node.addClass('ui-front').css(pos).show().trigger('resize');
setTimeout(function() {
// fix resize icon position and make elfinder active
node.trigger('resize').mousedown();
}, 200);
}
} else if (opts == 'close') {
var node = $(this).removeClass('ui-front');
if (node.is(':visible')) {
!!node.data(destroy)
? node.elfinder('destroy').remove()
: node.elfinder('close');
}
} else if (opts == 'instance') {
return $(this).getElFinder();
}
return this;
};
PK SPK<h js/jquery.elfinder.jsnu W+A /*** jQuery UI droppable performance tune for elFinder ***/
(function(){
if ($.ui) {
if ($.ui.ddmanager) {
var origin = $.ui.ddmanager.prepareOffsets;
$.ui.ddmanager.prepareOffsets = function( t, event ) {
var isOutView = function(elem) {
if (elem.is(':hidden')) {
return true;
}
var rect = elem[0].getBoundingClientRect();
return document.elementFromPoint(rect.left, rect.top)? false : true;
}
if (event.type === 'mousedown' || t.options.elfRefresh) {
var i, d,
m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
l = m.length;
for ( i = 0; i < l; i++ ) {
d = m[ i ];
if (d.options.autoDisable && (!d.options.disabled || d.options.autoDisable > 1)) {
d.options.disabled = isOutView(d.element);
d.options.autoDisable = d.options.disabled? 2 : 1;
}
}
}
// call origin function
return origin( t, event );
};
}
}
})();
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 2011–2014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
(function ($) {
// Detect touch support
$.support.touch = 'ontouchend' in document;
// Ignore browsers without touch support
if (!$.support.touch) {
return;
}
var mouseProto = $.ui.mouse.prototype,
_mouseInit = mouseProto._mouseInit,
_mouseDestroy = mouseProto._mouseDestroy,
touchHandled,
posX, posY;
/**
* Simulate a mouse event based on a corresponding touch event
* @param {Object} event A touch event
* @param {String} simulatedType The corresponding mouse event
*/
function simulateMouseEvent (event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
if (! $(event.currentTarget).hasClass('touch-punch-keep-default')) {
event.preventDefault();
}
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
// Initialize the simulated mouse event using the touch event's coordinates
simulatedEvent.initMouseEvent(
simulatedType, // type
true, // bubbles
true, // cancelable
window, // view
1, // detail
touch.screenX, // screenX
touch.screenY, // screenY
touch.clientX, // clientX
touch.clientY, // clientY
false, // ctrlKey
false, // altKey
false, // shiftKey
false, // metaKey
0, // button
null // relatedTarget
);
// Dispatch the simulated event to the target element
event.target.dispatchEvent(simulatedEvent);
}
/**
* Handle the jQuery UI widget's touchstart events
* @param {Object} event The widget element's touchstart event
*/
mouseProto._touchStart = function (event) {
var self = this;
// Ignore the event if another widget is already being handled
if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
return;
}
// Track element position to avoid "false" move
posX = event.originalEvent.changedTouches[0].screenX.toFixed(0);
posY = event.originalEvent.changedTouches[0].screenY.toFixed(0);
// Set the flag to prevent other widgets from inheriting the touch event
touchHandled = true;
// Track movement to determine if interaction was a click
self._touchMoved = false;
// Simulate the mouseover event
simulateMouseEvent(event, 'mouseover');
// Simulate the mousemove event
simulateMouseEvent(event, 'mousemove');
// Simulate the mousedown event
simulateMouseEvent(event, 'mousedown');
};
/**
* Handle the jQuery UI widget's touchmove events
* @param {Object} event The document's touchmove event
*/
mouseProto._touchMove = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Ignore if it's a "false" move (position not changed)
var x = event.originalEvent.changedTouches[0].screenX.toFixed(0);
var y = event.originalEvent.changedTouches[0].screenY.toFixed(0);
// Ignore if it's a "false" move (position not changed)
if (Math.abs(posX - x) <= 4 && Math.abs(posY - y) <= 4) {
return;
}
// Interaction was not a click
this._touchMoved = true;
// Simulate the mousemove event
simulateMouseEvent(event, 'mousemove');
};
/**
* Handle the jQuery UI widget's touchend events
* @param {Object} event The document's touchend event
*/
mouseProto._touchEnd = function (event) {
// Ignore event if not handled
if (!touchHandled) {
return;
}
// Simulate the mouseup event
simulateMouseEvent(event, 'mouseup');
// Simulate the mouseout event
simulateMouseEvent(event, 'mouseout');
// If the touch interaction did not move, it should trigger a click
if (!this._touchMoved) {
// Simulate the click event
simulateMouseEvent(event, 'click');
}
// Unset the flag to allow other widgets to inherit the touch event
touchHandled = false;
this._touchMoved = false;
};
/**
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
* This method extends the widget with bound touch event handlers that
* translate touch events to mouse events and pass them to the widget's
* original mouse event handling methods.
*/
mouseProto._mouseInit = function () {
var self = this;
if (self.element.hasClass('touch-punch')) {
// Delegate the touch handlers to the widget's element
self.element.on({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
}
// Call the original $.ui.mouse init method
_mouseInit.call(self);
};
/**
* Remove the touch event handlers
*/
mouseProto._mouseDestroy = function () {
var self = this;
if (self.element.hasClass('touch-punch')) {
// Delegate the touch handlers to the widget's element
self.element.off({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
}
// Call the original $.ui.mouse destroy method
_mouseDestroy.call(self);
};
})(jQuery);
$.fn.elfinder = function(o, o2) {
if (o === 'instance') {
return this.getElFinder();
}
return this.each(function() {
var cmd = typeof o === 'string' ? o : '',
bootCallback = typeof o2 === 'function'? o2 : void(0),
opts;
if (!this.elfinder) {
if ($.isPlainObject(o)) {
new elFinder(this, o, bootCallback);
}
} else {
switch(cmd) {
case 'close':
case 'hide':
this.elfinder.hide();
break;
case 'open':
case 'show':
this.elfinder.show();
break;
case 'destroy':
this.elfinder.destroy();
break;
case 'reload':
case 'restart':
if (this.elfinder) {
opts = this.elfinder.options;
bootCallback = this.elfinder.bootCallback;
this.elfinder.destroy();
new elFinder(this, $.extend(true, opts, $.isPlainObject(o2)? o2 : {}), bootCallback);
}
break;
}
}
});
};
$.fn.getElFinder = function() {
var instance;
this.each(function() {
if (this.elfinder) {
instance = this.elfinder;
return false;
}
});
return instance;
};
$.fn.elfUiWidgetInstance = function(name) {
try {
return this[name]('instance');
} catch(e) {
// fallback for jQuery UI < 1.11
var data = this.data('ui-' + name);
if (data && typeof data === 'object' && data.widgetFullName === 'ui-' + name) {
return data;
}
return null;
}
};
// function scrollRight
if (! $.fn.scrollRight) {
$.fn.extend({
scrollRight: function (val) {
if (val === undefined) {
return Math.max(0, this[0].scrollWidth - (this[0].scrollLeft + this[0].clientWidth));
}
return this.scrollLeft(this[0].scrollWidth - this[0].clientWidth - val);
}
});
}
PK SPK\/ob b js/ui/searchbutton.jsnu W+A "use strict";
/**
* @class elFinder toolbar search button widget.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindersearchbutton = function(cmd) {
return this.each(function() {
var result = false,
fm = cmd.fm,
isopts = cmd.options.incsearch || { enable: false },
id = function(name){return fm.namespace + name},
toolbar= fm.getUI('toolbar'),
btnCls = fm.res('class', 'searchbtn'),
button = $(this).hide().addClass('ui-widget-content elfinder-button '+btnCls),
search = function() {
input.data('inctm') && clearTimeout(input.data('inctm'));
opts && opts.slideUp();
var val = $.trim(input.val()),
from = !$('#' + id('SearchFromAll')).prop('checked'),
mime = $('#' + id('SearchMime')).prop('checked');
if (from) {
if ($('#' + id('SearchFromVol')).prop('checked')) {
from = fm.root(fm.cwd().hash);
} else {
from = fm.cwd().hash;
}
}
if (mime) {
mime = val;
val = '.';
}
if (val) {
cmd.exec(val, from, mime).done(function() {
result = true;
input.focus();
}).fail(function() {
abort();
});
} else {
fm.trigger('searchend');
}
},
abort = function() {
input.data('inctm') && clearTimeout(input.data('inctm'));
input.val('').blur();
if (result || incVal) {
result = false;
incVal = '';
fm.lazy(function() {
fm.trigger('searchend');
});
}
},
incVal = '',
input = $('')
.on('focus', function() {
incVal = '';
opts && opts.slideDown();
})
.on('blur', function(){
if (opts) {
if (!opts.data('infocus')) {
opts.slideUp();
} else {
opts.data('infocus', false);
}
}
})
.appendTo(button)
// to avoid fm shortcuts on arrows
.on('keypress', function(e) {
e.stopPropagation();
})
.on('keydown', function(e) {
e.stopPropagation();
e.keyCode == $.ui.keyCode.ENTER && search();
if (e.keyCode == $.ui.keyCode.ESCAPE) {
e.preventDefault();
abort();
}
}),
opts, cwdReady;
if (isopts.enable) {
isopts.minlen = isopts.minlen || 2;
isopts.wait = isopts.wait || 500;
input
.attr('title', fm.i18n('incSearchOnly'))
.on('compositionstart', function() {
input.data('composing', true);
})
.on('compositionend', function() {
input.removeData('composing');
input.trigger('input'); // for IE, edge
})
.on('input', function() {
if (! input.data('composing')) {
input.data('inctm') && clearTimeout(input.data('inctm'));
input.data('inctm', setTimeout(function() {
var val = input.val();
if (val.length === 0 || val.length >= isopts.minlen) {
(incVal !== val) && fm.trigger('incsearchstart', { query: val });
incVal = val;
if (val === '' && fm.searchStatus.state > 1 && fm.searchStatus.query) {
input.val(fm.searchStatus.query).select();
}
}
}, isopts.wait));
}
});
if (fm.UA.ltIE8) {
input.on('keydown', function(e) {
if (e.keyCode === 229) {
input.data('imetm') && clearTimeout(input.data('imetm'));
input.data('composing', true);
input.data('imetm', setTimeout(function() {
input.removeData('composing');
}, 100));
}
})
.on('keyup', function(e) {
input.data('imetm') && clearTimeout(input.data('imetm'));
if (input.data('composing')) {
e.keyCode === $.ui.keyCode.ENTER && input.trigger('compositionend');
} else {
input.trigger('input');
}
});
}
}
$('')
.appendTo(button)
.click(search);
$('')
.appendTo(button)
.click(abort);
// wait when button will be added to DOM
fm.bind('toolbarload', function(){
var parent = button.parent();
if (parent.length) {
toolbar.prepend(button.show());
parent.remove();
// position icons for ie7
if (fm.UA.ltIE7) {
var icon = button.children(fm.direction == 'ltr' ? '.ui-icon-close' : '.ui-icon-search');
icon.css({
right : '',
left : parseInt(button.width())-icon.outerWidth(true)
});
}
}
});
fm
.one('open', function() {
opts = (fm.api < 2.1)? null : $('')
.append(
$('')
.append(
$(''),
$(''),
$('')
),
$('')
.append(
$(''),
$('')
)
)
.hide()
.appendTo(button);
if (opts) {
opts.find('div.buttonset').buttonset();
$('#'+id('SearchFromAll')).next('label').attr('title', fm.i18n('searchTarget', fm.i18n('btnAll')));
$('#'+id('SearchMime')).next('label').attr('title', fm.i18n('searchMime'));
opts.on('mousedown', 'div.buttonset', function(e){
e.stopPropagation();
opts.data('infocus', true);
})
.on('click', 'input', function(e) {
e.stopPropagation();
$.trim(input.val()) && search();
});
}
})
.select(function() {
input.blur();
})
.bind('searchend', function() {
input.val('');
})
.bind('open parents', function() {
var dirs = [],
volroot = fm.file(fm.root(fm.cwd().hash));
if (volroot) {
$.each(fm.parents(fm.cwd().hash), function(i, hash) {
dirs.push(fm.file(hash).name);
});
$('#'+id('SearchFromCwd')).next('label').attr('title', fm.i18n('searchTarget', dirs.join(fm.option('separator'))));
$('#'+id('SearchFromVol')).next('label').attr('title', fm.i18n('searchTarget', volroot.name));
}
})
.bind('open', function() {
incVal && abort();
})
.bind('cwdinit', function() {
cwdReady = false;
})
.bind('cwdrender',function() {
cwdReady = true;
})
.bind('keydownEsc', function() {
if (incVal && incVal.substr(0, 1) === '/') {
incVal = '';
input.val('');
fm.trigger('searchend');
}
})
.shortcut({
pattern : 'ctrl+f f3',
description : cmd.title,
callback : function() {
input.select().focus();
}
})
.shortcut({
pattern : 'a b c d e f g h i j k l m n o p q r s t u v w x y z dig0 dig1 dig2 dig3 dig4 dig5 dig6 dig7 dig8 dig9 num0 num1 num2 num3 num4 num5 num6 num7 num8 num9',
description : fm.i18n('firstLetterSearch'),
callback : function(e) {
if (! cwdReady) { return; }
var code = e.originalEvent.keyCode,
next = function() {
var sel = fm.selected(),
key = $.ui.keyCode[(!sel.length || $('#'+fm.cwdHash2Id(sel[0])).next('[id]').length)? 'RIGHT' : 'HOME'];
$(document).trigger($.Event('keydown', { keyCode: key, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
},
val;
if (code >= 96 && code <= 105) {
code -= 48;
}
val = '/' + String.fromCharCode(code);
if (incVal !== val) {
input.val(val);
incVal = val;
fm
.trigger('incsearchstart', { query: val })
.one('cwdrender', next);
} else{
next();
}
}
});
});
};
PK SPK4 js/ui/uploadButton.jsnu W+A "use strict";
/**
* @class elFinder toolbar's button tor upload file
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderuploadbutton = function(cmd) {
return this.each(function() {
var button = $(this).elfinderbutton(cmd)
.off('click'),
form = $('').appendTo(button),
input = $('')
.change(function() {
var _input = $(this);
if (_input.val()) {
cmd.exec({input : _input.remove()[0]});
input.clone(true).appendTo(form);
}
})
.on('dragover', function(e) {
e.originalEvent.dataTransfer.dropEffect = 'copy';
});
form.append(input.clone(true));
cmd.change(function() {
form[cmd.disabled() ? 'hide' : 'show']();
})
.change();
});
};
PK SPK*= = js/ui/button.jsnu W+A "use strict";
/**
* @class elFinder toolbar button widget.
* If command has variants - create menu
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderbutton = function(cmd) {
return this.each(function() {
var c = 'class',
fm = cmd.fm,
disabled = fm.res(c, 'disabled'),
active = fm.res(c, 'active'),
hover = fm.res(c, 'hover'),
item = 'elfinder-button-menu-item',
selected = 'elfinder-button-menu-item-selected',
menu,
text = $(''+cmd.title+''),
button = $(this).addClass('ui-state-default elfinder-button')
.attr('title', cmd.title)
.append('', text)
.hover(function(e) { !button.hasClass(disabled) && button[e.type == 'mouseleave' ? 'removeClass' : 'addClass'](hover) /**button.toggleClass(hover);*/ })
.click(function(e) {
if (!button.hasClass(disabled)) {
if (menu && cmd.variants.length >= 1) {
// close other menus
menu.is(':hidden') && cmd.fm.getUI().click();
e.stopPropagation();
menu.slideToggle(100);
} else {
fm.exec(cmd.name, void(0), {_userAction: true, _currentType: 'toolbar', _currentNode: button });
}
}
}),
hideMenu = function() {
menu.hide();
};
text.hide();
// set self button object to cmd object
cmd.button = button;
// if command has variants create menu
if (Array.isArray(cmd.variants)) {
button.addClass('elfinder-menubutton');
menu = $('')
.hide()
.appendTo(button)
.on('mouseenter mouseleave', '.'+item, function() { $(this).toggleClass(hover) })
.on('click', '.'+item, function(e) {
var opts = $(this).data('value');
e.preventDefault();
e.stopPropagation();
button.removeClass(hover);
menu.hide();
if (typeof opts === 'undefined') {
opts = {};
}
if (typeof opts === 'object') {
opts._userAction = true;
}
fm.exec(cmd.name, fm.selected(), opts);
});
cmd.fm.bind('disable select', hideMenu).getUI().click(hideMenu);
cmd.change(function() {
menu.html('');
$.each(cmd.variants, function(i, variant) {
menu.append($(''+variant[1]+'
').data('value', variant[0]).addClass(variant[0] == cmd.value ? selected : ''));
});
});
}
cmd.change(function() {
if (cmd.disabled()) {
button.removeClass(active+' '+hover).addClass(disabled);
} else {
button.removeClass(disabled);
button[cmd.active() ? 'addClass' : 'removeClass'](active);
}
if (cmd.syncTitleOnChange) {
text.html(cmd.title);
button.attr('title', cmd.title);
}
})
.change();
});
};
PK SPK js/ui/overlay.jsnu W+A
$.fn.elfinderoverlay = function(opts) {
var fm = this.parent().elfinder('instance');
this.filter(':not(.elfinder-overlay)').each(function() {
opts = Object.assign({}, opts);
$(this).addClass('ui-front ui-widget-overlay elfinder-overlay')
.hide()
.mousedown(function(e) {
e.preventDefault();
e.stopPropagation();
})
.data({
cnt : 0,
show : typeof(opts.show) == 'function' ? opts.show : function() { },
hide : typeof(opts.hide) == 'function' ? opts.hide : function() { }
});
});
if (opts == 'show') {
var o = this.eq(0),
cnt = o.data('cnt') + 1,
show = o.data('show');
fm.toFront(o);
o.data('cnt', cnt);
if (o.is(':hidden')) {
o.show();
show();
}
}
if (opts == 'hide') {
var o = this.eq(0),
cnt = o.data('cnt') - 1,
hide = o.data('hide');
o.data('cnt', cnt);
if (cnt <= 0) {
o.hide();
hide();
}
}
return this;
};
PK SPKOB
js/ui/path.jsnu W+A "use strict";
/**
* @class elFinder ui
* Display current folder path in statusbar.
* Click on folder name in path - open folder
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderpath = function(fm, options) {
return this.each(function() {
var query = '',
target = '',
mimes = [],
place = 'statusbar',
clHover= fm.res('class', 'hover'),
prefix = 'path' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-',
wzbase = $(''),
path = $(this).addClass('elfinder-path').html(' ')
.on('mousedown', 'span.elfinder-path-dir', function(e) {
var hash = $(this).attr('id').substr(prefix.length);
e.preventDefault();
if (hash != fm.cwd().hash) {
$(this).addClass(clHover);
if (query) {
fm.exec('search', query, { target: hash, mime: mimes.join(' ') });
} else {
fm.trigger('select', {selected : [hash]}).exec('open', hash);
}
}
})
.prependTo(fm.getUI('statusbar').show()),
roots = $('').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
var roots = $.map(fm.roots, function(h) { return fm.file(h)}),
raw = [];
$.each(roots, function(i, f) {
if (! f.phash && fm.root(fm.cwd().hash, true) !== f.hash) {
raw.push({
label : fm.escape(f.i18 || f.name),
icon : 'home',
callback : function() { fm.exec('open', f.hash); },
options : {
iconClass : f.csscls || '',
iconImg : f.icon || ''
}
});
}
});
fm.trigger('contextmenu', {
raw: raw,
x: e.pageX,
y: e.pageY
});
}).append('').appendTo(wzbase),
render = function(cwd) {
var dirs = [],
names = [];
$.each(fm.parents(cwd), function(i, hash) {
var c = (cwd === hash)? 'elfinder-path-dir elfinder-path-cwd' : 'elfinder-path-dir',
f = fm.file(hash),
name = fm.escape(f.i18 || f.name);
names.push(name);
dirs.push(''+name+'');
});
return dirs.join(''+fm.option('separator')+'');
},
toWorkzone = function() {
var prev;
path.children('span.elfinder-path-dir').attr('style', '');
prev = fm.direction === 'ltr'? $('#'+prefix + fm.cwd().hash).prevAll('span.elfinder-path-dir:first') : $();
path.scrollLeft(prev.length? prev.position().left : 0);
},
fit = function() {
var dirs = path.children('span.elfinder-path-dir'),
cnt = dirs.length,
m, bg = 0, ids;
if (place === 'workzone' || cnt < 2) {
dirs.attr('style', '');
return;
}
path.width(path.css('max-width'));
dirs.css({maxWidth: (100/cnt)+'%', display: 'inline-block'});
m = path.width() - 9;
path.children('span.elfinder-path-other').each(function() {
m -= $(this).width();
});
ids = [];
dirs.each(function(i) {
var dir = $(this),
w = dir.width();
m -= w;
if (w < this.scrollWidth) {
ids.push(i);
}
});
path.width('');
if (ids.length) {
if (m > 0) {
m = m / ids.length;
$.each(ids, function(i, k) {
var d = $(dirs[k]);
d.css('max-width', d.width() + m);
});
}
dirs.last().attr('style', '');
} else {
dirs.attr('style', '');
}
},
hasUiTree;
fm.one('init', function() {
hasUiTree = fm.getUI('tree').length;
if (! hasUiTree && options.toWorkzoneWithoutNavbar) {
wzbase.append(path).insertBefore(fm.getUI('workzone'));
place = 'workzone';
fm.bind('open', toWorkzone)
.one('opendone', function() {
fm.getUI().trigger('resize');
});
}
})
.bind('open searchend parents', function() {
var dirs = [];
query = '';
target = '';
mimes = [];
path.html(render(fm.cwd().hash));
if (Object.keys(fm.roots).length > 1) {
path.css('margin', '');
roots.show();
} else {
path.css('margin', 0);
roots.hide();
}
fit();
})
.bind('searchstart', function(e) {
if (e.data) {
query = e.data.query || '';
target = e.data.target || '';
mimes = e.data.mimes || []
}
})
.bind('search', function(e) {
var dirs = [],
html = '';
if (target) {
html = render(target);
} else {
html = fm.i18n('btnAll');
}
path.html(''+fm.i18n('searcresult') + ': ' + html);
fit();
})
// on swipe to navbar show/hide
.bind('navbarshow navbarhide', function() {
var wz = fm.getUI('workzone');
if (this.type === 'navbarshow') {
fm.unbind('open', toWorkzone);
path.prependTo(fm.getUI('statusbar'));
wzbase.detach();
place = 'statusbar';
} else {
wzbase.append(path).insertBefore(wz);
place = 'workzone';
toWorkzone();
fm.bind('open', toWorkzone);
}
fm.trigger('uiresize');
})
.bind('resize', fit);
});
};
PK SPKnXjU U js/ui/dialog.jsnu W+A "use strict";
/**
* @class elFinder dialog
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderdialog = function(opts, fm) {
var platformWin = (window.navigator.platform.indexOf('Win') != -1),
delta = {},
syncSize = { enabled: false, width: false, height: false, defaultSize: null },
fitSize = function(dialog) {
var opts, node;
if (syncSize.enabled) {
node = fm.options.dialogContained? elfNode : $(window);
opts = {
maxWidth : syncSize.width? node.width() - delta.width : null,
maxHeight: syncSize.height? node.height() - delta.height : null
};
dialog.css(opts).trigger('resize');
if (dialog.data('hasResizable') && (dialog.resizable('option', 'maxWidth') < opts.maxWidth || dialog.resizable('option', 'maxHeight') < opts.maxHeight)) {
dialog.resizable('option', opts);
}
}
},
syncFunc = function(e) {
var dialog = e.data;
syncTm && clearTimeout(syncTm);
syncTm = setTimeout(function() {
var opts, prevH, offset;
if (syncSize.enabled) {
prevH = dialog.height();
if (prevH !== dialog.height()) {
offset = dialog.offset();
window.scrollTo(offset.top, offset.left);
}
fitSize(dialog);
}
}, 50);
},
syncTm, dialog, elfNode;
if (fm && fm.ui) {
elfNode = fm.getUI();
} else {
elfNode = this.closest('.elfinder');
if (! fm) {
fm = elfNode.elfinder('instance');
}
}
if (typeof opts === 'string') {
if ((dialog = this.closest('.ui-dialog')).length) {
if (opts == 'open') {
dialog.css('display') == 'none' && dialog.fadeIn(120, function() {
dialog.trigger('open');
});
} else if (opts == 'close' || opts == 'destroy') {
dialog.stop(true);
(dialog.is(':visible') || elfNode.is(':hidden')) && dialog.hide().trigger('close');
opts == 'destroy' && dialog.remove();
} else if (opts == 'toTop') {
dialog.trigger('totop');
} else if (opts == 'posInit') {
dialog.trigger('posinit');
} else if (opts == 'tabstopsInit') {
dialog.trigger('tabstopsInit');
}
}
return this;
}
opts = Object.assign({}, $.fn.elfinderdialog.defaults, opts);
if (opts.allowMinimize && opts.allowMinimize === 'auto') {
opts.allowMinimize = this.find('textarea,input').length? true : false;
}
if (opts.headerBtnPos && opts.headerBtnPos === 'auto') {
opts.headerBtnPos = platformWin? 'right' : 'left';
}
if (opts.headerBtnOrder && opts.headerBtnOrder === 'auto') {
opts.headerBtnOrder = platformWin? 'close:maximize:minimize' : 'close:minimize:maximize';
}
if (opts.modal && opts.allowMinimize) {
opts.allowMinimize = false;
}
if (fm.options.dialogContained) {
syncSize.width = syncSize.height = syncSize.enabled = true;
} else {
syncSize.width = (opts.maxWidth === 'window');
syncSize.height = (opts.maxHeight === 'window');
if (syncSize.width || syncSize.height) {
syncSize.enabled = true;
}
}
this.filter(':not(.ui-dialog-content)').each(function() {
var self = $(this).addClass('ui-dialog-content ui-widget-content'),
clactive = 'elfinder-dialog-active',
cldialog = 'elfinder-dialog',
clnotify = 'elfinder-dialog-notify',
clhover = 'ui-state-hover',
cltabstop = 'elfinder-tabstop',
cl1stfocus = 'elfinder-focus',
clmodal = 'elfinder-dialog-modal',
id = parseInt(Math.random()*1000000),
titlebar = $(''),
buttonset = $(''),
buttonpane = $('')
.append(buttonset),
btnWidth = 0,
btnCnt = 0,
tabstops = $(),
tabstopsInit = function() {
tabstops = dialog.find('.'+cltabstop);
if (tabstops.length) {
tabstops.attr('tabindex', '-1');
if (! tabstops.filter('.'+cl1stfocus).length) {
buttonset.children('.'+cltabstop+':'+(platformWin? 'first' : 'last')).addClass(cl1stfocus);
}
}
},
tabstopNext = function(cur) {
var elms = tabstops.filter(':visible'),
node = cur? null : elms.filter('.'+cl1stfocus+':first');
if (! node || ! node.length) {
node = elms.first();
}
if (cur) {
$.each(elms, function(i, elm) {
if (elm === cur && elms[i+1]) {
node = elms.eq(i+1);
return false;
}
});
}
return node;
},
tabstopPrev = function(cur) {
var elms = tabstops.filter(':visible'),
node = elms.last();
$.each(elms, function(i, elm) {
if (elm === cur && elms[i-1]) {
node = elms.eq(i-1);
return false;
}
});
return node;
},
makeHeaderBtn = function() {
$.each(opts.headerBtnOrder.split(':').reverse(), function(i, v) {
headerBtns[v] && headerBtns[v]();
})
if (platformWin) {
titlebar.children('.elfinder-titlebar-button').addClass('elfinder-titlebar-button-right');
}
},
headerBtns = {
close: function() {
titlebar.prepend($('')
.on('mousedown', function(e) {
e.preventDefault();
e.stopPropagation();
self.elfinderdialog('close');
})
);
},
maximize: function() {
if (opts.allowMaximize) {
dialog.on('resize', function(e, data) {
var full, elm;
e.preventDefault();
e.stopPropagation();
if (data && data.maximize) {
elm = titlebar.find('.elfinder-titlebar-full');
full = (data.maximize === 'on');
elm.children('span.ui-icon')
.toggleClass('ui-icon-plusthick', ! full)
.toggleClass('ui-icon-arrowreturnthick-1-s', full);
if (full) {
try {
dialog.hasClass('ui-draggable') && dialog.draggable('disable');
dialog.hasClass('ui-resizable') && dialog.resizable('disable');
} catch(e) {}
if (typeof elm.data('style') === 'undefined') {
self.height(self.height());
elm.data('style', self.attr('style') || '');
}
self.css('width', '100%').css('height', dialog.height() - dialog.children('.ui-dialog-titlebar').outerHeight(true) - buttonpane.outerHeight(true));
} else {
self.attr('style', elm.data('style'));
elm.removeData('style');
posCheck();
try {
dialog.hasClass('ui-draggable') && dialog.draggable('enable');
dialog.hasClass('ui-resizable') && dialog.resizable('enable');
} catch(e) {}
}
dialog.trigger('resize');
}
});
titlebar.prepend($('')
.on('mousedown', function(e) {
e.preventDefault();
e.stopPropagation();
fm.toggleMaximize(dialog);
})
);
}
},
minimize: function() {
if (opts.allowMinimize) {
titlebar.on('dblclick', function(e) {
$(this).children('.elfinder-titlebar-minimize').trigger('mousedown');
})
.prepend($('')
.on('mousedown', function(e) {
var $this = $(this),
w;
e.preventDefault();
e.stopPropagation();
if (typeof $this.data('style') !== 'undefined') {
dialog.trigger('beforedommove')
.appendTo(elfNode)
.trigger('dommove')
.attr('style', $this.data('style'))
.removeClass('elfinder-dialog-minimized')
.off('mousedown.minimize');
posCheck();
$this.removeData('style').show();
titlebar.children('.elfinder-titlebar-full').show();
dialog.children('.ui-widget-content').slideDown('fast', function() {
var eData;
if (this === dialog.children('.ui-widget-content:first').get(0)) {
if (dialog.find('.'+fm.res('class', 'editing'))) {
fm.disable();
}
eData = { minimize: 'off' };
if (! dialog.hasClass('elfinder-maximized')) {
try {
dialog.hasClass('ui-draggable') && dialog.draggable('enable');
dialog.hasClass('ui-resizable') && dialog.resizable('enable');
} catch(e) {}
} else {
eData.maximize = 'on';
}
dialog.trigger('resize', eData);
}
});
} else {
try {
dialog.hasClass('ui-draggable') && dialog.draggable('disable');
dialog.hasClass('ui-resizable') && dialog.resizable('disable');
} catch(e) {}
$this.data('style', dialog.attr('style') || '').hide();
titlebar.children('.elfinder-titlebar-full').hide();
w = dialog.width();
dialog.children('.ui-widget-content:first').slideUp(200, function() {
dialog.children('.ui-widget-content').hide().end()
.trigger('resize', { minimize: 'on' })
.attr('style', '').css({ maxWidth: w })
.addClass('elfinder-dialog-minimized')
.one('mousedown.minimize', function(e) {
$this.trigger('mousedown');
})
.trigger('beforedommove')
.appendTo(fm.getUI('bottomtray'))
.trigger('dommove');
});
}
})
);
}
}
},
dialog = $('')
.hide()
.append(self)
.appendTo(elfNode)
.draggable({
containment : fm.options.dialogContained? elfNode : null,
handle : '.ui-dialog-titlebar',
drag : function(e, ui) {
var top = ui.offset.top,
left = ui.offset.left;
if (top < 0) {
ui.position.top = ui.position.top - top;
}
if (left < 0) {
ui.position.left = ui.position.left - left;
}
if (fm.options.dialogContained) {
ui.position.top < 0 && (ui.position.top = 0);
ui.position.left < 0 && (ui.position.left = 0);
}
},
stop : function(e, ui) {
dialog.css({height : opts.height});
self.data('draged', true);
}
})
.css({
width : opts.width,
height : opts.height,
minWidth : opts.minWidth,
minHeight : opts.minHeight,
maxWidth : opts.maxWidth,
maxHeight : opts.maxHeight
})
.on('touchstart touchmove touchend', function(e) {
// stopPropagation of touch events
e.stopPropagation();
})
.on('mousedown', function(e) {
if (! dialog.hasClass('ui-front')) {
setTimeout(function() {
dialog.is(':visible:not(.elfinder-dialog-minimized)') && dialog.trigger('totop');
}, 10);
}
})
.on('open', function() {
var d = $(this);
if (syncSize.enabled) {
if (!syncSize.defaultSize) {
syncSize.defaultSize = { width: self.width(), height: self.height() };
}
fitSize(dialog);
dialog.trigger('resize').trigger('posinit');
elfNode.on('resize.'+fm.namespace, dialog, syncFunc);
}
if (!dialog.hasClass(clnotify)) {
elfNode.children('.'+cldialog+':visible:not(.'+clnotify+')').each(function() {
var d = $(this),
top = parseInt(d.css('top')),
left = parseInt(d.css('left')),
_top = parseInt(dialog.css('top')),
_left = parseInt(dialog.css('left')),
ct = Math.abs(top - _top) < 10,
cl = Math.abs(left - _left) < 10;
if (d[0] != dialog[0] && (ct || cl)) {
dialog.css({
top : ct ? (top + 10) : _top,
left : cl ? (left + 10) : _left
});
}
});
}
if (dialog.data('modal')) {
dialog.addClass(clmodal);
fm.getUI('overlay').elfinderoverlay('show');
}
dialog.trigger('totop');
typeof(opts.open) == 'function' && $.proxy(opts.open, self[0])();
fm.UA.Mobile && tabstopNext().focus();
if (opts.closeOnEscape) {
$(document).on('keyup.'+id, function(e) {
if (e.keyCode == $.ui.keyCode.ESCAPE && dialog.hasClass(clactive)) {
self.elfinderdialog('close');
}
});
}
})
.on('close', function() {
var dialogs;
syncSize.enabled && elfNode.off('resize.'+fm.namespace, syncFunc);
if (opts.closeOnEscape) {
$(document).off('keyup.'+id);
}
if (opts.allowMaximize) {
fm.toggleMaximize(dialog, false);
}
dialog.data('modal') && fm.getUI('overlay').elfinderoverlay('hide');
if (typeof(opts.close) == 'function') {
$.proxy(opts.close, self[0])();
} else if (opts.destroyOnClose) {
dialog.hide().remove();
}
// get focus to next dialog
dialogs = elfNode.children('.'+cldialog+':visible');
if (dialogs.length) {
dialogs.filter(':last').trigger('totop');
} else {
setTimeout(function() {
// return focus to elfNode
fm.enable();
}, 20);
}
})
.on('totop', function() {
if (dialog.hasClass('elfinder-dialog-minimized')) {
titlebar.children('.elfinder-titlebar-minimize').trigger('mousedown');
}
if (!dialog.data('modal') && fm.getUI('overlay').is(':visible')) {
fm.getUI('overlay').before(dialog);
} else {
fm.toFront(dialog);
}
elfNode.children('.'+cldialog+':not(.'+clmodal+')').removeClass(clactive+' ui-front');
dialog.addClass(clactive+' ui-front');
! fm.UA.Mobile && tabstopNext().focus();
})
.on('posinit', function() {
var css = opts.position,
nodeOffset, minTop, minLeft, outerSize, win, winSize;
if (dialog.hasClass('elfinder-maximized')) {
return;
}
if (! css && ! dialog.data('resizing')) {
win = $(window);
nodeOffset = elfNode.offset();
outerSize = {
width : dialog.outerWidth(true),
height: dialog.outerHeight(true)
};
outerSize.right = nodeOffset.left + outerSize.width;
outerSize.bottom = nodeOffset.top + outerSize.height;
winSize = {
scrLeft: win.scrollLeft(),
scrTop : win.scrollTop(),
width : win.width(),
height : win.height()
}
winSize.right = winSize.scrLeft + winSize.width;
winSize.bottom = winSize.scrTop + winSize.height;
if (fm.options.dialogContained) {
minTop = 0;
minLeft = 0;
} else {
minTop = nodeOffset.top * -1 + winSize.scrTop;
minLeft = nodeOffset.left * -1 + winSize.scrLeft;
}
css = {
top : outerSize.height >= winSize.height? minTop : Math.max(minTop, parseInt((elfNode.height() - outerSize.height)/2 - 42)),
left : outerSize.width >= winSize.width ? minLeft : Math.max(minLeft, parseInt((elfNode.width() - outerSize.width)/2))
};
if (outerSize.right + css.left > winSize.right) {
css.left = Math.max(minLeft, winSize.right - outerSize.right);
}
if (outerSize.bottom + css.top > winSize.bottom) {
css.top = Math.max(minTop, winSize.bottom - outerSize.bottom);
}
}
if (opts.absolute) {
css.position = 'absolute';
}
css && dialog.css(css);
})
.on('resize', function(e, data) {
var oh = 0, h, minH;
if ((data && (data.minimize || data.maxmize)) || dialog.hasClass('elfinder-dialog-minimized')) {
return;
}
e.stopPropagation();
e.preventDefault();
dialog.children('.ui-widget-header,.ui-dialog-buttonpane').each(function() {
oh += $(this).outerHeight(true);
});
if (syncSize.enabled && !e.originalEvent && !dialog.hasClass('elfinder-maximized')) {
h = Math.min(syncSize.defaultSize.height, Math.max(parseInt(dialog.css('max-height')), parseInt(dialog.css('min-height'))) - oh - dialog.data('margin-y'));
} else {
h = dialog.height() - oh - dialog.data('margin-y');
}
self.height(h);
posCheck();
setTimeout(function() { // Firefox need setTimeout to get new height value
minH = self.height();
minH = (h < minH)? (minH + oh + dialog.data('margin-y')) : opts.minHeight;
dialog.css('min-height', minH);
dialog.data('hasResizable') && dialog.resizable('option', { minHeight: minH });
}, 0);
if (typeof(opts.resize) === 'function') {
$.proxy(opts.resize, self[0])(e, data);
}
})
.on('tabstopsInit', tabstopsInit)
.on('focus', '.'+cltabstop, function() {
$(this).addClass(clhover).parent('label').addClass(clhover);
this.id && $(this).parent().find('label[for='+this.id+']').addClass(clhover);
})
.on('blur', '.'+cltabstop, function() {
$(this).removeClass(clhover).removeData('keepFocus').parent('label').removeClass(clhover);
this.id && $(this).parent().find('label[for='+this.id+']').removeClass(clhover);
})
.on('mouseenter mouseleave', '.'+cltabstop, function(e) {
var $this = $(this);
if (opts.btnHoverFocus) {
if (e.type == 'mouseenter' && ! $(':focus').data('keepFocus')) {
$this.focus();
}
} else {
$this.toggleClass(clhover, e.type == 'mouseenter');
}
})
.on('keydown', '.'+cltabstop, function(e) {
var $this = $(this);
if ($this.is(':focus')) {
e.stopPropagation();
if (e.keyCode == $.ui.keyCode.ENTER) {
e.preventDefault();
$this.click();
} else if ((e.keyCode == $.ui.keyCode.TAB && e.shiftKey) || e.keyCode == $.ui.keyCode.LEFT || e.keyCode == $.ui.keyCode.UP) {
if ($this.is('input:text') && (!(e.ctrlKey || e.metaKey) && e.keyCode == $.ui.keyCode.LEFT)) {
return;
}
if ($this.is('select') && e.keyCode != $.ui.keyCode.TAB) {
return;
}
if ($this.is('textarea') && !(e.ctrlKey || e.metaKey)) {
return;
}
e.preventDefault();
tabstopPrev(this).focus();
} else if (e.keyCode == $.ui.keyCode.TAB || e.keyCode == $.ui.keyCode.RIGHT || e.keyCode == $.ui.keyCode.DOWN) {
if ($this.is('input:text') && (!(e.ctrlKey || e.metaKey) && e.keyCode == $.ui.keyCode.RIGHT)) {
return;
}
if ($this.is('select') && e.keyCode != $.ui.keyCode.TAB) {
return;
}
if ($this.is('textarea') && !(e.ctrlKey || e.metaKey)) {
return;
}
e.preventDefault();
tabstopNext(this).focus();
}
}
})
.data({modal: opts.modal}),
posCheck = function() {
var node = fm.getUI(),
pos;
if (node.hasClass('elfinder-fullscreen')) {
pos = dialog.position();
dialog.css('top', Math.max(Math.min(Math.max(pos.top, 0), node.height() - 100), 0));
dialog.css('left', Math.max(Math.min(Math.max(pos.left, 0), node.width() - 200), 0));
}
},
maxSize;
dialog.prepend(titlebar);
makeHeaderBtn();
$.each(opts.buttons, function(name, cb) {
var button = $('')
.on('click', $.proxy(cb, self[0]));
if (platformWin) {
buttonset.append(button);
} else {
buttonset.prepend(button);
}
});
if (buttonset.children().length) {
dialog.append(buttonpane);
dialog.show();
buttonpane.find('button').each(function(i, btn) {
btnWidth += $(btn).outerWidth(true);
});
dialog.hide();
btnWidth += 20;
if (dialog.width() < btnWidth) {
dialog.width(btnWidth);
}
}
if (syncSize.enabled) {
delta.width = dialog.outerWidth(true) - dialog.width() + ((dialog.outerWidth() - dialog.width()) / 2);
delta.height = dialog.outerHeight(true) - dialog.height() + ((dialog.outerHeight() - dialog.height()) / 2);
}
if (fm.options.dialogContained) {
maxSize = {
maxWidth: elfNode.width() - delta.width,
maxHeight: elfNode.height() - delta.height
};
opts.maxWidth = opts.maxWidth? Math.min(maxSize.maxWidth, opts.maxWidth) : maxSize.maxWidth;
opts.maxHeight = opts.maxHeight? Math.min(maxSize.maxHeight, opts.maxHeight) : maxSize.maxHeight;
dialog.css(maxSize);
}
dialog.trigger('posinit').data('margin-y', self.outerHeight(true) - self.height());
if (opts.resizable) {
dialog.resizable({
minWidth : opts.minWidth,
minHeight : opts.minHeight,
maxWidth : opts.maxWidth,
maxHeight : opts.maxHeight,
start : function() {
if (dialog.data('resizing') !== true && dialog.data('resizing')) {
clearTimeout(dialog.data('resizing'));
}
dialog.data('resizing', true);
},
stop : function(e, ui) {
dialog.data('resizing', setTimeout(function() {
dialog.data('resizing', false);
}, 200));
if (syncSize.enabled) {
syncSize.defaultSize = { width: self.width(), height: self.height() };
}
}
}).data('hasResizable', true);
}
typeof(opts.create) == 'function' && $.proxy(opts.create, this)();
tabstopsInit();
opts.autoOpen && self.elfinderdialog('open');
});
return this;
};
$.fn.elfinderdialog.defaults = {
cssClass : '',
title : '',
modal : false,
resizable : true,
autoOpen : true,
closeOnEscape : true,
destroyOnClose : false,
buttons : {},
btnHoverFocus : true,
position : null,
absolute : false,
width : 320,
height : 'auto',
minWidth : 200,
minHeight : 70,
maxWidth : null,
maxHeight : null,
allowMinimize : 'auto',
allowMaximize : false,
headerBtnPos : 'auto',
headerBtnOrder : 'auto'
};
PK SPK,|u js/ui/toast.jsnu W+A "use strict";
/**
* @class elFinder toast
*
* This was created inspired by the toastr. Thanks to developers of toastr.
* CodeSeven/toastr: http://johnpapa.net
*
* @author Naoki Sawada
**/
$.fn.elfindertoast = function(opts, fm) {
var defOpts = {
mode: 'success',
msg: '',
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
showDuration: 300,
showEasing: 'swing', //swing and linear are built into jQuery
onShown: undefined,
hideMethod: 'fadeOut',
hideDuration: 1500,
hideEasing: 'swing',
onHidden: undefined,
timeOut: 3000,
extNode: undefined
};
return this.each(function() {
opts = Object.assign({}, defOpts, opts || {});
var self = $(this),
show = function(notm) {
self.stop();
self[opts.showMethod]({
duration: opts.showDuration,
easing: opts.showEasing,
complete: function() {
opts.onShown && opts.onShown();
if (!notm && opts.timeOut) {
rmTm = setTimeout(rm, opts.timeOut);
}
}
});
},
rm = function() {
self[opts.hideMethod]({
duration: opts.hideDuration,
easing: opts.hideEasing,
complete: function() {
opts.onHidden && opts.onHidden();
self.remove();
}
});
},
rmTm;
self.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
self.stop().remove();
}).on('mouseenter mouseleave', function(e) {
if (opts.timeOut) {
rmTm && clearTimeout(rmTm);
rmTm = null;
if (e.type === 'mouseenter') {
show(true);
} else {
rmTm = setTimeout(rm, opts.timeOut);
}
}
}).hide().addClass('toast-' + opts.mode).append($('').html(opts.msg));
if (opts.extNode) {
self.append(opts.extNode);
}
show();
});
};PK SPK O js/ui/panel.jsnu W+A $.fn.elfinderpanel = function(fm) {
return this.each(function() {
var panel = $(this).addClass('elfinder-panel ui-state-default ui-corner-all'),
margin = 'margin-'+(fm.direction == 'ltr' ? 'left' : 'right');
fm.one('load', function(e) {
var navbar = fm.getUI('navbar');
panel.css(margin, parseInt(navbar.outerWidth(true)));
navbar.on('resize', function(e) {
e.preventDefault();
e.stopPropagation();
panel.is(':visible') && panel.css(margin, parseInt(navbar.outerWidth(true)))
});
});
});
};
PK SPK,
js/ui/tree.jsnu W+A "use strict";
/**
* @class elFinder folders tree
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindertree = function(fm, opts) {
var treeclass = fm.res('class', 'tree');
this.not('.'+treeclass).each(function() {
var c = 'class', mobile = fm.UA.Mobile,
/**
* Root directory class name
*
* @type String
*/
root = fm.res(c, 'treeroot'),
/**
* Open root dir if not opened yet
*
* @type Boolean
*/
openRoot = opts.openRootOnLoad,
/**
* Open current work dir if not opened yet
*
* @type Boolean
*/
openCwd = opts.openCwdOnOpen,
/**
* Auto loading current directory parents and do expand their node
*
* @type Boolean
*/
syncTree = openCwd || opts.syncTree,
/**
* Subtree class name
*
* @type String
*/
subtree = fm.res(c, 'navsubtree'),
/**
* Directory class name
*
* @type String
*/
navdir = fm.res(c, 'treedir'),
/**
* Directory CSS selector
*
* @type String
*/
selNavdir = 'span.' + navdir,
/**
* Collapsed arrow class name
*
* @type String
*/
collapsed = fm.res(c, 'navcollapse'),
/**
* Expanded arrow class name
*
* @type String
*/
expanded = fm.res(c, 'navexpand'),
/**
* Class name to mark arrow for directory with already loaded children
*
* @type String
*/
loaded = 'elfinder-subtree-loaded',
/**
* Class name to mark need subdirs request
*
* @type String
*/
chksubdir = 'elfinder-subtree-chksubdir',
/**
* Arraw class name
*
* @type String
*/
arrow = fm.res(c, 'navarrow'),
/**
* Current directory class name
*
* @type String
*/
active = fm.res(c, 'active'),
/**
* Droppable dirs dropover class
*
* @type String
*/
dropover = fm.res(c, 'adroppable'),
/**
* Hover class name
*
* @type String
*/
hover = fm.res(c, 'hover'),
/**
* Disabled dir class name
*
* @type String
*/
disabled = fm.res(c, 'disabled'),
/**
* Draggable dir class name
*
* @type String
*/
draggable = fm.res(c, 'draggable'),
/**
* Droppable dir class name
*
* @type String
*/
droppable = fm.res(c, 'droppable'),
/**
* root wrapper class
*
* @type String
*/
wrapperRoot = 'elfinder-navbar-wrapper-root',
/**
* Un-disabled cmd `paste` volume's root wrapper class
*
* @type String
*/
pastable = 'elfinder-navbar-wrapper-pastable',
/**
* Un-disabled cmd `upload` volume's root wrapper class
*
* @type String
*/
uploadable = 'elfinder-navbar-wrapper-uploadable',
/**
* Is position x inside Navbar
*
* @param x Numbar
*
* @return
*/
insideNavbar = function(x) {
var left = navbar.offset().left;
return left <= x && x <= left + navbar.width();
},
/**
* To call subdirs elements queue
*
* @type Object
*/
subdirsQue = {},
/**
* To exec subdirs elements ids
*
*/
subdirsExecQue = [],
/**
* Request subdirs to backend
*
* @param id String
*
* @return Deferred
*/
subdirs = function(ids) {
var targets = [];
$.each(ids, function(i, id) {
subdirsQue[id] && targets.push(fm.navId2Hash(id));
delete subdirsQue[id];
});
if (targets.length) {
return fm.request({
data: {
cmd: 'subdirs',
targets: targets,
preventDefault : true
}
}).done(function(res) {
if (res && res.subdirs) {
$.each(res.subdirs, function(hash, subdirs) {
var elm = $('#'+fm.navHash2Id(hash));
elm.removeClass(chksubdir);
elm[subdirs? 'addClass' : 'removeClass'](collapsed);
});
}
});
}
},
subdirsJobRes = null,
/**
* To check target element is in window of subdirs
*
* @return void
*/
checkSubdirs = function() {
var ids = Object.keys(subdirsQue);
if (ids.length) {
subdirsJobRes && subdirsJobRes._abort();
execSubdirsTm && clearTimeout(execSubdirsTm);
subdirsExecQue = [];
subdirsJobRes = fm.asyncJob(function(id) {
return fm.isInWindow($('#'+id))? id : null;
}, ids, { numPerOnce: 200 })
.done(function(arr) {
if (arr.length) {
subdirsExecQue = arr;
execSubdirs();
}
});
}
},
subdirsPending = 0,
execSubdirsTm,
/**
* Exec subdirs as batch request
*
* @return void
*/
execSubdirs = function() {
var cnt = opts.subdirsMaxConn - subdirsPending,
i, ids;
execSubdirsTm && clearTimeout(execSubdirsTm);
if (subdirsExecQue.length) {
if (cnt > 0) {
for (i = 0; i < cnt; i++) {
if (subdirsExecQue.length) {
subdirsPending++;
subdirs(subdirsExecQue.splice(0, opts.subdirsAtOnce)).always(function() {
subdirsPending--;
execSubdirs();
});
}
}
} else {
execSubdirsTm = setTimeout(function() {
subdirsExecQue.length && execSubdirs();
}, 50);
}
}
},
drop = fm.droppable.drop,
/**
* Droppable options
*
* @type Object
*/
droppableopts = $.extend(true, {}, fm.droppable, {
// show subfolders on dropover
over : function(e, ui) {
var dst = $(this),
helper = ui.helper,
cl = hover+' '+dropover,
hash, status;
e.stopPropagation();
helper.data('dropover', helper.data('dropover') + 1);
dst.data('dropover', true);
if (ui.helper.data('namespace') !== fm.namespace || ! insideNavbar(e.clientX) || ! fm.insideWorkzone(e.pageX, e.pageY)) {
dst.removeClass(cl);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
dst.addClass(hover);
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.data('expandTimer', setTimeout(function() {
dst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).click();
}, 500));
}
if (dst.is('.elfinder-ro,.elfinder-na')) {
dst.removeClass(dropover);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
hash = fm.navId2Hash(dst.attr('id'));
dst.data('dropover', hash);
$.each(ui.helper.data('files'), function(i, h) {
if (h === hash || (fm.file(h).phash === hash && !ui.helper.hasClass('elfinder-drag-helper-plus'))) {
dst.removeClass(cl);
return false; // break $.each
}
});
if (helper.data('locked')) {
status = 'elfinder-drag-helper-plus';
} else {
status = 'elfinder-drag-helper-move';
if (e.shiftKey || e.ctrlKey || e.metaKey) {
status += ' elfinder-drag-helper-plus';
}
}
dst.hasClass(dropover) && helper.addClass(status);
setTimeout(function(){ dst.hasClass(dropover) && helper.addClass(status); }, 20);
},
out : function(e, ui) {
var dst = $(this),
helper = ui.helper;
e.stopPropagation();
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
dst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
dst.removeData('dropover')
.removeClass(hover+' '+dropover);
},
deactivate : function() {
$(this).removeData('dropover')
.removeClass(hover+' '+dropover);
},
drop : function(e, ui) {
insideNavbar(e.clientX) && drop.call(this, e, ui);
}
}),
spinner = $(fm.res('tpl', 'navspinner')),
/**
* Directory html template
*
* @type String
*/
tpl = fm.res('tpl', 'navdir'),
/**
* Permissions marker html template
*
* @type String
*/
ptpl = fm.res('tpl', 'perms'),
/**
* Lock marker html template
*
* @type String
*/
ltpl = fm.res('tpl', 'lock'),
/**
* Symlink marker html template
*
* @type String
*/
stpl = fm.res('tpl', 'symlink'),
/**
* Directory hashes that has more pages
*
* @type Object
*/
hasMoreDirs = {},
/**
* Html template replacement methods
*
* @type Object
*/
replace = {
id : function(dir) { return fm.navHash2Id(dir.hash); },
name : function(dir) { return fm.escape(dir.i18 || dir.name) },
cssclass : function(dir) {
var cname = (dir.phash && ! dir.isroot ? '' : root)+' '+navdir+' '+fm.perms2class(dir);
dir.dirs && !dir.link && (cname += ' ' + collapsed) && dir.dirs == -1 && (cname += ' ' + chksubdir);
opts.getClass && (cname += ' ' + opts.getClass(dir));
dir.csscls && (cname += ' ' + fm.escape(dir.csscls));
return cname;
},
root : function(dir) {
var cls = '';
if (!dir.phash || dir.isroot) {
cls += ' '+wrapperRoot;
if (!dir.disabled || dir.disabled.length < 1) {
cls += ' '+pastable+' '+uploadable;
} else {
if ($.inArray('paste', dir.disabled) === -1) {
cls += ' '+pastable;
}
if ($.inArray('upload', dir.disabled) === -1) {
cls += ' '+uploadable;
}
}
return cls;
} else {
return '';
}
},
permissions : function(dir) { return !dir.read || !dir.write ? ptpl : ''; },
symlink : function(dir) { return dir.alias ? stpl : ''; },
style : function(dir) { return dir.icon ? fm.getIconStyle(dir) : ''; }
},
/**
* Return html for given dir
*
* @param Object directory
* @return String
*/
itemhtml = function(dir) {
return tpl.replace(/(?:\{([a-z]+)\})/ig, function(m, key) {
var res = replace[key] ? replace[key](dir) : (dir[key] || '');
if (key === 'id' && dir.dirs == -1) {
subdirsQue[res] = res;
}
return res;
});
},
/**
* Return only dirs from files list
*
* @param Array files list
* @return Array
*/
filter = function(files) {
return $.map(files||[], function(f) { return f.mime == 'directory' ? f : null });
},
/**
* Find parent subtree for required directory
*
* @param String dir hash
* @return jQuery
*/
findSubtree = function(hash) {
return hash ? $('#'+fm.navHash2Id(hash)).next('.'+subtree) : tree;
},
/**
* Find directory (wrapper) in required node
* before which we can insert new directory
*
* @param jQuery parent directory
* @param Object new directory
* @return jQuery
*/
findSibling = function(subtree, dir) {
var node = subtree.children(':first'),
info;
while (node.length) {
info = fm.file(fm.navId2Hash(node.children('[id]').attr('id')));
if ((info = fm.file(fm.navId2Hash(node.children('[id]').attr('id'))))
&& compare(dir, info) < 0) {
return node;
}
node = node.next();
}
return subtree.children('button.elfinder-navbar-pager-next');
},
/**
* Add new dirs in tree
*
* @param Array dirs list
* @return void
*/
updateTree = function(dirs) {
var length = dirs.length,
orphans = [],
i = length,
tgts = $(),
done = {},
cwd = fm.cwd(),
append = function(parent, dirs, start, direction) {
var hashes = {},
curStart = 0,
max = fm.newAPI? Math.min(10000, Math.max(10, opts.subTreeMax)) : 10000,
setHashes = function() {
hashes = {};
$.each(dirs, function(i, d) {
hashes[d.hash] = i;
});
},
change = function(mode) {
if (mode === 'prepare') {
$.each(dirs, function(i, d) {
d.node && parent.append(d.node.hide());
});
} else if (mode === 'done') {
$.each(dirs, function(i, d) {
d.node && d.node.detach().show();
});
}
},
update = function(e, data) {
var i, changed;
e.stopPropagation();
if (data.select) {
render(getStart(data.select));
return;
}
if (data.change) {
change(data.change);
return;
}
if (data.removed && data.removed.length) {
dirs = $.map(dirs, function(d) {
if (data.removed.indexOf(d.hash) === -1) {
return d;
} else {
changed = true;
return null;
}
});
}
if (data.added && data.added.length) {
dirs = dirs.concat($.map(data.added, function(d) {
if (hashes[d.hash] === void(0)) {
changed = true;
return d;
} else {
return null;
}
}));
}
if (changed) {
dirs.sort(compare);
setHashes();
render(curStart);
}
},
getStart = function(target) {
if (hashes[target] !== void(0)) {
return Math.floor(hashes[target] / max) * max;
}
return void(0);
},
target = fm.navId2Hash(parent.prev('[id]').attr('id')),
render = function(start, direction) {
var html = [],
nodes = {},
total, page, s, parts, prev, next, prevBtn, nextBtn;
delete hasMoreDirs[target];
curStart = start;
parent.off('update.'+fm.namespace, update);
if (dirs.length > max) {
parent.on('update.'+fm.namespace, update);
if (start === void(0)) {
s = 0;
setHashes();
start = getStart(cwd.hash);
if (start === void(0)) {
start = 0;
}
}
parts = dirs.slice(start, start + max);
hasMoreDirs[target] = parent;
prev = start? Math.max(-1, start - max) : -1;
next = (start + max >= dirs.length)? 0 : start + max;
total = Math.ceil(dirs.length/max);
page = Math.ceil(start/max);
}
$.each(parts || dirs, function(i, d) {
html.push(itemhtml(d));
if (d.node) {
nodes[d.hash] = d.node;
}
});
if (prev > -1) {
prevBtn = $('')
.text(fm.i18n('btnPrevious', page, total))
.button({
icons: {
primary: "ui-icon-caret-1-n"
}
})
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
render(prev, 'up');
});
} else {
prevBtn = $();
}
if (next) {
nextBtn = $('')
.text(fm.i18n('btnNext', page + 2, total))
.button({
icons: {
primary: "ui-icon-caret-1-s"
}
})
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
render(next, 'down');
});
} else {
nextBtn = $();
}
detach();
parent.empty()[parts? 'addClass' : 'removeClass']('elfinder-navbar-hasmore').append(prevBtn, html.join(''), nextBtn);
$.each(nodes, function(h, n) {
$('#'+fm.navHash2Id(h)).parent().replaceWith(n);
});
if (direction) {
autoScroll(fm.navHash2Id(parts[direction === 'up'? parts.length - 1 : 0].hash));
}
! mobile && fm.lazy(function() { updateDroppable(null, parent); });
},
detach = function() {
$.each(parent.children('.elfinder-navbar-wrapper'), function(i, n) {
var n = $(n),
ch = n.children('[id]:first'),
h, c;
if (ch.hasClass(loaded)) {
h = fm.navId2Hash(ch.attr('id'));
if (h && (c = hashes[h]) !== void(0)) {
dirs[c].node = n.detach();
}
}
});
};
render();
},
dir, html, parent, sibling, init, atonce = {}, updates = [], base, node,
firstVol = true; // check for netmount volume
while (i--) {
dir = dirs[i];
if (done[dir.hash] || $('#'+fm.navHash2Id(dir.hash)).length) {
continue;
}
done[dir.hash] = true;
if ((parent = findSubtree(dir.phash)).length) {
if (dir.phash && ((init = !parent.children().length) || parent.hasClass('elfinder-navbar-hasmore') || (sibling = findSibling(parent, dir)).length)) {
if (init) {
if (!atonce[dir.phash]) {
atonce[dir.phash] = [];
}
atonce[dir.phash].push(dir);
} else {
if (sibling) {
node = itemhtml(dir);
sibling.before(node);
! mobile && (tgts = tgts.add(node));
} else {
updates.push(dir);
}
}
} else {
node = itemhtml(dir);
parent[firstVol || dir.phash ? 'append' : 'prepend'](node);
firstVol = false;
if (!dir.phash || dir.isroot) {
base = $('#'+fm.navHash2Id(dir.hash)).parent();
}
! mobile && updateDroppable(null, base);
}
} else {
orphans.push(dir);
}
}
// When init, html append at once
if (Object.keys(atonce).length){
$.each(atonce, function(p, dirs){
var parent = findSubtree(p),
html = [];
dirs.sort(compare);
append(parent, dirs);
});
}
if (updates.length) {
parent.trigger('update.' + fm.namespace, { added : updates });
}
if (orphans.length && orphans.length < length) {
updateTree(orphans);
return;
}
! mobile && tgts.length && fm.lazy(function() { updateDroppable(tgts); });
},
/**
* sort function by dir.name
*
*/
compare = function(dir1, dir2) {
if (! fm.sortAlsoTreeview) {
return fm.sortRules.name(dir1, dir2);
} else {
var asc = fm.sortOrder == 'asc',
type = fm.sortType,
rules = fm.sortRules,
res;
res = asc? rules[fm.sortType](dir1, dir2) : rules[fm.sortType](dir2, dir1);
return type !== 'name' && res === 0
? res = asc ? rules.name(dir1, dir2) : rules.name(dir2, dir1)
: res;
}
},
/**
* Auto scroll to cwd
*
* @return void
*/
autoScroll = function(target) {
var self = $(this),
dfrd = $.Deferred(),
current, parent, top, treeH, bottom, tgtTop;
self.data('autoScrTm') && clearTimeout(self.data('autoScrTm'));
self.data('autoScrTm', setTimeout(function() {
current = $('#'+(target || fm.navHash2Id(fm.cwd().hash)));
if (current.length) {
// expand parents directory
(openCwd? current : current.parent()).parents('.elfinder-navbar-wrapper').children('.'+loaded).addClass(expanded).next('.'+subtree).show();
parent = tree.parent().stop(false, true);
top = parent.offset().top;
treeH = parent.height();
bottom = top + treeH - current.outerHeight();
tgtTop = current.offset().top;
if (tgtTop < top || tgtTop > bottom) {
parent.animate({
scrollTop : parent.scrollTop() + tgtTop - top - treeH / 3
}, {
duration : 'fast',
complete : function() { dfrd.resolve(); }
});
} else {
dfrd.resolve();
}
} else {
dfrd.reject();
}
}, 100));
return dfrd;
},
/**
* Get hashes array of items of the bottom of the leaf root back from the target
*
* @param Object elFinder item(directory) object
* @return Array hashes
*/
getEnds = function(dir) {
var cur = dir || fm.cwd(),
res = [ cur.hash ],
phash, root, dir;
root = fm.root(cur.hash);
dir = fm.file(root);
while (phash = dir.phash) {
res.unshift(phash);
root = fm.root(phash);
dir = fm.file(root);
if ($('#'+fm.navHash2Id(dir.hash)).hasClass(loaded)) {
break;
}
}
return res;
},
/**
* Select pages back in order to display the target
*
* @param Object elFinder item(directory) object
* @return Object jQuery node object of target node
*/
selectPages = function(cur) {
var cur = cur || fm.cwd(),
curHash = cur.hash,
node = $('#'+fm.navHash2Id(curHash));
if (!node.length) {
while(cur && cur.phash) {
if (hasMoreDirs[cur.phash] && !$('#'+fm.navHash2Id(cur.hash)).length) {
hasMoreDirs[cur.phash].trigger('update.'+fm.namespace, { select : cur.hash });
}
cur = fm.file(cur.phash);
}
node = $('#'+fm.navHash2Id(curHash));
}
return node;
},
/**
* Mark current directory as active
* If current directory is not in tree - load it and its parents
*
* @param Array directory objects of cwd
* @param Boolean do auto scroll
* @return Object jQuery Deferred
*/
sync = function(cwdDirs, autoScr) {
var cwd = fm.cwd(),
cwdhash = cwd.hash,
autoScr = autoScr === void(0)? syncTree : autoScr,
loadParents = function(dir) {
var dfd = $.Deferred(),
reqs = [],
ends = getEnds(dir),
makeReq = function(cmd, h, until) {
var data = {
cmd : cmd,
target : h
};
if (until) {
data.until = until;
}
return fm.request({
data : data,
preventFail : true
});
},
baseHash, baseId;
reqs = $.map(ends, function(h) {
var d = fm.file(h),
isRoot = d? fm.isRoot(d) : false,
node = $('#'+fm.navHash2Id(h)),
getPhash = function(h, depth) {
var d, ph,
depth = depth || 1;
ph = (d = fm.file(h))? d.phash : false;
if (ph && depth > 1) {
return getPhash(ph, --depth);
}
return ph;
},
until,
closest = (function() {
var phash = getPhash(h);
until = phash;
while (phash) {
if ($('#'+fm.navHash2Id(phash)).hasClass(loaded)) {
break;
}
until = phash;
phash = getPhash(phash);
}
if (!phash) {
until = void(0);
phash = fm.root(h);
}
return phash;
})(),
cmd;
if (!node.hasClass(loaded) && (isRoot || !d || !$('#'+fm.navHash2Id(d.phash)).hasClass(loaded))) {
if (isRoot || closest === getPhash(h) || closest === getPhash(h, 2)) {
until = void(0);
cmd = 'tree';
if (!isRoot) {
h = getPhash(h);
}
} else {
cmd = 'parents';
}
if (!baseHash) {
baseHash = (cmd === 'tree')? h : closest;
}
return makeReq(cmd, h, until);
}
return null;
});
if (reqs.length) {
selectPages(fm.file(baseHash));
baseId = fm.navHash2Id(baseHash);
autoScr && autoScroll(baseId);
baseNode = $('#'+baseId);
spinner = $(fm.res('tpl', 'navspinner')).insertBefore(baseNode.children('.'+arrow));
baseNode.removeClass(collapsed);
$.when.apply($, reqs)
.done(function() {
var res = {},data, treeDirs, dirs, argLen, i;
argLen = arguments.length;
if (argLen > 0) {
for (i = 0; i < argLen; i++) {
data = arguments[i].tree || [];
res[ends[i]] = Object.assign([], filter(data));
}
}
dfd.resolve(res);
})
.fail(function() {
dfd.reject();
});
return dfd;
} else {
return dfd.resolve();
}
},
done= function(res, dfrd) {
var open = function() {
if (openRoot && baseNode) {
findSubtree(baseNode.hash).show().prev(selNavdir).addClass(expanded);
openRoot = false;
}
if (autoScr) {
autoScroll().done(checkSubdirs);
} else {
checkSubdirs();
}
},
current;
if (res) {
$.each(res, function(endHash, dirs) {
dirs && updateTree(dirs);
selectPages(fm.file(endHash));
dirs && updateArrows(dirs, loaded);
});
}
if (cwdDirs) {
(fm.api < 2.1) && cwdDirs.push(cwd);
updateTree(cwdDirs);
}
// set current node
current = selectPages();
if (!current.hasClass(active)) {
tree.find(selNavdir+'.'+active).removeClass(active);
current.addClass(active);
}
// mark as loaded to cwd parents
current.parents('.elfinder-navbar-wrapper').children('.'+navdir).addClass(loaded);
if (res) {
fm.lazy(open).done(function() {
dfrd.resolve();
});
} else {
open();
dfrd.resolve();
}
},
rmSpinner = function(fail) {
if (baseNode) {
spinner.remove();
baseNode.addClass(collapsed + (fail? '' : (' ' + loaded)));
}
},
dfrd = $.Deferred(),
baseNode, spinner;
if (!$('#'+fm.navHash2Id(cwdhash)).length) {
loadParents()
.done(function(res) {
done(res, dfrd);
rmSpinner();
})
.fail(function() {
rmSpinner(true);
dfrd.reject();
});
} else {
done(void(0), dfrd);
}
return dfrd;
},
/**
* Make writable and not root dirs droppable
*
* @return void
*/
updateDroppable = function(target, node) {
var limit = 100,
next;
if (!target) {
if (!node || node.closest('div.'+wrapperRoot).hasClass(uploadable)) {
(node || tree.find('div.'+uploadable)).find(selNavdir+':not(.elfinder-ro,.elfinder-na)').addClass('native-droppable');
}
if (!node || node.closest('div.'+wrapperRoot).hasClass(pastable)) {
target = (node || tree.find('div.'+pastable)).find(selNavdir+':not(.'+droppable+')');
} else {
target = $();
}
if (node) {
// check leaf roots
node.children('div.'+wrapperRoot).each(function() {
updateDroppable(null, $(this));
});
}
}
// make droppable on async
if (target.length) {
fm.asyncJob(function(elm) {
$(elm).droppable(droppableopts);
}, $.makeArray(target), {
interval : 20,
numPerOnce : 100
});
}
},
/**
* Check required folders for subfolders and update arrow classes
*
* @param Array folders to check
* @param String css class
* @return void
*/
updateArrows = function(dirs, cls) {
var sel = cls == loaded
? '.'+collapsed+':not(.'+loaded+')'
: ':not(.'+collapsed+')';
$.each(dirs, function(i, dir) {
$('#'+fm.navHash2Id(dir.phash)+sel)
.filter(function() { return $.map($(this).next('.'+subtree).children(), function(n) {
return ($(n).children().hasClass(root))? null : n;
}).length > 0 })
.addClass(cls);
})
},
/**
* Navigation tree
*
* @type JQuery
*/
tree = $(this).addClass(treeclass)
// make dirs draggable and toggle hover class
.on('mouseenter mouseleave', selNavdir, function(e) {
var enter = (e.type === 'mouseenter');
if (enter && scrolling) { return; }
var link = $(this);
if (!link.hasClass(dropover+' '+disabled)) {
if (!mobile && enter && !link.data('dragRegisted') && !link.hasClass(root+' '+draggable+' elfinder-na elfinder-wo')) {
link.data('dragRegisted', true);
if (fm.isCommandEnabled('copy', fm.navId2Hash(link.attr('id')))) {
link.draggable(fm.draggable);
}
}
link.toggleClass(hover, enter);
}
})
// native drag enter
.on('dragenter', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
var dst = $(this);
dst.addClass(hover);
if (dst.is('.'+collapsed+':not(.'+expanded+')')) {
dst.data('expandTimer', setTimeout(function() {
dst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).click();
}, 500));
}
}
})
// native drag leave
.on('dragleave', selNavdir, function(e) {
if (e.originalEvent.dataTransfer) {
var dst = $(this);
dst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
dst.removeClass(hover);
}
})
// open dir or open subfolders in tree
.on('click', selNavdir, function(e) {
var link = $(this),
hash = fm.navId2Hash(link.attr('id')),
file = fm.file(hash);
if (link.data('longtap')) {
e.stopPropagation();
return;
}
if (hash != fm.cwd().hash && !link.hasClass(disabled)) {
fm.exec('open', hash).done(function() {
fm.select({selected: [hash], origin: 'tree'});
});
} else {
if (link.hasClass(collapsed)) {
link.children('.'+arrow).click();
}
fm.select({selected: [hash], origin: 'tree'});
}
})
// for touch device
.on('touchstart', selNavdir, function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var evt = e.originalEvent,
p = $(this)
.addClass(hover)
.data('longtap', null)
.data('tmlongtap', setTimeout(function(e){
// long tap
p.data('longtap', true);
fm.trigger('contextmenu', {
'type' : 'navbar',
'targets' : [fm.navId2Hash(p.attr('id'))],
'x' : evt.touches[0].pageX,
'y' : evt.touches[0].pageY
});
}, 500));
})
.on('touchmove touchend', selNavdir, function(e) {
clearTimeout($(this).data('tmlongtap'));
if (e.type == 'touchmove') {
$(this).removeClass(hover);
}
})
// toggle subfolders in tree
.on('click', selNavdir+'.'+collapsed+' .'+arrow, function(e) {
var arrow = $(this),
link = arrow.parent(selNavdir),
stree = link.next('.'+subtree),
dfrd = $.Deferred(),
slideTH = 30, cnt;
e.stopPropagation();
if (link.hasClass(loaded)) {
link.toggleClass(expanded);
fm.lazy(function() {
cnt = link.hasClass(expanded)? stree.children().length + stree.find('div.elfinder-navbar-subtree[style*=block]').children().length : stree.find('div:visible').length;
if (cnt > slideTH) {
stree.toggle();
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
} else {
stree.stop(true, true).slideToggle('normal', function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
});
}
}).always(function() {
dfrd.resolve();
});
} else {
spinner.insertBefore(arrow);
link.removeClass(collapsed);
fm.request({cmd : 'tree', target : fm.navId2Hash(link.attr('id'))})
.done(function(data) {
updateTree(Object.assign([], filter(data.tree)));
if (stree.children().length) {
link.addClass(collapsed+' '+expanded);
if (stree.children().length > slideTH) {
stree.show();
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
} else {
stree.stop(true, true).slideDown('normal', function(){
fm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
checkSubdirs();
});
}
}
})
.always(function(data) {
spinner.remove();
link.addClass(loaded);
fm.one('treedone', function() {
dfrd.resolve();
});
});
}
arrow.data('dfrd', dfrd);
})
.on('contextmenu', selNavdir, function(e) {
var self = $(this);
e.preventDefault();
fm.trigger('contextmenu', {
'type' : 'navbar',
'targets' : [fm.navId2Hash($(this).attr('id'))],
'x' : e.pageX,
'y' : e.pageY
});
self.addClass('ui-state-hover');
fm.getUI('contextmenu').children().on('mouseenter', function() {
self.addClass('ui-state-hover');
});
fm.bind('closecontextmenu', function() {
self.removeClass('ui-state-hover');
});
})
.on('scrolltoview', selNavdir, function() {
var self = $(this);
autoScroll(self.attr('id')).done(function() {
fm.resources.blink(self, 'lookme');
});
})
// prepend fake dir
.on('create.'+fm.namespace, function(e, item) {
var pdir = findSubtree(item.phash),
lock = item.move || false,
dir = $(itemhtml(item)).addClass('elfinder-navbar-wrapper-tmp'),
selected = fm.selected();
lock && selected.length && fm.trigger('lockfiles', {files: selected});
pdir.prepend(dir);
}),
scrolling = false,
navbarScrTm,
// move tree into navbar
navbar = fm.getUI('navbar').append(tree).show().on('scroll', function() {
scrolling = true;
navbarScrTm && clearTimeout(navbarScrTm);
navbarScrTm = setTimeout(function() {
scrolling = false;
checkSubdirs();
}, 50);
}),
prevSortTreeview = fm.sortAlsoTreeview;
fm.open(function(e) {
var data = e.data,
dirs = filter(data.files),
contextmenu = fm.getUI('contextmenu');
data.init && tree.empty();
if (fm.UA.iOS) {
navbar.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
}
if (dirs.length) {
fm.lazy(function() {
if (!contextmenu.data('cmdMaps')) {
contextmenu.data('cmdMaps', {});
}
updateTree(dirs);
updateArrows(dirs, loaded);
sync(dirs);
});
} else {
sync();
}
})
// add new dirs
.add(function(e) {
var dirs = filter(e.data.added);
if (dirs.length) {
updateTree(dirs);
updateArrows(dirs, collapsed);
}
})
// update changed dirs
.change(function(e) {
var dirs = filter(e.data.changed),
length = dirs.length,
l = length,
tgts = $(),
changed = {},
dir, phash, node, tmp, realParent, reqParent, realSibling, reqSibling, isExpanded, isLoaded, parent, subdirs;
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'prepare' });
});
while (l--) {
dir = dirs[l];
phash = dir.phash;
if ((node = $('#'+fm.navHash2Id(dir.hash))).length) {
parent = node.parent();
if (phash) {
realParent = node.closest('.'+subtree);
reqParent = findSubtree(phash);
realSibling = node.parent().next();
reqSibling = findSibling(reqParent, dir);
if (!reqParent.length) {
continue;
}
if (reqParent[0] !== realParent[0] || realSibling.get(0) !== reqSibling.get(0)) {
reqSibling.length ? reqSibling.before(parent) : reqParent.append(parent);
}
}
isExpanded = node.hasClass(expanded);
isLoaded = node.hasClass(loaded);
tmp = $(itemhtml(dir));
node.replaceWith(tmp.children(selNavdir));
! mobile && updateDroppable(null, parent);
if (dir.dirs
&& (isExpanded || isLoaded)
&& (node = $('#'+fm.navHash2Id(dir.hash)))
&& node.next('.'+subtree).children().length) {
isExpanded && node.addClass(expanded);
isLoaded && node.addClass(loaded);
}
subdirs |= dir.dirs == -1;
}
}
// to check subdirs
if (subdirs) {
checkSubdirs();
}
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'done' });
});
sync(void(0), false);
})
// remove dirs
.remove(function(e) {
var dirs = e.data.removed,
l = dirs.length,
node, stree, removed;
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { removed : dirs });
node.trigger('update.'+fm.namespace, { change: 'prepare' });
});
while (l--) {
if ((node = $('#'+fm.navHash2Id(dirs[l]))).length) {
removed = true;
stree = node.closest('.'+subtree);
node.parent().detach();
if (!stree.children().length) {
stree.hide().prev(selNavdir).removeClass(collapsed+' '+expanded+' '+loaded);
}
}
}
removed && fm.getUI('navbar').children('.ui-resizable-handle').trigger('resize');
$.each(hasMoreDirs, function(h, node) {
node.trigger('update.'+fm.namespace, { change: 'done' });
});
})
// lock/unlock dirs while moving
.bind('lockfiles unlockfiles', function(e) {
var lock = e.type == 'lockfiles',
helperLocked = e.data.helper? e.data.helper.data('locked') : false,
act = (lock && !helperLocked) ? 'disable' : 'enable',
dirs = $.map(e.data.files||[], function(h) {
var dir = fm.file(h);
return dir && dir.mime == 'directory' ? h : null;
});
$.each(dirs, function(i, hash) {
var dir = $('#'+fm.navHash2Id(hash));
if (dir.length && !helperLocked) {
dir.hasClass(draggable) && dir.draggable(act);
dir.hasClass(droppable) && dir.droppable(act);
dir[lock ? 'addClass' : 'removeClass'](disabled);
}
});
})
.bind('sortchange', function() {
if (fm.sortAlsoTreeview || prevSortTreeview !== fm.sortAlsoTreeview) {
var dirs,
ends = [],
endsMap = {},
endsVid = {},
topVid = '',
single = false,
current;
fm.lazy(function() {
dirs = filter(fm.files());
prevSortTreeview = fm.sortAlsoTreeview;
tree.empty();
// append volume roots at first
updateTree($.map(fm.roots, function(h) {
var dir = fm.file(h);
return dir && fm.isRoot(dir)? dir : null;
}));
if (!Object.keys(hasMoreDirs).length) {
updateTree(dirs);
current = selectPages();
updateArrows(dirs, loaded);
} else {
ends = getEnds();
if (ends.length > 1) {
$.each(ends, function(i, end) {
var vid = fm.file(fm.root(end)).volumeid;
if (i === 0) {
topVid = vid;
}
endsVid[vid] = end;
endsMap[end] = [];
});
$.each(dirs, function(i, d) {
if (!d.volumeid) {
single = true;
return false;
}
endsMap[endsVid[d.volumeid] || endsVid[topVid]].push(d);
});
} else {
single = true;
}
if (single) {
$.each(ends, function(i, endHash) {
updateTree(dirs);
current = selectPages(fm.file(endHash));
updateArrows(dirs, loaded);
});
} else {
$.each(endsMap, function(endHash, dirs) {
updateTree(dirs);
current = selectPages(fm.file(endHash));
updateArrows(dirs, loaded);
});
}
}
sync();
}, 100);
}
});
});
return this;
};
PK SPK`ǐ
js/ui/stat.jsnu W+A "use strict";
/**
* @class elFinder ui
* Display number of files/selected files and its size in statusbar
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderstat = function(fm) {
return this.each(function() {
var size = $(this).addClass('elfinder-stat-size'),
sel = $('')
.on('click', 'a', function(e) {
var hash = $(this).data('hash');
e.preventDefault();
fm.exec('opendir', [ hash ]);
}),
titleitems = fm.i18n('items'),
titlesel = fm.i18n('selected'),
titlesize = fm.i18n('size'),
setstat = function(files) {
var c = 0,
s = 0,
cwd = fm.cwd(),
calc = true,
hasSize = true;
if (cwd.sizeInfo || cwd.size) {
s = cwd.size;
calc = false;
}
$.each(files, function(i, file) {
c++;
if (calc) {
s += parseInt(file.size) || 0;
if (hasSize === true && file.mime === 'directory' && !file.sizeInfo) {
hasSize = false;
}
}
});
size.html(titleitems+': '+c+', '+fm.i18n(hasSize? 'sum' : 'size')+': '+fm.formatSize(s)+'')
.attr('title', size.text());
},
setIncsearchStat = function(data) {
size.find('span.elfinder-stat-incsearch').html(data? data.hashes.length + ' / ' : '');
size.attr('title', size.text());
};
fm.getUI('statusbar').prepend(size).append(sel).show();
if (fm.UA.Mobile && $.fn.tooltip) {
fm.getUI('statusbar').tooltip({
classes: {
'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
},
tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
track: true
});
}
fm
.bind('cwdhasheschange', function(e) {
setstat($.map(e.data, function(h) { return fm.file(h); }));
})
.change(function(e) {
var files = e.data.changed || [],
cwdHash = fm.cwd().hash;
$.each(files, function() {
if (this.hash === cwdHash) {
if (this.size) {
size.children('.elfinder-stat-size').addClass('elfinder-stat-size-recursive').html(fm.i18n('sum')+': '+fm.formatSize(this.size));
size.attr('title', size.text());
}
return false;
}
});
})
.select(function() {
var s = 0,
c = 0,
files = fm.selectedFiles(),
dirs = [],
path, file;
if (files.length === 1) {
file = files[0];
s = file.size;
if (fm.searchStatus.state === 2) {
path = fm.escape(file.path? file.path.replace(/\/[^\/]*$/, '') : '..');
dirs.push(''+path+'');
}
dirs.push(fm.escape(file.i18 || file.name));
sel.html(dirs.join('/') + (s > 0 ? ', '+fm.formatSize(s) : ''));
} else if (files.length) {
$.each(files, function(i, file) {
c++;
s += parseInt(file.size)||0;
});
sel.html(c ? titlesel+': '+c+', '+titlesize+': '+fm.formatSize(s) : ' ');
} else {
sel.html('');
}
sel.attr('title', sel.text());
})
.bind('incsearch', function(e) {
setIncsearchStat(e.data);
})
.bind('incsearchend', function() {
setIncsearchStat();
})
;
});
};
PK SPKDi. i. js/ui/cwd.jsnu W+A "use strict";
/**
* elFinder current working directory ui.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindercwd = function(fm, options) {
this.not('.elfinder-cwd').each(function() {
// fm.time('cwdLoad');
var mobile = fm.UA.Mobile,
list = fm.viewType == 'list',
undef = 'undefined',
/**
* Select event full name
*
* @type String
**/
evtSelect = 'select.'+fm.namespace,
/**
* Unselect event full name
*
* @type String
**/
evtUnselect = 'unselect.'+fm.namespace,
/**
* Disable event full name
*
* @type String
**/
evtDisable = 'disable.'+fm.namespace,
/**
* Disable event full name
*
* @type String
**/
evtEnable = 'enable.'+fm.namespace,
c = 'class',
/**
* File css class
*
* @type String
**/
clFile = fm.res(c, 'cwdfile'),
/**
* Selected css class
*
* @type String
**/
fileSelector = '.'+clFile + (options.oldSchool? ':not(.elfinder-cwd-parent)' : ''),
/**
* Selected css class
*
* @type String
**/
clSelected = 'ui-selected',
/**
* Disabled css class
*
* @type String
**/
clDisabled = fm.res(c, 'disabled'),
/**
* Draggable css class
*
* @type String
**/
clDraggable = fm.res(c, 'draggable'),
/**
* Droppable css class
*
* @type String
**/
clDroppable = fm.res(c, 'droppable'),
/**
* Hover css class
*
* @type String
**/
clHover = fm.res(c, 'hover'),
/**
* Hover css class
*
* @type String
**/
clDropActive = fm.res(c, 'adroppable'),
/**
* Css class for temporary nodes (for mkdir/mkfile) commands
*
* @type String
**/
clTmp = clFile+'-tmp',
/**
* Number of thumbnails to load in one request (new api only)
*
* @type Number
**/
tmbNum = fm.options.loadTmbs > 0 ? fm.options.loadTmbs : 5,
/**
* Current search query.
*
* @type String
*/
query = '',
/**
* Currect clipboard(cut) hashes as object key
*
* @type Object
*/
clipCuts = {},
/**
* Parents hashes of cwd
*
* @type Array
*/
cwdParents = [],
/**
* cwd current hashes
*
* @type Array
*/
cwdHashes = [],
/**
* incsearch current hashes
*
* @type Array
*/
incHashes = void 0,
/**
* Custom columns name and order
*
* @type Array
*/
customCols = [],
/**
* Current clicked element id of first time for dblclick
*
* @type String
*/
curClickId = '',
/**
* Custom columns builder
*
* @type Function
*/
customColsBuild = function() {
var cols = '';
for (var i = 0; i < customCols.length; i++) {
cols += '{' + customCols[i] + '} | ';
}
return cols;
},
/**
* Make template.row from customCols
*
* @type Function
*/
makeTemplateRow = function() {
return '{marker}{name} '+selectCheckbox+' | '+customColsBuild()+'
';
},
selectCheckbox = ($.map(options.showSelectCheckboxUA, function(t) {return (fm.UA[t] || t.match(/^all$/i))? true : null;}).length)? '' : '',
colResizing = false,
colWidth = null,
/**
* File templates
*
* @type Object
**/
templates = {
icon : '',
row : ''
},
permsTpl = fm.res('tpl', 'perms'),
lockTpl = fm.res('tpl', 'lock'),
symlinkTpl = fm.res('tpl', 'symlink'),
/**
* Template placeholders replacement rules
*
* @type Object
**/
replacement = {
id : function(f) {
return fm.cwdHash2Id(f.hash);
},
name : function(f) {
var name = fm.escape(f.i18 || f.name);
!list && (name = name.replace(/([_.])/g, '$1'));
return name;
},
nametitle : function(f) {
return fm.escape(f.i18 || f.name);
},
permsclass : function(f) {
return fm.perms2class(f);
},
perm : function(f) {
return fm.formatPermissions(f);
},
dirclass : function(f) {
var cName = f.mime == 'directory' ? 'directory' : '';
f.isroot && (cName += ' isroot');
f.csscls && (cName += ' ' + fm.escape(f.csscls));
options.getClass && (cName += ' ' + options.getClass(f));
return cName;
},
style : function(f) {
return f.icon? fm.getIconStyle(f) : '';
},
mime : function(f) {
return fm.mime2class(f.mime);
},
size : function(f) {
return (f.mime === 'directory' && !f.size)? '-' : fm.formatSize(f.size);
},
date : function(f) {
return fm.formatDate(f);
},
kind : function(f) {
return fm.mime2kind(f);
},
mode : function(f) {
return f.perm? fm.formatFileMode(f.perm) : '';
},
modestr : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'string') : '';
},
modeoct : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'octal') : '';
},
modeboth : function(f) {
return f.perm? fm.formatFileMode(f.perm, 'both') : '';
},
marker : function(f) {
return (f.alias || f.mime == 'symlink-broken' ? symlinkTpl : '')+(!f.read || !f.write ? permsTpl : '')+(f.locked ? lockTpl : '');
},
tooltip : function(f) {
var title = fm.formatDate(f) + (f.size > 0 ? ' ('+fm.formatSize(f.size)+')' : ''),
info = '';
if (query && f.path) {
info = fm.escape(f.path.replace(/\/[^\/]*$/, ''));
} else {
info = f.tooltip? fm.escape(f.tooltip).replace(/\r/g, '
') : '';
}
if (list) {
info += (info? '
' : '') + fm.escape(f.i18 || f.name);
}
return info? info + '
' + title : title;
}
},
/**
* Type badge CSS added flag
*
* @type Object
*/
addedBadges = {},
/**
* Type badge style sheet element
*
* @type Object
*/
addBadgeStyleSheet,
/**
* Add type badge CSS into 'head'
*
* @type Fundtion
*/
addBadgeStyle = function(mime, name) {
var sel, ext, type;
if (! addedBadges[mime]) {
if (typeof addBadgeStyleSheet === 'undefined') {
if ($('#elfinderAddBadgeStyle'+fm.namespace).length) {
$('#elfinderAddBadgeStyle'+fm.namespace).remove();
}
addBadgeStyleSheet = $('').insertBefore($('head').children(':first')).get(0).sheet || null;
}
if (addBadgeStyleSheet) {
mime = mime.toLowerCase();
type = mime.split('/');
ext = fm.escape(fm.mimeTypes[mime] || (name.replace(/.bac?k$/i, '').match(/\.([^.]+)$/) || ['',''])[1]);
if (ext) {
sel = '.elfinder-cwd-icon-' + type[0].replace(/(\.|\+)/g, '-');
if (typeof type[1] !== 'undefined') {
sel += '.elfinder-cwd-icon-' + type[1].replace(/(\.|\+)/g, '-');
}
try {
addBadgeStyleSheet.insertRule(sel + ':before{content:"' + ext.toLowerCase() + '"}', 0);
} catch(e) {}
}
addedBadges[mime] = true;
}
}
},
/**
* Return file html
*
* @param Object file info
* @return String
**/
itemhtml = function(f) {
f.mime && f.mime !== 'directory' && !addedBadges[f.mime] && addBadgeStyle(f.mime, f.name);
return templates[list ? 'row' : 'icon']
.replace(/\{([a-z0-9_]+)\}/g, function(s, e) {
return replacement[e] ? replacement[e](f, fm) : (f[e] ? f[e] : '');
});
},
/**
* jQueery node that will be selected next
*
* @type Object jQuery node
*/
selectedNext = $(),
/**
* Flag. Required for msie to avoid unselect files on dragstart
*
* @type Boolean
**/
selectLock = false,
/**
* Move selection to prev/next file
*
* @param String move direction
* @param Boolean append to current selection
* @return void
* @rise select
*/
select = function(keyCode, append) {
var code = $.ui.keyCode,
prev = keyCode == code.LEFT || keyCode == code.UP,
sel = cwd.find('[id].'+clSelected),
selector = prev ? 'first:' : 'last',
s, n, sib, top, left;
function sibling(n, direction) {
return n[direction+'All']('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):first');
}
if (sel.length) {
s = sel.filter(prev ? ':first' : ':last');
sib = sibling(s, prev ? 'prev' : 'next');
if (!sib.length) {
// there is no sibling on required side - do not move selection
n = s;
} else if (list || keyCode == code.LEFT || keyCode == code.RIGHT) {
// find real prevoius file
n = sib;
} else {
// find up/down side file in icons view
top = s.position().top;
left = s.position().left;
n = s;
if (prev) {
do {
n = n.prev('[id]');
} while (n.length && !(n.position().top < top && n.position().left <= left));
if (n.hasClass(clDisabled)) {
n = sibling(n, 'next');
}
} else {
do {
n = n.next('[id]');
} while (n.length && !(n.position().top > top && n.position().left >= left));
if (n.hasClass(clDisabled)) {
n = sibling(n, 'prev');
}
// there is row before last one - select last file
if (!n.length) {
sib = cwd.find('[id]:not(.'+clDisabled+'):last');
if (sib.position().top > top) {
n = sib;
}
}
}
}
// !append && unselectAll();
} else {
if (selectedNext.length) {
n = prev? selectedNext.prev() : selectedNext;
} else {
// there are no selected file - select first/last one
n = cwd.find('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):'+(prev ? 'last' : 'first'));
}
}
if (n && n.length && !n.hasClass('elfinder-cwd-parent')) {
if (s && append) {
// append new files to selected
n = s.add(s[prev ? 'prevUntil' : 'nextUntil']('#'+n.attr('id'))).add(n);
} else {
// unselect selected files
sel.trigger(evtUnselect);
}
// select file(s)
n.trigger(evtSelect);
// set its visible
scrollToView(n.filter(prev ? ':first' : ':last'));
// update cache/view
trigger();
}
},
selectedFiles = {},
selectFile = function(hash) {
$('#'+fm.cwdHash2Id(hash)).trigger(evtSelect);
},
allSelected = false,
selectAll = function() {
var phash = fm.cwd().hash;
selectCheckbox && selectAllCheckbox.find('input').prop('checked', true);
fm.lazy(function() {
var files;
cwd.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').trigger(evtSelect);
if (fm.maxTargets && (incHashes || cwdHashes).length > fm.maxTargets) {
files = $.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null });
files = fm.sortFiles(files).slice(0, fm.maxTargets);
selectedFiles = {};
$.each(files, function(i, v) {
selectedFiles[v.hash] = true;
});
fm.toast({mode: 'warning', msg: fm.i18n(['errMaxTargets', fm.maxTargets])});
} else {
selectedFiles = fm.arrayFlip(incHashes || cwdHashes, true);
}
trigger();
selectCheckbox && selectAllCheckbox.data('pending', false);
}, 0, {repaint: true});
},
/**
* Unselect all files
*
* @return void
*/
unselectAll = function() {
selectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
if (Object.keys(selectedFiles).length) {
selectLock = false;
selectedFiles = {};
cwd.find('[id].'+clSelected).trigger(evtUnselect);
selectCheckbox && cwd.find('input:checkbox').prop('checked', false);
}
trigger();
selectCheckbox && selectAllCheckbox.data('pending', false);
cwd.removeClass('elfinder-cwd-allselected');
},
selectInvert = function() {
var invHashes = {};
if (allSelected) {
unselectAll();
} else if (! Object.keys(selectedFiles).length) {
selectAll();
} else {
$.each((incHashes || cwdHashes), function(i, h) {
var itemNode = $('#'+fm.cwdHash2Id(h));
if (! selectedFiles[h]) {
invHashes[h] = true;
itemNode.length && itemNode.trigger(evtSelect);
} else {
itemNode.length && itemNode.trigger(evtUnselect);
}
});
selectedFiles = invHashes;
trigger();
}
},
/**
* Return selected files hashes list
*
* @return Array
*/
selected = function() {
return Object.keys(selectedFiles);
},
/**
* Last selected node id
*
* @type String|Void
*/
lastSelect = void 0,
/**
* Fire elfinder "select" event and pass selected files to it
*
* @return void
*/
trigger = function() {
var selected = Object.keys(selectedFiles),
opts = { selected : selected };
allSelected = selected.length && (selected.length === (incHashes || cwdHashes).length) && (!fm.maxTargets || selected.length <= fm.maxTargets);
if (selectCheckbox) {
selectAllCheckbox.find('input').prop('checked', allSelected);
cwd[allSelected? 'addClass' : 'removeClass']('elfinder-cwd-allselected');
}
if (allSelected) {
opts.selectall = true;
} else if (! selected.length) {
opts.unselectall = true;
}
fm.trigger('select', opts);
},
/**
* Scroll file to set it visible
*
* @param DOMElement file/dir node
* @return void
*/
scrollToView = function(o, blink) {
if (! o.length) {
return;
}
var ftop = o.position().top,
fheight = o.outerHeight(true),
wtop = wrapper.scrollTop(),
wheight = wrapper.get(0).clientHeight,
thheight = tableHeader? tableHeader.outerHeight(true) : 0;
if (ftop + thheight + fheight > wtop + wheight) {
wrapper.scrollTop(parseInt(ftop + thheight + fheight - wheight));
} else if (ftop < wtop) {
wrapper.scrollTop(ftop);
}
list && wrapper.scrollLeft(0);
!!blink && fm.resources.blink(o, 'lookme');
},
/**
* Files we get from server but not show yet
*
* @type Array
**/
buffer = [],
/**
* Extra data of buffer
*
* @type Object
**/
bufferExt = {},
/**
* Return index of elements with required hash in buffer
*
* @param String file hash
* @return Number
*/
index = function(hash) {
var l = buffer.length;
while (l--) {
if (buffer[l].hash == hash) {
return l;
}
}
return -1;
},
/**
* Scroll start event name
*
* @type String
**/
scrollStartEvent = 'elfscrstart',
/**
* Scroll stop event name
*
* @type String
**/
scrollEvent = 'elfscrstop',
scrolling = false,
/**
* jQuery UI selectable option
*
* @type Object
*/
selectableOption = {
disabled : true,
filter : '[id]:first',
stop : trigger,
delay : 250,
appendTo : 'body',
autoRefresh: false,
selected : function(e, ui) { $(ui.selected).trigger(evtSelect); },
unselected : function(e, ui) { $(ui.unselected).trigger(evtUnselect); }
},
/**
* hashes of items displayed in current view
*
* @type Object ItemHash => DomId
*/
inViewHashes = {},
/**
* Processing when the current view is changed (On open, search, scroll, resize etc.)
*
* @return void
*/
wrapperRepaint = function(init) {
var selectable = cwd.data('selectable'),
rec = (function() {
var wos = wrapper.offset(),
w = $(window),
l = wos.left - w.scrollLeft() + (fm.direction === 'ltr'? 30 : wrapper.width() - 30),
t = wos.top - w.scrollTop() + 10 + (list? bufferExt.itemH || 24 : 0);
return {left: Math.max(0, Math.round(l)), top: Math.max(0, Math.round(t))};
})(),
tgt = $(document.elementFromPoint(rec.left , rec.top)),
ids = {},
tmbs = {},
cnt = bufferExt.hpi? Math.ceil((wz.data('rectangle').height / bufferExt.hpi) * 1.5) : showFiles,
chk = function() {
var id = tgt.attr('id'),
hash, file;
if (id) {
bufferExt.getTmbs = [];
hash = fm.cwdId2Hash(id);
inViewHashes[hash] = id;
// for tmbs
if (bufferExt.attachTmbs[hash]) {
tmbs[hash] = bufferExt.attachTmbs[hash];
}
// for selectable
selectable && (ids[id] = true);
}
// next node
tgt = tgt.next();
},
done = function() {
if (cwd.data('selectable')) {
Object.assign(ids, selectedFiles);
ids = Object.keys(ids);
if (ids.length) {
selectableOption.filter = '#'+ids.join(', #');
cwd.selectable('enable').selectable('option', {filter : selectableOption.filter}).selectable('refresh');
}
}
if (Object.keys(tmbs).length) {
bufferExt.getTmbs = [];
attachThumbnails(tmbs);
}
},
arr;
inViewHashes = {};
selectable && cwd.selectable('option', 'disabled');
if (tgt.length) {
if (! tgt.hasClass(clFile)) {
tgt = tgt.closest(fileSelector);
}
if (tgt.attr('id')) {
if (init) {
for (var i = 0; i < cnt; i++) {
chk();
if (! tgt.length) {
break;
}
}
done();
} else {
bufferExt.repaintJob && bufferExt.repaintJob._abort();
arr = new Array(cnt);
bufferExt.repaintJob = fm.asyncJob(function() {
chk();
if (! tgt.length) {
bufferExt.repaintJob && bufferExt.repaintJob._abort(true);
}
}, arr).done(done);
}
}
}
},
/**
* display parent folder with ".." name
*
* @param String phash
* @return void
*/
oldSchool = function(phash) {
var phash = fm.cwd().phash,
pdir = fm.file(phash) || null,
set = function(pdir) {
if (pdir) {
parent = $(itemhtml($.extend(true, {}, pdir, {name : '..', i18 : '..', mime : 'directory'})))
.addClass('elfinder-cwd-parent')
.on('dblclick', function() {
var hash = fm.cwdId2Hash(this.id);
fm.trigger('select', {selected : [hash]}).exec('open', hash);
}
);
(list ? parent.children('td:first') : parent).children('.elfinder-cwd-select').remove();
(list ? cwd.find('tbody') : cwd).prepend(parent);
}
};
if (pdir) {
set(pdir);
} else {
if (fm.getUI('tree').length) {
fm.one('parents', function() {
set(fm.file(phash) || null);
wrapper.trigger(scrollEvent);
});
} else {
fm.request({
data : {cmd : 'parents', target : fm.cwd().hash},
preventFail : true
})
.done(function(data) {
set(fm.file(phash) || null);
wrapper.trigger(scrollEvent);
});
}
}
},
showFiles = fm.options.showFiles,
/**
* Cwd scroll event handler.
* Lazy load - append to cwd not shown files
*
* @return void
*/
render = function() {
if (bufferExt.rendering || (bufferExt.renderd && ! buffer.length)) {
return;
}
var place = (list ? cwd.children('table').children('tbody') : cwd),
phash,
chk,
// created document fragment for jQuery >= 1.12, 2.2, 3.0
// see Studio-42/elFinder#1544 @ github
docFlag = $.htmlPrefilter? true : false,
tempDom = docFlag? $(document.createDocumentFragment()) : $(''),
go = function(over){
var over = over || null,
html = [],
dirs = false,
atmb = {},
stmb = (fm.option('tmbUrl') === 'self'),
init = bufferExt.renderd? false : true,
files, locks, selected, init;
files = buffer.splice(0, showFiles + (over || 0) / (bufferExt.hpi || 1));
bufferExt.renderd += files.length;
if (! buffer.length) {
bottomMarker.hide();
wrapper.off(scrollEvent, render);
}
locks = [];
html = $.map(files, function(f) {
if (f.hash && f.name) {
if (f.mime == 'directory') {
dirs = true;
}
if (f.tmb || (stmb && f.mime.indexOf('image/') === 0)) {
atmb[f.hash] = f.tmb;
}
clipCuts[f.hash] && locks.push(f.hash);
return itemhtml(f);
}
return null;
});
// html into temp node
tempDom.empty().append(html.join(''));
// make directory droppable
dirs && !mobile && makeDroppable(tempDom);
// check selected items
selected = [];
if (Object.keys(selectedFiles).length) {
tempDom.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').each(function() {
selectedFiles[fm.cwdId2Hash(this.id)] && selected.push($(this));
});
}
// append to cwd
place.append(docFlag? tempDom : tempDom.children());
// trigger select
if (selected.length) {
$.each(selected, function(i, n) { n.trigger(evtSelect); });
trigger();
}
locks.length && fm.trigger('lockfiles', {files: locks});
!bufferExt.hpi && bottomMarkerShow(place, files.length);
if (list) {
// show thead
cwd.find('thead').show();
// fixed table header
fixTableHeader({fitWidth: ! colWidth});
}
if (Object.keys(atmb).length) {
Object.assign(bufferExt.attachTmbs, atmb);
}
if (init) {
if (! mobile && ! cwd.data('selectable')) {
// make files selectable
cwd.selectable(selectableOption).data('selectable', true);
}
wrapperRepaint(true);
}
! scrolling && wrapper.trigger(scrollEvent);
};
if (! bufferExt.renderd) {
// first time to go()
bufferExt.rendering = true;
// scroll top on dir load to avoid scroll after page reload
wrapper.scrollTop(0);
phash = fm.cwd().phash;
go();
if (options.oldSchool && phash && !query) {
oldSchool(phash);
}
if (list) {
colWidth && setColwidth();
fixTableHeader({fitWidth: true});
}
bufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
fm.trigger('cwdrender');
bufferExt.rendering = false;
}
if (! bufferExt.rendering && buffer.length) {
// next go()
if ((chk = (wrapper.height() + wrapper.scrollTop() + fm.options.showThreshold + bufferExt.row) - (bufferExt.renderd * bufferExt.hpi)) > 0) {
bufferExt.rendering = true;
fm.lazy(function() {
go(chk);
bufferExt.rendering = false;
});
}
}
},
// fixed table header jQuery object
tableHeader = null,
// To fixed table header colmun
fixTableHeader = function(opts) {
if (! options.listView.fixedHeader) {
return;
}
var setPos = function() {
var val;
val = (fm.direction === 'ltr')? wrapper.scrollLeft() * -1 : table.outerWidth(true) - wrapper.width() - wrapper.scrollLeft();
if (base.css('left') !== val) {
base.css('left', val);
}
},
opts = opts || {},
cnt, base, table, thead, tbody, hheight, htr, btr, htd, btd, htw, btw, init;
tbody = cwd.find('tbody');
btr = tbody.children('tr:first');
if (btr.length) {
table = tbody.parent();
if (! tableHeader) {
init = true;
tbody.addClass('elfinder-cwd-fixheader');
thead = cwd.find('thead').attr('id', fm.namespace+'-cwd-thead');
htr = thead.children('tr:first');
hheight = htr.outerHeight(true);
cwd.css('margin-top', hheight - parseInt(table.css('padding-top')));
base = $('').addClass(cwd.attr('class')).append($('').append(thead));
tableHeader = $('').addClass(wrapper.attr('class') + ' elfinder-cwd-fixheader')
.removeClass('ui-droppable native-droppable')
.css(wrapper.position())
.css({ height: hheight, width: cwd.outerWidth() })
.append(base);
if (fm.direction === 'rtl') {
tableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
}
setPos();
wrapper.after(tableHeader)
.on('scroll.fixheader resize.fixheader', function(e) {
setPos();
if (e.type === 'resize') {
e.stopPropagation();
tableHeader.css(wrapper.position());
wrapper.data('width', wrapper.css('overflow', 'hidden').width());
wrapper.css('overflow', 'auto');
fixTableHeader();
}
});
} else {
thead = $('#'+fm.namespace+'-cwd-thead');
htr = thead.children('tr:first');
}
if (init || opts.fitWidth || Math.abs(btr.outerWidth() - htr.outerWidth()) > 2) {
cnt = customCols.length + 1;
for (var i = 0; i < cnt; i++) {
htd = htr.children('td:eq('+i+')');
btd = btr.children('td:eq('+i+')');
htw = htd.width();
btw = btd.width();
if (typeof htd.data('delta') === 'undefined') {
htd.data('delta', (htd.outerWidth() - htw) - (btd.outerWidth() - btw));
}
btw -= htd.data('delta');
if (! init && ! opts.fitWidth && htw === btw) {
break;
}
htd.css('width', btw + 'px');
}
}
tableHeader.data('widthTimer') && clearTimeout(tableHeader.data('widthTimer'));
tableHeader.data('widthTimer', setTimeout(function() {
if (tableHeader) {
tableHeader.css('width', cwd.outerWidth() + 'px');
if (fm.direction === 'rtl') {
tableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
}
}
}, 10));
}
},
// Set colmun width
setColwidth = function() {
if (list && colWidth) {
var cl = 'elfinder-cwd-colwidth',
first = cwd.find('tr[id]:first'),
former;
if (! first.hasClass(cl)) {
former = cwd.find('tr.'+cl);
former.removeClass(cl).find('td').css('width', '');
first.addClass(cl);
cwd.find('table:first').css('table-layout', 'fixed');
$.each($.merge(['name'], customCols), function(i, k) {
var w = colWidth[k] || first.find('td.elfinder-col-'+k).width();
first.find('td.elfinder-col-'+k).width(w);
});
}
}
},
/**
* Droppable options for cwd.
* Drop target is `wrapper`
* Do not add class on childs file over
*
* @type Object
*/
droppable = Object.assign({}, fm.droppable, {
over : function(e, ui) {
var dst = $(this),
helper = ui.helper,
ctr = (e.shiftKey || e.ctrlKey || e.metaKey),
hash, status, inParent;
e.stopPropagation();
helper.data('dropover', helper.data('dropover') + 1);
dst.data('dropover', true);
if (helper.data('namespace') !== fm.namespace || ! fm.insideWorkzone(e.pageX, e.pageY)) {
dst.removeClass(clDropActive);
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
return;
}
if (dst.hasClass(fm.res(c, 'cwdfile'))) {
hash = fm.cwdId2Hash(dst.attr('id'));
dst.data('dropover', hash);
} else {
hash = fm.cwd().hash;
fm.cwd().write && dst.data('dropover', hash);
}
inParent = (fm.file(helper.data('files')[0]).phash === hash);
if (dst.data('dropover') === hash) {
$.each(helper.data('files'), function(i, h) {
if (h === hash || (inParent && !ctr && !helper.hasClass('elfinder-drag-helper-plus'))) {
dst.removeClass(clDropActive);
return false; // break $.each
}
});
} else {
dst.removeClass(clDropActive);
}
if (helper.data('locked') || inParent) {
status = 'elfinder-drag-helper-plus';
} else {
status = 'elfinder-drag-helper-move';
if (ctr) {
status += ' elfinder-drag-helper-plus';
}
}
dst.hasClass(clDropActive) && helper.addClass(status);
setTimeout(function(){ dst.hasClass(clDropActive) && helper.addClass(status); }, 20);
},
out : function(e, ui) {
var helper = ui.helper;
e.stopPropagation();
helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
$(this).removeData('dropover')
.removeClass(clDropActive);
},
deactivate : function() {
$(this).removeData('dropover')
.removeClass(clDropActive);
},
drop : function(e, ui) {
unselectAll();
fm.droppable.drop.call(this, e, ui);
}
}),
/**
* Make directory droppable
*
* @return void
*/
makeDroppable = function(place) {
place = place? place : (list ? cwd.find('tbody') : cwd);
var targets = place.children('.directory:not(.'+clDroppable+',.elfinder-na,.elfinder-ro)');
if (fm.isCommandEnabled('paste')) {
targets.droppable(droppable);
}
if (fm.isCommandEnabled('upload')) {
targets.addClass('native-droppable');
}
place.children('.isroot').each(function(i, n) {
var $n = $(n),
hash = fm.cwdId2Hash(n.id);
if (fm.isCommandEnabled('paste', hash)) {
if (! $n.hasClass(clDroppable+',elfinder-na,elfinder-ro')) {
$n.droppable(droppable);
}
} else {
if ($n.hasClass(clDroppable)) {
$n.droppable('destroy');
}
}
if (fm.isCommandEnabled('upload', hash)) {
if (! $n.hasClass('native-droppable,elfinder-na,elfinder-ro')) {
$n.addClass('native-droppable');
}
} else {
if ($n.hasClass('native-droppable')) {
$n.removeClass('native-droppable');
}
}
});
},
/**
* Preload required thumbnails and on load add css to files.
* Return false if required file is not visible yet (in buffer) -
* required for old api to stop loading thumbnails.
*
* @param Object file hash -> thumbnail map
* @param Bool reload
* @return void
*/
attachThumbnails = function(tmbs, reload) {
var attach = function(node, tmb) {
$('')
.on('load', function() {
node.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')");
})
.attr('src', tmb.url);
},
chk = function(hash, tmb) {
var node = $('#'+fm.cwdHash2Id(hash)),
file, tmbObj, reloads = [];
if (node.length) {
if (tmb != '1') {
file = fm.file(hash);
if (file.tmb !== tmb) {
file.tmb = tmb;
}
tmbObj = fm.tmb(file);
if (reload) {
node.find('.elfinder-cwd-icon').addClass(tmbObj.className).css('background-image', "url('"+tmbObj.url+"')");
} else {
attach(node, tmbObj);
}
delete bufferExt.attachTmbs[hash];
} else {
if (reload) {
loadThumbnails([hash]);
} else if (! bufferExt.tmbLoading[hash]) {
bufferExt.getTmbs.push(hash);
}
}
}
};
if ($.isPlainObject(tmbs) && Object.keys(tmbs).length) {
Object.assign(bufferExt.attachTmbs, tmbs);
$.each(tmbs, chk);
if (! reload && bufferExt.getTmbs.length && ! Object.keys(bufferExt.tmbLoading).length) {
loadThumbnails();
}
}
},
/**
* Load thumbnails from backend.
*
* @param Array|void reloads hashes list for reload thumbnail items
* @return void
*/
loadThumbnails = function(reloads) {
var tmbs = [],
reload = false;
if (fm.oldAPI) {
fm.request({
data : {cmd : 'tmb', current : fm.cwd().hash},
preventFail : true
})
.done(function(data) {
if (data.images && Object.keys(data.images).length) {
attachThumbnails(data.images);
}
if (data.tmb) {
loadThumbnails();
}
});
return;
}
if (reloads) {
reload = true;
tmbs = reloads.splice(0, tmbNum);
} else {
tmbs = bufferExt.getTmbs.splice(0, tmbNum);
}
if (tmbs.length) {
if (reload || inViewHashes[tmbs[0]] || inViewHashes[tmbs[tmbs.length-1]]) {
$.each(tmbs, function(i, h) {
bufferExt.tmbLoading[h] = true;
});
fm.request({
data : {cmd : 'tmb', targets : tmbs},
preventFail : true
})
.done(function(data) {
var errs = [],
resLen;
if (data.images) {
if (resLen = Object.keys(data.images).length) {
if (resLen < tmbs.length) {
$.each(tmbs, function(i, h) {
if (! data.images[h]) {
errs.push(h);
}
});
}
attachThumbnails(data.images, reload);
} else {
errs = tmbs;
}
// unset error items from bufferExt.attachTmbs
if (errs.length) {
$.each(errs, function(i, h) {
delete bufferExt.attachTmbs[h];
});
}
}
if (reload) {
if (reloads.length) {
loadThumbnails(reloads);
}
}
})
.always(function() {
bufferExt.tmbLoading = {};
if (! reload && bufferExt.getTmbs.length) {
loadThumbnails();
}
});
}
}
},
/**
* Add new files to cwd/buffer
*
* @param Array new files
* @return void
*/
add = function(files, mode) {
var place = list ? cwd.find('tbody') : cwd,
l = files.length,
atmb = {},
findNode = function(file) {
var pointer = cwd.find('[id]:first'), file2;
while (pointer.length) {
file2 = fm.file(fm.cwdId2Hash(pointer.attr('id')));
if (!pointer.hasClass('elfinder-cwd-parent') && file2 && fm.compare(file, file2) < 0) {
return pointer;
}
pointer = pointer.next('[id]');
}
},
findIndex = function(file) {
var l = buffer.length, i;
for (i =0; i < l; i++) {
if (fm.compare(file, buffer[i]) < 0) {
return i;
}
}
return l || -1;
},
// created document fragment for jQuery >= 1.12, 2.2, 3.0
// see Studio-42/elFinder#1544 @ github
docFlag = $.htmlPrefilter? true : false,
tempDom = docFlag? $(document.createDocumentFragment()) : $(''),
file, hash, node, nodes, ndx;
if (l > showFiles) {
// re-render for performance tune
content();
selectedFiles = fm.arrayFlip(files, true);
trigger();
} else {
// add the item immediately
l && wz.removeClass('elfinder-cwd-wrapper-empty');
while (l--) {
file = files[l];
hash = file.hash;
if ($('#'+fm.cwdHash2Id(hash)).length) {
continue;
}
if ((node = findNode(file)) && ! node.length) {
node = null;
}
if (! node && (ndx = findIndex(file)) >= 0) {
buffer.splice(ndx, 0, file);
} else {
tempDom.empty().append(itemhtml(file));
(file.mime === 'directory') && !mobile && makeDroppable(tempDom);
nodes = docFlag? tempDom : tempDom.children();
if (node) {
node.before(nodes);
} else {
place.append(nodes);
}
}
if ($('#'+fm.cwdHash2Id(hash)).length) {
if (file.tmb) {
atmb[hash] = file.tmb;
}
}
}
if (list) {
setColwidth();
fixTableHeader({fitWidth: ! colWidth});
}
bottomMarkerShow(place);
if (Object.keys(atmb).length) {
Object.assign(bufferExt.attachTmbs, atmb);
}
}
},
/**
* Remove files from cwd/buffer
*
* @param Array files hashes
* @return void
*/
remove = function(files) {
var l = files.length,
inSearch = fm.searchStatus.state > 1,
curCmd = fm.getCommand(fm.currentReqCmd) || {},
hash, n, ndx, allItems;
// removed cwd
if (!fm.cwd().hash && !curCmd.noChangeDirOnRemovedCwd) {
allItems = fm.files();
$.each(cwdParents.reverse(), function(i, h) {
if (allItems[h]) {
fm.one(fm.currentReqCmd + 'done', function() {
!fm.cwd().hash && fm.exec('open', h);
});
return false;
}
});
return;
}
while (l--) {
hash = files[l];
if ((n = $('#'+fm.cwdHash2Id(hash))).length) {
try {
n.remove();
--bufferExt.renderd;
} catch(e) {
fm.debug('error', e);
}
} else if ((ndx = index(hash)) !== -1) {
buffer.splice(ndx, 1);
}
selectedFiles[hash] && delete selectedFiles[hash]
if (inSearch) {
if ((ndx = $.inArray(hash, cwdHashes)) !== -1) {
cwdHashes.splice(ndx, 1);
}
}
}
inSearch && fm.trigger('cwdhasheschange', cwdHashes);
if (list) {
setColwidth();
fixTableHeader({fitWidth: ! colWidth});
}
},
msg = {
name : fm.i18n('name'),
perm : fm.i18n('perms'),
date : fm.i18n('modify'),
size : fm.i18n('size'),
kind : fm.i18n('kind'),
modestr : fm.i18n('mode'),
modeoct : fm.i18n('mode'),
modeboth : fm.i18n('mode')
},
customColsNameBuild = function() {
var name = '',
customColsName = '',
names = Object.assign({}, msg, options.listView.columnsCustomName);
for (var i = 0; i < customCols.length; i++) {
if (typeof names[customCols[i]] !== 'undefined') {
name = names[customCols[i]];
} else {
name = fm.i18n(customCols[i]);
}
customColsName +=''+name+' | ';
}
return customColsName;
},
bottomMarkerShow = function(place, cnt) {
var ph, col = 1;
place = place || (list ? cwd.find('tbody') : cwd);
if (buffer.length > 0) {
place.css({height: 'auto'});
ph = place.height();
if (cnt) {
if (! list) {
col = Math.floor(place.width()/place.find('[id]:first').width());
cnt = Math.ceil(cnt/col) * col;
}
bufferExt.hpi = ph / cnt;
bufferExt.row = bufferExt.hpi * col;
}
bottomMarker.css({top: (bufferExt.hpi * buffer.length + ph) + 'px'}).show();
}
},
wrapperContextMenu = {
contextmenu : function(e) {
e.preventDefault();
fm.trigger('contextmenu', {
'type' : 'cwd',
'targets' : [fm.cwd().hash],
'x' : e.pageX,
'y' : e.pageY
});
},
touchstart : function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
cwd.data('longtap', null);
wrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
if (e.target === this || e.target === cwd.get(0)) {
cwd.data('tmlongtap', setTimeout(function(){
// long tap
cwd.data('longtap', true);
fm.trigger('contextmenu', {
'type' : 'cwd',
'targets' : [fm.cwd().hash],
'x' : wrapper.data('touching').x,
'y' : wrapper.data('touching').y
});
}, 500));
}
},
touchend : function(e) {
if (e.type === 'touchmove') {
if (! wrapper.data('touching') ||
( Math.abs(wrapper.data('touching').x - e.originalEvent.touches[0].pageX)
+ Math.abs(wrapper.data('touching').y - e.originalEvent.touches[0].pageY)) > 4) {
wrapper.data('touching', null);
}
}
clearTimeout(cwd.data('tmlongtap'));
},
click : function(e) {
if (cwd.data('longtap')) {
e.preventDefault();
e.stopPropagation();
}
}
},
/**
* Update directory content
*
* @return void
*/
content = function() {
var phash, emptyMethod, thtr;
wz.append(selectAllCheckbox).removeClass('elfinder-cwd-wrapper-empty elfinder-search-result elfinder-incsearch-result elfinder-letsearch-result');
if (fm.searchStatus.state > 1 || fm.searchStatus.ininc) {
wz.addClass('elfinder-search-result' + (fm.searchStatus.ininc? ' elfinder-'+(query.substr(0,1) === '/' ? 'let':'inc')+'search-result' : ''));
}
// abort attachThumbJob
bufferExt.attachThumbJob && bufferExt.attachThumbJob._abort();
// destroy selectable for GC
cwd.data('selectable') && cwd.selectable('disable').selectable('destroy').removeData('selectable');
// notify cwd init
fm.trigger('cwdinit');
selectedNext = $();
try {
// to avoid problem with draggable
cwd.empty();
} catch (e) {
cwd.html('');
}
if (tableHeader) {
wrapper.off('scroll.fixheader resize.fixheader');
tableHeader.remove();
tableHeader = null;
}
cwd.removeClass('elfinder-cwd-view-icons elfinder-cwd-view-list')
.addClass('elfinder-cwd-view-'+(list ? 'list' :'icons'))
.attr('style', '')
.css('height', 'auto');
bottomMarker.hide();
wrapper[list ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-list')
._padding = parseInt(wrapper.css('padding-top')) + parseInt(wrapper.css('padding-bottom'));
if (fm.UA.iOS) {
wrapper.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
}
if (list) {
cwd.html('');
thtr = $(''+msg.name+' | '+customColsNameBuild()+'
');
cwd.find('thead').hide().append(
thtr
.on('contextmenu.'+fm.namespace, wrapperContextMenu.contextmenu)
.on('touchstart.'+fm.namespace, 'td', wrapperContextMenu.touchstart)
.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace+' mouseup.'+fm.namespace, 'td', wrapperContextMenu.touchend)
.on('click.'+fm.namespace,'td', wrapperContextMenu.click)
).find('td:first').append(selectAllCheckbox);
if ($.fn.sortable) {
thtr.addClass('touch-punch touch-punch-keep-default')
.sortable({
axis: 'x',
distance: 8,
items: '> .sortable-item',
start: function(e, ui) {
$(ui.item[0]).data('dragging', true);
ui.placeholder
.width(ui.helper.removeClass('ui-state-hover').width())
.removeClass('ui-state-active')
.addClass('ui-state-hover')
.css('visibility', 'visible');
},
update: function(e, ui){
var target = $(ui.item[0]).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', ''),
prev, done;
customCols = $.map($(this).children(), function(n) {
var name = $(n).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '');
if (! done) {
if (target === name) {
done = true;
} else {
prev = name;
}
}
return (name === 'name')? null : name;
});
templates.row = makeTemplateRow();
fm.storage('cwdCols', customCols);
prev = '.elfinder-col-'+prev+':first';
target = '.elfinder-col-'+target+':first';
fm.lazy(function() {
cwd.find('tbody tr').each(function() {
var $this = $(this);
$this.children(prev).after($this.children(target));
});
});
},
stop: function(e, ui) {
setTimeout(function() {
$(ui.item[0]).removeData('dragging');
}, 100);
}
});
}
thtr.find('td').addClass('touch-punch').resizable({
handles: fm.direction === 'ltr'? 'e' : 'w',
start: function(e, ui) {
var target = cwd.find('td.elfinder-col-'
+ ui.element.attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '')
+ ':first');
ui.element
.data('resizeTarget', target)
.data('targetWidth', target.width());
colResizing = true;
if (cwd.find('table').css('table-layout') !== 'fixed') {
cwd.find('tbody tr:first td').each(function() {
$(this).width($(this).width());
});
cwd.find('table').css('table-layout', 'fixed');
}
},
resize: function(e, ui) {
ui.element.data('resizeTarget').width(ui.element.data('targetWidth') - (ui.originalSize.width - ui.size.width));
},
stop : function() {
colResizing = false;
fixTableHeader({fitWidth: true});
colWidth = {};
cwd.find('tbody tr:first td').each(function() {
var name = $(this).attr('class').split(' ')[0].replace('elfinder-col-', '');
colWidth[name] = $(this).width();
});
fm.storage('cwdColWidth', colWidth);
}
})
.find('.ui-resizable-handle').addClass('ui-icon ui-icon-grip-dotted-vertical');
}
fm.lazy(function() {
buffer = $.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null });
buffer = fm.sortFiles(buffer);
bufferExt = {
renderd: 0,
attachTmbs: {},
getTmbs: [],
tmbLoading: {},
lazyOpts: { tm : 0 }
};
wz[(buffer.length < 1) ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-empty');
wrapper.off(scrollEvent, render).on(scrollEvent, render).trigger(scrollEvent);
// set droppable
if (!fm.cwd().write) {
wrapper.removeClass('native-droppable')
.droppable('disable')
.removeClass('ui-state-disabled'); // for old jQueryUI see https://bugs.jqueryui.com/ticket/5974
} else {
wrapper[fm.isCommandEnabled('upload')? 'addClass' : 'removeClass']('native-droppable');
wrapper.droppable(fm.isCommandEnabled('paste')? 'enable' : 'disable');
}
});
},
/**
* CWD node itself
*
* @type JQuery
**/
cwd = $(this)
.addClass('ui-helper-clearfix elfinder-cwd')
.attr('unselectable', 'on')
// fix ui.selectable bugs and add shift+click support
.on('click.'+fm.namespace, fileSelector, function(e) {
var p = this.id ? $(this) : $(this).parents('[id]:first'),
tgt = $(e.target),
prev,
next,
pl,
nl,
sib;
if (selectCheckbox && (tgt.is('input:checkbox') || tgt.hasClass('elfinder-cwd-select'))) {
e.stopPropagation();
e.preventDefault();
if (! wrapper.data('touching')) {
p.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
trigger();
}
setTimeout(function() {
tgt.prop('checked', p.hasClass(clSelected));
}, 10);
return false;
}
if (cwd.data('longtap')) {
e.stopPropagation();
return;
}
if (!curClickId) {
curClickId = p.attr('id');
setTimeout(function() {
curClickId = '';
}, 500);
}
if (e.shiftKey) {
prev = p.prevAll(lastSelect || '.'+clSelected+':first');
next = p.nextAll(lastSelect || '.'+clSelected+':first');
pl = prev.length;
nl = next.length;
}
if (e.shiftKey && (pl || nl)) {
sib = pl ? p.prevUntil('#'+prev.attr('id')) : p.nextUntil('#'+next.attr('id'));
sib.add(p).trigger(evtSelect);
} else if (e.ctrlKey || e.metaKey) {
p.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
} else {
if (wrapper.data('touching') && p.hasClass(clSelected)) {
wrapper.data('touching', null);
fm.dblclick({file : fm.cwdId2Hash(this.id)});
return;
} else {
unselectAll();
p.trigger(evtSelect);
}
}
trigger();
})
// call fm.open()
.on('dblclick.'+fm.namespace, fileSelector, function(e) {
if (curClickId) {
var hash = fm.cwdId2Hash(curClickId);
e.stopPropagation();
if (this.id !== curClickId) {
$(this).trigger(evtUnselect);
$('#'+curClickId).trigger(evtSelect);
trigger();
}
fm.dblclick({file : hash});
}
})
// for touch device
.on('touchstart.'+fm.namespace, fileSelector, function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
var p = this.id ? $(this) : $(this).parents('[id]:first'),
tgt = $(e.target),
sel;
wrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
if (selectCheckbox && (tgt.is('input:checkbox') || tgt.hasClass('elfinder-cwd-select'))) {
setTimeout(function() {
if (wrapper.data('touching')) {
p.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
trigger();
}
}, 150);
return;
}
if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') {
return;
}
sel = p.prevAll('.'+clSelected+':first').length +
p.nextAll('.'+clSelected+':first').length;
cwd.data('longtap', null);
p.addClass(clHover)
.data('tmlongtap', setTimeout(function(){
// long tap
cwd.data('longtap', true);
if (e.target.nodeName != 'TD' || fm.selected().length > 0) {
p.trigger(evtSelect);
trigger();
fm.trigger('contextmenu', {
'type' : 'files',
'targets' : fm.selected(),
'x' : e.originalEvent.touches[0].pageX,
'y' : e.originalEvent.touches[0].pageY
});
}
}, 500));
})
.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, fileSelector, function(e) {
if (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA' || $(e.target).hasClass('elfinder-cwd-select')) {
return;
}
var p = this.id ? $(this) : $(this).parents('[id]:first');
clearTimeout(p.data('tmlongtap'));
if (e.type === 'touchmove') {
wrapper.data('touching', null);
p.removeClass(clHover);
} else if (wrapper.data('touching') && !cwd.data('longtap') && p.hasClass(clSelected)) {
e.preventDefault();
wrapper.data('touching', null);
fm.dblclick({file : fm.cwdId2Hash(this.id)});
}
})
// attach draggable
.on('mouseenter.'+fm.namespace, fileSelector, function(e) {
if (scrolling) { return; }
var $this = $(this), helper = null,
target = list ? $this : $this.children('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename');
if (!mobile && !$this.data('dragRegisted') && !$this.hasClass(clTmp) && !target.hasClass(clDraggable) && !target.hasClass(clDisabled)) {
$this.data('dragRegisted', true);
if (!fm.isCommandEnabled('copy', fm.searchStatus.state > 1? fm.cwdId2Hash($this.attr('id')) : void 0)) {
return;
}
target.on('mousedown', function(e) {
// shiftKey or altKey + drag start for HTML5 native drag function
// Note: can no use shiftKey with the Google Chrome
var metaKey = e.shiftKey || e.altKey;
if (metaKey && !fm.UA.IE && cwd.data('selectable')) {
// destroy jQuery-ui selectable while trigger native drag
cwd.selectable('disable').selectable('destroy').removeData('selectable');
setTimeout(function(){
cwd.selectable(selectableOption).selectable('option', {disabled: false}).selectable('refresh').data('selectable', true);
}, 10);
}
target.draggable('option', 'disabled', metaKey).removeClass('ui-state-disabled');
if (metaKey) {
target.attr('draggable', 'true');
} else {
target.removeAttr('draggable')
.draggable('option', 'cursorAt', {left: 50 - parseInt($(e.currentTarget).css('margin-left')), top: 47});
}
})
.on('dragstart', function(e) {
var dt = e.dataTransfer || e.originalEvent.dataTransfer || null;
helper = null;
if (dt && !fm.UA.IE) {
var p = this.id ? $(this) : $(this).parents('[id]:first'),
elm = $(''),
url = '',
durl = null,
murl = null,
files = [],
icon = function(f) {
var mime = f.mime, i, tmb = fm.tmb(f);
i = '';
if (tmb) {
i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML;
}
return i;
}, l, geturl = [];
p.trigger(evtSelect);
trigger();
$.each(selectedFiles, function(v){
var file = fm.file(v),
furl = file.url;
if (file && file.mime !== 'directory') {
if (!furl) {
furl = fm.url(file.hash);
} else if (furl == '1') {
geturl.push(v);
return true;
}
if (furl) {
furl = fm.convAbsUrl(furl);
files.push(v);
$('').attr('href', furl).text(furl).appendTo(elm);
url += furl + "\n";
if (!durl) {
durl = file.mime + ':' + file.name + ':' + furl;
}
if (!murl) {
murl = furl + "\n" + file.name;
}
}
}
});
if (geturl.length) {
$.each(geturl, function(i, v){
var rfile = fm.file(v);
rfile.url = '';
fm.request({
data : {cmd : 'url', target : v},
notify : {type : 'url', cnt : 1},
preventDefault : true
})
.always(function(data) {
rfile.url = data.url? data.url : '1';
});
});
return false;
} else if (url) {
if (dt.setDragImage) {
helper = $('').append(icon(fm.file(files[0]))).appendTo($(document.body));
if ((l = files.length) > 1) {
helper.append(icon(fm.file(files[l-1])) + ''+l+'');
}
dt.setDragImage(helper.get(0), 50, 47);
}
dt.effectAllowed = 'copyLink';
dt.setData('DownloadURL', durl);
dt.setData('text/x-moz-url', murl);
dt.setData('text/uri-list', url);
dt.setData('text/plain', url);
dt.setData('text/html', elm.html());
dt.setData('elfinderfrom', window.location.href + fm.cwd().hash);
dt.setData('elfinderfrom:' + dt.getData('elfinderfrom'), '');
} else {
return false;
}
}
})
.on('dragend', function(e){
unselectAll();
helper && helper.remove();
})
.draggable(fm.draggable);
}
})
// add hover class to selected file
.on(evtSelect, fileSelector, function(e) {
var $this = $(this),
id = fm.cwdId2Hash($this.attr('id'));
if (!selectLock && !$this.hasClass(clDisabled)) {
lastSelect = '#'+ this.id;
$this.addClass(clSelected).children().addClass(clHover).find('input:checkbox').prop('checked', true);
if (! selectedFiles[id]) {
selectedFiles[id] = true;
}
// will be selected next
selectedNext = cwd.find('[id].'+clSelected+':last').next();
}
})
// remove hover class from unselected file
.on(evtUnselect, fileSelector, function(e) {
var $this = $(this),
id = fm.cwdId2Hash($this.attr('id'));
if (!selectLock) {
$this.removeClass(clSelected).children().removeClass(clHover).find('input:checkbox').prop('checked', false);
if (cwd.hasClass('elfinder-cwd-allselected')) {
selectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
cwd.removeClass('elfinder-cwd-allselected');
}
selectedFiles[id] && delete selectedFiles[id];
}
})
// disable files wich removing or moving
.on(evtDisable, fileSelector, function() {
var $this = $(this).removeClass(clHover+' '+clSelected).addClass(clDisabled),
child = $this.children(),
target = (list ? $this : child.find('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename'));
child.removeClass(clHover+' '+clSelected);
$this.hasClass(clDroppable) && $this.droppable('disable');
target.hasClass(clDraggable) && target.draggable('disable');
})
// if any files was not removed/moved - unlock its
.on(evtEnable, fileSelector, function() {
var $this = $(this).removeClass(clDisabled),
target = list ? $this : $this.children('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename');
$this.hasClass(clDroppable) && $this.droppable('enable');
target.hasClass(clDraggable) && target.draggable('enable');
})
.on('scrolltoview', fileSelector, function(e, data) {
scrollToView($(this), (data && typeof data.blink !== 'undefined')? data.blink : true);
})
.on('mouseenter.'+fm.namespace+' mouseleave.'+fm.namespace, fileSelector, function(e) {
var enter = (e.type === 'mouseenter');
if (enter && scrolling) { return; }
fm.trigger('hover', {hash : fm.cwdId2Hash($(this).attr('id')), type : e.type});
$(this).toggleClass(clHover, (e.type == 'mouseenter'));
})
.on('contextmenu.'+fm.namespace, function(e) {
var file = $(e.target).closest(fileSelector);
if (file.length && (e.target.nodeName != 'TD' || $.inArray(fm.cwdId2Hash(file.get(0).id), fm.selected()) > -1)) {
e.stopPropagation();
e.preventDefault();
if (!file.hasClass(clDisabled) && !wrapper.data('touching')) {
if (!file.hasClass(clSelected)) {
unselectAll();
file.trigger(evtSelect);
trigger();
}
fm.trigger('contextmenu', {
'type' : 'files',
'targets' : fm.selected(),
'x' : e.pageX,
'y' : e.pageY
});
}
}
})
// unselect all on cwd click
.on('click.'+fm.namespace, function(e) {
if (e.target === this && ! cwd.data('longtap')) {
!e.shiftKey && !e.ctrlKey && !e.metaKey && unselectAll();
}
})
// prepend fake file/dir
.on('create.'+fm.namespace, function(e, file) {
var parent = list ? cwd.find('tbody') : cwd,
p = parent.find('.elfinder-cwd-parent'),
lock = file.move || false,
file = $(itemhtml(file)).addClass(clTmp),
selected = fm.selected();
if (selected.length) {
lock && fm.trigger('lockfiles', {files: selected});
} else {
unselectAll();
}
if (p.length) {
p.after(file);
} else {
parent.prepend(file);
}
setColwidth();
wrapper.scrollTop(0).scrollLeft(0);
})
// unselect all selected files
.on('unselectall', unselectAll)
.on('selectfile', function(e, id) {
$('#'+fm.cwdHash2Id(id)).trigger(evtSelect);
trigger();
})
.on('colwidth', function() {
if (list) {
cwd.find('table').css('table-layout', '')
.find('td').css('width', '');
fixTableHeader({fitWidth: true});
fm.storage('cwdColWidth', colWidth = null);
}
}),
wrapper = $('')
// make cwd itself droppable for folders from nav panel
.droppable(Object.assign({}, droppable, {autoDisable: false}))
.on('contextmenu.'+fm.namespace, wrapperContextMenu.contextmenu)
.on('touchstart.'+fm.namespace, wrapperContextMenu.touchstart)
.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, wrapperContextMenu.touchend)
.on('click.'+fm.namespace, wrapperContextMenu.click)
.on('scroll.'+fm.namespace, function() {
if (! scrolling) {
cwd.data('selectable') && cwd.selectable('disable');
wrapper.trigger(scrollStartEvent);
}
scrolling = true;
bufferExt.scrtm && clearTimeout(bufferExt.scrtm);
if (bufferExt.scrtm && Math.abs((bufferExt.scrolltop || 0) - (bufferExt.scrolltop = (this.scrollTop || $(this).scrollTop()))) < 5) {
bufferExt.scrtm = 0;
wrapper.trigger(scrollEvent);
}
bufferExt.scrtm = setTimeout(function() {
bufferExt.scrtm = 0;
wrapper.trigger(scrollEvent);
}, 20);
})
.on(scrollEvent, function() {
scrolling = false;
wrapperRepaint();
}),
bottomMarker = $('
')
.css({position: 'absolute', width: '1px', height: '1px'})
.hide(),
selectAllCheckbox = selectCheckbox? $('')
.attr('title', fm.i18n('selectall'))
.on('touchstart mousedown click', function(e) {
e.stopPropagation();
e.preventDefault();
if ($(this).data('pending') || e.type === 'click') {
return false;
}
selectAllCheckbox.data('pending', true);
if (cwd.hasClass('elfinder-cwd-allselected')) {
selectAllCheckbox.find('input').prop('checked', false);
setTimeout(function() {
unselectAll();
}, 10);
} else {
selectAll();
}
}) : $(),
restm = null,
resize = function(init) {
var initHeight = function() {
var h = 0;
wrapper.siblings('div.elfinder-panel:visible').each(function() {
h += $(this).outerHeight(true);
});
wrapper.height(wz.height() - h - wrapper._padding);
};
init && initHeight();
restm && clearTimeout(restm);
restm = setTimeout(function(){
!init && initHeight();
var wph, cwdoh;
// fix cwd height if it less then wrapper
cwd.css('height', 'auto');
wph = wrapper[0].clientHeight - parseInt(wrapper.css('padding-top')) - parseInt(wrapper.css('padding-bottom')) - parseInt(cwd.css('margin-top')),
cwdoh = cwd.outerHeight(true);
if (cwdoh < wph) {
cwd.height(wph);
}
}, 10);
list && ! colResizing && (init? wrapper.trigger('resize.fixheader') : fixTableHeader());
wrapperRepaint();
},
// elfinder node
parent = $(this).parent().resize(resize),
// workzone node
wz = parent.children('.elfinder-workzone').append(wrapper.append(this).append(bottomMarker)),
// has UI tree
hasUiTree,
winScrTm;
// setup by options
replacement = Object.assign(replacement, options.replacement || {});
try {
colWidth = fm.storage('cwdColWidth')? fm.storage('cwdColWidth') : null;
} catch(e) {
colWidth = null;
}
// setup costomCols
if (customCols = fm.storage('cwdCols')) {
customCols = $.map(customCols, function(n) {
return (options.listView.columns.indexOf(n) !== -1)? n : null;
});
if (options.listView.columns.length > customCols.length) {
$.each(options.listView.columns, function(i, n) {
if (customCols.indexOf(n) === -1) {
customCols.push(n);
}
});
}
} else {
customCols = options.listView.columns;
}
templates.row = makeTemplateRow();
if (mobile) {
// for iOS5 bug
$('body').on('touchstart touchmove touchend', function(e){});
}
selectCheckbox && cwd.addClass('elfinder-has-checkbox');
$(window).on('scroll.'+fm.namespace, function() {
winScrTm && clearTimeout(winScrTm);
winScrTm = setTimeout(function() {
wrapper.trigger(scrollEvent);
}, 50);
});
$(document).on('keydown.'+fm.namespace, function(e) {
if (e.keyCode == $.ui.keyCode.ESCAPE) {
if (! fm.getUI().find('.ui-widget:visible').length) {
unselectAll();
}
}
});
fm
.one('init', function(){
var style = document.createElement('style'),
sheet, node, base, resizeTm, i = 0;
if (document.head) {
document.head.appendChild(style);
sheet = style.sheet;
sheet.insertRule('.elfinder-cwd-wrapper-empty .elfinder-cwd:after{ content:"'+fm.i18n('emptyFolder')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty .ui-droppable .elfinder-cwd:after{ content:"'+fm.i18n('emptyFolder'+(mobile? 'LTap' : 'Drop'))+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty .ui-droppable-disabled .elfinder-cwd:after{ content:"'+fm.i18n('emptyFolder')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result .elfinder-cwd:after{ content:"'+fm.i18n('emptySearch')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-incsearch-result .elfinder-cwd:after{ content:"'+fm.i18n('emptyIncSearch')+'" }', i++);
sheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-letsearch-result .elfinder-cwd:after{ content:"'+fm.i18n('emptyLetSearch')+'" }', i++);
}
if (! mobile) {
fm.one('open', function() {
sheet && fm.zIndex && sheet.insertRule('.ui-selectable-helper{z-index:'+fm.zIndex+';}', i++);
});
base = $('');
node = fm.getUI();
node.on('resize', function(e, data) {
var offset;
e.preventDefault();
e.stopPropagation();
if (data && data.fullscreen) {
offset = node.offset();
if (data.fullscreen === 'on') {
base.css({top:offset.top * -1 , left:offset.left * -1 }).appendTo(node);
selectableOption.appendTo = base;
} else {
base.detach();
selectableOption.appendTo = 'body';
}
cwd.data('selectable') && cwd.selectable('option', {appendTo : selectableOption.appendTo});
}
});
}
hasUiTree = fm.getUI('tree').length;
})
.bind('enable', function() {
resize();
})
.bind('request.open', function() {
bufferExt.getTmbs = [];
})
.bind('open add remove searchend', function() {
var phash = fm.cwd().hash,
type = this.type;
if (type === 'open' || type === 'searchend' || fm.searchStatus.state < 2) {
cwdHashes = $.map(fm.files(phash), function(f) { return f.hash; });
fm.trigger('cwdhasheschange', cwdHashes);
}
if (type === 'open') {
var inTrash = function() {
var isIn = false;
$.each(cwdParents, function(i, h) {
if (fm.trashes[h]) {
isIn = true;
return false;
}
});
return isIn;
},
phash = fm.cwd().phash,
req = phash?
(! fm.file(phash)?
(! hasUiTree?
fm.request({
data: {
cmd : 'parents',
target : fm.cwd().hash
},
preventFail : true
}) : (function() {
var dfd = $.Deferred();
fm.one('parents', function() {
dfd.resolve();
});
return dfd;
})()
) : null
) : null;
$.when(req).done(function() {
cwdParents = fm.parents(fm.cwd().hash);
wrapper[inTrash()? 'addClass':'removeClass']('elfinder-cwd-wrapper-trash');
});
incHashes = void 0;
unselectAll();
content();
resize();
}
})
.bind('search', function(e) {
cwdHashes = $.map(e.data.files, function(f) { return f.hash; });
fm.trigger('cwdhasheschange', cwdHashes);
incHashes = void 0;
fm.searchStatus.ininc = false;
content();
fm.autoSync('stop');
resize();
})
.bind('searchend', function(e) {
if (query || incHashes) {
query = '';
if (incHashes) {
fm.trigger('incsearchend', e.data);
} else {
if (!e.data || !e.data.noupdate) {
content();
}
}
}
fm.autoSync();
resize();
})
.bind('searchstart', function(e) {
unselectAll();
query = e.data.query;
})
.bind('incsearchstart', function(e) {
selectedFiles = {};
fm.lazy(function() {
// incremental search
var regex, q, fst = '';
q = query = e.data.query || '';
if (q) {
if (q.substr(0,1) === '/') {
q = q.substr(1);
fst = '^';
}
regex = new RegExp(fst + q.replace(/([\\*\;\.\?\[\]\{\}\(\)\^\$\-\|])/g, '\\$1'), 'i');
incHashes = $.map(cwdHashes, function(hash) {
var file = fm.file(hash);
return (file && (file.name.match(regex) || (file.i18 && file.i18.match(regex))))? file.hash : null;
});
fm.trigger('incsearch', { hashes: incHashes, query: q })
.searchStatus.ininc = true;
content();
fm.autoSync('stop');
} else {
fm.trigger('incsearchend');
}
resize();
});
})
.bind('incsearchend', function(e) {
query = '';
fm.searchStatus.ininc = false;
incHashes = void 0;
if (!e.data || !e.data.noupdate) {
content();
}
fm.autoSync();
})
.bind('sortchange', function() {
var lastScrollLeft = wrapper.scrollLeft();
content();
fm.one('cwdrender', function() {
wrapper.scrollLeft(lastScrollLeft);
Object.keys(selectedFiles).length && trigger();
resize();
});
})
.bind('viewchange', function() {
var l = fm.storage('view') == 'list',
allsel = cwd.hasClass('elfinder-cwd-allselected');
if (l != list) {
list = l;
fm.viewType = list? 'list' : 'icons';
content();
if (allsel) {
cwd.addClass('elfinder-cwd-allselected');
selectAllCheckbox.find('input').prop('checked', true);
}
Object.keys(selectedFiles).length && trigger();
}
resize();
})
.bind('wzresize', function() {
var place = list ? cwd.find('tbody') : cwd,
cwdOffset;
resize(true);
if (bufferExt.hpi) {
bottomMarkerShow(place, place.find('[id]').length);
}
cwdOffset = cwd.offset();
wz.data('rectangle', Object.assign(
{
width: wz.width(),
height: wz.height(),
cwdEdge: (fm.direction === 'ltr')? cwdOffset.left : cwdOffset.left + cwd.width()
},
wz.offset())
);
bufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
})
.bind('changeclipboard', function(e) {
clipCuts = {};
if (e.data && e.data.clipboard && e.data.clipboard.length) {
$.each(e.data.clipboard, function(i, f) {
if (f.cut) {
clipCuts[f.hash] = true;
}
});
}
})
.bind('resMixinMake', function() {
setColwidth();
})
.bind('tmbreload', function(e) {
var imgs = {},
files = (e.data && e.data.files)? e.data.files : null;
$.each(files, function(i, f) {
if (f.tmb && f.tmb != '1') {
imgs[f.hash] = f.tmb;
}
});
if (Object.keys(imgs).length) {
attachThumbnails(imgs, true);
}
})
.add(function(e) {
var regex = query? new RegExp(query.replace(/([\\*\;\.\?\[\]\{\}\(\)\^\$\-\|])/g, '\\$1'), 'i') : null,
mime = fm.searchStatus.mime,
inSearch = fm.searchStatus.state > 1,
phash = inSearch && fm.searchStatus.target? fm.searchStatus.target : fm.cwd().hash,
curPath = fm.path(phash),
inTarget = function(f) {
var res, parents, path;
res = (f.phash === phash);
if (!res && inSearch) {
path = f.path || fm.path(f.hash);
res = (curPath && path.indexOf(curPath) === 0);
if (! res && fm.searchStatus.mixed) {
res = $.map(fm.searchStatus.mixed, function(vid) { return f.hash.indexOf(vid) === 0? true : null; }).length? true : false;
}
}
if (res && inSearch) {
if (mime) {
res = (f.mime.indexOf(mime) === 0);
} else {
res = (f.name.match(regex) || (f.i18 && f.i18.match(regex)))? true : false;
}
}
return res;
},
files = $.map(e.data.added || [], function(f) { return inTarget(f)? f : null ;});
add(files);
if (fm.searchStatus.state === 2) {
$.each(files, function(i, f) {
if ($.inArray(f.hash, cwdHashes) === -1) {
cwdHashes.push(f.hash);
}
});
fm.trigger('cwdhasheschange', cwdHashes);
}
list && resize();
wrapper.trigger(scrollEvent);
})
.change(function(e) {
var phash = fm.cwd().hash,
sel = fm.selected(),
files, added;
if (query) {
$.each(e.data.changed || [], function(i, file) {
remove([file.hash]);
if (file.name.indexOf(query) !== -1) {
add([file], 'change');
$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
added = true;
}
});
} else {
$.each($.map(e.data.changed || [], function(f) { return f.phash == phash ? f : null; }), function(i, file) {
remove([file.hash]);
add([file], 'change');
$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
added = true;
});
}
if (added) {
fm.trigger('cwdhasheschange', cwdHashes);
list && resize();
wrapper.trigger(scrollEvent);
}
trigger();
})
.remove(function(e) {
var place = list ? cwd.find('tbody') : cwd;
remove(e.data.removed || []);
trigger();
if (buffer.length < 1 && place.children(fileSelector).length < 1) {
wz.addClass('elfinder-cwd-wrapper-empty');
selectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
bottomMarker.hide();
wrapper.off(scrollEvent, render);
resize();
} else {
bottomMarkerShow(place);
wrapper.trigger(scrollEvent);
}
})
// select dragged file if no selected, disable selectable
.dragstart(function(e) {
var target = $(e.data.target),
oe = e.data.originalEvent;
if (target.hasClass(clFile)) {
if (!target.hasClass(clSelected)) {
!(oe.ctrlKey || oe.metaKey || oe.shiftKey) && unselectAll();
target.trigger(evtSelect);
trigger();
}
}
cwd.removeClass(clDisabled).data('selectable') && cwd.selectable('disable');
selectLock = true;
})
// enable selectable
.dragstop(function() {
cwd.data('selectable') && cwd.selectable('enable');
selectLock = false;
})
.bind('lockfiles unlockfiles selectfiles unselectfiles', function(e) {
var events = {
lockfiles : evtDisable ,
unlockfiles : evtEnable ,
selectfiles : evtSelect,
unselectfiles : evtUnselect },
event = events[e.type],
files = e.data.files || [],
l = files.length,
helper = e.data.helper || $(),
parents, ctr, add;
if (l > 0) {
parents = fm.parents(files[0]);
}
if (event === evtSelect || event === evtUnselect) {
add = (event === evtSelect),
$.each(files, function(i, hash) {
var all = cwd.hasClass('elfinder-cwd-allselected');
if (! selectedFiles[hash]) {
add && (selectedFiles[hash] = true);
} else {
if (all) {
selectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
cwd.removeClass('elfinder-cwd-allselected');
all = false;
}
! add && delete selectedFiles[hash];
}
});
}
if (!helper.data('locked')) {
while (l--) {
try {
$('#'+fm.cwdHash2Id(files[l])).trigger(event);
} catch(e) {}
}
! e.data.inselect && trigger();
}
if (wrapper.data('dropover') && parents.indexOf(wrapper.data('dropover')) !== -1) {
ctr = e.type !== 'lockfiles';
helper.toggleClass('elfinder-drag-helper-plus', ctr);
wrapper.toggleClass(clDropActive, ctr);
}
})
// select new files after some actions
.bind('mkdir mkfile duplicate upload rename archive extract paste multiupload', function(e) {
if (e.type == 'upload' && e.data._multiupload) return;
var phash = fm.cwd().hash, files;
unselectAll();
$.each((e.data.added || []).concat(e.data.changed || []), function(i, file) {
file && file.phash == phash && selectFile(file.hash);
});
trigger();
})
.shortcut({
pattern :'ctrl+a',
description : 'selectall',
callback : selectAll
})
.shortcut({
pattern :'ctrl+shift+i',
description : 'selectinvert',
callback : selectInvert
})
.shortcut({
pattern : 'left right up down shift+left shift+right shift+up shift+down',
description : 'selectfiles',
type : 'keydown' , //fm.UA.Firefox || fm.UA.Opera ? 'keypress' : 'keydown',
callback : function(e) { select(e.keyCode, e.shiftKey); }
})
.shortcut({
pattern : 'home',
description : 'selectffile',
callback : function(e) {
unselectAll();
scrollToView(cwd.find('[id]:first').trigger(evtSelect));
trigger();
}
})
.shortcut({
pattern : 'end',
description : 'selectlfile',
callback : function(e) {
unselectAll();
scrollToView(cwd.find('[id]:last').trigger(evtSelect)) ;
trigger();
}
})
.shortcut({
pattern : 'page_up',
description : 'pageTurning',
callback : function(e) {
if (bufferExt.itemH) {
wrapper.scrollTop(
Math.round(
wrapper.scrollTop()
- (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
)
);
}
}
}).shortcut({
pattern : 'page_down',
description : 'pageTurning',
callback : function(e) {
if (bufferExt.itemH) {
wrapper.scrollTop(
Math.round(
wrapper.scrollTop()
+ (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
)
);
}
}
});
});
// fm.timeEnd('cwdLoad')
return this;
};
PK SPKh js/ui/fullscreenbutton.jsnu W+A "use strict";
/**
* @class elFinder toolbar button to switch full scrren mode.
*
* @author Naoki Sawada
**/
$.fn.elfinderfullscreenbutton = function(cmd) {
return this.each(function() {
var button = $(this).elfinderbutton(cmd),
icon = button.children('.elfinder-button-icon');
cmd.change(function() {
var fullscreen = cmd.value;
icon.toggleClass('elfinder-button-icon-unfullscreen', fullscreen);
cmd.className = fullscreen? 'unfullscreen' : '';
});
});
};
PK SPK0)R
R
js/ui/sortbutton.jsnu W+A "use strict";
/**
* @class elFinder toolbar button menu with sort variants.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindersortbutton = function(cmd) {
return this.each(function() {
var fm = cmd.fm,
name = cmd.name,
c = 'class',
disabled = fm.res(c, 'disabled'),
hover = fm.res(c, 'hover'),
item = 'elfinder-button-menu-item',
selected = item+'-selected',
asc = selected+'-asc',
desc = selected+'-desc',
text = $(''+cmd.title+''),
button = $(this).addClass('ui-state-default elfinder-button elfinder-menubutton elfiner-button-'+name)
.attr('title', cmd.title)
.append('', text)
.hover(function(e) { !button.hasClass(disabled) && button.toggleClass(hover); })
.click(function(e) {
if (!button.hasClass(disabled)) {
e.stopPropagation();
menu.is(':hidden') && cmd.fm.getUI().click();
menu.slideToggle(100);
}
}),
menu = $('')
.hide()
.appendTo(button)
.on('mouseenter mouseleave', '.'+item, function() { $(this).toggleClass(hover) })
.on('click', '.'+item, function(e) {
e.preventDefault();
e.stopPropagation();
hide();
}),
update = function() {
menu.children('[rel]').removeClass(selected+' '+asc+' '+desc)
.filter('[rel="'+fm.sortType+'"]')
.addClass(selected+' '+(fm.sortOrder == 'asc' ? asc : desc));
menu.children('.elfinder-sort-stick').toggleClass(selected, fm.sortStickFolders);
menu.children('.elfinder-sort-tree').toggleClass(selected, fm.sortAlsoTreeview);
},
hide = function() { menu.hide(); };
text.hide();
$.each(fm.sortRules, function(name, value) {
menu.append($(''+fm.i18n('sort'+name)+'
').data('type', name));
});
menu.children().click(function(e) {
var type = $(this).attr('rel');
cmd.exec([], {
type : type,
order : type == fm.sortType ? fm.sortOrder == 'asc' ? 'desc' : 'asc' : fm.sortOrder,
stick : fm.sortStickFolders,
tree : fm.sortAlsoTreeview
});
});
$(''+fm.i18n('sortFoldersFirst')+'
')
.appendTo(menu)
.click(function() {
cmd.exec([], {type : fm.sortType, order : fm.sortOrder, stick : !fm.sortStickFolders, tree : fm.sortAlsoTreeview});
});
if ($.fn.elfindertree && $.inArray('tree', fm.options.ui) !== -1) {
$(''+fm.i18n('sortAlsoTreeview')+'
')
.appendTo(menu)
.click(function() {
cmd.exec([], {type : fm.sortType, order : fm.sortOrder, stick : fm.sortStickFolders, tree : !fm.sortAlsoTreeview});
});
}
fm.bind('disable select', hide).getUI().click(hide);
fm.bind('sortchange', update)
if (menu.children().length > 1) {
cmd.change(function() {
button.toggleClass(disabled, cmd.disabled());
update();
})
.change();
} else {
button.addClass(disabled);
}
});
};
PK SPK@4F F js/ui/viewbutton.jsnu W+A "use strict";
/**
* @class elFinder toolbar button to switch current directory view.
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderviewbutton = function(cmd) {
return this.each(function() {
var button = $(this).elfinderbutton(cmd),
icon = button.children('.elfinder-button-icon');
cmd.change(function() {
var icons = cmd.value == 'icons';
icon.toggleClass('elfinder-button-icon-view-list', icons);
cmd.className = icons? 'view-list' : '';
cmd.title = cmd.fm.i18n(icons ? 'viewlist' : 'viewicons');
button.attr('title', cmd.title);
});
});
};
PK SPK{= = js/ui/workzone.jsnu W+A "use strict";
/**
* @class elfinderworkzone - elFinder container for nav and current directory
* @author Dmitry (dio) Levashov
**/
$.fn.elfinderworkzone = function(fm) {
var cl = 'elfinder-workzone';
this.not('.'+cl).each(function() {
var wz = $(this).addClass(cl),
wdelta = wz.outerHeight(true) - wz.height(),
prevH = Math.round(wz.height()),
parent = wz.parent(),
fitsize = function(e) {
var height = parent.height() - wdelta,
style = parent.attr('style'),
curH = Math.round(wz.height());
if (e) {
e.preventDefault();
e.stopPropagation();
}
parent.css('overflow', 'hidden')
.children(':visible:not(.'+cl+')').each(function() {
var ch = $(this);
if (ch.css('position') != 'absolute' && ch.css('position') != 'fixed') {
height -= ch.outerHeight(true);
}
});
parent.attr('style', style || '');
height = Math.max(0, Math.round(height));
if (prevH !== height || curH !== height) {
prevH = Math.round(wz.height());
wz.height(height);
fm.trigger('wzresize');
}
},
cssloaded = function() {
wdelta = wz.outerHeight(true) - wz.height();
fitsize();
};
parent.on('resize.' + fm.namespace, fitsize);
fm.one('cssloaded', cssloaded).bind('uiresize', fitsize);
});
return this;
};
PK SPK%# # js/ui/toolbar.jsnu W+A "use strict";
/**
* @class elFinder toolbar
*
* @author Dmitry (dio) Levashov
**/
$.fn.elfindertoolbar = function(fm, opts) {
this.not('.elfinder-toolbar').each(function() {
var commands = fm._commands,
self = $(this).addClass('ui-helper-clearfix ui-widget-header ui-corner-top elfinder-toolbar'),
options = {
// default options
displayTextLabel: false,
labelExcludeUA: ['Mobile'],
autoHideUA: ['Mobile'],
showPreferenceButton: 'none'
},
filter = function(opts) {
return $.map(opts, function(v) {
if ($.isPlainObject(v)) {
options = Object.assign(options, v);
return null;
}
return [v];
});
},
render = function(disabled){
var name,cmdPref;
$.each(buttons, function(i, b) { b.detach(); });
self.empty();
l = panels.length;
while (l--) {
if (panels[l]) {
panel = $('');
i = panels[l].length;
while (i--) {
name = panels[l][i];
if ((!disabled || $.inArray(name, disabled) === -1) && (cmd = commands[name])) {
button = 'elfinder'+cmd.options.ui;
if (! buttons[name] && $.fn[button]) {
buttons[name] = $('')[button](cmd);
}
if (buttons[name]) {
buttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
panel.prepend(buttons[name]);
}
}
}
panel.children().length && self.prepend(panel);
panel.children(':gt(0)').before('');
}
}
if (cmdPref = commands['preference']) {
//cmdPref.state = !self.children().length? 0 : -1;
if (options.showPreferenceButton === 'always' || (!self.children().length && options.showPreferenceButton === 'auto')) {
//cmdPref.state = 0;
panel = $('');
name = 'preference';
button = 'elfinder'+cmd.options.ui;
buttons[name] = $('')[button](cmdPref);
buttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
panel.prepend(buttons[name]);
self.append(panel);
}
}
(! self.data('swipeClose') && self.children().length)? self.show() : self.hide();
fm.trigger('toolbarload').trigger('uiresize');
},
buttons = {},
panels = filter(opts || []),
dispre = null,
uiCmdMapPrev = '',
l, i, cmd, panel, button, swipeHandle, autoHide, textLabel;
// normalize options
options.showPreferenceButton = options.showPreferenceButton.toLowerCase();
// correction of options.displayTextLabel
textLabel = fm.storage('toolbarTextLabel');
if (textLabel === null) {
textLabel = (options.displayTextLabel && (! options.labelExcludeUA || ! options.labelExcludeUA.length || ! $.map(options.labelExcludeUA, function(v){ return fm.UA[v]? true : null; }).length));
} else {
textLabel = (textLabel == 1);
}
// add contextmenu
self.on('contextmenu', function(e) {
e.stopPropagation();
e.preventDefault();
fm.trigger('contextmenu', {
raw: [{
label : fm.i18n('textLabel'),
icon : 'accept',
callback : function() {
textLabel = ! textLabel;
self.height('').find('.elfinder-button-text')[textLabel? 'show':'hide']();
fm.trigger('uiresize').storage('toolbarTextLabel', textLabel? '1' : '0');
},
},{
label : fm.i18n('toolbarPref'),
icon : 'preference',
callback : function() {
fm.exec('help', void(0), {tab: 'preference'});
}
}],
x: e.pageX,
y: e.pageY
});
}).on('touchstart', function(e) {
if (e.originalEvent.touches.length > 1) {
return;
}
self.data('tmlongtap') && clearTimeout(self.data('tmlongtap'));
self.removeData('longtap')
.data('longtap', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY})
.data('tmlongtap', setTimeout(function() {
self.removeData('longtapTm')
.trigger({
type: 'contextmenu',
pageX: self.data('longtap').x,
pageY: self.data('longtap').y
})
.data('longtap', {longtap: true});
}, 500));
}).on('touchmove touchend', function(e) {
if (self.data('tmlongtap')) {
if (e.type === 'touchend' ||
( Math.abs(self.data('longtap').x - e.originalEvent.touches[0].pageX)
+ Math.abs(self.data('longtap').y - e.originalEvent.touches[0].pageY)) > 4)
clearTimeout(self.data('tmlongtap'));
self.removeData('longtapTm');
}
}).on('click', function(e) {
if (self.data('longtap') && self.data('longtap').longtap) {
e.stopImmediatePropagation();
e.preventDefault();
}
}).on('touchend click', '.elfinder-button', function(e) {
if (self.data('longtap') && self.data('longtap').longtap) {
e.stopImmediatePropagation();
e.preventDefault();
}
});
self.prev().length && self.parent().prepend(this);
render();
fm.bind('open sync select toolbarpref', function() {
var disabled = Object.assign([], fm.option('disabled')),
userHides = fm.storage('toolbarhides'),
doRender, sel;
if (! userHides && Array.isArray(options.defaultHides)) {
userHides = {};
$.each(options.defaultHides, function() {
userHides[this] = true;
});
fm.storage('toolbarhides', userHides);
}
if (this.type === 'select') {
if (fm.searchStatus.state < 2) {
return;
}
sel = fm.selected();
if (sel.length) {
disabled = fm.getDisabledCmds(sel);
}
}
$.each(userHides, function(n) {
if ($.inArray(n, disabled) === -1) {
disabled.push(n);
}
});
if (Object.keys(fm.commandMap).length) {
$.each(fm.commandMap, function(from, to){
if (to === 'hidden') {
disabled.push(from);
}
});
}
if (!dispre || dispre.toString() !== disabled.sort().toString()) {
render(disabled && disabled.length? disabled : null);
doRender = true;
}
dispre = disabled.concat().sort();
if (doRender || uiCmdMapPrev !== JSON.stringify(fm.commandMap)) {
uiCmdMapPrev = JSON.stringify(fm.commandMap);
if (! doRender) {
// reset toolbar
$.each($('div.elfinder-button'), function(){
var origin = $(this).data('origin');
if (origin) {
$(this).after(origin).detach();
}
});
}
if (Object.keys(fm.commandMap).length) {
$.each(fm.commandMap, function(from, to){
var cmd = fm._commands[to],
button = cmd? 'elfinder'+cmd.options.ui : null,
btn;
if (button && $.fn[button]) {
btn = buttons[from];
if (btn) {
if (! buttons[to] && $.fn[button]) {
buttons[to] = $('')[button](fm._commands[to]);
if (buttons[to]) {
buttons[to].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
if (cmd.extendsCmd) {
buttons[to].children('span.elfinder-button-icon').addClass('elfinder-button-icon-' + cmd.extendsCmd)
};
}
}
if (buttons[to]) {
btn.after(buttons[to]);
buttons[to].data('origin', btn.detach());
}
}
}
});
}
}
});
if (fm.UA.Touch) {
autoHide = fm.storage('autoHide') || {};
if (typeof autoHide.toolbar === 'undefined') {
autoHide.toolbar = (options.autoHideUA && options.autoHideUA.length > 0 && $.map(options.autoHideUA, function(v){ return fm.UA[v]? true : null; }).length);
fm.storage('autoHide', autoHide);
}
if (autoHide.toolbar) {
fm.one('init', function() {
fm.uiAutoHide.push(function(){ self.stop(true, true).trigger('toggle', { duration: 500, init: true }); });
});
}
fm.bind('load', function() {
swipeHandle = $('').hide().appendTo(fm.getUI());
if (swipeHandle.css('pointer-events') !== 'none') {
swipeHandle.remove();
swipeHandle = null;
}
});
self.on('toggle', function(e, data) {
var wz = fm.getUI('workzone'),
toshow= self.is(':hidden'),
wzh = wz.height(),
h = self.height(),
tbh = self.outerHeight(true),
delta = tbh - h,
opt = Object.assign({
step: function(now) {
wz.height(wzh + (toshow? (now + delta) * -1 : h - now));
fm.trigger('resize');
},
always: function() {
self.css('height', '');
fm.trigger('uiresize');
if (swipeHandle) {
if (toshow) {
swipeHandle.stop(true, true).hide();
} else {
swipeHandle.height(data.handleH? data.handleH : '');
fm.resources.blink(swipeHandle, 'slowonce');
}
}
data.init && fm.trigger('uiautohide');
}
}, data);
self.data('swipeClose', ! toshow).stop(true, true).animate({height : 'toggle'}, opt);
autoHide.toolbar = !toshow;
fm.storage('autoHide', Object.assign(fm.storage('autoHide'), {toolbar: autoHide.toolbar}));
});
}
});
return this;
};
PK SPKä<