<?php

use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;

/* @bundles/CoreBundle/Assets/js/libraries/filemanager/elfinder/dist/js/elfinder.full.js */
class __TwigTemplate_dd2fc503b027a0baeaee6fbe7068658425f1d563fba36b8f385539634baac8a4 extends Template
{
    private $source;
    private $macros = [];

    public function __construct(Environment $env)
    {
        parent::__construct($env);

        $this->source = $this->getSourceContext();

        $this->parent = false;

        $this->blocks = [
        ];
    }

    protected function doDisplay(array $context, array $blocks = [])
    {
        $macros = $this->macros;
        // line 1
        echo "/*!
 * elFinder - file manager for web
 * Version 2.1.57 (2020-06-05)
 * http://elfinder.org
 * 
 * Copyright 2009-2020, Studio 42
 * Licensed under a 3-clauses BSD license
 */
(function(root, factory) {
\tif (typeof define === 'function' && define.amd) {
\t\t// AMD
\t\tdefine(['jquery','jquery-ui'], factory);
\t} else if (typeof exports !== 'undefined') {
\t\t// CommonJS
\t\tvar \$, ui;
\t\ttry {
\t\t\t\$ = require('jquery');
\t\t\tui = require('jquery-ui');
\t\t} catch (e) {}
\t\tmodule.exports = factory(\$, ui);
\t} else {
\t\t// Browser globals (Note: root is window)
\t\tfactory(root.jQuery, root.jQuery.ui, true);
\t}
}(this, function(\$, _ui, toGlobal) {
toGlobal = toGlobal || false;


/*
 * File: /js/elFinder.js
 */

/**
 * @class elFinder - file manager for web
 *
 * @author Dmitry (dio) Levashov
 **/
var elFinder = function(elm, opts, bootCallback) {
\t\t//this.time('load');
\tvar self = this,
\t\t
\t\t/**
\t\t * Objects array of jQuery.Deferred that calls before elFinder boot up
\t\t * 
\t\t * @type Array
\t\t */
\t\tdfrdsBeforeBootup = [],
\t\t
\t\t/**
\t\t * Plugin name to check for conflicts with bootstrap etc
\t\t *
\t\t * @type Array
\t\t **/
\t\tconflictChecks = ['button', 'tooltip'],
\t\t
\t\t/**
\t\t * Node on which elfinder creating
\t\t *
\t\t * @type jQuery
\t\t **/
\t\tnode = \$(elm),
\t\t
\t\t/**
\t\t * Object of events originally registered in this node
\t\t * 
\t\t * @type Object
\t\t */
\t\tprevEvents = \$.extend(true, {}, \$._data(node.get(0), 'events')),
\t\t
\t\t/**
\t\t * Store node contents.
\t\t *
\t\t * @see this.destroy
\t\t * @type jQuery
\t\t **/
\t\tprevContent = \$('<div></div>').append(node.contents()).attr('class', node.attr('class') || '').attr('style', node.attr('style') || ''),
\t\t
\t\t/**
\t\t * Instance ID. Required to get/set cookie
\t\t *
\t\t * @type String
\t\t **/
\t\tid = node.attr('id') || node.attr('id', 'elfauto' + \$('.elfinder').length).attr('id'),
\t\t
\t\t/**
\t\t * Events namespace
\t\t *
\t\t * @type String
\t\t **/
\t\tnamespace = 'elfinder-' + id,
\t\t
\t\t/**
\t\t * Mousedown event
\t\t *
\t\t * @type String
\t\t **/
\t\tmousedown = 'mousedown.'+namespace,
\t\t
\t\t/**
\t\t * Keydown event
\t\t *
\t\t * @type String
\t\t **/
\t\tkeydown = 'keydown.'+namespace,
\t\t
\t\t/**
\t\t * Keypress event
\t\t *
\t\t * @type String
\t\t **/
\t\tkeypress = 'keypress.'+namespace,
\t\t
\t\t/**
\t\t * Keypup event
\t\t *
\t\t * @type String
\t\t **/
\t\tkeyup    = 'keyup.'+namespace,

\t\t/**
\t\t * Is shortcuts/commands enabled
\t\t *
\t\t * @type Boolean
\t\t **/
\t\tenabled = false,
\t\t
\t\t/**
\t\t * Store enabled value before ajax request
\t\t *
\t\t * @type Boolean
\t\t **/
\t\tprevEnabled = false,
\t\t
\t\t/**
\t\t * List of build-in events which mapped into methods with same names
\t\t *
\t\t * @type Array
\t\t **/
\t\tevents = ['enable', 'disable', 'load', 'open', 'reload', 'select',  'add', 'remove', 'change', 'dblclick', 'getfile', 'lockfiles', 'unlockfiles', 'selectfiles', 'unselectfiles', 'dragstart', 'dragstop', 'search', 'searchend', 'viewchange'],
\t\t
\t\t/**
\t\t * Rules to validate data from backend
\t\t *
\t\t * @type Object
\t\t **/
\t\trules = {},
\t\t
\t\t/**
\t\t * Current working directory hash
\t\t *
\t\t * @type String
\t\t **/
\t\tcwd = '',
\t\t
\t\t/**
\t\t * Current working directory options default
\t\t *
\t\t * @type Object
\t\t **/
\t\tcwdOptionsDefault = {
\t\t\tpath          : '',
\t\t\turl           : '',
\t\t\ttmbUrl        : '',
\t\t\tdisabled      : [],
\t\t\tseparator     : '/',
\t\t\tarchives      : [],
\t\t\textract       : [],
\t\t\tcopyOverwrite : true,
\t\t\tuploadOverwrite : true,
\t\t\tuploadMaxSize : 0,
\t\t\tjpgQuality    : 100,
\t\t\ttmbCrop       : false,
\t\t\ttmbReqCustomData : false,
\t\t\ttmb           : false // old API
\t\t},
\t\t
\t\t/**
\t\t * Current working directory options
\t\t *
\t\t * @type Object
\t\t **/
\t\tcwdOptions = {},
\t\t
\t\t/**
\t\t * Files/dirs cache
\t\t *
\t\t * @type Object
\t\t **/
\t\tfiles = {},
\t\t
\t\t/**
\t\t * Hidden Files/dirs cache
\t\t *
\t\t * @type Object
\t\t **/
\t\thiddenFiles = {},

\t\t/**
\t\t * Files/dirs hash cache of each dirs
\t\t *
\t\t * @type Object
\t\t **/
\t\townFiles = {},
\t\t
\t\t/**
\t\t * Selected files hashes
\t\t *
\t\t * @type Array
\t\t **/
\t\tselected = [],
\t\t
\t\t/**
\t\t * Events listeners
\t\t *
\t\t * @type Object
\t\t **/
\t\tlisteners = {},
\t\t
\t\t/**
\t\t * Shortcuts
\t\t *
\t\t * @type Object
\t\t **/
\t\tshortcuts = {},
\t\t
\t\t/**
\t\t * Buffer for copied files
\t\t *
\t\t * @type Array
\t\t **/
\t\tclipboard = [],
\t\t
\t\t/**
\t\t * Copied/cuted files hashes
\t\t * Prevent from remove its from cache.
\t\t * Required for dispaly correct files names in error messages
\t\t *
\t\t * @type Object
\t\t **/
\t\tremember = {},
\t\t
\t\t/**
\t\t * Queue for 'open' requests
\t\t *
\t\t * @type Array
\t\t **/
\t\tqueue = [],
\t\t
\t\t/**
\t\t * Queue for only cwd requests e.g. `tmb`
\t\t *
\t\t * @type Array
\t\t **/
\t\tcwdQueue = [],
\t\t
\t\t/**
\t\t * Commands prototype
\t\t *
\t\t * @type Object
\t\t **/
\t\tbase = new self.command(self),
\t\t
\t\t/**
\t\t * elFinder node width
\t\t *
\t\t * @type String
\t\t * @default \"auto\"
\t\t **/
\t\twidth  = 'auto',
\t\t
\t\t/**
\t\t * elFinder node height
\t\t * Number: pixcel or String: Number + \"%\"
\t\t *
\t\t * @type Number | String
\t\t * @default 400
\t\t **/
\t\theight = 400,
\t\t
\t\t/**
\t\t * Base node object or selector
\t\t * Element which is the reference of the height percentage
\t\t *
\t\t * @type Object|String
\t\t * @default null | \$(window) (if height is percentage)
\t\t **/
\t\theightBase = null,
\t\t
\t\t/**
\t\t * MIME type list(Associative array) handled as a text file
\t\t * 
\t\t * @type Object|null
\t\t */
\t\ttextMimes = null,
\t\t
\t\t/**
\t\t * elfinder path for sound played on remove
\t\t * @type String
\t\t * @default ./sounds/
\t\t **/
\t\tsoundPath = 'sounds/',
\t\t
\t\t/**
\t\t * JSON.stringify of previous fm.sorters
\t\t * @type String
\t\t */
\t\tprevSorterStr = '',

\t\t/**
\t\t * Map table of file extention to MIME-Type
\t\t * @type Object
\t\t */
\t\textToMimeTable,

\t\t/**
\t\t * Disabled page unload function
\t\t * @type Boolean
\t\t */
\t\tdiableUnloadCheck = false,

\t\tbeeper = \$(document.createElement('audio')).hide().appendTo('body')[0],
\t\t\t
\t\tsyncInterval,
\t\tautoSyncStop = 0,
\t\t
\t\tuiCmdMapPrev = '',
\t\t
\t\tgcJobRes = null,
\t\t
\t\topen = function(data) {
\t\t\t// NOTES: Do not touch data object
\t\t
\t\t\tvar volumeid, contextmenu, emptyDirs = {}, stayDirs = {},
\t\t\t\trmClass, hashes, calc, gc, collapsed, prevcwd, sorterStr, diff;
\t\t\t
\t\t\tif (self.api >= 2.1) {
\t\t\t\t// support volume driver option `uiCmdMap`
\t\t\t\tself.commandMap = (data.options.uiCmdMap && Object.keys(data.options.uiCmdMap).length)? data.options.uiCmdMap : {};
\t\t\t\tif (uiCmdMapPrev !== JSON.stringify(self.commandMap)) {
\t\t\t\t\tuiCmdMapPrev = JSON.stringify(self.commandMap);
\t\t\t\t}
\t\t\t} else {
\t\t\t\tself.options.sync = 0;
\t\t\t}
\t\t\t
\t\t\tif (data.init) {
\t\t\t\t// init - reset cache
\t\t\t\tfiles = {};
\t\t\t\townFiles = {};
\t\t\t} else {
\t\t\t\t// remove only files from prev cwd
\t\t\t\t// and collapsed directory (included 100+ directories) to empty for perfomance tune in DnD
\t\t\t\tprevcwd = cwd;
\t\t\t\trmClass = 'elfinder-subtree-loaded ' + self.res('class', 'navexpand');
\t\t\t\tcollapsed = self.res('class', 'navcollapse');
\t\t\t\thashes = Object.keys(files);
\t\t\t\tcalc = function(i) {
\t\t\t\t\tif (!files[i]) {
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tvar isDir = (files[i].mime === 'directory'),
\t\t\t\t\t\tphash = files[i].phash,
\t\t\t\t\t\tpnav;
\t\t\t\t\t\t
\t\t\t\t\tif (
\t\t\t\t\t\t(!isDir
\t\t\t\t\t\t\t|| emptyDirs[phash]
\t\t\t\t\t\t\t|| (!stayDirs[phash]
\t\t\t\t\t\t\t\t&& self.navHash2Elm(files[i].hash).is(':hidden')
\t\t\t\t\t\t\t\t&& self.navHash2Elm(phash).next('.elfinder-navbar-subtree').children().length > 100
\t\t\t\t\t\t\t)
\t\t\t\t\t\t)
\t\t\t\t\t\t&& (isDir || phash !== cwd)
\t\t\t\t\t\t&& ! remember[i]
\t\t\t\t\t) {
\t\t\t\t\t\tif (isDir && !emptyDirs[phash]) {
\t\t\t\t\t\t\temptyDirs[phash] = true;
\t\t\t\t\t\t\tself.navHash2Elm(phash)
\t\t\t\t\t\t\t .removeClass(rmClass)
\t\t\t\t\t\t\t .next('.elfinder-navbar-subtree').empty();
\t\t\t\t\t\t}
\t\t\t\t\t\tdeleteCache(files[i]);
\t\t\t\t\t} else if (isDir) {
\t\t\t\t\t\tstayDirs[phash] = true;
\t\t\t\t\t}
\t\t\t\t};
\t\t\t\tgc = function() {
\t\t\t\t\tif (hashes.length) {
\t\t\t\t\t\tgcJobRes && gcJobRes._abort();
\t\t\t\t\t\tgcJobRes = self.asyncJob(calc, hashes, {
\t\t\t\t\t\t\tinterval : 20,
\t\t\t\t\t\t\tnumPerOnce : 100
\t\t\t\t\t\t}).done(function() {
\t\t\t\t\t\t\tvar hd = self.storage('hide') || {items: {}};
\t\t\t\t\t\t\tif (Object.keys(hiddenFiles).length) {
\t\t\t\t\t\t\t\t\$.each(hiddenFiles, function(h) {
\t\t\t\t\t\t\t\t\tif (!hd.items[h]) {
\t\t\t\t\t\t\t\t\t\tdelete hiddenFiles[h];
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t};
\t\t\t\t
\t\t\t\tself.trigger('filesgc').one('filesgc', function() {
\t\t\t\t\thashes = [];
\t\t\t\t});
\t\t\t\t
\t\t\t\tself.one('opendone', function() {
\t\t\t\t\tif (prevcwd !== cwd) {
\t\t\t\t\t\tif (! node.data('lazycnt')) {
\t\t\t\t\t\t\tgc();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tself.one('lazydone', gc);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}

\t\t\tself.sorters = {};
\t\t\tcwd = data.cwd.hash;
\t\t\tcache(data.files);
\t\t\tif (!files[cwd]) {
\t\t\t\tcache([data.cwd]);
\t\t\t} else {
\t\t\t\tdiff = self.diff([data.cwd], true);
\t\t\t\tif (diff.changed.length) {
\t\t\t\t\tcache(diff.changed, 'change');
\t\t\t\t\tself.change({changed: diff.changed});
\t\t\t\t}
\t\t\t}
\t\t\tdata.changed && data.changed.length && cache(data.changed, 'change');

\t\t\t// trigger event 'sorterupdate'
\t\t\tsorterStr = JSON.stringify(self.sorters);
\t\t\tif (prevSorterStr !== sorterStr) {
\t\t\t\tself.trigger('sorterupdate');
\t\t\t\tprevSorterStr = sorterStr;
\t\t\t}

\t\t\tself.lastDir(cwd);
\t\t\t
\t\t\tself.autoSync();
\t\t},
\t\t
\t\t/**
\t\t * Store info about files/dirs in \"files\" object.
\t\t *
\t\t * @param  Array  files
\t\t * @param  String data type
\t\t * @return void
\t\t **/
\t\tcache = function(data, type) {
\t\t\tvar type      = type || 'files',
\t\t\t\tkeeps = ['sizeInfo', 'encoding'],
\t\t\t\tdefsorter = { name: true, perm: true, date: true,  size: true, kind: true },
\t\t\t\tsorterChk = !self.sorters._checked && (type === 'files'),
\t\t\t\tl         = data.length,
\t\t\t\tsetSorter = function(file) {
\t\t\t\t\tvar f = file || {},
\t\t\t\t\t\tsorters = [];
\t\t\t\t\t\$.each(self.sortRules, function(key) {
\t\t\t\t\t\tif (defsorter[key] || typeof f[key] !== 'undefined' || (key === 'mode' && typeof f.perm !== 'undefined')) {
\t\t\t\t\t\t\tsorters.push(key);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tself.sorters = self.arrayFlip(sorters, true);
\t\t\t\t\tself.sorters._checked = true;
\t\t\t\t},
\t\t\t\tchangedParents = {},
\t\t\t\thideData = self.storage('hide') || {},
\t\t\t\thides = hideData.items || {},
\t\t\t\tf, i, i1, keepProp, parents, hidden;

\t\t\tfor (i = 0; i < l; i++) {
\t\t\t\tf = Object.assign({}, data[i]);
\t\t\t\thidden = (!hideData.show && hides[f.hash])? true : false;
\t\t\t\tif (f.name && f.hash && f.mime) {
\t\t\t\t\tif (!hidden) {
\t\t\t\t\t\tif (sorterChk && f.phash === cwd) {
\t\t\t\t\t\t\tsetSorter(f);
\t\t\t\t\t\t\tsorterChk = false;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (f.phash && (type === 'add' || (type === 'change' && (!files[f.hash] || f.size !== files[f.hash])))) {
\t\t\t\t\t\t\tif (parents = self.parents(f.phash)) {
\t\t\t\t\t\t\t\t\$.each(parents, function() {
\t\t\t\t\t\t\t\t\tchangedParents[this] = true;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\tif (files[f.hash]) {
\t\t\t\t\t\tfor (i1 =0; i1 < keeps.length; i1++) {
\t\t\t\t\t\t\tif(files[f.hash][keeps[i1]] && ! f[keeps[i1]]) {
\t\t\t\t\t\t\t\tf[keeps[i1]] = files[f.hash][keeps[i1]];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (f.sizeInfo && !f.size) {
\t\t\t\t\t\t\tf.size = f.sizeInfo.size;
\t\t\t\t\t\t}
\t\t\t\t\t\tdeleteCache(files[f.hash], true);
\t\t\t\t\t}
\t\t\t\t\tif (hides[f.hash]) {
\t\t\t\t\t\thiddenFiles[f.hash] = f;
\t\t\t\t\t}
\t\t\t\t\tif (hidden) {
\t\t\t\t\t\tl--;
\t\t\t\t\t\tdata.splice(i--, 1);
\t\t\t\t\t} else {
\t\t\t\t\t\tfiles[f.hash] = f;
\t\t\t\t\t\tif (f.mime === 'directory' && !ownFiles[f.hash]) {
\t\t\t\t\t\t\townFiles[f.hash] = {};
\t\t\t\t\t\t}
\t\t\t\t\t\tif (f.phash) {
\t\t\t\t\t\t\tif (!ownFiles[f.phash]) {
\t\t\t\t\t\t\t\townFiles[f.phash] = {};
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\townFiles[f.phash][f.hash] = true;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t// delete sizeInfo cache
\t\t\t\$.each(Object.keys(changedParents), function() {
\t\t\t\tvar target = files[this];
\t\t\t\tif (target && target.sizeInfo) {
\t\t\t\t\tdelete target.sizeInfo;
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\t// for empty folder
\t\t\tsorterChk && setSorter();
\t\t},
\t\t
\t\t/**
\t\t * Delete file object from files caches
\t\t * 
\t\t * @param  Array  removed hashes
\t\t * @return void
\t\t */
\t\tremove = function(removed) {
\t\t\tvar l       = removed.length,
\t\t\t\troots   = {},
\t\t\t\trm      = function(hash) {
\t\t\t\t\tvar file = files[hash], i;
\t\t\t\t\tif (file) {
\t\t\t\t\t\tif (file.mime === 'directory') {
\t\t\t\t\t\t\tif (roots[hash]) {
\t\t\t\t\t\t\t\tdelete self.roots[roots[hash]];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t// restore stats of deleted root parent directory
\t\t\t\t\t\t\t\$.each(self.leafRoots, function(phash, roots) {
\t\t\t\t\t\t\t\tvar idx, pdir;
\t\t\t\t\t\t\t\tif ((idx = \$.inArray(hash, roots))!== -1) {
\t\t\t\t\t\t\t\t\tif (roots.length === 1) {
\t\t\t\t\t\t\t\t\t\tif ((pdir = Object.assign({}, files[phash])) && pdir._realStats) {
\t\t\t\t\t\t\t\t\t\t\t\$.each(pdir._realStats, function(k, v) {
\t\t\t\t\t\t\t\t\t\t\t\tpdir[k] = v;
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\tremove(files[phash]._realStats);
\t\t\t\t\t\t\t\t\t\t\tself.change({ changed: [pdir] });
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tdelete self.leafRoots[phash];
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tself.leafRoots[phash].splice(idx, 1);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tif (self.searchStatus.state < 2) {
\t\t\t\t\t\t\t\t\$.each(files, function(h, f) {
\t\t\t\t\t\t\t\t\tf.phash == hash && rm(h);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (file.phash) {
\t\t\t\t\t\t\tif (parents = self.parents(file.phash)) {
\t\t\t\t\t\t\t\t\$.each(parents, function() {
\t\t\t\t\t\t\t\t\tchangedParents[this] = true;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tdeleteCache(files[hash]);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tchangedParents = {},
\t\t\t\tparents;
\t\t
\t\t\t\$.each(self.roots, function(k, v) {
\t\t\t\troots[v] = k;
\t\t\t});
\t\t\twhile (l--) {
\t\t\t\trm(removed[l]);
\t\t\t}
\t\t\t// delete sizeInfo cache
\t\t\t\$.each(Object.keys(changedParents), function() {
\t\t\t\tvar target = files[this];
\t\t\t\tif (target && target.sizeInfo) {
\t\t\t\t\tdelete target.sizeInfo;
\t\t\t\t}
\t\t\t});
\t\t},
\t\t
\t\t/**
\t\t * Update file object in files caches
\t\t * 
\t\t * @param  Array  changed file objects
\t\t * @return void
\t\t * @deprecated should be use `cache(updatesArrayData, 'change');`
\t\t */
\t\tchange = function(changed) {
\t\t\t\$.each(changed, function(i, file) {
\t\t\t\tvar hash = file.hash;
\t\t\t\tif (files[hash]) {
\t\t\t\t\t\$.each(Object.keys(files[hash]), function(i, v){
\t\t\t\t\t\tif (typeof file[v] === 'undefined') {
\t\t\t\t\t\t\tdelete files[hash][v];
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tfiles[hash] = files[hash] ? Object.assign(files[hash], file) : file;
\t\t\t});
\t\t},
\t\t
\t\t/**
\t\t * Delete cache data of files, ownFiles and self.optionsByHashes
\t\t * 
\t\t * @param  Object  file
\t\t * @param  Boolean update
\t\t * @return void
\t\t */
\t\tdeleteCache = function(file, update) {
\t\t\tvar hash = file.hash,
\t\t\t\tphash = file.phash;
\t\t\t
\t\t\tif (phash && ownFiles[phash]) {
\t\t\t\t delete ownFiles[phash][hash];
\t\t\t}
\t\t\tif (!update) {
\t\t\t\townFiles[hash] && delete ownFiles[hash];
\t\t\t\tself.optionsByHashes[hash] && delete self.optionsByHashes[hash];
\t\t\t}
\t\t\tdelete files[hash];
\t\t},
\t\t
\t\t/**
\t\t * Maximum number of concurrent connections on request
\t\t * 
\t\t * @type Number
\t\t */
\t\trequestMaxConn,
\t\t
\t\t/**
\t\t * Current number of connections
\t\t * 
\t\t * @type Number
\t\t */
\t\trequestCnt = 0,
\t\t
\t\t/**
\t\t * Queue waiting for connection
\t\t * 
\t\t * @type Array
\t\t */
\t\trequestQueue = [],
\t\t
\t\t/**
\t\t * Current open command instance
\t\t * 
\t\t * @type Object
\t\t */
\t\tcurrentOpenCmd = null,

\t\t/**
\t\t * Exec shortcut
\t\t *
\t\t * @param  jQuery.Event  keydown/keypress event
\t\t * @return void
\t\t */
\t\texecShortcut = function(e) {
\t\t\tvar code    = e.keyCode,
\t\t\t\tctrlKey = !!(e.ctrlKey || e.metaKey),
\t\t\t\tisMousedown = e.type === 'mousedown',
\t\t\t\tddm;

\t\t\t!isMousedown && (self.keyState.keyCode = code);
\t\t\tself.keyState.ctrlKey  = ctrlKey;
\t\t\tself.keyState.shiftKey = e.shiftKey;
\t\t\tself.keyState.metaKey  = e.metaKey;
\t\t\tself.keyState.altKey   = e.altKey;
\t\t\tif (isMousedown) {
\t\t\t\treturn;
\t\t\t} else if (e.type === 'keyup') {
\t\t\t\tself.keyState.keyCode = null;
\t\t\t\treturn;
\t\t\t}

\t\t\tif (enabled) {

\t\t\t\t\$.each(shortcuts, function(i, shortcut) {
\t\t\t\t\tif (shortcut.type    == e.type 
\t\t\t\t\t&& shortcut.keyCode  == code 
\t\t\t\t\t&& shortcut.shiftKey == e.shiftKey 
\t\t\t\t\t&& shortcut.ctrlKey  == ctrlKey 
\t\t\t\t\t&& shortcut.altKey   == e.altKey) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tshortcut.callback(e, self);
\t\t\t\t\t\tself.debug('shortcut-exec', i+' : '+shortcut.description);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\t// prevent tab out of elfinder
\t\t\t\tif (code == \$.ui.keyCode.TAB && !\$(e.target).is(':input')) {
\t\t\t\t\te.preventDefault();
\t\t\t\t}
\t\t\t\t
\t\t\t\t// cancel any actions by [Esc] key
\t\t\t\tif (e.type === 'keydown' && code == \$.ui.keyCode.ESCAPE) {
\t\t\t\t\t// copy or cut 
\t\t\t\t\tif (! node.find('.ui-widget:visible').length) {
\t\t\t\t\t\tself.clipboard().length && self.clipboard([]);
\t\t\t\t\t}
\t\t\t\t\t// dragging
\t\t\t\t\tif (\$.ui.ddmanager) {
\t\t\t\t\t\tddm = \$.ui.ddmanager.current;
\t\t\t\t\t\tddm && ddm.helper && ddm.cancel();
\t\t\t\t\t}
\t\t\t\t\t// button menus
\t\t\t\t\tself.toHide(node.find('.ui-widget.elfinder-button-menu.elfinder-frontmost:visible'));
\t\t\t\t\t// trigger keydownEsc
\t\t\t\t\tself.trigger('keydownEsc', e);
\t\t\t\t}

\t\t\t}
\t\t},
\t\tdate = new Date(),
\t\tutc,
\t\ti18n,
\t\tinFrame = (window.parent !== window),
\t\tparentIframe = (function() {
\t\t\tvar pifm, ifms;
\t\t\tif (inFrame) {
\t\t\t\ttry {
\t\t\t\t\tifms = \$('iframe', window.parent.document);
\t\t\t\t\tif (ifms.length) {
\t\t\t\t\t\t\$.each(ifms, function(i, ifm) {
\t\t\t\t\t\t\tif (ifm.contentWindow === window) {
\t\t\t\t\t\t\t\tpifm = \$(ifm);
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t} catch(e) {}
\t\t\t}
\t\t\treturn pifm;
\t\t})(),
\t\t/**
\t\t * elFinder boot up function
\t\t * 
\t\t * @type Function
\t\t */
\t\tbootUp,
\t\t/**
\t\t * Original function of XMLHttpRequest.prototype.send
\t\t * 
\t\t * @type Function
\t\t */
\t\tsavedXhrSend;
\t
\t// opts must be an object
\tif (!opts) {
\t\topts = {};
\t}
\t
\t// set UA.Angle, UA.Rotated for mobile devices
\tif (self.UA.Mobile) {
\t\t\$(window).on('orientationchange.'+namespace, function() {
\t\t\tvar a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0;
\t\t\tif (a === -90) {
\t\t\t\ta = 270;
\t\t\t}
\t\t\tself.UA.Angle = a;
\t\t\tself.UA.Rotated = a % 180 === 0? false : true;
\t\t}).trigger('orientationchange.'+namespace);
\t}
\t
\t// check opt.bootCallback
\tif (opts.bootCallback && typeof opts.bootCallback === 'function') {
\t\t(function() {
\t\t\tvar func = bootCallback,
\t\t\t\topFunc = opts.bootCallback;
\t\t\tbootCallback = function(fm, extraObj) {
\t\t\t\tfunc && typeof func === 'function' && func.call(this, fm, extraObj);
\t\t\t\topFunc.call(this, fm, extraObj);
\t\t\t};
\t\t})();
\t}
\tdelete opts.bootCallback;

\t/**
\t * Protocol version
\t *
\t * @type String
\t **/
\tthis.api = null;
\t
\t/**
\t * elFinder use new api
\t *
\t * @type Boolean
\t **/
\tthis.newAPI = false;
\t
\t/**
\t * elFinder use old api
\t *
\t * @type Boolean
\t **/
\tthis.oldAPI = false;
\t
\t/**
\t * Net drivers names
\t *
\t * @type Array
\t **/
\tthis.netDrivers = [];
\t
\t/**
\t * Base URL of elfFinder library starting from Manager HTML
\t * 
\t * @type String
\t */
\tthis.baseUrl = '';
\t
\t/**
\t * Base URL of i18n js files
\t * baseUrl + \"js/i18n/\" when empty value
\t * 
\t * @type String
\t */
\tthis.i18nBaseUrl = '';

\t/**
\t * Is elFinder CSS loaded
\t * 
\t * @type Boolean
\t */
\tthis.cssloaded = false;
\t
\t/**
\t * Current theme object
\t * 
\t * @type Object|Null
\t */
\tthis.theme = null;

\tthis.mimesCanMakeEmpty = {};

\t/**
\t * Callback function at boot up that option specified at elFinder starting
\t * 
\t * @type Function
\t */
\tthis.bootCallback;

\t/**
\t * Callback function at reload(restart) elFinder 
\t * 
\t * @type Function
\t */
\tthis.reloadCallback;

\t/**
\t * ID. Required to create unique cookie name
\t *
\t * @type String
\t **/
\tthis.id = id;

\t/**
\t * Method to store/fetch data
\t *
\t * @type Function
\t **/
\tthis.storage = (function() {
\t\ttry {
\t\t\tif ('localStorage' in window && window.localStorage !== null) {
\t\t\t\tif (self.UA.Safari) {
\t\t\t\t\t// check for Mac/iOS safari private browsing mode
\t\t\t\t\twindow.localStorage.setItem('elfstoragecheck', 1);
\t\t\t\t\twindow.localStorage.removeItem('elfstoragecheck');
\t\t\t\t}
\t\t\t\treturn self.localStorage;
\t\t\t} else {
\t\t\t\treturn self.cookie;
\t\t\t}
\t\t} catch (e) {
\t\t\treturn self.cookie;
\t\t}
\t})();

\t/**
\t * Set pause page unload check function or Get state
\t *
\t * @param      Boolean   state   To set state
\t * @param      Boolean   keep    Keep disabled
\t * @return     Boolean|void
\t */
\tthis.pauseUnloadCheck = function(state, keep) {
\t\tif (typeof state === 'undefined') {
\t\t\treturn diableUnloadCheck;
\t\t} else {
\t\t\tdiableUnloadCheck = !!state;
\t\t\tif (state && !keep) {
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tdiableUnloadCheck = false;
\t\t\t\t});
\t\t\t}
\t\t}
\t};

\t/**
\t * Configuration options
\t *
\t * @type Object
\t **/
\t//this.options = \$.extend(true, {}, this._options, opts);
\tthis.options = Object.assign({}, this._options);
\t
\t// for old type configuration
\tif (opts.uiOptions) {
\t\tif (opts.uiOptions.toolbar && Array.isArray(opts.uiOptions.toolbar)) {
\t\t\tif (\$.isPlainObject(opts.uiOptions.toolbar[opts.uiOptions.toolbar.length - 1])) {
\t\t\t\tself.options.uiOptions.toolbarExtra = Object.assign(self.options.uiOptions.toolbarExtra || {}, opts.uiOptions.toolbar.pop());
\t\t\t}
\t\t}
\t}
\t
\t// Overwrite if opts value is an array
\t(function() {
\t\tvar arrOv = function(obj, base) {
\t\t\tif (\$.isPlainObject(obj)) {
\t\t\t\t\$.each(obj, function(k, v) {
\t\t\t\t\tif (\$.isPlainObject(v)) {
\t\t\t\t\t\tif (!base[k]) {
\t\t\t\t\t\t\tbase[k] = {};
\t\t\t\t\t\t}
\t\t\t\t\t\tarrOv(v, base[k]);
\t\t\t\t\t} else {
\t\t\t\t\t\tbase[k] = v;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t};
\t\tarrOv(opts, self.options);
\t})();
\t
\t// join toolbarExtra to toolbar
\tthis.options.uiOptions.toolbar.push(this.options.uiOptions.toolbarExtra);
\tdelete this.options.uiOptions.toolbarExtra;

\t/**
\t * Arrays that has to unbind events
\t * 
\t * @type Object
\t */
\tthis.toUnbindEvents = {};
\t
\t/**
\t * Attach listener to events
\t * To bind to multiply events at once, separate events names by space
\t * 
\t * @param  String  event(s) name(s)
\t * @param  Object  event handler or {done: handler}
\t * @param  Boolean priority first
\t * @return elFinder
\t */
\tthis.bind = function(event, callback, priorityFirst) {
\t\tvar i, len;
\t\t
\t\tif (callback && (typeof callback === 'function' || typeof callback.done === 'function')) {
\t\t\tevent = ('' + event).toLowerCase().replace(/^\\s+|\\s+\$/g, '').split(/\\s+/);
\t\t\t
\t\t\tlen = event.length;
\t\t\tfor (i = 0; i < len; i++) {
\t\t\t\tif (listeners[event[i]] === void(0)) {
\t\t\t\t\tlisteners[event[i]] = [];
\t\t\t\t}
\t\t\t\tlisteners[event[i]][priorityFirst? 'unshift' : 'push'](callback);
\t\t\t}
\t\t}
\t\treturn this;
\t};
\t
\t/**
\t * Remove event listener if exists
\t * To un-bind to multiply events at once, separate events names by space
\t *
\t * @param  String    event(s) name(s)
\t * @param  Function  callback
\t * @return elFinder
\t */
\tthis.unbind = function(event, callback) {
\t\tvar i, len, l, ci;
\t\t
\t\tevent = ('' + event).toLowerCase().split(/\\s+/);
\t\t
\t\tlen = event.length;
\t\tfor (i = 0; i < len; i++) {
\t\t\tif (l = listeners[event[i]]) {
\t\t\t\tci = \$.inArray(callback, l);
\t\t\t\tci > -1 && l.splice(ci, 1);
\t\t\t}
\t\t}
\t\t
\t\tcallback = null;
\t\treturn this;
\t};
\t
\t/**
\t * Fire event - send notification to all event listeners
\t * In the callback `this` becames an event object
\t *
\t * @param  String   event type
\t * @param  Object   data to send across event
\t * @param  Boolean  allow modify data (call by reference of data) default: true
\t * @return elFinder
\t */
\tthis.trigger = function(evType, data, allowModify) {
\t\tvar type      = evType.toLowerCase(),
\t\t\tisopen    = (type === 'open'),
\t\t\tdataIsObj = (typeof data === 'object'),
\t\t\thandlers  = listeners[type] || [],
\t\t\tdones     = [],
\t\t\ti, l, jst, event;
\t\t
\t\tthis.debug('event-'+type, data);
\t\t
\t\tif (! dataIsObj || typeof allowModify === 'undefined') {
\t\t\tallowModify = true;
\t\t}
\t\tif (l = handlers.length) {
\t\t\tevent = \$.Event(type);
\t\t\tif (data) {
\t\t\t\tdata._getEvent = function() {
\t\t\t\t\treturn event;
\t\t\t\t};
\t\t\t}
\t\t\tif (allowModify) {
\t\t\t\tevent.data = data;
\t\t\t}

\t\t\tfor (i = 0; i < l; i++) {
\t\t\t\tif (! handlers[i]) {
\t\t\t\t\t// probably un-binded this handler
\t\t\t\t\tcontinue;
\t\t\t\t}

\t\t\t\t// handler is \$.Deferred(), call all functions upon completion
\t\t\t\tif (handlers[i].done) {
\t\t\t\t\tdones.push(handlers[i].done);
\t\t\t\t\tcontinue;
\t\t\t\t}
\t\t\t\t
\t\t\t\t// set `event.data` only callback has argument
\t\t\t\tif (handlers[i].length) {
\t\t\t\t\tif (!allowModify) {
\t\t\t\t\t\t// to avoid data modifications. remember about \"sharing\" passing arguments in js :) 
\t\t\t\t\t\tif (typeof jst === 'undefined') {
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tjst = JSON.stringify(data);
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tjst = false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tevent.data = jst? JSON.parse(jst) : data;
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\ttry {
\t\t\t\t\tif (handlers[i].call(event, event, this) === false || event.isDefaultPrevented()) {
\t\t\t\t\t\tthis.debug('event-stoped', event.type);
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t} catch (ex) {
\t\t\t\t\twindow.console && window.console.log && window.console.log(ex);
\t\t\t\t}
\t\t\t\t
\t\t\t}
\t\t\t
\t\t\t// call done functions
\t\t\tif (l = dones.length) {
\t\t\t\tfor (i = 0; i < l; i++) {
\t\t\t\t\ttry {
\t\t\t\t\t\tif (dones[i].call(event, event, this) === false || event.isDefaultPrevented()) {
\t\t\t\t\t\t\tthis.debug('event-stoped', event.type + '(done)');
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t} catch (ex) {
\t\t\t\t\t\twindow.console && window.console.log && window.console.log(ex);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\tif (this.toUnbindEvents[type] && this.toUnbindEvents[type].length) {
\t\t\t\t\$.each(this.toUnbindEvents[type], function(i, v) {
\t\t\t\t\tself.unbind(v.type, v.callback);
\t\t\t\t});
\t\t\t\tdelete this.toUnbindEvents[type];
\t\t\t}
\t\t}
\t\treturn this;
\t};
\t
\t/**
\t * Get event listeners
\t *
\t * @param  String   event type
\t * @return Array    listed event functions
\t */
\tthis.getListeners = function(event) {
\t\treturn event? listeners[event.toLowerCase()] : listeners;
\t};

\t// set fm.baseUrl
\tthis.baseUrl = (function() {
\t\tvar myTag, base, baseUrl;
\t\t
\t\tif (self.options.baseUrl) {
\t\t\treturn self.options.baseUrl;
\t\t} else {
\t\t\tbaseUrl = '';
\t\t\tmyTag = null;
\t\t\t\$('head > script').each(function() {
\t\t\t\tif (this.src && this.src.match(/js\\/elfinder(?:-[a-z0-9_-]+)?\\.(?:min|full)\\.js\$/i)) {
\t\t\t\t\tmyTag = \$(this);
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t});
\t\t\tif (myTag) {
\t\t\t\tbaseUrl = myTag.attr('src').replace(/js\\/[^\\/]+\$/, '');
\t\t\t\tif (! baseUrl.match(/^(https?\\/\\/|\\/)/)) {
\t\t\t\t\t// check <base> tag
\t\t\t\t\tif (base = \$('head > base[href]').attr('href')) {
\t\t\t\t\t\tbaseUrl = base.replace(/\\/\$/, '') + '/' + baseUrl; 
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\tif (baseUrl !== '') {
\t\t\t\tself.options.baseUrl = baseUrl;
\t\t\t} else {
\t\t\t\tif (! self.options.baseUrl) {
\t\t\t\t\tself.options.baseUrl = './';
\t\t\t\t}
\t\t\t\tbaseUrl = self.options.baseUrl;
\t\t\t}
\t\t\treturn baseUrl;
\t\t}
\t})();
\t
\tthis.i18nBaseUrl = (this.options.i18nBaseUrl || this.baseUrl + 'js/i18n').replace(/\\/\$/, '') + '/';

\tthis.options.maxErrorDialogs = Math.max(1, parseInt(this.options.maxErrorDialogs || 5));

\t// set dispInlineRegex
\tcwdOptionsDefault.dispInlineRegex = this.options.dispInlineRegex;

\t// auto load required CSS
\tif (this.options.cssAutoLoad) {
\t\t(function() {
\t\t\tvar baseUrl = self.baseUrl,
\t\t\t\tmyCss = \$('head > link[href\$=\"css/elfinder.min.css\"],link[href\$=\"css/elfinder.full.css\"]:first').length,
\t\t\t\trmTag = function() {
\t\t\t\t\tif (node.data('cssautoloadHide')) {
\t\t\t\t\t\tnode.data('cssautoloadHide').remove();
\t\t\t\t\t\tnode.removeData('cssautoloadHide');
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tloaded = function() {
\t\t\t\t\tif (!self.cssloaded) {
\t\t\t\t\t\trmTag();
\t\t\t\t\t\tself.cssloaded = true;
\t\t\t\t\t\tself.trigger('cssloaded');
\t\t\t\t\t}
\t\t\t\t};
\t\t\t
\t\t\tif (! myCss) {
\t\t\t\t// to request CSS auto loading
\t\t\t\tself.cssloaded = null;
\t\t\t}

\t\t\t// additional CSS files
\t\t\tif (Array.isArray(self.options.cssAutoLoad)) {
\t\t\t\tif (!self.options.themes.default) {
\t\t\t\t\t// set as default theme
\t\t\t\t\tself.options.themes = Object.assign({
\t\t\t\t\t\t'default' : {
\t\t\t\t\t\t\t'name': 'default',
\t\t\t\t\t\t\t'cssurls': self.options.cssAutoLoad
\t\t\t\t\t\t}
\t\t\t\t\t}, self.options.themes);
\t\t\t\t\tif (!self.options.theme) {
\t\t\t\t\t\tself.options.theme = 'default';
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (self.cssloaded === true) {
\t\t\t\t\t\tself.loadCss(self.options.cssAutoLoad);
\t\t\t\t\t} else {
\t\t\t\t\t\tself.bind('cssloaded', function() {
\t\t\t\t\t\t\tself.loadCss(self.options.cssAutoLoad);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}

\t\t\t// try to load main css
\t\t\tif (self.cssloaded === null) {
\t\t\t\t// hide elFinder node while css loading
\t\t\t\tnode.addClass('elfinder')
\t\t\t\t\t.data('cssautoloadHide', \$('<style>.elfinder{visibility:hidden;overflow:hidden}</style>'));
\t\t\t\t\$('head').append(node.data('cssautoloadHide'));

\t\t\t\t// set default theme
\t\t\t\tif (!self.options.themes.default) {
\t\t\t\t\tself.options.themes = Object.assign({
\t\t\t\t\t\t'default' : {
\t\t\t\t\t\t\t'name': 'default',
\t\t\t\t\t\t\t'cssurls': 'css/theme.css',
\t\t\t\t\t\t\t'author': 'elFinder Project',
\t\t\t\t\t\t\t'license': '3-clauses BSD'
\t\t\t\t\t\t}
\t\t\t\t\t}, self.options.themes);
\t\t\t\t\tif (!self.options.theme) {
\t\t\t\t\t\tself.options.theme = 'default';
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\t// Delay 'visibility' check it required for browsers such as Safari
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tif (node.css('visibility') === 'hidden') {
\t\t\t\t\t\t// load CSS
\t\t\t\t\t\tself.loadCss([baseUrl+'css/elfinder.min.css'], {
\t\t\t\t\t\t\tdfd: \$.Deferred().done(function() {
\t\t\t\t\t\t\t\tloaded();
\t\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\t\trmTag();
\t\t\t\t\t\t\t\tif (!self.cssloaded) {
\t\t\t\t\t\t\t\t\tself.cssloaded = false;
\t\t\t\t\t\t\t\t\tself.bind('init', function() {
\t\t\t\t\t\t\t\t\t\tif (!self.cssloaded) {
\t\t\t\t\t\t\t\t\t\t\tself.error(['errRead', 'CSS (elfinder.min)']);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tloaded();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t})();
\t}

\t// load theme if exists
\t(function() {
\t\tvar theme,
\t\t\tthemes = self.options.themes,
\t\t\tids = Object.keys(themes || {});
\t\tif (ids.length) {
\t\t\ttheme = self.storage('theme') || self.options.theme;
\t\t\tif (!themes[theme]) {
\t\t\t\ttheme = ids[0];
\t\t\t}
\t\t\tif (self.cssloaded) {
\t\t\t\tself.changeTheme(theme);
\t\t\t} else {
\t\t\t\tself.bind('cssloaded', function() {
\t\t\t\t\tself.changeTheme(theme);
\t\t\t\t});
\t\t\t}
\t\t}
\t})();
\t
\t/**
\t * Volume option to set the properties of the root Stat
\t * 
\t * @type Object
\t */
\tthis.optionProperties = {
\t\ticon: void(0),
\t\tcsscls: void(0),
\t\ttmbUrl: void(0),
\t\tuiCmdMap: {},
\t\tnetkey: void(0),
\t\tdisabled: []
\t};
\t
\tif (! inFrame && ! this.options.enableAlways && \$('body').children().length === 2) { // only node and beeper
\t\tthis.options.enableAlways = true;
\t}
\t
\t// make options.debug
\tif (this.options.debug === true) {
\t\tthis.options.debug = 'all';
\t} else if (Array.isArray(this.options.debug)) {
\t\t(function() {
\t\t\tvar d = {};
\t\t\t\$.each(self.options.debug, function() {
\t\t\t\td[this] = true;
\t\t\t});
\t\t\tself.options.debug = d;
\t\t})();
\t} else {
\t\tthis.options.debug = false;
\t}
\t
\t/**
\t * Original functions evacuated by conflict check
\t * 
\t * @type Object
\t */
\tthis.noConflicts = {};
\t
\t/**
\t * Check and save conflicts with bootstrap etc
\t * 
\t * @type Function
\t */
\tthis.noConflict = function() {
\t\t\$.each(conflictChecks, function(i, p) {
\t\t\tif (\$.fn[p] && typeof \$.fn[p].noConflict === 'function') {
\t\t\t\tself.noConflicts[p] = \$.fn[p].noConflict();
\t\t\t}
\t\t});
\t};
\t// do check conflict
\tthis.noConflict();
\t
\t/**
\t * Is elFinder over CORS
\t *
\t * @type Boolean
\t **/
\tthis.isCORS = false;
\t
\t// configure for CORS
\t(function(){
\t\tif (typeof self.options.cors !== 'undefined' && self.options.cors !== null) {
\t\t\tself.isCORS = self.options.cors? true : false;
\t\t} else {
\t\t\tvar parseUrl = document.createElement('a'),
\t\t\t\tparseUploadUrl,
\t\t\t\tselfProtocol = window.location.protocol,
\t\t\t\tportReg = function(protocol) {
\t\t\t\t\tprotocol = (!protocol || protocol === ':')? selfProtocol : protocol;
\t\t\t\t\treturn protocol === 'https:'? /\\:443\$/ : /\\:80\$/;
\t\t\t\t},
\t\t\t\tselfHost = window.location.host.replace(portReg(selfProtocol), '');
\t\t\tparseUrl.href = opts.url;
\t\t\tif (opts.urlUpload && (opts.urlUpload !== opts.url)) {
\t\t\t\tparseUploadUrl = document.createElement('a');
\t\t\t\tparseUploadUrl.href = opts.urlUpload;
\t\t\t}
\t\t\tif (selfHost !== parseUrl.host.replace(portReg(parseUrl.protocol), '')
\t\t\t\t|| (parseUrl.protocol !== ':'&& parseUrl.protocol !== '' && (selfProtocol !== parseUrl.protocol))
\t\t\t\t|| (parseUploadUrl && 
\t\t\t\t\t(selfHost !== parseUploadUrl.host.replace(portReg(parseUploadUrl.protocol), '')
\t\t\t\t\t|| (parseUploadUrl.protocol !== ':' && parseUploadUrl.protocol !== '' && (selfProtocol !== parseUploadUrl.protocol))
\t\t\t\t\t)
\t\t\t\t)
\t\t\t) {
\t\t\t\tself.isCORS = true;
\t\t\t}
\t\t}
\t\tif (self.isCORS) {
\t\t\tif (!\$.isPlainObject(self.options.customHeaders)) {
\t\t\t\tself.options.customHeaders = {};
\t\t\t}
\t\t\tif (!\$.isPlainObject(self.options.xhrFields)) {
\t\t\t\tself.options.xhrFields = {};
\t\t\t}
\t\t\tself.options.requestType = 'post';
\t\t\tself.options.customHeaders['X-Requested-With'] = 'XMLHttpRequest';
\t\t\tself.options.xhrFields['withCredentials'] = true;
\t\t}
\t})();

\t/**
\t * Ajax request type
\t *
\t * @type String
\t * @default \"get\"
\t **/
\tthis.requestType = /^(get|post)\$/i.test(this.options.requestType) ? this.options.requestType.toLowerCase() : 'get';
\t
\t// set `requestMaxConn` by option
\trequestMaxConn = Math.max(parseInt(this.options.requestMaxConn), 1);
\t
\t/**
\t * Custom data that given as options
\t * 
\t * @type Object
\t * @default {}
\t */
\tthis.optsCustomData = \$.isPlainObject(this.options.customData) ? this.options.customData : {};

\t/**
\t * Any data to send across every ajax request
\t *
\t * @type Object
\t * @default {}
\t **/
\tthis.customData = Object.assign({}, this.optsCustomData);

\t/**
\t * Previous custom data from connector
\t * 
\t * @type Object|null
\t */
\tthis.prevCustomData = null;

\t/**
\t * Any custom headers to send across every ajax request
\t *
\t * @type Object
\t * @default {}
\t*/
\tthis.customHeaders = \$.isPlainObject(this.options.customHeaders) ? this.options.customHeaders : {};

\t/**
\t * Any custom xhrFields to send across every ajax request
\t *
\t * @type Object
\t * @default {}
\t */
\tthis.xhrFields = \$.isPlainObject(this.options.xhrFields) ? this.options.xhrFields : {};

\t/**
\t * Replace XMLHttpRequest.prototype.send to extended function for 3rd party libs XHR request etc.
\t * 
\t * @type Function
\t */
\tthis.replaceXhrSend = function() {
\t\tif (! savedXhrSend) {
\t\t\tsavedXhrSend = XMLHttpRequest.prototype.send;
\t\t}
\t\tXMLHttpRequest.prototype.send = function() {
\t\t\tvar xhr = this;
\t\t\t// set request headers
\t\t\tif (self.customHeaders) {
\t\t\t\t\$.each(self.customHeaders, function(key) {
\t\t\t\t\txhr.setRequestHeader(key, this);
\t\t\t\t});
\t\t\t}
\t\t\t// set xhrFields
\t\t\tif (self.xhrFields) {
\t\t\t\t\$.each(self.xhrFields, function(key) {
\t\t\t\t\tif (key in xhr) {
\t\t\t\t\t\txhr[key] = this;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t\treturn savedXhrSend.apply(this, arguments);
\t\t};
\t};
\t
\t/**
\t * Restore saved original XMLHttpRequest.prototype.send
\t * 
\t * @type Function
\t */
\tthis.restoreXhrSend = function() {
\t\tsavedXhrSend && (XMLHttpRequest.prototype.send = savedXhrSend);
\t};

\t/**
\t * command names for into queue for only cwd requests
\t * these commands aborts before `open` request
\t *
\t * @type Array
\t * @default ['tmb', 'parents']
\t */
\tthis.abortCmdsOnOpen = this.options.abortCmdsOnOpen || ['tmb', 'parents'];

\t/**
\t * ui.nav id prefix
\t * 
\t * @type String
\t */
\tthis.navPrefix = 'nav' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-';
\t
\t/**
\t * ui.cwd id prefix
\t * 
\t * @type String
\t */
\tthis.cwdPrefix = elFinder.prototype.uniqueid? ('cwd' + elFinder.prototype.uniqueid + '-') : '';
\t
\t// Increment elFinder.prototype.uniqueid
\t++elFinder.prototype.uniqueid;
\t
\t/**
\t * URL to upload files
\t *
\t * @type String
\t **/
\tthis.uploadURL = opts.urlUpload || opts.url;
\t
\t/**
\t * Events namespace
\t *
\t * @type String
\t **/
\tthis.namespace = namespace;

\t/**
\t * Today timestamp
\t *
\t * @type Number
\t **/
\tthis.today = (new Date(date.getFullYear(), date.getMonth(), date.getDate())).getTime()/1000;
\t
\t/**
\t * Yesterday timestamp
\t *
\t * @type Number
\t **/
\tthis.yesterday = this.today - 86400;
\t
\tutc = this.options.UTCDate ? 'UTC' : '';
\t
\tthis.getHours    = 'get'+utc+'Hours';
\tthis.getMinutes  = 'get'+utc+'Minutes';
\tthis.getSeconds  = 'get'+utc+'Seconds';
\tthis.getDate     = 'get'+utc+'Date';
\tthis.getDay      = 'get'+utc+'Day';
\tthis.getMonth    = 'get'+utc+'Month';
\tthis.getFullYear = 'get'+utc+'FullYear';
\t
\t/**
\t * elFinder node z-index (auto detect on elFinder load)
\t *
\t * @type null | Number
\t **/
\tthis.zIndex;

\t/**
\t * Current search status
\t * 
\t * @type Object
\t */
\tthis.searchStatus = {
\t\tstate  : 0, // 0: search ended, 1: search started, 2: in search result
\t\tquery  : '',
\t\ttarget : '',
\t\tmime   : '',
\t\tmixed  : false, // in multi volumes search: false or Array that target volume ids
\t\tininc  : false // in incremental search
\t};

\t/**
\t * Interface language
\t *
\t * @type String
\t * @default \"en\"
\t **/
\tthis.lang = this.storage('lang') || this.options.lang;
\tif (this.lang === 'jp') {
\t\tthis.lang = this.options.lang = 'ja';
\t}

\tthis.viewType = this.storage('view') || this.options.defaultView || 'icons';

\tthis.sortType = this.storage('sortType') || this.options.sortType || 'name';
\t
\tthis.sortOrder = this.storage('sortOrder') || this.options.sortOrder || 'asc';

\tthis.sortStickFolders = this.storage('sortStickFolders');
\tif (this.sortStickFolders === null) {
\t\tthis.sortStickFolders = !!this.options.sortStickFolders;
\t} else {
\t\tthis.sortStickFolders = !!this.sortStickFolders;
\t}

\tthis.sortAlsoTreeview = this.storage('sortAlsoTreeview');
\tif (this.sortAlsoTreeview === null || this.options.sortAlsoTreeview === null) {
\t\tthis.sortAlsoTreeview = !!this.options.sortAlsoTreeview;
\t} else {
\t\tthis.sortAlsoTreeview = !!this.sortAlsoTreeview;
\t}

\tthis.sortRules = \$.extend(true, {}, this._sortRules, this.options.sortRules);
\t
\t\$.each(this.sortRules, function(name, method) {
\t\tif (typeof method != 'function') {
\t\t\tdelete self.sortRules[name];
\t\t} 
\t});
\t
\tthis.compare = \$.proxy(this.compare, this);
\t
\t/**
\t * Delay in ms before open notification dialog
\t *
\t * @type Number
\t * @default 500
\t **/
\tthis.notifyDelay = this.options.notifyDelay > 0 ? parseInt(this.options.notifyDelay) : 500;
\t
\t/**
\t * Dragging UI Helper object
\t *
\t * @type jQuery | null
\t **/
\tthis.draggingUiHelper = null;
\t
\t/**
\t * Base droppable options
\t *
\t * @type Object
\t **/
\tthis.droppable = {
\t\tgreedy     : true,
\t\ttolerance  : 'pointer',
\t\taccept     : '.elfinder-cwd-file-wrapper,.elfinder-navbar-dir,.elfinder-cwd-file,.elfinder-cwd-filename',
\t\thoverClass : this.res('class', 'adroppable'),
\t\tclasses    : { // Deprecated hoverClass jQueryUI>=1.12.0
\t\t\t'ui-droppable-hover': this.res('class', 'adroppable')
\t\t},
\t\tautoDisable: true, // elFinder original, see jquery.elfinder.js
\t\tdrop : function(e, ui) {
\t\t\tvar dst     = \$(this),
\t\t\t\ttargets = \$.grep(ui.helper.data('files')||[], function(h) { return h? true : false; }),
\t\t\t\tresult  = [],
\t\t\t\tdups    = [],
\t\t\t\tfaults  = [],
\t\t\t\tisCopy  = ui.helper.hasClass('elfinder-drag-helper-plus'),
\t\t\t\tc       = 'class',
\t\t\t\tcnt, hash, i, h;
\t\t\t
\t\t\tif (typeof e.button === 'undefined' || ui.helper.data('namespace') !== namespace || ! self.insideWorkzone(e.pageX, e.pageY)) {
\t\t\t\treturn false;
\t\t\t}
\t\t\tif (dst.hasClass(self.res(c, 'cwdfile'))) {
\t\t\t\thash = self.cwdId2Hash(dst.attr('id'));
\t\t\t} else if (dst.hasClass(self.res(c, 'navdir'))) {
\t\t\t\thash = self.navId2Hash(dst.attr('id'));
\t\t\t} else {
\t\t\t\thash = cwd;
\t\t\t}

\t\t\tcnt = targets.length;
\t\t\t
\t\t\twhile (cnt--) {
\t\t\t\th = targets[cnt];
\t\t\t\t// ignore drop into itself or in own location
\t\t\t\tif (h != hash && files[h].phash != hash) {
\t\t\t\t\tresult.push(h);
\t\t\t\t} else {
\t\t\t\t\t((isCopy && h !== hash && files[hash].write)? dups : faults).push(h);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (faults.length) {
\t\t\t\treturn false;
\t\t\t}
\t\t\t
\t\t\tui.helper.data('droped', true);
\t\t\t
\t\t\tif (dups.length) {
\t\t\t\tui.helper.hide();
\t\t\t\tself.exec('duplicate', dups, {_userAction: true});
\t\t\t}
\t\t\t
\t\t\tif (result.length) {
\t\t\t\tui.helper.hide();
\t\t\t\tself.clipboard(result, !isCopy);
\t\t\t\tself.exec('paste', hash, {_userAction: true}, hash).always(function(){
\t\t\t\t\tself.clipboard([]);
\t\t\t\t\tself.trigger('unlockfiles', {files : targets});
\t\t\t\t});
\t\t\t\tself.trigger('drop', {files : targets});
\t\t\t}
\t\t}
\t};
\t
\t/**
\t * Return true if filemanager is active
\t *
\t * @return Boolean
\t **/
\tthis.enabled = function() {
\t\treturn enabled && this.visible();
\t};
\t
\t/**
\t * Return true if filemanager is visible
\t *
\t * @return Boolean
\t **/
\tthis.visible = function() {
\t\treturn node[0].elfinder && node.is(':visible');
\t};
\t
\t/**
\t * Return file is root?
\t * 
\t * @param  Object  target file object
\t * @return Boolean
\t */
\tthis.isRoot = function(file) {
\t\treturn (file.isroot || ! file.phash)? true : false;
\t};
\t
\t/**
\t * Return root dir hash for current working directory
\t * 
\t * @param  String   target hash
\t * @param  Boolean  include fake parent (optional)
\t * @return String
\t */
\tthis.root = function(hash, fake) {
\t\thash = hash || cwd;
\t\tvar dir, i;
\t\t
\t\tif (! fake) {
\t\t\t\$.each(self.roots, function(id, rhash) {
\t\t\t\tif (hash.indexOf(id) === 0) {
\t\t\t\t\tdir = rhash;
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t});
\t\t\tif (dir) {
\t\t\t\treturn dir;
\t\t\t}
\t\t}
\t\t
\t\tdir = files[hash];
\t\twhile (dir && dir.phash && (fake || ! dir.isroot)) {
\t\t\tdir = files[dir.phash];
\t\t}
\t\tif (dir) {
\t\t\treturn dir.hash;
\t\t}
\t\t
\t\twhile (i in files && files.hasOwnProperty(i)) {
\t\t\tdir = files[i];
\t\t\tif (dir.mime === 'directory' && !dir.phash && dir.read) {
\t\t\t\treturn dir.hash;
\t\t\t}
\t\t}
\t\t
\t\treturn '';
\t};
\t
\t/**
\t * Return current working directory info
\t * 
\t * @return Object
\t */
\tthis.cwd = function() {
\t\treturn files[cwd] || {};
\t};
\t
\t/**
\t * Return required cwd option
\t * 
\t * @param  String  option name
\t * @param  String  target hash (optional)
\t * @return mixed
\t */
\tthis.option = function(name, target) {
\t\tvar res, item;
\t\ttarget = target || cwd;
\t\tif (self.optionsByHashes[target] && typeof self.optionsByHashes[target][name] !== 'undefined') {
\t\t\treturn self.optionsByHashes[target][name];
\t\t}
\t\tif (self.hasVolOptions && cwd !== target && (!(item = self.file(target)) || item.phash !== cwd)) {
\t\t\tres = '';
\t\t\t\$.each(self.volOptions, function(id, opt) {
\t\t\t\tif (target.indexOf(id) === 0) {
\t\t\t\t\tres = opt[name] || '';
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t});
\t\t\treturn res;
\t\t} else {
\t\t\treturn cwdOptions[name] || '';
\t\t}
\t};
\t
\t/**
\t * Return disabled commands by each folder
\t * 
\t * @param  Array  target hashes
\t * @return Array
\t */
\tthis.getDisabledCmds = function(targets, flip) {
\t\tvar disabled = {'hidden': true};
\t\tif (! Array.isArray(targets)) {
\t\t\ttargets = [ targets ];
\t\t}
\t\t\$.each(targets, function(i, h) {
\t\t\tvar disCmds = self.option('disabledFlip', h);
\t\t\tif (disCmds) {
\t\t\t\tObject.assign(disabled, disCmds);
\t\t\t}
\t\t});
\t\treturn flip? disabled : Object.keys(disabled);
\t};
\t
\t/**
\t * Return file data from current dir or tree by it's hash
\t * 
\t * @param  String  file hash
\t * @return Object
\t */
\tthis.file = function(hash, alsoHidden) { 
\t\treturn hash? (files[hash] || (alsoHidden? hiddenFiles[hash] : void(0))) : void(0); 
\t};
\t
\t/**
\t * Return all cached files
\t * 
\t * @param  String  parent hash
\t * @return Object
\t */
\tthis.files = function(phash) {
\t\tvar items = {};
\t\tif (phash) {
\t\t\tif (!ownFiles[phash]) {
\t\t\t\treturn {};
\t\t\t}
\t\t\t\$.each(ownFiles[phash], function(h) {
\t\t\t\tif (files[h]) {
\t\t\t\t\titems[h] = files[h];
\t\t\t\t} else {
\t\t\t\t\tdelete ownFiles[phash][h];
\t\t\t\t}
\t\t\t});
\t\t\treturn Object.assign({}, items);
\t\t}
\t\treturn Object.assign({}, files);
\t};
\t
\t/**
\t * Return list of file parents hashes include file hash
\t * 
\t * @param  String  file hash
\t * @return Array
\t */
\tthis.parents = function(hash) {
\t\tvar parents = [],
\t\t\tdir;
\t\t
\t\twhile (hash && (dir = this.file(hash))) {
\t\t\tparents.unshift(dir.hash);
\t\t\thash = dir.phash;
\t\t}
\t\treturn parents;
\t};
\t
\tthis.path2array = function(hash, i18) {
\t\tvar file, 
\t\t\tpath = [];
\t\t\t
\t\twhile (hash) {
\t\t\tif ((file = files[hash]) && file.hash) {
\t\t\t\tpath.unshift(i18 && file.i18 ? file.i18 : file.name);
\t\t\t\thash = file.isroot? null : file.phash;
\t\t\t} else {
\t\t\t\tpath = [];
\t\t\t\tbreak;
\t\t\t}
\t\t}
\t\t\t
\t\treturn path;
\t};
\t
\t/**
\t * Return file path or Get path async with jQuery.Deferred
\t * 
\t * @param  Object  file
\t * @param  Boolean i18
\t * @param  Object  asyncOpt
\t * @return String|jQuery.Deferred
\t */
\tthis.path = function(hash, i18, asyncOpt) { 
\t\tvar path = files[hash] && files[hash].path
\t\t\t? files[hash].path
\t\t\t: this.path2array(hash, i18).join(cwdOptions.separator);
\t\tif (! asyncOpt || ! files[hash]) {
\t\t\treturn path;
\t\t} else {
\t\t\tasyncOpt = Object.assign({notify: {type : 'parents', cnt : 1, hideCnt : true}}, asyncOpt);
\t\t\t
\t\t\tvar dfd    = \$.Deferred(),
\t\t\t\tnotify = asyncOpt.notify,
\t\t\t\tnoreq  = false,
\t\t\t\treq    = function() {
\t\t\t\t\tself.request({
\t\t\t\t\t\tdata : {cmd : 'parents', target : files[hash].phash},
\t\t\t\t\t\tnotify : notify,
\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t})
\t\t\t\t\t.done(done)
\t\t\t\t\t.fail(function() {
\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\tdone   = function() {
\t\t\t\t\tself.one('parentsdone', function() {
\t\t\t\t\t\tpath = self.path(hash, i18);
\t\t\t\t\t\tif (path === '' && noreq) {
\t\t\t\t\t\t\t//retry with request
\t\t\t\t\t\t\tnoreq = false;
\t\t\t\t\t\t\treq();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (notify) {
\t\t\t\t\t\t\t\tclearTimeout(ntftm);
\t\t\t\t\t\t\t\tnotify.cnt = -(parseInt(notify.cnt || 0));
\t\t\t\t\t\t\t\tself.notify(notify);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdfd.resolve(path);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\tntftm;
\t\t
\t\t\tif (path) {
\t\t\t\treturn dfd.resolve(path);
\t\t\t} else {
\t\t\t\tif (self.ui['tree']) {
\t\t\t\t\t// try as no request
\t\t\t\t\tif (notify) {
\t\t\t\t\t\tntftm = setTimeout(function() {
\t\t\t\t\t\t\tself.notify(notify);
\t\t\t\t\t\t}, self.notifyDelay);
\t\t\t\t\t}
\t\t\t\t\tnoreq = true;
\t\t\t\t\tdone(true);
\t\t\t\t} else {
\t\t\t\t\treq();
\t\t\t\t}
\t\t\t\treturn dfd;
\t\t\t}
\t\t}
\t};
\t
\t/**
\t * Return file url if set
\t * 
\t * @param  String  file hash
\t * @param  Object  Options
\t * @return String|Object of jQuery Deferred
\t */
\tthis.url = function(hash, o) {
\t\tvar file   = files[hash],
\t\t\topts   = o || {},
\t\t\tasync  = opts.async || false,
\t\t\ttemp   = opts.temporary || false,
\t\t\tonetm  = (opts.onetime && self.option('onetimeUrl', hash)) || false,
\t\t\tabsurl = opts.absurl || false,
\t\t\tdfrd   = (async || onetm)? \$.Deferred() : null,
\t\t\tfilter = function(url) {
\t\t\t\tif (url && absurl) {
\t\t\t\t\turl = self.convAbsUrl(url);
\t\t\t\t}
\t\t\t\treturn url;
\t\t\t},
\t\t\tgetUrl = function(url) {
\t\t\t\tif (url) {
\t\t\t\t\treturn filter(url);
\t\t\t\t}
\t\t\t\tif (file.url) {
\t\t\t\t\treturn filter(file.url);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (typeof baseUrl === 'undefined') {
\t\t\t\t\tbaseUrl = getBaseUrl();
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (baseUrl) {
\t\t\t\t\treturn filter(baseUrl + \$.map(self.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/'));
\t\t\t\t}

\t\t\t\tvar params = Object.assign({}, self.customData, {
\t\t\t\t\tcmd: 'file',
\t\t\t\t\ttarget: file.hash
\t\t\t\t});
\t\t\t\tif (self.oldAPI) {
\t\t\t\t\tparams.cmd = 'open';
\t\t\t\t\tparams.current = file.phash;
\t\t\t\t}
\t\t\t\treturn filter(self.options.url + (self.options.url.indexOf('?') === -1 ? '?' : '&') + \$.param(params, true));
\t\t\t},
\t\t\tgetBaseUrl = function() {
\t\t\t\treturn self.option('url', (!self.isRoot(file) && file.phash) || file.hash);
\t\t\t},
\t\t\tbaseUrl, res;
\t\t
\t\tif (!file || !file.read) {
\t\t\treturn async? dfrd.resolve('') : '';
\t\t}
\t\t
\t\tif (onetm && (!file.url || file.url == '1') && !(baseUrl = getBaseUrl())) {
\t\t\tasync = true;
\t\t\tthis.request({
\t\t\t\tdata : { cmd : 'url', target : hash, options : { onetime: 1 } },
\t\t\t\tpreventDefault : true,
\t\t\t\toptions: {async: async},
\t\t\t\tnotify: {type : 'file', cnt : 1, hideCnt : true},
\t\t\t\tprogressBar: opts.progressBar
\t\t\t}).done(function(data) {
\t\t\t\tdfrd.resolve(filter(data.url || ''));
\t\t\t}).fail(function() {
\t\t\t\tdfrd.resolve('');
\t\t\t});
\t\t} else {
\t\t\tif (file.url == '1' || (temp && !file.url && !(baseUrl = getBaseUrl()))) {
\t\t\t\tthis.request({
\t\t\t\t\tdata : { cmd : 'url', target : hash, options : { temporary: temp? 1 : 0 } },
\t\t\t\t\tpreventDefault : true,
\t\t\t\t\toptions: {async: async},
\t\t\t\t\tnotify: async? {type : temp? 'file' : 'url', cnt : 1, hideCnt : true} : {},
\t\t\t\t\tprogressBar: opts.progressBar
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tfile.url = data.url || '';
\t\t\t\t})
\t\t\t\t.fail(function() {
\t\t\t\t\tfile.url = '';
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\tvar url;
\t\t\t\t\tif (file.url && temp) {
\t\t\t\t\t\turl = file.url;
\t\t\t\t\t\tfile.url = '1'; // restore
\t\t\t\t\t}
\t\t\t\t\tif (async) {
\t\t\t\t\t\tdfrd.resolve(getUrl(url));
\t\t\t\t\t} else {
\t\t\t\t\t\treturn getUrl(url);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t} else {
\t\t\t\tif (async) {
\t\t\t\t\tdfrd.resolve(getUrl());
\t\t\t\t} else {
\t\t\t\t\treturn getUrl();
\t\t\t\t}
\t\t\t}
\t\t}
\t\tif (async) {
\t\t\treturn dfrd;
\t\t}
\t};
\t
\t/**
\t * Return file url for the extarnal service
\t *
\t * @param      String  hash     The hash
\t * @param      Object  options  The options
\t * @return     Object  jQuery Deferred
\t */
\tthis.forExternalUrl = function(hash, options) {
\t\tvar onetime = self.option('onetimeUrl', hash),
\t\t\topts = {
\t\t\t\tasync: true,
\t\t\t\tabsurl: true
\t\t\t};

\t\topts[onetime? 'onetime' : 'temporary'] = true;
\t\treturn self.url(hash, Object.assign({}, options, opts));
\t};

\t/**
\t * Return file url for open in elFinder
\t * 
\t * @param  String  file hash
\t * @param  Boolean for download link
\t * @param      Object  requestOpts   The request options
\t * @return String
\t */
\tthis.openUrl = function(hash, download, callback, requestOpts) {
\t\tvar file = files[hash],
\t\t\turl  = '',
\t\t\tonetimeSize = (requestOpts || {}).onetimeSize || (5 * 1024 * 1024);
\t\t
\t\tif (!file || !file.read) {
\t\t\treturn '';
\t\t}
\t\t
\t\tif (!download || download === 'sameorigin') {
\t\t\tif (file.url) {
\t\t\t\tif (file.url != 1) {
\t\t\t\t\turl = file.url;
\t\t\t\t}
\t\t\t} else if (cwdOptions.url && file.hash.indexOf(self.cwd().volumeid) === 0) {
\t\t\t\turl = cwdOptions.url + \$.map(this.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/');
\t\t\t}
\t\t\tif (!download || this.isSameOrigin(url)) {
\t\t\t\tif (url) {
\t\t\t\t\turl += (url.match(/\\?/)? '&' : '?') + '_'.repeat((url.match(/[\\?&](_+)t=/g) || ['&t=']).sort().shift().match(/[\\?&](_*)t=/)[1].length + 1) + 't=' + (file.ts || parseInt(+new Date()/1000));
\t\t\t\t\tif (callback) {
\t\t\t\t\t\tcallback(url);
\t\t\t\t\t\treturn;
\t\t\t\t\t} else {
\t\t\t\t\t\treturn url;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (callback && this.hasParrotHeaders()) {
\t\t\tif (!requestOpts) {
\t\t\t\trequestOpts = {};
\t\t\t} else {
\t\t\t\tdelete requestOpts.onetimeSize;
\t\t\t}
\t\t\tif (!requestOpts.onetime && !requestOpts.temporary && file.size > onetimeSize) {
\t\t\t\tif (file.mime.match(/^video|audio/)) {
\t\t\t\t\trequestOpts.temporary = true;
\t\t\t\t} else {
\t\t\t\t\trequestOpts.onetime = true;
\t\t\t\t}
\t\t\t}
\t\t\tif (requestOpts.onetime || requestOpts.temporary) {
\t\t\t\treturn this.url(file.hash, Object.assign({
\t\t\t\t\tasync: true
\t\t\t\t}, requestOpts)).done(function(url) {
\t\t\t\t\tcallback(url);
\t\t\t\t}).fail(function() {
\t\t\t\t\tcallback('');
\t\t\t\t});
\t\t\t} else {
\t\t\t\treturn this.getContents(hash, 'blob', requestOpts).done(function(blob){
\t\t\t\t\turl = (window.URL || window.webkitURL).createObjectURL(blob);
\t\t\t\t\tcallback(url);
\t\t\t\t}).fail(function() {
\t\t\t\t\tcallback('');
\t\t\t\t});
\t\t\t}
\t\t} else {
\t\t\turl = this.options.url;
\t\t\turl = url + (url.indexOf('?') === -1 ? '?' : '&')
\t\t\t\t+ (this.oldAPI ? 'cmd=open&current='+file.phash : 'cmd=file')
\t\t\t\t+ '&target=' + file.hash
\t\t\t\t+ '&_t=' + (file.ts || parseInt(+new Date()/1000));
\t\t\t
\t\t\tif (download === true) {
\t\t\t\turl += '&download=1';
\t\t\t}
\t\t\t
\t\t\t\$.each(this.customData, function(key, val) {
\t\t\t\turl += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
\t\t\t});
\t\t\tif (callback) {
\t\t\t\tcallback(url);
\t\t\t\treturn;
\t\t\t} else {
\t\t\t\treturn url;
\t\t\t}
\t\t}
\t};
\t
\t/**
\t * Return thumbnail url
\t * 
\t * @param  Object  file object
\t * @return String
\t */
\tthis.tmb = function(file) {
\t\tvar tmbUrl, tmbCrop,
\t\t\tcls    = 'elfinder-cwd-bgurl',
\t\t\turl    = '',
\t\t\tcData  = {},
\t\t\tn      = 0;

\t\tif (\$.isPlainObject(file)) {
\t\t\tif (self.searchStatus.state && file.hash.indexOf(self.cwd().volumeid) !== 0) {
\t\t\t\ttmbUrl = self.option('tmbUrl', file.hash);
\t\t\t\ttmbCrop = self.option('tmbCrop', file.hash);
\t\t\t} else {
\t\t\t\ttmbUrl = cwdOptions.tmbUrl;
\t\t\t\ttmbCrop = cwdOptions.tmbCrop;
\t\t\t}
\t\t\tif (tmbCrop) {
\t\t\t\tcls += ' elfinder-cwd-bgurl-crop';
\t\t\t}
\t\t\tif (tmbUrl === 'self' && file.mime.indexOf('image/') === 0) {
\t\t\t\turl = self.openUrl(file.hash);
\t\t\t\tcls += ' elfinder-cwd-bgself';
\t\t\t} else if ((self.oldAPI || tmbUrl) && file && file.tmb && file.tmb != 1) {
\t\t\t\turl = tmbUrl + file.tmb;
\t\t\t} else if (self.newAPI && file && file.tmb && file.tmb != 1) {
\t\t\t\turl = file.tmb;
\t\t\t}
\t\t\tif (url) {
\t\t\t\tif (tmbUrl !== 'self') {
\t\t\t\t\tif (file.ts) {
\t\t\t\t\t\tcData._t = file.ts;
\t\t\t\t\t}
\t\t\t\t\tif (cwdOptions.tmbReqCustomData && Object.keys(this.customData).length) {
\t\t\t\t\t\tcData = Object.assign(cData, this.customData);
\t\t\t\t\t}
\t\t\t\t\tif (Object.keys(cData).length) {
\t\t\t\t\t\turl += (url.match(/\\?/) ? '&' : '?');
\t\t\t\t\t\t\$.each(cData, function (key, val) {
\t\t\t\t\t\t\turl += ((n++ === 0)? '' : '&') + encodeURIComponent(key) + '=' + encodeURIComponent(val);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn { url: url, className: cls };
\t\t\t}
\t\t}
\t\t
\t\treturn false;
\t};
\t
\t/**
\t * Return selected files hashes
\t *
\t * @return Array
\t **/
\tthis.selected = function() {
\t\treturn selected.slice(0);
\t};
\t
\t/**
\t * Return selected files info
\t * 
\t * @return Array
\t */
\tthis.selectedFiles = function() {
\t\treturn \$.map(selected, function(hash) { return files[hash] ? Object.assign({}, files[hash]) : null; });
\t};
\t
\t/**
\t * Return true if file with required name existsin required folder
\t * 
\t * @param  String  file name
\t * @param  String  parent folder hash
\t * @return Boolean
\t */
\tthis.fileByName = function(name, phash) {
\t\tvar hash;
\t
\t\tfor (hash in files) {
\t\t\tif (files.hasOwnProperty(hash) && files[hash].phash == phash && files[hash].name == name) {
\t\t\t\treturn files[hash];
\t\t\t}
\t\t}
\t};
\t
\t/**
\t * Valid data for required command based on rules
\t * 
\t * @param  String  command name
\t * @param  Object  cammand's data
\t * @return Boolean
\t */
\tthis.validResponse = function(cmd, data) {
\t\treturn data.error || this.rules[this.rules[cmd] ? cmd : 'defaults'](data);
\t};
\t
\t/**
\t * Return bytes from ini formated size
\t * 
\t * @param  String  ini formated size
\t * @return Integer
\t */
\tthis.returnBytes = function(val) {
\t\tvar last;
\t\tif (isNaN(val)) {
\t\t\tif (! val) {
\t\t\t\tval = '';
\t\t\t}
\t\t\t// for ex. 1mb, 1KB
\t\t\tval = val.replace(/b\$/i, '');
\t\t\tlast = val.charAt(val.length - 1).toLowerCase();
\t\t\tval = val.replace(/[tgmk]\$/i, '');
\t\t\tif (last == 't') {
\t\t\t\tval = val * 1024 * 1024 * 1024 * 1024;
\t\t\t} else if (last == 'g') {
\t\t\t\tval = val * 1024 * 1024 * 1024;
\t\t\t} else if (last == 'm') {
\t\t\t\tval = val * 1024 * 1024;
\t\t\t} else if (last == 'k') {
\t\t\t\tval = val * 1024;
\t\t\t}
\t\t\tval = isNaN(val)? 0 : parseInt(val);
\t\t} else {
\t\t\tval = parseInt(val);
\t\t\tif (val < 1) val = 0;
\t\t}
\t\treturn val;
\t};
\t
\t/**
\t * Process ajax request.
\t * Fired events :
\t * @todo
\t * @example
\t * @todo
\t * @return \$.Deferred
\t */
\tthis.request = function(opts) { 
\t\tvar self     = this,
\t\t\to        = this.options,
\t\t\tdfrd     = \$.Deferred(),
\t\t\t// request ID
\t\t\treqId    = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16), 
\t\t\t// request data
\t\t\tdata     = Object.assign({}, self.customData, {mimes : o.onlyMimes}, opts.data || opts),
\t\t\t// command name
\t\t\tcmd      = data.cmd,
\t\t\t// request type is binary
\t\t\tisBinary = (opts.options || {}).dataType === 'binary',
\t\t\t// current cmd is \"open\"
\t\t\tisOpen   = (!opts.asNotOpen && cmd === 'open'),
\t\t\t// call default fail callback (display error dialog) ?
\t\t\tdeffail  = !(isBinary || opts.preventDefault || opts.preventFail),
\t\t\t// call default success callback ?
\t\t\tdefdone  = !(isBinary || opts.preventDefault || opts.preventDone),
\t\t\t// current progress of receive data
\t\t\tprog     = opts.progressVal || 20,
\t\t\t// timer of fake progress
\t\t\tprogTm   = null,
\t\t\t// whether the notification dialog is currently displayed
\t\t\thasNotify= false,
\t\t\t// options for notify dialog
\t\t\tnotify   = !opts.progressBar? (opts.notify? Object.assign({progress: prog * opts.notify.cnt}, opts.notify) : {}) : {},
\t\t\t// make cancel button
\t\t\tcancel   = !!opts.cancel,
\t\t\t// do not normalize data - return as is
\t\t\traw      = isBinary || !!opts.raw,
\t\t\t// sync files on request fail
\t\t\tsyncOnFail = opts.syncOnFail,
\t\t\t// use lazy()
\t\t\tlazy     = !!opts.lazy,
\t\t\t// prepare function before done()
\t\t\tprepare  = opts.prepare,
\t\t\t// navigate option object when cmd done
\t\t\tnavigate = opts.navigate,
\t\t\t// open notify dialog timeout
\t\t\ttimeout,
\t\t\t// use browser cache
\t\t\tuseCache = (opts.options || {}).cache,
\t\t\t// request options
\t\t\toptions = Object.assign({
\t\t\t\turl      : o.url,
\t\t\t\tasync    : true,
\t\t\t\ttype     : this.requestType,
\t\t\t\tdataType : 'json',
\t\t\t\tcache    : (self.api >= 2.1029), // api >= 2.1029 has unique request ID
\t\t\t\tdata     : data,
\t\t\t\theaders  : this.customHeaders,
\t\t\t\txhrFields: this.xhrFields,
\t\t\t\tprogress : function(e) {
\t\t\t\t\tvar p = e.loaded / e.total * 100;
\t\t\t\t\tprogTm && clearTimeout(progTm);
\t\t\t\t\tif (opts.progressBar) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\topts.progressBar.width(p + '%');
\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (hasNotify && notify.type) {
\t\t\t\t\t\t\tp = p * notify.cnt;
\t\t\t\t\t\t\tif (prog < p) {
\t\t\t\t\t\t\t\tself.notify({
\t\t\t\t\t\t\t\t\ttype: notify.type,
\t\t\t\t\t\t\t\t\tprogress: p - prog,
\t\t\t\t\t\t\t\t\tcnt: 0,
\t\t\t\t\t\t\t\t\thideCnt: notify.hideCnt
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tprog = p;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (opts.progress) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\topts.progress(e);
\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}, opts.options || {}),
\t\t\t/**
\t\t\t * Default success handler. 
\t\t\t * Call default data handlers and fire event with command name.
\t\t\t *
\t\t\t * @param Object  normalized response data
\t\t\t * @return void
\t\t\t **/
\t\t\tdone = function(data) {
\t\t\t\tdata.warning && self.error(data.warning);
\t\t\t\t
\t\t\t\tif (isOpen) {
\t\t\t\t\topen(data);
\t\t\t\t} else {
\t\t\t\t\tself.updateCache(data);
\t\t\t\t}
\t\t\t\t
\t\t\t\tself.lazy(function() {
\t\t\t\t\t// fire some event to update cache/ui
\t\t\t\t\tdata.removed && data.removed.length && self.remove(data);
\t\t\t\t\tdata.added   && data.added.length   && self.add(data);
\t\t\t\t\tdata.changed && data.changed.length && self.change(data);
\t\t\t\t}).then(function() {
\t\t\t\t\t// fire event with command name
\t\t\t\t\treturn self.lazy(function() {
\t\t\t\t\t\tself.trigger(cmd, data, false);
\t\t\t\t\t});
\t\t\t\t}).then(function() {
\t\t\t\t\t// fire event with command name + 'done'
\t\t\t\t\treturn self.lazy(function() {
\t\t\t\t\t\tself.trigger(cmd + 'done');
\t\t\t\t\t});
\t\t\t\t}).then(function() {
\t\t\t\t\t// make toast message
\t\t\t\t\tif (data.toasts && Array.isArray(data.toasts)) {
\t\t\t\t\t\t\$.each(data.toasts, function() {
\t\t\t\t\t\t\tthis.msg && self.toast(this);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\t// force update content
\t\t\t\t\tdata.sync && self.sync();
\t\t\t\t});
\t\t\t},
\t\t\t/**
\t\t\t * Request error handler. Reject dfrd with correct error message.
\t\t\t *
\t\t\t * @param jqxhr  request object
\t\t\t * @param String request status
\t\t\t * @return void
\t\t\t **/
\t\t\terror = function(xhr, status) {
\t\t\t\tvar error, data, 
\t\t\t\t\td = self.options.debug;
\t\t\t\t
\t\t\t\tswitch (status) {
\t\t\t\t\tcase 'abort':
\t\t\t\t\t\terror = xhr.quiet ? '' : ['errConnect', 'errAbort'];
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 'timeout':\t    
\t\t\t\t\t\terror = ['errConnect', 'errTimeout'];
\t\t\t\t\t\tbreak;
\t\t\t\t\tcase 'parsererror': 
\t\t\t\t\t\terror = ['errResponse', 'errDataNotJSON'];
\t\t\t\t\t\tif (xhr.responseText) {
\t\t\t\t\t\t\tif (! cwd || (d && (d === 'all' || d['backend-error']))) {
\t\t\t\t\t\t\t\terror.push(xhr.responseText);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tbreak;
\t\t\t\t\tdefault:
\t\t\t\t\t\tif (xhr.responseText) {
\t\t\t\t\t\t\t// check responseText, Is that JSON?
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tdata = JSON.parse(xhr.responseText);
\t\t\t\t\t\t\t\tif (data && data.error) {
\t\t\t\t\t\t\t\t\terror = data.error;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (! error) {
\t\t\t\t\t\t\tif (xhr.status == 403) {
\t\t\t\t\t\t\t\terror = ['errConnect', 'errAccess', 'HTTP error ' + xhr.status];
\t\t\t\t\t\t\t} else if (xhr.status == 404) {
\t\t\t\t\t\t\t\terror = ['errConnect', 'errNotFound', 'HTTP error ' + xhr.status];
\t\t\t\t\t\t\t} else if (xhr.status >= 500) {
\t\t\t\t\t\t\t\terror = ['errResponse', 'errServerError', 'HTTP error ' + xhr.status];
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (xhr.status == 414 && options.type === 'get') {
\t\t\t\t\t\t\t\t\t// retry by POST method
\t\t\t\t\t\t\t\t\toptions.type = 'post';
\t\t\t\t\t\t\t\t\tself.abortXHR(xhr);
\t\t\t\t\t\t\t\t\tdfrd.xhr = xhr = self.transport.send(options).fail(error).done(success);
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\terror = xhr.quiet ? '' : ['errConnect', 'HTTP error ' + xhr.status];
\t\t\t\t\t\t\t} 
\t\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tself.trigger(cmd + 'done');
\t\t\t\tdfrd.reject({error: error}, xhr, status);
\t\t\t},
\t\t\t/**
\t\t\t * Request success handler. Valid response data and reject/resolve dfrd.
\t\t\t *
\t\t\t * @param Object  response data
\t\t\t * @param String request status
\t\t\t * @return void
\t\t\t **/
\t\t\tsuccess = function(response) {
\t\t\t\t// Set currrent request command name
\t\t\t\tself.currentReqCmd = cmd;
\t\t\t\t
\t\t\t\tresponse.debug && self.responseDebug(response);
\t\t\t\t
\t\t\t\tself.setCustomHeaderByXhr(xhr);

\t\t\t\tif (raw) {
\t\t\t\t\tself.abortXHR(xhr);
\t\t\t\t\tresponse && response.debug && self.debug('backend-debug', response);
\t\t\t\t\treturn dfrd.resolve(response);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (!response) {
\t\t\t\t\treturn dfrd.reject({error :['errResponse', 'errDataEmpty']}, xhr, response);
\t\t\t\t} else if (!\$.isPlainObject(response)) {
\t\t\t\t\treturn dfrd.reject({error :['errResponse', 'errDataNotJSON']}, xhr, response);
\t\t\t\t} else if (response.error) {
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\t// check leafRoots
\t\t\t\t\t\t\$.each(self.leafRoots, function(phash, roots) {
\t\t\t\t\t\t\tself.leafRoots[phash] = \$.grep(roots, function(h) { return h !== data.target; });
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\treturn dfrd.reject({error :response.error}, xhr, response);
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar resolve = function() {
\t\t\t\t\tvar pushLeafRoots = function(name) {
\t\t\t\t\t\tif (self.leafRoots[data.target] && response[name]) {
\t\t\t\t\t\t\t\$.each(self.leafRoots[data.target], function(i, h) {
\t\t\t\t\t\t\t\tvar root;
\t\t\t\t\t\t\t\tif (root = self.file(h)) {
\t\t\t\t\t\t\t\t\tresponse[name].push(root);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetTextMimes = function() {
\t\t\t\t\t\tself.textMimes = {};
\t\t\t\t\t\t\$.each(self.res('mimes', 'text'), function() {
\t\t\t\t\t\t\tself.textMimes[this.toLowerCase()] = true;
\t\t\t\t\t\t});
\t\t\t\t\t},
\t\t\t\t\tactionTarget;
\t\t\t\t\t
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\tpushLeafRoots('files');
\t\t\t\t\t} else if (cmd === 'tree') {
\t\t\t\t\t\tpushLeafRoots('tree');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tresponse = self.normalize(response);
\t\t\t\t\t
\t\t\t\t\tif (!self.validResponse(cmd, response)) {
\t\t\t\t\t\treturn dfrd.reject({error :(response.norError || 'errResponse')}, xhr, response);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\tif (!self.api) {
\t\t\t\t\t\t\tself.api    = response.api || 1;
\t\t\t\t\t\t\tif (self.api == '2.0' && typeof response.options.uploadMaxSize !== 'undefined') {
\t\t\t\t\t\t\t\tself.api = '2.1';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tself.newAPI = self.api >= 2;
\t\t\t\t\t\t\tself.oldAPI = !self.newAPI;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (response.textMimes && Array.isArray(response.textMimes)) {
\t\t\t\t\t\t\tself.resources.mimes.text = response.textMimes;
\t\t\t\t\t\t\tsetTextMimes();
\t\t\t\t\t\t}
\t\t\t\t\t\t!self.textMimes && setTextMimes();
\t\t\t\t\t\t
\t\t\t\t\t\tif (response.options) {
\t\t\t\t\t\t\tcwdOptions = Object.assign({}, cwdOptionsDefault, response.options);
\t\t\t\t\t\t}

\t\t\t\t\t\tif (response.netDrivers) {
\t\t\t\t\t\t\tself.netDrivers = response.netDrivers;
\t\t\t\t\t\t}

\t\t\t\t\t\tif (response.maxTargets) {
\t\t\t\t\t\t\tself.maxTargets = response.maxTargets;
\t\t\t\t\t\t}

\t\t\t\t\t\tif (!!data.init) {
\t\t\t\t\t\t\tself.uplMaxSize = self.returnBytes(response.uplMaxSize);
\t\t\t\t\t\t\tself.uplMaxFile = !!response.uplMaxFile? Math.min(parseInt(response.uplMaxFile), 50) : 20;
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\tif (typeof prepare === 'function') {
\t\t\t\t\t\tprepare(response);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (navigate) {
\t\t\t\t\t\tactionTarget = navigate.target || 'added';
\t\t\t\t\t\tif (response[actionTarget] && response[actionTarget].length) {
\t\t\t\t\t\t\tself.one(cmd + 'done', function() {
\t\t\t\t\t\t\t\tvar targets  = response[actionTarget],
\t\t\t\t\t\t\t\t\tnewItems = self.findCwdNodes(targets),
\t\t\t\t\t\t\t\t\tinCwdHashes = function() {
\t\t\t\t\t\t\t\t\t\tvar cwdHash = self.cwd().hash;
\t\t\t\t\t\t\t\t\t\treturn \$.map(targets, function(f) { return (f.phash && cwdHash === f.phash)? f.hash : null; });
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\thashes   = inCwdHashes(),
\t\t\t\t\t\t\t\t\tmakeToast  = function(t) {
\t\t\t\t\t\t\t\t\t\tvar node = void(0),
\t\t\t\t\t\t\t\t\t\t\tdata = t.action? t.action.data : void(0),
\t\t\t\t\t\t\t\t\t\t\tcmd, msg, done;
\t\t\t\t\t\t\t\t\t\tif ((data || hashes.length) && t.action && (msg = t.action.msg) && (cmd = t.action.cmd) && (!t.action.cwdNot || t.action.cwdNot !== self.cwd().hash)) {
\t\t\t\t\t\t\t\t\t\t\tdone = t.action.done;
\t\t\t\t\t\t\t\t\t\t\tdata = t.action.data;
\t\t\t\t\t\t\t\t\t\t\tnode = \$('<div></div>')
\t\t\t\t\t\t\t\t\t\t\t\t.append(
\t\t\t\t\t\t\t\t\t\t\t\t\t\$('<button type=\"button\" class=\"ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop\"><span class=\"ui-button-text\">'
\t\t\t\t\t\t\t\t\t\t\t\t\t\t+self.i18n(msg)
\t\t\t\t\t\t\t\t\t\t\t\t\t\t+'</span></button>')
\t\t\t\t\t\t\t\t\t\t\t\t\t.on('mouseenter mouseleave', function(e) { 
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tself.exec(cmd, data || hashes, {_userAction: true, _currentType: 'toast', _currentNode: \$(this) });
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (done) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tself.one(cmd+'done', function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (typeof done === 'function') {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdone();
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else if (done === 'select') {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tself.trigger('selectfiles', {files : inCwdHashes()});
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tdelete t.action;
\t\t\t\t\t\t\t\t\t\tt.extNode = node;
\t\t\t\t\t\t\t\t\t\treturn t;
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (! navigate.toast) {
\t\t\t\t\t\t\t\t\tnavigate.toast = {};
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t!navigate.noselect && self.trigger('selectfiles', {files : self.searchStatus.state > 1 ? \$.map(targets, function(f) { return f.hash; }) : hashes});
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (newItems.length) {
\t\t\t\t\t\t\t\t\tif (!navigate.noscroll) {
\t\t\t\t\t\t\t\t\t\tnewItems.first().trigger('scrolltoview', {blink : false});
\t\t\t\t\t\t\t\t\t\tself.resources.blink(newItems, 'lookme');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (\$.isPlainObject(navigate.toast.incwd)) {
\t\t\t\t\t\t\t\t\t\tself.toast(makeToast(navigate.toast.incwd));
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tif (\$.isPlainObject(navigate.toast.inbuffer)) {
\t\t\t\t\t\t\t\t\t\tself.toast(makeToast(navigate.toast.inbuffer));
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tdfrd.resolve(response);
\t\t\t\t\t
\t\t\t\t\tresponse.debug && self.debug('backend-debug', response);
\t\t\t\t};
\t\t\t\tself.abortXHR(xhr);
\t\t\t\tlazy? self.lazy(resolve) : resolve();
\t\t\t},
\t\t\txhr, _xhr,
\t\t\txhrAbort = function(e) {
\t\t\t\tif (xhr && xhr.state() === 'pending') {
\t\t\t\t\tself.abortXHR(xhr, { quiet: true , abort: true });
\t\t\t\t\tif (!e || (e.type !== 'unload' && e.type !== 'destroy')) {
\t\t\t\t\t\tself.autoSync();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tabort = function(e){
\t\t\t\tself.trigger(cmd + 'done');
\t\t\t\tif (e.type == 'autosync') {
\t\t\t\t\tif (e.data.action != 'stop') return;
\t\t\t\t} else if (e.type != 'unload' && e.type != 'destroy' && e.type != 'openxhrabort') {
\t\t\t\t\tif (!e.data.added || !e.data.added.length) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\txhrAbort(e);
\t\t\t},
\t\t\trequest = function(mode) {
\t\t\t\tvar queueAbort = function() {
\t\t\t\t\tsyncOnFail = false;
\t\t\t\t\tdfrd.reject();
\t\t\t\t};
\t\t\t\t
\t\t\t\tif (mode) {
\t\t\t\t\tif (mode === 'cmd') {
\t\t\t\t\t\treturn cmd;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (isOpen) {
\t\t\t\t\tif (currentOpenCmd && currentOpenCmd.state() === 'pending') {
\t\t\t\t\t\tif (currentOpenCmd._target === data.target) {
\t\t\t\t\t\t\treturn dfrd.reject('openabort');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (currentOpenCmd.xhr) {
\t\t\t\t\t\t\t\tcurrentOpenCmd.xhr.queueAbort();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tcurrentOpenCmd.reject('openabort');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tcurrentOpenCmd = dfrd;
\t\t\t\t\tcurrentOpenCmd._target = data.target;
\t\t\t\t}
\t\t\t\t
\t\t\t\tdfrd.always(function() {
\t\t\t\t\tdelete options.headers['X-elFinderReqid'];
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\tcurrentOpenCmd = null;
\t\t\t\t\t}
\t\t\t\t}).fail(function(error, xhr, response) {
\t\t\t\t\tvar errData, errMsg;

\t\t\t\t\tif (isOpen && error === 'openabort') {
\t\t\t\t\t\terror = '';
\t\t\t\t\t\tsyncOnFail = false;
\t\t\t\t\t}

\t\t\t\t\terrData = {
\t\t\t\t\t\tcmd: cmd,
\t\t\t\t\t\terr: error,
\t\t\t\t\t\txhr: xhr,
\t\t\t\t\t\trc: response
\t\t\t\t\t};

\t\t\t\t\t// unset this cmd queue when user canceling
\t\t\t\t\t// see notify : function - `cancel.reject(0);`
\t\t\t\t\tif (error === 0) {
\t\t\t\t\t\tif (requestQueue.length) {
\t\t\t\t\t\t\trequestQueue = \$.grep(requestQueue, function(req) {
\t\t\t\t\t\t\t\treturn (req('cmd') === cmd) ? false : true;
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t// trigger \"requestError\" event
\t\t\t\t\tself.trigger('requestError', errData);
\t\t\t\t\tif (errData._getEvent && errData._getEvent().isDefaultPrevented()) {
\t\t\t\t\t\tdeffail = false;
\t\t\t\t\t\tsyncOnFail = false;
\t\t\t\t\t\tif (error) {
\t\t\t\t\t\t\terror.error = '';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t// abort xhr
\t\t\t\t\txhrAbort();
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\topenDir = self.file(data.target);
\t\t\t\t\t\topenDir && openDir.volumeid && self.isRoot(openDir) && delete self.volumeExpires[openDir.volumeid];
\t\t\t\t\t}
\t\t\t\t\tself.trigger(cmd + 'fail', response);
\t\t\t\t\terrMsg = (typeof error === 'object')? error.error : error;
\t\t\t\t\tif (errMsg) {
\t\t\t\t\t\tdeffail ? self.error(errMsg) : self.debug('error', self.i18n(errMsg));
\t\t\t\t\t}
\t\t\t\t\tsyncOnFail && self.sync();
\t\t\t\t});

\t\t\t\tif (!cmd) {
\t\t\t\t\tsyncOnFail = false;
\t\t\t\t\treturn dfrd.reject({error :'errCmdReq'});
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (self.maxTargets && data.targets && data.targets.length > self.maxTargets) {
\t\t\t\t\tsyncOnFail = false;
\t\t\t\t\treturn dfrd.reject({error :['errMaxTargets', self.maxTargets]});
\t\t\t\t}

\t\t\t\tdefdone && dfrd.done(done);
\t\t\t\t
\t\t\t\t// quiet abort not completed \"open\" requests
\t\t\t\tif (isOpen) {
\t\t\t\t\twhile ((_xhr = queue.pop())) {
\t\t\t\t\t\t_xhr.queueAbort();
\t\t\t\t\t}
\t\t\t\t\tif (cwd !== data.target) {
\t\t\t\t\t\twhile ((_xhr = cwdQueue.pop())) {
\t\t\t\t\t\t\t_xhr.queueAbort();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\t// trigger abort autoSync for commands to add the item
\t\t\t\tif (\$.inArray(cmd, (self.cmdsToAdd + ' autosync').split(' ')) !== -1) {
\t\t\t\t\tif (cmd !== 'autosync') {
\t\t\t\t\t\tself.autoSync('stop');
\t\t\t\t\t\tdfrd.always(function() {
\t\t\t\t\t\t\tself.autoSync();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tself.trigger('openxhrabort');
\t\t\t\t}

\t\t\t\tdelete options.preventFail;

\t\t\t\tif (self.api >= 2.1029) {
\t\t\t\t\tif (useCache) {
\t\t\t\t\t\toptions.headers['X-elFinderReqid'] = reqId;
\t\t\t\t\t} else {
\t\t\t\t\t\tObject.assign(options.data, { reqid : reqId });
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// function for set value of this syncOnFail
\t\t\t\tdfrd.syncOnFail = function(state) {
\t\t\t\t\tsyncOnFail = !!state;
\t\t\t\t};

\t\t\t\trequestCnt++;

\t\t\t\tdfrd.xhr = xhr = self.transport.send(options).always(function() {
\t\t\t\t\t// set responseURL from native xhr object
\t\t\t\t\tif (options._xhr && typeof options._xhr.responseURL !== 'undefined') {
\t\t\t\t\t\txhr.responseURL = options._xhr.responseURL || '';
\t\t\t\t\t}
\t\t\t\t\t--requestCnt;
\t\t\t\t\tif (requestQueue.length) {
\t\t\t\t\t\trequestQueue.shift()();
\t\t\t\t\t}
\t\t\t\t}).fail(error).done(success);
\t\t\t\t
\t\t\t\tif (self.api >= 2.1029) {
\t\t\t\t\txhr._requestId = reqId;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (isOpen || (data.compare && cmd === 'info')) {
\t\t\t\t\t// regist function queueAbort
\t\t\t\t\txhr.queueAbort = queueAbort;
\t\t\t\t\t// add autoSync xhr into queue
\t\t\t\t\tqueue.unshift(xhr);
\t\t\t\t\t// bind abort()
\t\t\t\t\tdata.compare && self.bind(self.cmdsToAdd + ' autosync openxhrabort', abort);
\t\t\t\t\tdfrd.always(function() {
\t\t\t\t\t\tvar ndx = \$.inArray(xhr, queue);
\t\t\t\t\t\tdata.compare && self.unbind(self.cmdsToAdd + ' autosync openxhrabort', abort);
\t\t\t\t\t\tndx !== -1 && queue.splice(ndx, 1);
\t\t\t\t\t});
\t\t\t\t} else if (\$.inArray(cmd, self.abortCmdsOnOpen) !== -1) {
\t\t\t\t\t// regist function queueAbort
\t\t\t\t\txhr.queueAbort = queueAbort;
\t\t\t\t\t// add \"open\" xhr, only cwd xhr into queue
\t\t\t\t\tcwdQueue.unshift(xhr);
\t\t\t\t\tdfrd.always(function() {
\t\t\t\t\t\tvar ndx = \$.inArray(xhr, cwdQueue);
\t\t\t\t\t\tndx !== -1 && cwdQueue.splice(ndx, 1);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\t// abort pending xhr on window unload or elFinder destroy
\t\t\t\tself.bind('unload destroy', abort);
\t\t\t\tdfrd.always(function() {
\t\t\t\t\tself.unbind('unload destroy', abort);
\t\t\t\t});
\t\t\t\t
\t\t\t\treturn dfrd;
\t\t\t},
\t\t\tqueueingRequest = function() {
\t\t\t\t// show notify
\t\t\t\tif (notify.type && notify.cnt) {
\t\t\t\t\tif (cancel) {
\t\t\t\t\t\tnotify.cancel = dfrd;
\t\t\t\t\t\topts.eachCancel && (notify.id = +new Date());
\t\t\t\t\t}
\t\t\t\t\ttimeout = setTimeout(function() {
\t\t\t\t\t\t// start fake count up
\t\t\t\t\t\tprogTm = setTimeout(progFakeUp, 1000);
\t\t\t\t\t\tself.notify(notify);
\t\t\t\t\t\thasNotify = true;
\t\t\t\t\t\tdfrd.always(function() {
\t\t\t\t\t\t\tnotify.cnt = -(parseInt(notify.cnt)||0);
\t\t\t\t\t\t\tself.notify(notify);
\t\t\t\t\t\t\thasNotify = false;
\t\t\t\t\t\t});
\t\t\t\t\t}, self.notifyDelay);
\t\t\t\t\t
\t\t\t\t\tdfrd.always(function() {
\t\t\t\t\t\tclearTimeout(timeout);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t// queueing
\t\t\t\tif (requestCnt < requestMaxConn) {
\t\t\t\t\t// do request
\t\t\t\t\treturn request();
\t\t\t\t} else {
\t\t\t\t\tif (isOpen) {
\t\t\t\t\t\trequestQueue.unshift(request);
\t\t\t\t\t} else {
\t\t\t\t\t\trequestQueue.push(request);
\t\t\t\t\t}
\t\t\t\t\treturn dfrd;
\t\t\t\t}
\t\t\t},
\t\t\tprogFakeUp = function() {
\t\t\t\tvar add;
\t\t\t\tif (hasNotify && progTm) {
\t\t\t\t\tadd = 1 * notify.cnt;
\t\t\t\t\tprogTm = null;
\t\t\t\t\tself.notify({
\t\t\t\t\t\ttype: notify.type,
\t\t\t\t\t\tprogress: add,
\t\t\t\t\t\tcnt: 0,
\t\t\t\t\t\thideCnt: notify.hideCnt
\t\t\t\t\t});
\t\t\t\t\tprog += add;
\t\t\t\t\tif ((prog / notify.cnt) < 80) {
\t\t\t\t\t\tprogTm = setTimeout(progFakeUp, 500);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tbindData = {opts: opts, result: true},
\t\t\topenDir;
\t\t
\t\t// prevent request initial request is completed
\t\tif (!self.api && !data.init) {
\t\t\tsyncOnFail = false;
\t\t\treturn dfrd.reject();
\t\t}

\t\t// trigger \"request.cmd\" that callback be able to cancel request by substituting \"false\" for \"event.data.result\"
\t\tself.trigger('request.' + cmd, bindData, true);
\t\t
\t\tif (! bindData.result) {
\t\t\tself.trigger(cmd + 'done');
\t\t\treturn dfrd.reject();
\t\t} else if (typeof bindData.result === 'object' && bindData.result.promise) {
\t\t\tbindData.result
\t\t\t\t.done(queueingRequest)
\t\t\t\t.fail(function() {
\t\t\t\t\tself.trigger(cmd + 'done');
\t\t\t\t\tdfrd.reject();
\t\t\t\t});
\t\t\treturn dfrd;
\t\t}
\t\t
\t\treturn queueingRequest();
\t};
\t
\t/**
\t * Call cache()
\t * Store info about files/dirs in \"files\" object.
\t *
\t * @param  Array  files
\t * @param  String type
\t * @return void
\t */
\tthis.cache = function(dataArray, type) {
\t\tif (! Array.isArray(dataArray)) {
\t\t\tdataArray = [ dataArray ];
\t\t}
\t\tcache(dataArray, type);
\t};
\t
\t/**
\t * Update file object caches by respose data object
\t * 
\t * @param  Object  respose data object
\t * @return void
\t */
\tthis.updateCache = function(data) {
\t\tif (\$.isPlainObject(data)) {
\t\t\tdata.files && data.files.length && cache(data.files, 'files');
\t\t\tdata.tree && data.tree.length && cache(data.tree, 'tree');
\t\t\tdata.removed && data.removed.length && remove(data.removed);
\t\t\tdata.added && data.added.length && cache(data.added, 'add');
\t\t\tdata.changed && data.changed.length && cache(data.changed, 'change');
\t\t}
\t};
\t
\t/**
\t * Compare current files cache with new files and return diff
\t * 
\t * @param  Array   new files
\t * @param  String  target folder hash
\t * @param  Array   exclude properties to compare
\t * @return Object
\t */
\tthis.diff = function(incoming, onlydir, excludeProps) {
\t\tvar raw       = {},
\t\t\tadded     = [],
\t\t\tremoved   = [],
\t\t\tchanged   = [],
\t\t\texcludes  = null,
\t\t\tisChanged = function(hash) {
\t\t\t\tvar l = changed.length;

\t\t\t\twhile (l--) {
\t\t\t\t\tif (changed[l].hash == hash) {
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t};
\t\t
\t\t\$.each(incoming, function(i, f) {
\t\t\traw[f.hash] = f;
\t\t});
\t\t
\t\t// make excludes object
\t\tif (excludeProps && excludeProps.length) {
\t\t\texcludes = {};
\t\t\t\$.each(excludeProps, function() {
\t\t\t\texcludes[this] = true;
\t\t\t});
\t\t}
\t\t
\t\t// find removed
\t\t\$.each(files, function(hash, f) {
\t\t\tif (! raw[hash] && (! onlydir || f.phash === onlydir)) {
\t\t\t\tremoved.push(hash);
\t\t\t}
\t\t});
\t\t
\t\t// compare files
\t\t\$.each(raw, function(hash, file) {
\t\t\tvar origin  = files[hash],
\t\t\t\torgKeys = {},
\t\t\t\tchkKeyLen;

\t\t\tif (!origin) {
\t\t\t\tadded.push(file);
\t\t\t} else {
\t\t\t\t// make orgKeys object
\t\t\t\t\$.each(Object.keys(origin), function() {
\t\t\t\t\torgKeys[this] = true;
\t\t\t\t});
\t\t\t\t\$.each(file, function(prop) {
\t\t\t\t\tdelete orgKeys[prop];
\t\t\t\t\tif (! excludes || ! excludes[prop]) {
\t\t\t\t\t\tif (file[prop] !== origin[prop]) {
\t\t\t\t\t\t\tchanged.push(file);
\t\t\t\t\t\t\torgKeys = {};
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tchkKeyLen = Object.keys(orgKeys).length;
\t\t\t\tif (chkKeyLen !== 0) {
\t\t\t\t\tif (excludes) {
\t\t\t\t\t\t\$.each(orgKeys, function(prop) {
\t\t\t\t\t\t\tif (excludes[prop]) {
\t\t\t\t\t\t\t\t--chkKeyLen;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\t(chkKeyLen !== 0) && changed.push(file);
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\t// parents of removed dirs mark as changed (required for tree correct work)
\t\t\$.each(removed, function(i, hash) {
\t\t\tvar file  = files[hash], 
\t\t\t\tphash = file.phash;

\t\t\tif (phash 
\t\t\t&& file.mime == 'directory' 
\t\t\t&& \$.inArray(phash, removed) === -1 
\t\t\t&& raw[phash] 
\t\t\t&& !isChanged(phash)) {
\t\t\t\tchanged.push(raw[phash]);
\t\t\t}
\t\t});
\t\t
\t\treturn {
\t\t\tadded   : added,
\t\t\tremoved : removed,
\t\t\tchanged : changed
\t\t};
\t};
\t
\t/**
\t * Sync content
\t * 
\t * @return jQuery.Deferred
\t */
\tthis.sync = function(onlydir, polling) {
\t\tthis.autoSync('stop');
\t\tvar self  = this,
\t\t\tcompare = function(){
\t\t\t\tvar c = '', cnt = 0, mtime = 0;
\t\t\t\tif (onlydir && polling) {
\t\t\t\t\t\$.each(files, function(h, f) {
\t\t\t\t\t\tif (f.phash && f.phash === onlydir) {
\t\t\t\t\t\t\t++cnt;
\t\t\t\t\t\t\tmtime = Math.max(mtime, f.ts);
\t\t\t\t\t\t}
\t\t\t\t\t\tc = cnt+':'+mtime;
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\treturn c;
\t\t\t},
\t\t\tcomp  = compare(),
\t\t\tdfrd  = \$.Deferred().always(function() { !reqFail && self.trigger('sync'); }),
\t\t\topts = [this.request({
\t\t\t\tdata           : {cmd : 'open', reload : 1, target : cwd, tree : (! onlydir && this.ui.tree) ? 1 : 0, compare : comp},
\t\t\t\tpreventDefault : true
\t\t\t})],
\t\t\texParents = function() {
\t\t\t\tvar parents = [],
\t\t\t\t\tcurRoot = self.file(self.root(cwd)),
\t\t\t\t\tcurId = curRoot? curRoot.volumeid : null,
\t\t\t\t\tphash = self.cwd().phash,
\t\t\t\t\tisroot,pdir;
\t\t\t\t
\t\t\t\twhile(phash) {
\t\t\t\t\tif (pdir = self.file(phash)) {
\t\t\t\t\t\tif (phash.indexOf(curId) !== 0) {
\t\t\t\t\t\t\tparents.push( {target: phash, cmd: 'tree'} );
\t\t\t\t\t\t\tif (! self.isRoot(pdir)) {
\t\t\t\t\t\t\t\tparents.push( {target: phash, cmd: 'parents'} );
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tcurRoot = self.file(self.root(phash));
\t\t\t\t\t\t\tcurId = curRoot? curRoot.volumeid : null;
\t\t\t\t\t\t}
\t\t\t\t\t\tphash = pdir.phash;
\t\t\t\t\t} else {
\t\t\t\t\t\tphash = null;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn parents;
\t\t\t},
\t\t\treqFail;
\t\t
\t\tif (! onlydir && self.api >= 2) {
\t\t\t(cwd !== this.root()) && opts.push(this.request({
\t\t\t\tdata           : {cmd : 'parents', target : cwd},
\t\t\t\tpreventDefault : true
\t\t\t}));
\t\t\t\$.each(exParents(), function(i, data) {
\t\t\t\topts.push(self.request({
\t\t\t\t\tdata           : {cmd : data.cmd, target : data.target},
\t\t\t\t\tpreventDefault : true
\t\t\t\t}));
\t\t\t});
\t\t}
\t\t\$.when.apply(\$, opts)
\t\t.fail(function(error, xhr) {
\t\t\treqFail = (xhr && xhr.status != 200);
\t\t\tif (! polling || \$.inArray('errOpen', error) !== -1) {
\t\t\t\tdfrd.reject(error);
\t\t\t\tself.parseError(error) && self.request({
\t\t\t\t\tdata   : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1},
\t\t\t\t\tnotify : {type : 'open', cnt : 1, hideCnt : true}
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfrd.reject((error && xhr.status != 0)? error : void 0);
\t\t\t}
\t\t})
\t\t.done(function(odata) {
\t\t\tvar pdata, argLen, i;
\t\t\t
\t\t\tif (odata.cwd.compare) {
\t\t\t\tif (comp === odata.cwd.compare) {
\t\t\t\t\treturn dfrd.reject();
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// for 2nd and more requests
\t\t\tpdata = {tree : []};
\t\t\t
\t\t\t// results marge of 2nd and more requests
\t\t\targLen = arguments.length;
\t\t\tif (argLen > 1) {
\t\t\t\tfor(i = 1; i < argLen; i++) {
\t\t\t\t\tif (arguments[i].tree && arguments[i].tree.length) {
\t\t\t\t\t\tpdata.tree.push.apply(pdata.tree, arguments[i].tree);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (self.api < 2.1) {
\t\t\t\tif (! pdata.tree) {
\t\t\t\t\tpdata.tree = [];
\t\t\t\t}
\t\t\t\tpdata.tree.push(odata.cwd);
\t\t\t}
\t\t\t
\t\t\t// data normalize
\t\t\todata = self.normalize(odata);
\t\t\tif (!self.validResponse('open', odata)) {
\t\t\t\treturn dfrd.reject((odata.norError || 'errResponse'));
\t\t\t}
\t\t\tpdata = self.normalize(pdata);
\t\t\tif (!self.validResponse('tree', pdata)) {
\t\t\t\treturn dfrd.reject((pdata.norError || 'errResponse'));
\t\t\t}
\t\t\t
\t\t\tvar diff = self.diff(odata.files.concat(pdata && pdata.tree ? pdata.tree : []), onlydir);

\t\t\tdiff.added.push(odata.cwd);
\t\t\t
\t\t\tself.updateCache(diff);
\t\t\t
\t\t\t// trigger events
\t\t\tdiff.removed.length && self.remove(diff);
\t\t\tdiff.added.length   && self.add(diff);
\t\t\tdiff.changed.length && self.change(diff);
\t\t\treturn dfrd.resolve(diff);
\t\t})
\t\t.always(function() {
\t\t\tself.autoSync();
\t\t});
\t\t
\t\treturn dfrd;
\t};
\t
\tthis.upload = function(files) {
\t\treturn this.transport.upload(files, this);
\t};
\t
\t/**
\t * Bind keybord shortcut to keydown event
\t *
\t * @example
\t *    elfinder.shortcut({ 
\t *       pattern : 'ctrl+a', 
\t *       description : 'Select all files', 
\t *       callback : function(e) { ... }, 
\t *       keypress : true|false (bind to keypress instead of keydown) 
\t *    })
\t *
\t * @param  Object  shortcut config
\t * @return elFinder
\t */
\tthis.shortcut = function(s) {
\t\tvar patterns, pattern, code, i, parts;
\t\t
\t\tif (this.options.allowShortcuts && s.pattern && \$.isFunction(s.callback)) {
\t\t\tpatterns = s.pattern.toUpperCase().split(/\\s+/);
\t\t\t
\t\t\tfor (i= 0; i < patterns.length; i++) {
\t\t\t\tpattern = patterns[i];
\t\t\t\tparts   = pattern.split('+');
\t\t\t\tcode    = (code = parts.pop()).length == 1 
\t\t\t\t\t? (code > 0 ? code : code.charCodeAt(0))
\t\t\t\t\t: (code > 0 ? code : \$.ui.keyCode[code]);

\t\t\t\tif (code && !shortcuts[pattern]) {
\t\t\t\t\tshortcuts[pattern] = {
\t\t\t\t\t\tkeyCode     : code,
\t\t\t\t\t\taltKey      : \$.inArray('ALT', parts)   != -1,
\t\t\t\t\t\tctrlKey     : \$.inArray('CTRL', parts)  != -1,
\t\t\t\t\t\tshiftKey    : \$.inArray('SHIFT', parts) != -1,
\t\t\t\t\t\ttype        : s.type || 'keydown',
\t\t\t\t\t\tcallback    : s.callback,
\t\t\t\t\t\tdescription : s.description,
\t\t\t\t\t\tpattern     : pattern
\t\t\t\t\t};
\t\t\t\t}
\t\t\t}
\t\t}
\t\treturn this;
\t};
\t
\t/**
\t * Registered shortcuts
\t *
\t * @type Object
\t **/
\tthis.shortcuts = function() {
\t\tvar ret = [];
\t\t
\t\t\$.each(shortcuts, function(i, s) {
\t\t\tret.push([s.pattern, self.i18n(s.description)]);
\t\t});
\t\treturn ret;
\t};
\t
\t/**
\t * Get/set clipboard content.
\t * Return new clipboard content.
\t *
\t * @example
\t *   this.clipboard([]) - clean clipboard
\t *   this.clipboard([{...}, {...}], true) - put 2 files in clipboard and mark it as cutted
\t * 
\t * @param  Array    new files hashes
\t * @param  Boolean  cut files?
\t * @return Array
\t */
\tthis.clipboard = function(hashes, cut) {
\t\tvar map = function() { return \$.map(clipboard, function(f) { return f.hash; }); };

\t\tif (hashes !== void(0)) {
\t\t\tclipboard.length && this.trigger('unlockfiles', {files : map()});
\t\t\tremember = {};
\t\t\t
\t\t\tclipboard = \$.map(hashes||[], function(hash) {
\t\t\t\tvar file = files[hash];
\t\t\t\tif (file) {
\t\t\t\t\t
\t\t\t\t\tremember[hash] = true;
\t\t\t\t\t
\t\t\t\t\treturn {
\t\t\t\t\t\thash   : hash,
\t\t\t\t\t\tphash  : file.phash,
\t\t\t\t\t\tname   : file.name,
\t\t\t\t\t\tmime   : file.mime,
\t\t\t\t\t\tread   : file.read,
\t\t\t\t\t\tlocked : file.locked,
\t\t\t\t\t\tcut    : !!cut
\t\t\t\t\t};
\t\t\t\t}
\t\t\t\treturn null;
\t\t\t});
\t\t\tthis.trigger('changeclipboard', {clipboard : clipboard.slice(0, clipboard.length)});
\t\t\tcut && this.trigger('lockfiles', {files : map()});
\t\t}

\t\t// return copy of clipboard instead of refrence
\t\treturn clipboard.slice(0, clipboard.length);
\t};
\t
\t/**
\t * Return true if command enabled
\t * 
\t * @param  String       command name
\t * @param  String|void  hash for check of own volume's disabled cmds
\t * @return Boolean
\t */
\tthis.isCommandEnabled = function(name, dstHash) {
\t\tvar disabled, cmd,
\t\t\tcvid = self.cwd().volumeid || '';
\t\t
\t\t// In serach results use selected item hash to check
\t\tif (!dstHash && self.searchStatus.state > 1 && self.selected().length) {
\t\t\tdstHash = self.selected()[0];
\t\t}
\t\tif (dstHash && (! cvid || dstHash.indexOf(cvid) !== 0)) {
\t\t\tdisabled = self.option('disabledFlip', dstHash);
\t\t\t//if (! disabled) {
\t\t\t//\tdisabled = {};
\t\t\t//}
\t\t} else {
\t\t\tdisabled = cwdOptions.disabledFlip/* || {}*/;
\t\t}
\t\tcmd = this._commands[name];
\t\treturn cmd ? (cmd.alwaysEnabled || !disabled[name]) : false;
\t};
\t
\t/**
\t * Exec command and return result;
\t *
\t * @param  String         command name
\t * @param  String|Array   usualy files hashes
\t * @param  String|Array   command options
\t * @param  String|void    hash for enabled check of own volume's disabled cmds
\t * @return \$.Deferred
\t */\t\t
\tthis.exec = function(cmd, files, opts, dstHash) {
\t\tvar dfrd, resType;
\t\t
\t\t// apply commandMap for keyboard shortcut
\t\tif (!dstHash && this.commandMap[cmd] && this.commandMap[cmd] !== 'hidden') {
\t\t\tcmd = this.commandMap[cmd];
\t\t}

\t\tif (cmd === 'open') {
\t\t\tif (this.searchStatus.state || this.searchStatus.ininc) {
\t\t\t\tthis.trigger('searchend', { noupdate: true });
\t\t\t}
\t\t\tthis.autoSync('stop');
\t\t}
\t\tif (!dstHash && files) {
\t\t\tif (\$.isArray(files)) {
\t\t\t\tif (files.length) {
\t\t\t\t\tdstHash = files[0];
\t\t\t\t}
\t\t\t} else {
\t\t\t\tdstHash = files;
\t\t\t}
\t\t}
\t\tdfrd = this._commands[cmd] && this.isCommandEnabled(cmd, dstHash) 
\t\t\t? this._commands[cmd].exec(files, opts) 
\t\t\t: \$.Deferred().reject('errUnknownCmd');
\t\t
\t\tresType = typeof dfrd;
\t\tif (!(resType === 'object' && dfrd.promise)) {
\t\t\tself.debug('warning', '\"cmd.exec()\" should be returned \"\$.Deferred\" but cmd \"' + cmd + '\" returned \"' + resType + '\"');
\t\t\tdfrd = \$.Deferred().resolve();
\t\t}
\t\t
\t\tthis.trigger('exec', { dfrd : dfrd, cmd : cmd, files : files, opts : opts, dstHash : dstHash });
\t\treturn dfrd;
\t};
\t
\t/**
\t * Create and return dialog.
\t *
\t * @param  String|DOMElement  dialog content
\t * @param  Object             dialog options
\t * @return jQuery
\t */
\tthis.dialog = function(content, options) {
\t\tvar dialog = \$('<div></div>').append(content).appendTo(node).elfinderdialog(options, self),
\t\t\tdnode  = dialog.closest('.ui-dialog'),
\t\t\tresize = function(){
\t\t\t\t! dialog.data('draged') && dialog.is(':visible') && dialog.elfinderdialog('posInit');
\t\t\t};
\t\tif (dnode.length) {
\t\t\tself.bind('resize', resize);
\t\t\tdnode.on('remove', function() {
\t\t\t\tself.unbind('resize', resize);
\t\t\t});
\t\t}
\t\treturn dialog;
\t};
\t
\t/**
\t * Create and return toast.
\t *
\t * @param  Object  toast options - see ui/toast.js
\t * @return jQuery
\t */
\tthis.toast = function(options) {
\t\treturn \$('<div class=\"ui-front\"></div>').appendTo(this.ui.toast).elfindertoast(options || {}, this);
\t};
\t
\t/**
\t * Return UI widget or node
\t *
\t * @param  String  ui name
\t * @return jQuery
\t */
\tthis.getUI = function(ui) {
\t\treturn ui? (this.ui[ui] || \$()) : node;
\t};
\t
\t/**
\t * Return elFinder.command instance or instances array
\t *
\t * @param  String  command name
\t * @return Object | Array
\t */
\tthis.getCommand = function(name) {
\t\treturn name === void(0) ? this._commands : this._commands[name];
\t};
\t
\t/**
\t * Resize elfinder node
\t * 
\t * @param  String|Number  width
\t * @param  String|Number  height
\t * @return void
\t */
\tthis.resize = function(w, h) {
\t\tvar getMargin = function() {
\t\t\t\tvar m = node.outerHeight(true) - node.innerHeight(),
\t\t\t\t\tp = node;
\t\t\t\t
\t\t\t\twhile(p.get(0) !== heightBase.get(0)) {
\t\t\t\t\tp = p.parent();
\t\t\t\t\tm += p.outerHeight(true) - p.innerHeight();
\t\t\t\t\tif (! p.parent().length) {
\t\t\t\t\t\t// reached the document
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn m;
\t\t\t},
\t\t\tfit = ! node.hasClass('ui-resizable'),
\t\t\tprv = node.data('resizeSize') || {w: 0, h: 0},
\t\t\tmt, size = {};

\t\tif (heightBase && heightBase.data('resizeTm')) {
\t\t\tclearTimeout(heightBase.data('resizeTm'));
\t\t}
\t\t
\t\tif (typeof h === 'string') {
\t\t\tif (mt = h.match(/^([0-9.]+)%\$/)) {
\t\t\t\t// setup heightBase
\t\t\t\tif (! heightBase || ! heightBase.length) {
\t\t\t\t\theightBase = \$(window);
\t\t\t\t}
\t\t\t\tif (! heightBase.data('marginToMyNode')) {
\t\t\t\t\theightBase.data('marginToMyNode', getMargin());
\t\t\t\t}
\t\t\t\tif (! heightBase.data('fitToBaseFunc')) {
\t\t\t\t\theightBase.data('fitToBaseFunc', function(e) {
\t\t\t\t\t\tvar tm = heightBase.data('resizeTm');
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\ttm && cancelAnimationFrame(tm);
\t\t\t\t\t\tif (! node.hasClass('elfinder-fullscreen') && (!self.UA.Mobile || heightBase.data('rotated') !== self.UA.Rotated)) {
\t\t\t\t\t\t\theightBase.data('rotated', self.UA.Rotated);
\t\t\t\t\t\t\theightBase.data('resizeTm', requestAnimationFrame(function() {
\t\t\t\t\t\t\t\tself.restoreSize();
\t\t\t\t\t\t\t}));
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (typeof heightBase.data('rotated') === 'undefined') {
\t\t\t\t\theightBase.data('rotated', self.UA.Rotated);
\t\t\t\t}
\t\t\t\th = heightBase.height() * (mt[1] / 100) - heightBase.data('marginToMyNode');
\t\t\t\t
\t\t\t\theightBase.off('resize.' + self.namespace, heightBase.data('fitToBaseFunc'));
\t\t\t\tfit && heightBase.on('resize.' + self.namespace, heightBase.data('fitToBaseFunc'));
\t\t\t}
\t\t}
\t\t
\t\tnode.css({ width : w, height : parseInt(h) });
\t\tsize.w = Math.round(node.width());
\t\tsize.h = Math.round(node.height());
\t\tnode.data('resizeSize', size);
\t\tif (size.w !== prv.w || size.h !== prv.h) {
\t\t\tnode.trigger('resize');
\t\t\tthis.trigger('resize', {width : size.w, height : size.h});
\t\t}
\t};
\t
\t/**
\t * Restore elfinder node size
\t * 
\t * @return elFinder
\t */
\tthis.restoreSize = function() {
\t\tthis.resize(width, height);
\t};
\t
\tthis.show = function() {
\t\tnode.show();
\t\tthis.enable().trigger('show');
\t};
\t
\tthis.hide = function() {
\t\tif (this.options.enableAlways) {
\t\t\tprevEnabled = enabled;
\t\t\tenabled = false;
\t\t}
\t\tthis.disable();
\t\tthis.trigger('hide');
\t\tnode.hide();
\t};
\t
\t/**
\t * Lazy execution function
\t * 
\t * @param  Object  function
\t * @param  Number  delay
\t * @param  Object  options
\t * @return Object  jQuery.Deferred
\t */
\tthis.lazy = function(func, delay, opts) {
\t\tvar busy = function(state) {
\t\t\t\tvar cnt = node.data('lazycnt'),
\t\t\t\t\trepaint;
\t\t\t\t
\t\t\t\tif (state) {
\t\t\t\t\trepaint = node.data('lazyrepaint')? false : opts.repaint;
\t\t\t\t\tif (! cnt) {
\t\t\t\t\t\tnode.data('lazycnt', 1)
\t\t\t\t\t\t\t.addClass('elfinder-processing');
\t\t\t\t\t} else {
\t\t\t\t\t\tnode.data('lazycnt', ++cnt);
\t\t\t\t\t}
\t\t\t\t\tif (repaint) {
\t\t\t\t\t\tnode.data('lazyrepaint', true).css('display'); // force repaint
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (cnt && cnt > 1) {
\t\t\t\t\t\tnode.data('lazycnt', --cnt);
\t\t\t\t\t} else {
\t\t\t\t\t\trepaint = node.data('lazyrepaint');
\t\t\t\t\t\tnode.data('lazycnt', 0)
\t\t\t\t\t\t\t.removeData('lazyrepaint')
\t\t\t\t\t\t\t.removeClass('elfinder-processing');
\t\t\t\t\t\trepaint && node.css('display'); // force repaint;
\t\t\t\t\t\tself.trigger('lazydone');
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tdfd  = \$.Deferred(),
\t\t\tcallFunc = function() {
\t\t\t\tdfd.resolve(func.call(dfd));
\t\t\t\tbusy(false);
\t\t\t};
\t\t
\t\tdelay = delay || 0;
\t\topts = opts || {};
\t\tbusy(true);
\t\t
\t\tif (delay) {
\t\t\tsetTimeout(callFunc, delay);
\t\t} else {
\t\t\trequestAnimationFrame(callFunc);
\t\t}
\t\t
\t\treturn dfd;
\t};
\t
\t/**
\t * Destroy this elFinder instance
\t *
\t * @return void
\t **/
\tthis.destroy = function() {
\t\tif (node && node[0].elfinder) {
\t\t\tnode.hasClass('elfinder-fullscreen') && self.toggleFullscreen(node);
\t\t\tthis.options.syncStart = false;
\t\t\tthis.autoSync('forcestop');
\t\t\tthis.trigger('destroy').disable();
\t\t\tclipboard = [];
\t\t\tselected = [];
\t\t\tlisteners = {};
\t\t\tshortcuts = {};
\t\t\t\$(window).off('.' + namespace);
\t\t\t\$(document).off('.' + namespace);
\t\t\tself.trigger = function(){};
\t\t\t\$(beeper).remove();
\t\t\tnode.off()
\t\t\t\t.removeData()
\t\t\t\t.empty()
\t\t\t\t.append(prevContent.contents())
\t\t\t\t.attr('class', prevContent.attr('class'))
\t\t\t\t.attr('style', prevContent.attr('style'));
\t\t\tdelete node[0].elfinder;
\t\t\t// restore kept events
\t\t\t\$.each(prevEvents, function(n, arr) {
\t\t\t\t\$.each(arr, function(i, o) {
\t\t\t\t\tnode.on(o.type + (o.namespace? '.'+o.namespace : ''), o.selector, o.handler);
\t\t\t\t});
\t\t\t});
\t\t}
\t};
\t
\t/**
\t * Start or stop auto sync
\t * 
\t * @param  String|Bool  stop
\t * @return void
\t */
\tthis.autoSync = function(mode) {
\t\tvar sync;
\t\tif (self.options.sync >= 1000) {
\t\t\tif (syncInterval) {
\t\t\t\tclearTimeout(syncInterval);
\t\t\t\tsyncInterval = null;
\t\t\t\tself.trigger('autosync', {action : 'stop'});
\t\t\t}
\t\t\t
\t\t\tif (mode === 'stop') {
\t\t\t\t++autoSyncStop;
\t\t\t} else {
\t\t\t\tautoSyncStop = Math.max(0, --autoSyncStop);
\t\t\t}
\t\t\t
\t\t\tif (autoSyncStop || mode === 'forcestop' || ! self.options.syncStart) {
\t\t\t\treturn;
\t\t\t} 
\t\t\t
\t\t\t// run interval sync
\t\t\tsync = function(start){
\t\t\t\tvar timeout;
\t\t\t\tif (cwdOptions.syncMinMs && (start || syncInterval)) {
\t\t\t\t\tstart && self.trigger('autosync', {action : 'start'});
\t\t\t\t\ttimeout = Math.max(self.options.sync, cwdOptions.syncMinMs);
\t\t\t\t\tsyncInterval && clearTimeout(syncInterval);
\t\t\t\t\tsyncInterval = setTimeout(function() {
\t\t\t\t\t\tvar dosync = true, hash = cwd, cts;
\t\t\t\t\t\tif (cwdOptions.syncChkAsTs && files[hash] && (cts = files[hash].ts)) {
\t\t\t\t\t\t\tself.request({
\t\t\t\t\t\t\t\tdata : {cmd : 'info', targets : [hash], compare : cts, reload : 1},
\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function(data){
\t\t\t\t\t\t\t\tvar ts;
\t\t\t\t\t\t\t\tdosync = true;
\t\t\t\t\t\t\t\tif (data.compare) {
\t\t\t\t\t\t\t\t\tts = data.compare;
\t\t\t\t\t\t\t\t\tif (ts == cts) {
\t\t\t\t\t\t\t\t\t\tdosync = false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (dosync) {
\t\t\t\t\t\t\t\t\tself.sync(hash).always(function(){
\t\t\t\t\t\t\t\t\t\tif (ts) {
\t\t\t\t\t\t\t\t\t\t\t// update ts for cache clear etc.
\t\t\t\t\t\t\t\t\t\t\tfiles[hash].ts = ts;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tsync();
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tsync();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function(error, xhr){
\t\t\t\t\t\t\t\tvar err = self.parseError(error);
\t\t\t\t\t\t\t\tif (err && xhr.status != 0) {
\t\t\t\t\t\t\t\t\tself.error(err);
\t\t\t\t\t\t\t\t\tif (Array.isArray(err) && \$.inArray('errOpen', err) !== -1) {
\t\t\t\t\t\t\t\t\t\tself.request({
\t\t\t\t\t\t\t\t\t\t\tdata   : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1},
\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'open', cnt : 1, hideCnt : true}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tsyncInterval = setTimeout(function() {
\t\t\t\t\t\t\t\t\t\tsync();
\t\t\t\t\t\t\t\t\t}, timeout);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tself.sync(cwd, true).always(function(){
\t\t\t\t\t\t\t\tsync();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}, timeout);
\t\t\t\t}
\t\t\t};
\t\t\tsync(true);
\t\t}
\t};
\t
\t/**
\t * Return bool is inside work zone of specific point
\t * 
\t * @param  Number event.pageX
\t * @param  Number event.pageY
\t * @return Bool
\t */
\tthis.insideWorkzone = function(x, y, margin) {
\t\tvar rectangle = this.getUI('workzone').data('rectangle');
\t\t
\t\tmargin = margin || 1;
\t\tif (x < rectangle.left + margin
\t\t|| x > rectangle.left + rectangle.width + margin
\t\t|| y < rectangle.top + margin
\t\t|| y > rectangle.top + rectangle.height + margin) {
\t\t\treturn false;
\t\t}
\t\treturn true;
\t};
\t
\t/**
\t * Target ui node move to last of children of elFinder node fot to show front
\t * 
\t * @param  Object  target    Target jQuery node object
\t */
\tthis.toFront = function(target) {
\t\tvar nodes = node.children('.ui-front').removeClass('elfinder-frontmost'),
\t\t\tlastnode = nodes.last();
\t\tnodes.css('z-index', '');
\t\t\$(target).addClass('ui-front elfinder-frontmost').css('z-index', lastnode.css('z-index') + 1);
\t};
\t
\t/**
\t * Remove class 'elfinder-frontmost' and hide() to target ui node
\t *
\t * @param      Object   target  Target jQuery node object
\t * @param      Boolean  nohide  Do not hide
\t */
\tthis.toHide =function(target, nohide) {
\t\tvar tgt = \$(target),
\t\t\tlast;

\t\t!nohide && tgt.hide();
\t\tif (tgt.hasClass('elfinder-frontmost')) {
\t\t\ttgt.removeClass('elfinder-frontmost');
\t\t\tlast = node.children('.ui-front:visible:not(.elfinder-frontmost)').last();
\t\t\tif (last.length) {
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tif (!node.children('.elfinder-frontmost:visible').length) {
\t\t\t\t\t\tself.toFront(last);
\t\t\t\t\t\tlast.trigger('frontmost');
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t}
\t};

\t/**
\t * Return css object for maximize
\t * 
\t * @return Object
\t */
\tthis.getMaximizeCss = function() {
\t\treturn {
\t\t\twidth   : '100%',
\t\t\theight  : '100%',
\t\t\tmargin  : 0,
\t\t\ttop     : 0,
\t\t\tleft    : 0,
\t\t\tdisplay : 'block',
\t\t\tposition: 'fixed',
\t\t\tzIndex  : Math.max(self.zIndex? (self.zIndex + 1) : 0 , 1000),
\t\t\tmaxWidth : '',
\t\t\tmaxHeight: ''
\t\t};
\t};
\t
\t// Closure for togglefullscreen
\t(function() {
\t\t// check is in iframe
\t\tif (inFrame && self.UA.Fullscreen) {
\t\t\tself.UA.Fullscreen = false;
\t\t\tif (parentIframe && typeof parentIframe.attr('allowfullscreen') !== 'undefined') {
\t\t\t\tself.UA.Fullscreen = true;
\t\t\t}
\t\t}

\t\tvar orgStyle, bodyOvf, resizeTm, fullElm, exitFull, toFull, funcObj,
\t\t\tcls = 'elfinder-fullscreen',
\t\t\tclsN = 'elfinder-fullscreen-native',
\t\t\tcheckDialog = function() {
\t\t\t\tvar t = 0,
\t\t\t\t\tl = 0;
\t\t\t\t\$.each(node.children('.ui-dialog,.ui-draggable'), function(i, d) {
\t\t\t\t\tvar \$d = \$(d),
\t\t\t\t\t\tpos = \$d.position();
\t\t\t\t\t
\t\t\t\t\tif (pos.top < 0) {
\t\t\t\t\t\t\$d.css('top', t);
\t\t\t\t\t\tt += 20;
\t\t\t\t\t}
\t\t\t\t\tif (pos.left < 0) {
\t\t\t\t\t\t\$d.css('left', l);
\t\t\t\t\t\tl += 20;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\tsetFuncObj = function() {
\t\t\t\tvar useFullscreen = self.storage('useFullscreen');
\t\t\t\tfuncObj = self.UA.Fullscreen && (useFullscreen? useFullscreen > 0 : self.options.commandsOptions.fullscreen.mode === 'screen') ? {
\t\t\t\t\t// native full screen mode
\t\t\t\t\t
\t\t\t\t\tfullElm: function() {
\t\t\t\t\t\treturn document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null;
\t\t\t\t\t},
\t\t\t\t\t
\t\t\t\t\texitFull: function() {
\t\t\t\t\t\tif (document.exitFullscreen) {
\t\t\t\t\t\t\treturn document.exitFullscreen();
\t\t\t\t\t\t} else if (document.webkitExitFullscreen) {
\t\t\t\t\t\t\treturn document.webkitExitFullscreen();
\t\t\t\t\t\t} else if (document.mozCancelFullScreen) {
\t\t\t\t\t\t\treturn document.mozCancelFullScreen();
\t\t\t\t\t\t} else if (document.msExitFullscreen) {
\t\t\t\t\t\t\treturn document.msExitFullscreen();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\t
\t\t\t\t\ttoFull: function(elem) {
\t\t\t\t\t\tif (elem.requestFullscreen) {
\t\t\t\t\t\t\treturn elem.requestFullscreen();
\t\t\t\t\t\t} else if (elem.webkitRequestFullscreen) {
\t\t\t\t\t\t\treturn elem.webkitRequestFullscreen();
\t\t\t\t\t\t} else if (elem.mozRequestFullScreen) {
\t\t\t\t\t\t\treturn elem.mozRequestFullScreen();
\t\t\t\t\t\t} else if (elem.msRequestFullscreen) {
\t\t\t\t\t\t\treturn elem.msRequestFullscreen();
\t\t\t\t\t\t}
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t} : {
\t\t\t\t\t// node element maximize mode
\t\t\t\t\t
\t\t\t\t\tfullElm: function() {
\t\t\t\t\t\tvar full;
\t\t\t\t\t\tif (node.hasClass(cls)) {
\t\t\t\t\t\t\treturn node.get(0);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfull = node.find('.' + cls);
\t\t\t\t\t\t\tif (full.length) {
\t\t\t\t\t\t\t\treturn full.get(0);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn null;
\t\t\t\t\t},
\t\t\t\t\t
\t\t\t\t\texitFull: function() {
\t\t\t\t\t\tvar elm;
\t\t\t\t\t\t
\t\t\t\t\t\t\$(window).off('resize.' + namespace, resize);
\t\t\t\t\t\tif (bodyOvf !== void(0)) {
\t\t\t\t\t\t\t\$('body').css('overflow', bodyOvf);
\t\t\t\t\t\t}
\t\t\t\t\t\tbodyOvf = void(0);
\t\t\t\t\t\t
\t\t\t\t\t\tif (orgStyle) {
\t\t\t\t\t\t\telm = orgStyle.elm;
\t\t\t\t\t\t\trestoreStyle(elm);
\t\t\t\t\t\t\t\$(elm).trigger('resize', {fullscreen: 'off'});
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t\$(window).trigger('resize');
\t\t\t\t\t},
\t\t\t\t\t
\t\t\t\t\ttoFull: function(elem) {
\t\t\t\t\t\tbodyOvf = \$('body').css('overflow') || '';
\t\t\t\t\t\t\$('body').css('overflow', 'hidden');
\t\t\t\t\t\t
\t\t\t\t\t\t\$(elem).css(self.getMaximizeCss())
\t\t\t\t\t\t\t.addClass(cls)
\t\t\t\t\t\t\t.trigger('resize', {fullscreen: 'on'});
\t\t\t\t\t\t
\t\t\t\t\t\tcheckDialog();
\t\t\t\t\t\t
\t\t\t\t\t\t\$(window).on('resize.' + namespace, resize).trigger('resize');
\t\t\t\t\t\t
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t};
\t\t\t},
\t\t\trestoreStyle = function(elem) {
\t\t\t\tif (orgStyle && orgStyle.elm == elem) {
\t\t\t\t\t\$(elem).removeClass(cls + ' ' + clsN).attr('style', orgStyle.style);
\t\t\t\t\torgStyle = null;
\t\t\t\t}
\t\t\t},
\t\t\tresize = function(e) {
\t\t\t\tvar elm;
\t\t\t\tif (e.target === window) {
\t\t\t\t\tresizeTm && cancelAnimationFrame(resizeTm);
\t\t\t\t\tresizeTm = requestAnimationFrame(function() {
\t\t\t\t\t\tif (elm = funcObj.fullElm()) {
\t\t\t\t\t\t\t\$(elm).trigger('resize', {fullscreen: 'on'});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t};
\t\t
\t\tsetFuncObj();

\t\t\$(document).on('fullscreenchange.' + namespace + ' webkitfullscreenchange.' + namespace + ' mozfullscreenchange.' + namespace + ' MSFullscreenChange.' + namespace, function(e){
\t\t\tif (self.UA.Fullscreen) {
\t\t\t\tvar elm = funcObj.fullElm(),
\t\t\t\t\twin = \$(window);
\t\t\t\t
\t\t\t\tresizeTm && cancelAnimationFrame(resizeTm);
\t\t\t\tif (elm === null) {
\t\t\t\t\twin.off('resize.' + namespace, resize);
\t\t\t\t\tif (orgStyle) {
\t\t\t\t\t\telm = orgStyle.elm;
\t\t\t\t\t\trestoreStyle(elm);
\t\t\t\t\t\t\$(elm).trigger('resize', {fullscreen: 'off'});
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\t\$(elm).addClass(cls + ' ' + clsN)
\t\t\t\t\t\t.attr('style', 'width:100%; height:100%; margin:0; padding:0;')
\t\t\t\t\t\t.trigger('resize', {fullscreen: 'on'});
\t\t\t\t\twin.on('resize.' + namespace, resize);
\t\t\t\t\tcheckDialog();
\t\t\t\t}
\t\t\t\twin.trigger('resize');
\t\t\t}
\t\t});
\t\t
\t\t/**
\t\t * Toggle Full Scrren Mode
\t\t * 
\t\t * @param  Object target
\t\t * @param  Bool   full
\t\t * @return Object | Null  DOM node object of current full scrren
\t\t */
\t\tself.toggleFullscreen = function(target, full) {
\t\t\tvar elm = \$(target).get(0),
\t\t\t\tcurElm = null;
\t\t\t
\t\t\tcurElm = funcObj.fullElm();
\t\t\tif (curElm) {
\t\t\t\tif (curElm == elm) {
\t\t\t\t\tif (full === true) {
\t\t\t\t\t\treturn curElm;
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (full === false) {
\t\t\t\t\t\treturn curElm;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tfuncObj.exitFull();
\t\t\t\treturn null;
\t\t\t} else {
\t\t\t\tif (full === false) {
\t\t\t\t\treturn null;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tsetFuncObj();
\t\t\torgStyle = {elm: elm, style: \$(elm).attr('style')};
\t\t\tif (funcObj.toFull(elm) !== false) {
\t\t\t\treturn elm;
\t\t\t} else {
\t\t\t\torgStyle = null;
\t\t\t\treturn null;
\t\t\t}
\t\t};
\t})();
\t
\t// Closure for toggleMaximize
\t(function(){
\t\tvar cls = 'elfinder-maximized',
\t\tresizeTm,
\t\tresize = function(e) {
\t\t\tif (e.target === window && e.data && e.data.elm) {
\t\t\t\tvar elm = e.data.elm;
\t\t\t\tresizeTm && cancelAnimationFrame(resizeTm);
\t\t\t\tresizeTm = requestAnimationFrame(function() {
\t\t\t\t\telm.trigger('resize', {maximize: 'on'});
\t\t\t\t});
\t\t\t}
\t\t},
\t\texitMax = function(elm) {
\t\t\t\$(window).off('resize.' + namespace, resize);
\t\t\t\$('body').css('overflow', elm.data('bodyOvf'));
\t\t\telm.removeClass(cls)
\t\t\t\t.attr('style', elm.data('orgStyle'))
\t\t\t\t.removeData('bodyOvf')
\t\t\t\t.removeData('orgStyle');
\t\t\telm.trigger('resize', {maximize: 'off'});
\t\t},
\t\ttoMax = function(elm) {
\t\t\telm.data('bodyOvf', \$('body').css('overflow') || '')
\t\t\t\t.data('orgStyle', elm.attr('style'))
\t\t\t\t.addClass(cls)
\t\t\t\t.css(self.getMaximizeCss());
\t\t\t\$('body').css('overflow', 'hidden');
\t\t\t\$(window).on('resize.' + namespace, {elm: elm}, resize);
\t\t\telm.trigger('resize', {maximize: 'on'});
\t\t};
\t\t
\t\t/**
\t\t * Toggle Maximize target node
\t\t * 
\t\t * @param  Object target
\t\t * @param  Bool   max
\t\t * @return void
\t\t */
\t\tself.toggleMaximize = function(target, max) {
\t\t\tvar elm = \$(target),
\t\t\t\tmaximized = elm.hasClass(cls);
\t\t\t
\t\t\tif (maximized) {
\t\t\t\tif (max === true) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\texitMax(elm);
\t\t\t} else {
\t\t\t\tif (max === false) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\ttoMax(elm);
\t\t\t}
\t\t};
\t})();
\t
\t/*************  init stuffs  ****************/
\tObject.assign(\$.ui.keyCode, {
\t\t'F1' : 112,
\t\t'F2' : 113,
\t\t'F3' : 114,
\t\t'F4' : 115,
\t\t'F5' : 116,
\t\t'F6' : 117,
\t\t'F7' : 118,
\t\t'F8' : 119,
\t\t'F9' : 120,
\t\t'F10' : 121,
\t\t'F11' : 122,
\t\t'F12' : 123,
\t\t'DIG0' : 48,
\t\t'DIG1' : 49,
\t\t'DIG2' : 50,
\t\t'DIG3' : 51,
\t\t'DIG4' : 52,
\t\t'DIG5' : 53,
\t\t'DIG6' : 54,
\t\t'DIG7' : 55,
\t\t'DIG8' : 56,
\t\t'DIG9' : 57,
\t\t'NUM0' : 96,
\t\t'NUM1' : 97,
\t\t'NUM2' : 98,
\t\t'NUM3' : 99,
\t\t'NUM4' : 100,
\t\t'NUM5' : 101,
\t\t'NUM6' : 102,
\t\t'NUM7' : 103,
\t\t'NUM8' : 104,
\t\t'NUM9' : 105,
\t\t'CONTEXTMENU' : 93,
\t\t'DOT'  : 190
\t});
\t
\tthis.dragUpload = false;
\tthis.xhrUpload  = (typeof XMLHttpRequestUpload != 'undefined' || typeof XMLHttpRequestEventTarget != 'undefined') && typeof File != 'undefined' && typeof FormData != 'undefined';
\t
\t// configure transport object
\tthis.transport = {};

\tif (typeof(this.options.transport) == 'object') {
\t\tthis.transport = this.options.transport;
\t\tif (typeof(this.transport.init) == 'function') {
\t\t\tthis.transport.init(this);
\t\t}
\t}
\t
\tif (typeof(this.transport.send) != 'function') {
\t\tthis.transport.send = function(opts) {
\t\t\tif (!self.UA.IE) {
\t\t\t\t// keep native xhr object for handling property responseURL
\t\t\t\topts._xhr = new XMLHttpRequest();
\t\t\t\topts.xhr = function() { 
\t\t\t\t\tif (opts.progress) {
\t\t\t\t\t\topts._xhr.addEventListener('progress', opts.progress); 
\t\t\t\t\t}
\t\t\t\t\treturn opts._xhr;
\t\t\t\t};
\t\t\t}
\t\t\treturn \$.ajax(opts);
\t\t};
\t}
\t
\tif (this.transport.upload == 'iframe') {
\t\tthis.transport.upload = \$.proxy(this.uploads.iframe, this);
\t} else if (typeof(this.transport.upload) == 'function') {
\t\tthis.dragUpload = !!this.options.dragUploadAllow;
\t} else if (this.xhrUpload && !!this.options.dragUploadAllow) {
\t\tthis.transport.upload = \$.proxy(this.uploads.xhr, this);
\t\tthis.dragUpload = true;
\t} else {
\t\tthis.transport.upload = \$.proxy(this.uploads.iframe, this);
\t}

\t/**
\t * Decoding 'raw' string converted to unicode
\t * 
\t * @param  String str
\t * @return String
\t */
\tthis.decodeRawString = function(str) {
\t\tvar charCodes = function(str) {
\t\t\tvar i, len, arr;
\t\t\tfor (i=0,len=str.length,arr=[]; i<len; i++) {
\t\t\t\tarr.push(str.charCodeAt(i));
\t\t\t}
\t\t\treturn arr;
\t\t},
\t\tscalarValues = function(arr) {
\t\t\tvar scalars = [], i, len, c;
\t\t\tif (typeof arr === 'string') {arr = charCodes(arr);}
\t\t\tfor (i=0,len=arr.length; c=arr[i],i<len; i++) {
\t\t\t\tif (c >= 0xd800 && c <= 0xdbff) {
\t\t\t\t\tscalars.push((c & 1023) + 64 << 10 | arr[++i] & 1023);
\t\t\t\t} else {
\t\t\t\t\tscalars.push(c);
\t\t\t\t}
\t\t\t}
\t\t\treturn scalars;
\t\t},
\t\tdecodeUTF8 = function(arr) {
\t\t\tvar i, len, c, str, char = String.fromCharCode;
\t\t\tfor (i=0,len=arr.length,str=\"\"; c=arr[i],i<len; i++) {
\t\t\t\tif (c <= 0x7f) {
\t\t\t\t\tstr += char(c);
\t\t\t\t} else if (c <= 0xdf && c >= 0xc2) {
\t\t\t\t\tstr += char((c&31)<<6 | arr[++i]&63);
\t\t\t\t} else if (c <= 0xef && c >= 0xe0) {
\t\t\t\t\tstr += char((c&15)<<12 | (arr[++i]&63)<<6 | arr[++i]&63);
\t\t\t\t} else if (c <= 0xf7 && c >= 0xf0) {
\t\t\t\t\tstr += char(
\t\t\t\t\t\t0xd800 | ((c&7)<<8 | (arr[++i]&63)<<2 | arr[++i]>>>4&3) - 64,
\t\t\t\t\t\t0xdc00 | (arr[i++]&15)<<6 | arr[i]&63
\t\t\t\t\t);
\t\t\t\t} else {
\t\t\t\t\tstr += char(0xfffd);
\t\t\t\t}
\t\t\t}
\t\t\treturn str;
\t\t};
\t\t
\t\treturn decodeUTF8(scalarValues(str));
\t};

\t/**
\t * Gets target file contents by file.hash
\t *
\t * @param      String  hash          The hash
\t * @param      String  responseType  'blob' or 'arraybuffer' (default)
\t * @param      Object  requestOpts   The request options
\t * @return     arraybuffer|blob  The contents.
\t */
\tthis.getContents = function(hash, responseType, requestOpts) {
\t\tvar self = this,
\t\t\tdfd = \$.Deferred(),
\t\t\ttype = responseType || 'arraybuffer',
\t\t\turl, req;

\t\tdfd.fail(function() {
\t\t\treq && req.state() === 'pending' && req.reject();
\t\t});

\t\turl = self.openUrl(hash);
\t\tif (!self.isSameOrigin(url)) {
\t\t\turl = self.openUrl(hash, true);
\t\t}
\t\treq = self.request(Object.assign({
\t\t\tdata    : {cmd : 'get'},
\t\t\toptions : {
\t\t\t\turl: url,
\t\t\t\ttype: 'get',
\t\t\t\tcache : true,
\t\t\t\tdataType : 'binary',
\t\t\t\tresponseType : type,
\t\t\t\tprocessData: false
\t\t\t},
\t\t\tnotify : {
\t\t\t\ttype: 'file',
\t\t\t\tcnt: 1,
\t\t\t\thideCnt: true
\t\t\t},
\t\t\tcancel : true
\t\t}, requestOpts || {}))
\t\t.fail(function() {
\t\t\tdfd.reject();
\t\t})
\t\t.done(function(data) {
\t\t\tdfd.resolve(data);
\t\t});

\t\treturn dfd;
\t};

\t/**
\t * Gets the binary by url.
\t *
\t * @param      {Object}    opts      The options
\t * @param      {Function}  callback  The callback
\t * @param      {Object}    requestOpts The request options
\t * @return     arraybuffer|blob  The contents.
\t */
\tthis.getBinaryByUrl = function(opts, callback, requestOpts) {
\t\tvar self = this,
\t\t\tdfd = \$.Deferred(),
\t\t\turl, req;

\t\tdfd.fail(function() {
\t\t\treq && req.state() === 'pending' && req.reject();
\t\t});

\t\treq = self.request(Object.assign({
\t\t\tdata    : {cmd : 'get'},
\t\t\toptions : Object.assign({
\t\t\t\ttype: 'get',
\t\t\t\tcache : true,
\t\t\t\tdataType : 'binary',
\t\t\t\tresponseType : 'blob',
\t\t\t\tprocessData: false
\t\t\t}, opts)
\t\t}, requestOpts || {}))
\t\t.fail(function() {
\t\t\tdfd.reject();
\t\t})
\t\t.done(function(data) {
\t\t\tcallback && callback(data);
\t\t\tdfd.resolve(data);
\t\t});

\t\treturn dfd;
\t};

\t/**
\t * Gets the mimetype.
\t *
\t * @param      {string}  name     The name
\t * @param      {string}  orgMime  The organization mime
\t * @return     {string}  The mimetype.
\t */
\tthis.getMimetype = function(name, orgMime) {
\t\tvar mime = orgMime,
\t\t\text, m;
\t\tm = (name + '').match(/\\.([^.]+)\$/);
\t\tif (m && (ext = m[1])) {
\t\t\tif (!extToMimeTable) {
\t\t\t\textToMimeTable = self.arrayFlip(self.mimeTypes);
\t\t\t}
\t\t\tif (!(mime = extToMimeTable[ext.toLowerCase()])) {
\t\t\t\tmime = orgMime;
\t\t\t}
\t\t}
\t\treturn mime;
\t};

\t/**
\t * Supported check hash algorisms
\t * 
\t * @type Array
\t */
\tself.hashCheckers = [];

\t/**
\t * Closure of getContentsHashes()
\t */
\t(function(self) {
\t\tvar hashLibs = {};

\t\tif (window.Worker && window.ArrayBuffer) {
\t\t\t// make fm.hashCheckers
\t\t\tif (self.options.cdns.sparkmd5) {
\t\t\t\thashLibs.SparkMD5 = true;
\t\t\t\tself.hashCheckers.push('md5');
\t\t\t}
\t\t\tif (self.options.cdns.jssha) {
\t\t\t\thashLibs.jsSHA = true;
\t\t\t\tself.hashCheckers = self.hashCheckers.concat(['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'shake128', 'shake256']);
\t\t\t}
\t\t}

\t\t/**
\t\t * Gets the contents hashes.
\t\t *
\t\t * @param      String  target      target file.hash
\t\t * @param      Object  needHashes  need hash lib names
\t\t * @param      Object  requestOpts The request options
\t\t * @return     Object  hashes with lib name as key
\t\t */
\t\tself.getContentsHashes = function(target, needHashes, hashOpts, requestOpts) {
\t\t\tvar dfd = \$.Deferred(),
\t\t\t\tneeds = self.arrayFlip(needHashes || ['md5'], true),
\t\t\t\tlibs = [],
\t\t\t\tjobs = [],
\t\t\t\tres = {},
\t\t\t\topts = hashOpts? hashOpts : {
\t\t\t\t\tshake128len : 256,
\t\t\t\t\tshake256len : 512
\t\t\t\t},
\t\t\t\treq;

\t\t\tdfd.fail(function() {
\t\t\t\treq && req.reject();
\t\t\t});

\t\t\tif (Object.keys(hashLibs).length) {
\t\t\t\treq = self.getContents(target, 'arraybuffer', requestOpts).done(function(arrayBuffer) {
\t\t\t\t\tif (needs.md5 && hashLibs.SparkMD5) {
\t\t\t\t\t\tjobs.push((function() {
\t\t\t\t\t\t\tvar job = \$.Deferred();
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tvar wk = self.getWorker();
\t\t\t\t\t\t\t\tjob.fail(function() {
\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\twk.onmessage = function(ans) {
\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\tif (ans.data.hash) {
\t\t\t\t\t\t\t\t\t\tvar f;
\t\t\t\t\t\t\t\t\t\tres.md5 = ans.data.hash;
\t\t\t\t\t\t\t\t\t\tif (f = self.file(target)) {
\t\t\t\t\t\t\t\t\t\t\tf.md5 = res.md5;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t} else if (ans.data.error) {
\t\t\t\t\t\t\t\t\t\tres.md5 = ans.data.error;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tdfd.notify(res);
\t\t\t\t\t\t\t\t\tjob.resolve();
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\twk.onerror = function(e) {
\t\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\tscripts: [self.options.cdns.sparkmd5, self.getWorkerUrl('calcfilehash.js')],
\t\t\t\t\t\t\t\t\tdata: { type: 'md5', bin: arrayBuffer }
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tdfd.fail(function() {
\t\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\tdelete hashLibs.SparkMD5;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\treturn job;
\t\t\t\t\t\t})());
\t\t\t\t\t}
\t\t\t\t\tif (hashLibs.jsSHA) {
\t\t\t\t\t\t\$.each(['1', '224', '256', '384', '512', '3-224', '3-256', '3-384', '3-512', 'ke128', 'ke256'], function(i, v) {
\t\t\t\t\t\t\tif (needs['sha' + v]) {
\t\t\t\t\t\t\t\tjobs.push((function() {
\t\t\t\t\t\t\t\t\tvar job = \$.Deferred();
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tvar wk = self.getWorker();
\t\t\t\t\t\t\t\t\t\tjob.fail(function() {
\t\t\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\twk.onmessage = function(ans) {
\t\t\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\t\t\tif (ans.data.hash) {
\t\t\t\t\t\t\t\t\t\t\t\tvar f;
\t\t\t\t\t\t\t\t\t\t\t\tres['sha' + v] = ans.data.hash;
\t\t\t\t\t\t\t\t\t\t\t\tif (f = self.file(target)) {
\t\t\t\t\t\t\t\t\t\t\t\t\tf['sha' + v] = res['sha' + v];
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t} else if (ans.data.error) {
\t\t\t\t\t\t\t\t\t\t\t\tres['sha' + v] = ans.data.error;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\tdfd.notify(res);
\t\t\t\t\t\t\t\t\t\t\tjob.resolve();
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\twk.onerror = function(e) {
\t\t\t\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\t\t\tscripts: [self.options.cdns.jssha, self.getWorkerUrl('calcfilehash.js')],
\t\t\t\t\t\t\t\t\t\t\tdata: { type: v, bin: arrayBuffer, hashOpts: opts }
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tdfd.fail(function() {
\t\t\t\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\t\tjob.reject();
\t\t\t\t\t\t\t\t\t\tdelete hashLibs.jsSHA;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\treturn job;
\t\t\t\t\t\t\t\t})());
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tif (jobs.length) {
\t\t\t\t\t\t\$.when.apply(null, jobs).always(function() {
\t\t\t\t\t\t\tdfd.resolve(res);
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t}
\t\t\t\t}).fail(function() {
\t\t\t\t\tdfd.reject();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfd.reject();
\t\t\t}

\t\t\treturn dfd;
\t\t};
\t})(this);

\t/**
\t * Parse error value to display
\t *
\t * @param  Mixed  error
\t * @return Mixed  parsed error
\t */
\tthis.parseError = function(error) {
\t\tvar arg = error;
\t\tif (\$.isPlainObject(arg)) {
\t\t\targ = arg.error;
\t\t}
\t\treturn arg;
\t};

\t/**
\t * Alias for this.trigger('error', {error : 'message'})
\t *
\t * @param  String  error message
\t * @return elFinder
\t **/
\tthis.error = function() {
\t\tvar arg = arguments[0],
\t\t\topts = arguments[1] || null,
\t\t\terr;
\t\tif (arguments.length == 1 && typeof(arg) === 'function') {
\t\t\treturn self.bind('error', arg);
\t\t} else {
\t\t\terr = this.parseError(arg);
\t\t\treturn (err === true || !err)? this : self.trigger('error', {error: err, opts : opts});
\t\t}
\t};
\t
\t// create bind/trigger aliases for build-in events
\t\$.each(events, function(i, name) {
\t\tself[name] = function() {
\t\t\tvar arg = arguments[0];
\t\t\treturn arguments.length == 1 && typeof(arg) == 'function'
\t\t\t\t? self.bind(name, arg)
\t\t\t\t: self.trigger(name, \$.isPlainObject(arg) ? arg : {});
\t\t};
\t});

\t// bind core event handlers
\tthis
\t\t.enable(function() {
\t\t\tif (!enabled && self.api && self.visible() && self.ui.overlay.is(':hidden') && ! node.children('.elfinder-dialog.' + self.res('class', 'editing') + ':visible').length) {
\t\t\t\tenabled = true;
\t\t\t\tdocument.activeElement && document.activeElement.blur();
\t\t\t\tnode.removeClass('elfinder-disabled');
\t\t\t}
\t\t})
\t\t.disable(function() {
\t\t\tprevEnabled = enabled;
\t\t\tenabled = false;
\t\t\tnode.addClass('elfinder-disabled');
\t\t})
\t\t.open(function() {
\t\t\tselected = [];
\t\t})
\t\t.select(function(e) {
\t\t\tvar cnt = 0,
\t\t\t\tunselects = [];
\t\t\tselected = \$.grep(e.data.selected || e.data.value|| [], function(hash) {
\t\t\t\tif (unselects.length || (self.maxTargets && ++cnt > self.maxTargets)) {
\t\t\t\t\tunselects.push(hash);
\t\t\t\t\treturn false;
\t\t\t\t} else {
\t\t\t\t\treturn files[hash] ? true : false;
\t\t\t\t}
\t\t\t});
\t\t\tif (unselects.length) {
\t\t\t\tself.trigger('unselectfiles', {files: unselects, inselect: true});
\t\t\t\tself.toast({mode: 'warning', msg: self.i18n(['errMaxTargets', self.maxTargets])});
\t\t\t}
\t\t})
\t\t.error(function(e) { 
\t\t\tvar opts  = {
\t\t\t\t\tcssClass  : 'elfinder-dialog-error',
\t\t\t\t\ttitle     : self.i18n('error'),
\t\t\t\t\tresizable : false,
\t\t\t\t\tdestroyOnClose : true,
\t\t\t\t\tbuttons   : {}
\t\t\t\t},
\t\t\t\tnode = self.getUI(),
\t\t\t\tcnt = node.children('.elfinder-dialog-error').length,
\t\t\t\tlast, counter;
\t\t\t
\t\t\tif (cnt < self.options.maxErrorDialogs) {
\t\t\t\topts.buttons[self.i18n(self.i18n('btnClose'))] = function() { \$(this).elfinderdialog('close'); };

\t\t\t\tif (e.data.opts && \$.isPlainObject(e.data.opts)) {
\t\t\t\t\tObject.assign(opts, e.data.opts);
\t\t\t\t}

\t\t\t\tself.dialog('<span class=\"elfinder-dialog-icon elfinder-dialog-icon-error\"></span>'+self.i18n(e.data.error), opts);
\t\t\t} else {
\t\t\t\tlast = node.children('.elfinder-dialog-error:last').children('.ui-dialog-content:first');
\t\t\t\tcounter = last.children('.elfinder-error-counter');
\t\t\t\tif (counter.length) {
\t\t\t\t\tcounter.data('cnt', parseInt(counter.data('cnt')) + 1).html(self.i18n(['moreErrors', counter.data('cnt')]));
\t\t\t\t} else {
\t\t\t\t\tcounter = \$('<span class=\"elfinder-error-counter\">'+ self.i18n(['moreErrors', 1]) +'</span>').data('cnt', 1);
\t\t\t\t\tlast.append('<br/>', counter);
\t\t\t\t}
\t\t\t}
\t\t})
\t\t.bind('tmb', function(e) {
\t\t\t\$.each(e.data.images||[], function(hash, tmb) {
\t\t\t\tif (files[hash]) {
\t\t\t\t\tfiles[hash].tmb = tmb;
\t\t\t\t}
\t\t\t});
\t\t})
\t\t.bind('searchstart', function(e) {
\t\t\tObject.assign(self.searchStatus, e.data);
\t\t\tself.searchStatus.state = 1;
\t\t})
\t\t.bind('search', function(e) {
\t\t\tself.searchStatus.state = 2;
\t\t})
\t\t.bind('searchend', function() {
\t\t\tself.searchStatus.state = 0;
\t\t\tself.searchStatus.ininc = false;
\t\t\tself.searchStatus.mixed = false;
\t\t})
\t\t.bind('canMakeEmptyFile', function(e) {
\t\t\tvar data = e.data,
\t\t\t\tobj = {};
\t\t\tif (data && Array.isArray(data.mimes)) {
\t\t\t\tif (!data.unshift) {
\t\t\t\t\tobj = self.mimesCanMakeEmpty;
\t\t\t\t}
\t\t\t\t\$.each(data.mimes, function() {
\t\t\t\t\tif (!obj[this]) {
\t\t\t\t\t\tobj[this] = self.mimeTypes[this];
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (data.unshift) {
\t\t\t\t\tself.mimesCanMakeEmpty = Object.assign(obj, self.mimesCanMakeEmpty);
\t\t\t\t}
\t\t\t}
\t\t})
\t\t.bind('themechange', function() {
\t\t\trequestAnimationFrame(function() {
\t\t\t\tself.trigger('uiresize');
\t\t\t});
\t\t})
\t\t;

\t// We listen and emit a sound on delete according to option
\tif (true === this.options.sound) {
\t\tthis.bind('playsound', function(e) {
\t\t\tvar play  = beeper.canPlayType && beeper.canPlayType('audio/wav; codecs=\"1\"'),
\t\t\t\tfile = e.data && e.data.soundFile;

\t\t\tplay && file && play != '' && play != 'no' && \$(beeper).html('<source src=\"' + soundPath + file + '\" type=\"audio/wav\">')[0].play();
\t\t});
\t}

\t// bind external event handlers
\t\$.each(this.options.handlers, function(event, callback) {
\t\tself.bind(event, callback);
\t});

\t/**
\t * History object. Store visited folders
\t *
\t * @type Object
\t **/
\tthis.history = new this.history(this);
\t
\t/**
\t * Root hashed
\t * 
\t * @type Object
\t */
\tthis.roots = {};
\t
\t/**
\t * leaf roots
\t * 
\t * @type Object
\t */
\tthis.leafRoots = {};
\t
\tthis.volumeExpires = {};

\t/**
\t * Loaded commands
\t *
\t * @type Object
\t **/
\tthis._commands = {};
\t
\tif (!Array.isArray(this.options.commands)) {
\t\tthis.options.commands = [];
\t}
\t
\tif (\$.inArray('*', this.options.commands) !== -1) {
\t\tthis.options.commands = Object.keys(this.commands);
\t}
\t
\t/**
\t * UI command map of cwd volume ( That volume driver option `uiCmdMap` )
\t *
\t * @type Object
\t **/
\tthis.commandMap = {};
\t
\t/**
\t * cwd options of each volume
\t * key: volumeid
\t * val: options object
\t * 
\t * @type Object
\t */
\tthis.volOptions = {};

\t/**
\t * Has volOptions data
\t * 
\t * @type Boolean
\t */
\tthis.hasVolOptions = false;

\t/**
\t * Hash of trash holders
\t * key: trash folder hash
\t * val: source volume hash
\t * 
\t * @type Object
\t */
\tthis.trashes = {};

\t/**
\t * cwd options of each folder/file
\t * key: hash
\t * val: options object
\t *
\t * @type Object
\t */
\tthis.optionsByHashes = {};
\t
\t/**
\t * UI Auto Hide Functions
\t * Each auto hide function mast be call to `fm.trigger('uiautohide')` at end of process
\t *
\t * @type Array
\t **/
\tthis.uiAutoHide = [];
\t
\t// trigger `uiautohide`
\tthis.one('open', function() {
\t\tif (self.uiAutoHide.length) {
\t\t\tsetTimeout(function() {
\t\t\t\tself.trigger('uiautohide');
\t\t\t}, 500);
\t\t}
\t});
\t
\t// Auto Hide Functions sequential processing start
\tthis.bind('uiautohide', function() {
\t\tif (self.uiAutoHide.length) {
\t\t\tself.uiAutoHide.shift()();
\t\t}
\t});

\tif (this.options.width) {
\t\twidth = this.options.width;
\t}
\t
\tif (this.options.height) {
\t\theight = this.options.height;
\t}
\t
\tif (this.options.heightBase) {
\t\theightBase = \$(this.options.heightBase);
\t}
\t
\tif (this.options.soundPath) {
\t\tsoundPath = this.options.soundPath.replace(/\\/+\$/, '') + '/';
\t} else {
\t\tsoundPath = this.baseUrl + soundPath;
\t}
\t
\tif (this.options.parrotHeaders && Array.isArray(this.options.parrotHeaders) && this.options.parrotHeaders.length) {
\t\tthis.parrotHeaders = this.options.parrotHeaders;
\t\t// check sessionStorage
\t\t\$.each(this.parrotHeaders, function(i, h) {
\t\t\tvar v = self.sessionStorage('core-ph:' + h);
\t\t\tif (v) {
\t\t\t\tself.customHeaders[h] = v;
\t\t\t}
\t\t});
\t} else {
\t\tthis.parrotHeaders = [];
\t}

\tself.one('opendone', function() {
\t\tvar tm;
\t\t// attach events to document
\t\t\$(document)
\t\t\t// disable elfinder on click outside elfinder
\t\t\t.on('click.'+namespace, function(e) { enabled && ! self.options.enableAlways && !\$(e.target).closest(node).length && self.disable(); })
\t\t\t// exec shortcuts
\t\t\t.on(keydown+' '+keypress+' '+keyup+' '+mousedown, execShortcut);
\t\t
\t\t// attach events to window
\t\tself.options.useBrowserHistory && \$(window)
\t\t\t.on('popstate.' + namespace, function(ev) {
\t\t\t\tvar state = ev.originalEvent.state || {},
\t\t\t\t\thasThash = state.thash? true : false,
\t\t\t\t\tdialog = node.find('.elfinder-frontmost:visible'),
\t\t\t\t\tinput = node.find('.elfinder-navbar-dir,.elfinder-cwd-filename').find('input,textarea'),
\t\t\t\t\tonOpen, toast;
\t\t\t\tif (!hasThash) {
\t\t\t\t\tstate = { thash: self.cwd().hash };
\t\t\t\t\t// scroll to elFinder node
\t\t\t\t\t\$('html,body').animate({ scrollTop: node.offset().top });
\t\t\t\t}
\t\t\t\tif (dialog.length || input.length) {
\t\t\t\t\thistory.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
\t\t\t\t\tif (dialog.length) {
\t\t\t\t\t\tif (!dialog.hasClass(self.res('class', 'preventback'))) {
\t\t\t\t\t\t\tif (dialog.hasClass('elfinder-contextmenu')) {
\t\t\t\t\t\t\t\t\$(document).trigger(\$.Event('keydown', { keyCode: \$.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
\t\t\t\t\t\t\t} else if (dialog.hasClass('elfinder-dialog')) {
\t\t\t\t\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tdialog.trigger('close');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tinput.trigger(\$.Event('keydown', { keyCode: \$.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (hasThash) {
\t\t\t\t\t\t!\$.isEmptyObject(self.files()) && self.request({
\t\t\t\t\t\t\tdata   : {cmd  : 'open', target : state.thash, onhistory : 1},
\t\t\t\t\t\t\tnotify : {type : 'open', cnt : 1, hideCnt : true},
\t\t\t\t\t\t\tsyncOnFail : true
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tonOpen = function() {
\t\t\t\t\t\t\ttoast.trigger('click');
\t\t\t\t\t\t};
\t\t\t\t\t\tself.one('open', onOpen, true);
\t\t\t\t\t\ttoast = self.toast({
\t\t\t\t\t\t\tmsg: self.i18n('pressAgainToExit'),
\t\t\t\t\t\t\tonHidden: function() {
\t\t\t\t\t\t\t\tself.unbind('open', onOpen);
\t\t\t\t\t\t\t\thistory.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t
\t\t\$(window).on('resize.' + namespace, function(e){
\t\t\tif (e.target === this) {
\t\t\t\ttm && cancelAnimationFrame(tm);
\t\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\t\tvar prv = node.data('resizeSize') || {w: 0, h: 0},
\t\t\t\t\t\tsize = {w: Math.round(node.width()), h: Math.round(node.height())};
\t\t\t\t\tnode.data('resizeSize', size);
\t\t\t\t\tif (size.w !== prv.w || size.h !== prv.h) {
\t\t\t\t\t\tnode.trigger('resize');
\t\t\t\t\t\tself.trigger('resize', {width : size.w, height : size.h});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t})
\t\t.on('beforeunload.' + namespace,function(e){
\t\t\tvar msg, cnt;
\t\t\tif (!self.pauseUnloadCheck()) {
\t\t\t\tif (node.is(':visible')) {
\t\t\t\t\tif (self.ui.notify.children().length && \$.inArray('hasNotifyDialog', self.options.windowCloseConfirm) !== -1) {
\t\t\t\t\t\tmsg = self.i18n('ntfsmth');
\t\t\t\t\t} else if (node.find('.'+self.res('class', 'editing')).length && \$.inArray('editingFile', self.options.windowCloseConfirm) !== -1) {
\t\t\t\t\t\tmsg = self.i18n('editingFile');
\t\t\t\t\t} else if ((cnt = Object.keys(self.selected()).length) && \$.inArray('hasSelectedItem', self.options.windowCloseConfirm) !== -1) {
\t\t\t\t\t\tmsg = self.i18n('hasSelected', ''+cnt);
\t\t\t\t\t} else if ((cnt = Object.keys(self.clipboard()).length) && \$.inArray('hasClipboardData', self.options.windowCloseConfirm) !== -1) {
\t\t\t\t\t\tmsg = self.i18n('hasClipboard', ''+cnt);
\t\t\t\t\t}
\t\t\t\t\tif (msg) {
\t\t\t\t\t\te.returnValue = msg;
\t\t\t\t\t\treturn msg;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tself.trigger('unload');
\t\t\t}
\t\t});

\t\t// bind window onmessage for CORS
\t\t\$(window).on('message.' + namespace, function(e){
\t\t\tvar res = e.originalEvent || null,
\t\t\t\tobj, data;
\t\t\tif (res && (self.convAbsUrl(self.options.url).indexOf(res.origin) === 0 || self.convAbsUrl(self.uploadURL).indexOf(res.origin) === 0)) {
\t\t\t\ttry {
\t\t\t\t\tobj = JSON.parse(res.data);
\t\t\t\t\tdata = obj.data || null;
\t\t\t\t\tif (data) {
\t\t\t\t\t\tif (data.error) {
\t\t\t\t\t\t\tif (obj.bind) {
\t\t\t\t\t\t\t\tself.trigger(obj.bind+'fail', data);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tself.error(data.error);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdata.warning && self.error(data.warning);
\t\t\t\t\t\t\tself.updateCache(data);
\t\t\t\t\t\t\tdata.removed && data.removed.length && self.remove(data);
\t\t\t\t\t\t\tdata.added   && data.added.length   && self.add(data);
\t\t\t\t\t\t\tdata.changed && data.changed.length && self.change(data);
\t\t\t\t\t\t\tif (obj.bind) {
\t\t\t\t\t\t\t\tself.trigger(obj.bind, data);
\t\t\t\t\t\t\t\tself.trigger(obj.bind+'done');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdata.sync && self.sync();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} catch (e) {
\t\t\t\t\tself.sync();
\t\t\t\t}
\t\t\t}
\t\t});

\t\t// elFinder enable always
\t\tif (self.options.enableAlways) {
\t\t\t\$(window).on('focus.' + namespace, function(e){
\t\t\t\t(e.target === this) && self.enable();
\t\t\t});
\t\t\tif (inFrame) {
\t\t\t\t\$(window.top).on('focus.' + namespace, function() {
\t\t\t\t\tif (self.enable() && (! parentIframe || parentIframe.is(':visible'))) {
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\$(window).trigger('focus');
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t} else if (inFrame) {
\t\t\t\$(window).on('blur.' + namespace, function(e){
\t\t\t\tenabled && e.target === this && self.disable();
\t\t\t});
\t\t}

\t\t// return focus to the window on click (elFInder in the frame)
\t\tif (inFrame) {
\t\t\tnode.on('click', function(e) {
\t\t\t\t\$(window).trigger('focus');
\t\t\t});
\t\t}
\t\t
\t\t// elFinder to enable by mouse over
\t\tif (self.options.enableByMouseOver) {
\t\t\tnode.on('mouseenter touchstart', function(e) {
\t\t\t\t(inFrame) && \$(window).trigger('focus');
\t\t\t\t! self.enabled() && self.enable();
\t\t\t});
\t\t}

\t\t// When the browser tab turn to foreground/background
\t\t\$(window).on('visibilitychange.' + namespace, function(e) {
\t\t\tvar background = document.hidden || document.webkitHidden || document.msHidden;
\t\t\t// AutoSync turn On/Off
\t\t\tif (self.options.syncStart) {
\t\t\t\tself.autoSync(background? 'stop' : void(0));
\t\t\t}
\t\t});
\t});

\t// store instance in node
\tnode[0].elfinder = this;

\t// auto load language file
\tdfrdsBeforeBootup.push((function() {
\t\tvar lang   = self.lang,
\t\t\tlangJs = self.i18nBaseUrl + 'elfinder.' + lang + '.js',
\t\t\tdfd    = \$.Deferred().done(function() {
\t\t\t\tif (self.i18[lang]) {
\t\t\t\t\tself.lang = lang;
\t\t\t\t}
\t\t\t\tself.trigger('i18load');
\t\t\t\ti18n = self.lang === 'en' 
\t\t\t\t\t? self.i18['en'] 
\t\t\t\t\t: \$.extend(true, {}, self.i18['en'], self.i18[self.lang]);
\t\t\t});
\t\t
\t\tif (!self.i18[lang]) {
\t\t\tself.lang = 'en';
\t\t\tif (self.hasRequire) {
\t\t\t\trequire([langJs], function() {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}, function() {
\t\t\t\t\tdfd.resolve();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tself.loadScript([langJs], function() {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}, {
\t\t\t\t\tloadType: 'tag',
\t\t\t\t\terror : function() {
\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t} else {
\t\t\tdfd.resolve();
\t\t}
\t\treturn dfd;
\t})());
\t
\t// elFinder boot up function
\tbootUp = function() {
\t\tvar columnNames;

\t\t/**
\t\t * i18 messages
\t\t *
\t\t * @type Object
\t\t **/
\t\tself.messages = i18n.messages;
\t\t
\t\t// check jquery ui
\t\tif (!(\$.fn.selectable && \$.fn.draggable && \$.fn.droppable && \$.fn.resizable && \$.fn.button && \$.fn.slider)) {
\t\t\treturn alert(self.i18n('errJqui'));
\t\t}
\t\t
\t\t// check node
\t\tif (!node.length) {
\t\t\treturn alert(self.i18n('errNode'));
\t\t}
\t\t// check connector url
\t\tif (!self.options.url) {
\t\t\treturn alert(self.i18n('errURL'));
\t\t}
\t\t
\t\t// column key/name map for fm.getColumnName()
\t\tcolumnNames = Object.assign({
\t\t\tname : self.i18n('name'),
\t\t\tperm : self.i18n('perms'),
\t\t\tdate : self.i18n('modify'),
\t\t\tsize : self.i18n('size'),
\t\t\tkind : self.i18n('kind'),
\t\t\tmodestr : self.i18n('mode'),
\t\t\tmodeoct : self.i18n('mode'),
\t\t\tmodeboth : self.i18n('mode')
\t\t}, self.options.uiOptions.cwd.listView.columnsCustomName);

\t\t/**
\t\t * Gets the column name of cwd list view
\t\t *
\t\t * @param      String  key     The key
\t\t * @return     String  The column name.
\t\t */
\t\tself.getColumnName = function(key) {
\t\t\treturn columnNames[key] || self.i18n(key);
\t\t};

\t\t/**
\t\t * Interface direction
\t\t *
\t\t * @type String
\t\t * @default \"ltr\"
\t\t **/
\t\tself.direction = i18n.direction;
\t\t
\t\t/**
\t\t * Date/time format
\t\t *
\t\t * @type String
\t\t * @default \"m.d.Y\"
\t\t **/
\t\tself.dateFormat = self.options.dateFormat || i18n.dateFormat;
\t\t
\t\t/**
\t\t * Date format like \"Yesterday 10:20:12\"
\t\t *
\t\t * @type String
\t\t * @default \"{day} {time}\"
\t\t **/
\t\tself.fancyFormat = self.options.fancyDateFormat || i18n.fancyDateFormat;
\t\t
\t\t/**
\t\t * Date format for if upload file has not original unique name
\t\t * e.g. Clipboard image data, Image data taken with iOS
\t\t *
\t\t * @type String
\t\t * @default \"ymd-His\"
\t\t **/
\t\tself.nonameDateFormat = (self.options.nonameDateFormat || i18n.nonameDateFormat).replace(/[\\/\\\\]/g, '_');

\t\t/**
\t\t * Css classes 
\t\t *
\t\t * @type String
\t\t **/
\t\tself.cssClass = 'ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-'
\t\t\t\t+(self.direction == 'rtl' ? 'rtl' : 'ltr')
\t\t\t\t+(self.UA.Touch? (' elfinder-touch' + (self.options.resizable ? ' touch-punch' : '')) : '')
\t\t\t\t+(self.UA.Mobile? ' elfinder-mobile' : '')
\t\t\t\t+(self.UA.iOS? ' elfinder-ios' : '')
\t\t\t\t+' '+self.options.cssClass;

\t\t// prepare node
\t\tnode.addClass(self.cssClass)
\t\t\t.on(mousedown, function() {
\t\t\t\t!enabled && self.enable();
\t\t\t});

\t\t// draggable closure
\t\t(function() {
\t\t\tvar ltr, wzRect, wzBottom, wzBottom2, nodeStyle,
\t\t\t\tkeyEvt = keydown + 'draggable' + ' keyup.' + namespace + 'draggable';
\t\t\t
\t\t\t/**
\t\t\t * Base draggable options
\t\t\t *
\t\t\t * @type Object
\t\t\t **/
\t\t\tself.draggable = {
\t\t\t\tappendTo   : node,
\t\t\t\taddClasses : false,
\t\t\t\tdistance   : 4,
\t\t\t\trevert     : true,
\t\t\t\trefreshPositions : false,
\t\t\t\tcursor     : 'crosshair',
\t\t\t\tcursorAt   : {left : 50, top : 47},
\t\t\t\tscroll     : false,
\t\t\t\tstart      : function(e, ui) {
\t\t\t\t\tvar helper   = ui.helper,
\t\t\t\t\t\ttargets  = \$.grep(helper.data('files')||[], function(h) {
\t\t\t\t\t\t\tif (h) {
\t\t\t\t\t\t\t\tremember[h] = true;
\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}),
\t\t\t\t\t\tlocked   = false,
\t\t\t\t\t\tcnt, h;
\t\t\t\t\t
\t\t\t\t\t// fix node size
\t\t\t\t\tnodeStyle = node.attr('style');
\t\t\t\t\tnode.width(node.width()).height(node.height());
\t\t\t\t\t
\t\t\t\t\t// set var for drag()
\t\t\t\t\tltr = (self.direction === 'ltr');
\t\t\t\t\twzRect = self.getUI('workzone').data('rectangle');
\t\t\t\t\twzBottom = wzRect.top + wzRect.height;
\t\t\t\t\twzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true);
\t\t\t\t\t
\t\t\t\t\tself.draggingUiHelper = helper;
\t\t\t\t\tcnt = targets.length;
\t\t\t\t\twhile (cnt--) {
\t\t\t\t\t\th = targets[cnt];
\t\t\t\t\t\tif (files[h].locked) {
\t\t\t\t\t\t\tlocked = true;
\t\t\t\t\t\t\thelper.data('locked', true);
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t!locked && self.trigger('lockfiles', {files : targets});
\t\t
\t\t\t\t\thelper.data('autoScrTm', setInterval(function() {
\t\t\t\t\t\tif (helper.data('autoScr')) {
\t\t\t\t\t\t\tself.autoScroll[helper.data('autoScr')](helper.data('autoScrVal'));
\t\t\t\t\t\t}
\t\t\t\t\t}, 50));
\t\t\t\t},
\t\t\t\tdrag       : function(e, ui) {
\t\t\t\t\tvar helper = ui.helper,
\t\t\t\t\t\tautoScr, autoUp, bottom;
\t\t\t\t\t
\t\t\t\t\tif ((autoUp = wzRect.top > e.pageY) || wzBottom2 < e.pageY) {
\t\t\t\t\t\tif (wzRect.cwdEdge > e.pageX) {
\t\t\t\t\t\t\tautoScr = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tautoScr = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!autoUp) {
\t\t\t\t\t\t\tif (autoScr.substr(0, 3) === 'cwd') {
\t\t\t\t\t\t\t\tif (wzBottom < e.pageY) {
\t\t\t\t\t\t\t\t\tbottom = wzBottom;
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tautoScr = null;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tbottom = wzBottom2;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (autoScr) {
\t\t\t\t\t\t\thelper.data('autoScr', autoScr);
\t\t\t\t\t\t\thelper.data('autoScrVal', Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - bottom), 1.3));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (! autoScr) {
\t\t\t\t\t\tif (helper.data('autoScr')) {
\t\t\t\t\t\t\thelper.data('refreshPositions', 1).data('autoScr', null);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (helper.data('refreshPositions') && \$(this).elfUiWidgetInstance('draggable')) {
\t\t\t\t\t\tif (helper.data('refreshPositions') > 0) {
\t\t\t\t\t\t\t\$(this).draggable('option', { refreshPositions : true, elfRefresh : true });
\t\t\t\t\t\t\thelper.data('refreshPositions', -1);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$(this).draggable('option', { refreshPositions : false, elfRefresh : false });
\t\t\t\t\t\t\thelper.data('refreshPositions', null);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tstop       : function(e, ui) {
\t\t\t\t\tvar helper = ui.helper,
\t\t\t\t\t\tfiles;
\t\t\t\t\t
\t\t\t\t\t\$(document).off(keyEvt);
\t\t\t\t\t\$(this).elfUiWidgetInstance('draggable') && \$(this).draggable('option', { refreshPositions : false });
\t\t\t\t\tself.draggingUiHelper = null;
\t\t\t\t\tself.trigger('focus').trigger('dragstop');
\t\t\t\t\tif (! helper.data('droped')) {
\t\t\t\t\t\tfiles = \$.grep(helper.data('files')||[], function(h) { return h? true : false ;});
\t\t\t\t\t\tself.trigger('unlockfiles', {files : files});
\t\t\t\t\t\tself.trigger('selectfiles', {files : self.selected()});
\t\t\t\t\t}
\t\t\t\t\tself.enable();
\t\t\t\t\t
\t\t\t\t\t// restore node style
\t\t\t\t\tnode.attr('style', nodeStyle);
\t\t\t\t\t
\t\t\t\t\thelper.data('autoScrTm') && clearInterval(helper.data('autoScrTm'));
\t\t\t\t},
\t\t\t\thelper     : function(e, ui) {
\t\t\t\t\tvar element = this.id ? \$(this) : \$(this).parents('[id]:first'),
\t\t\t\t\t\thelper  = \$('<div class=\"elfinder-drag-helper\"><span class=\"elfinder-drag-helper-icon-status\"></span></div>'),
\t\t\t\t\t\ticon    = function(f) {
\t\t\t\t\t\t\tvar mime = f.mime, i, tmb = self.tmb(f);
\t\t\t\t\t\t\ti = '<div class=\"elfinder-cwd-icon elfinder-cwd-icon-drag '+self.mime2class(mime)+' ui-corner-all\"></div>';
\t\t\t\t\t\t\tif (tmb) {
\t\t\t\t\t\t\t\ti = \$(i).addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\").get(0).outerHTML;
\t\t\t\t\t\t\t} else if (f.icon) {
\t\t\t\t\t\t\t\ti = \$(i).css(self.getIconStyle(f, true)).get(0).outerHTML;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (f.csscls) {
\t\t\t\t\t\t\t\ti = '<div class=\"'+f.csscls+'\">' + i + '</div>';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\treturn i;
\t\t\t\t\t\t},
\t\t\t\t\t\thashes, l, ctr;
\t\t\t\t\t
\t\t\t\t\tself.draggingUiHelper && self.draggingUiHelper.stop(true, true);
\t\t\t\t\t
\t\t\t\t\tself.trigger('dragstart', {target : element[0], originalEvent : e}, true);
\t\t\t\t\t
\t\t\t\t\thashes = element.hasClass(self.res('class', 'cwdfile')) 
\t\t\t\t\t\t? self.selected() 
\t\t\t\t\t\t: [self.navId2Hash(element.attr('id'))];
\t\t\t\t\t
\t\t\t\t\thelper.append(icon(files[hashes[0]])).data('files', hashes).data('locked', false).data('droped', false).data('namespace', namespace).data('dropover', 0);
\t\t
\t\t\t\t\tif ((l = hashes.length) > 1) {
\t\t\t\t\t\thelper.append(icon(files[hashes[l-1]]) + '<span class=\"elfinder-drag-num\">'+l+'</span>');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t\$(document).on(keyEvt, function(e){
\t\t\t\t\t\tvar chk = (e.shiftKey||e.ctrlKey||e.metaKey);
\t\t\t\t\t\tif (ctr !== chk) {
\t\t\t\t\t\t\tctr = chk;
\t\t\t\t\t\t\tif (helper.is(':visible') && helper.data('dropover') && ! helper.data('droped')) {
\t\t\t\t\t\t\t\thelper.toggleClass('elfinder-drag-helper-plus', helper.data('locked')? true : ctr);
\t\t\t\t\t\t\t\tself.trigger(ctr? 'unlockfiles' : 'lockfiles', {files : hashes, helper: helper});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\treturn helper;
\t\t\t\t}
\t\t\t};
\t\t})();

\t\t// in getFileCallback set - change default actions on double click/enter/ctrl+enter
\t\tif (self.commands.getfile) {
\t\t\tif (typeof(self.options.getFileCallback) == 'function') {
\t\t\t\tself.bind('dblclick', function(e) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\tself.exec('getfile').fail(function() {
\t\t\t\t\t\tself.exec('open', e.data && e.data.file? [ e.data.file ]: void(0));
\t\t\t\t\t});
\t\t\t\t});
\t\t\t\tself.shortcut({
\t\t\t\t\tpattern     : 'enter',
\t\t\t\t\tdescription : self.i18n('cmdgetfile'),
\t\t\t\t\tcallback    : function() { self.exec('getfile').fail(function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }); }
\t\t\t\t})
\t\t\t\t.shortcut({
\t\t\t\t\tpattern     : 'ctrl+enter',
\t\t\t\t\tdescription : self.i18n(self.OS == 'mac' ? 'cmdrename' : 'cmdopen'),
\t\t\t\t\tcallback    : function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }
\t\t\t\t});
\t\t\t} else {
\t\t\t\tself.options.getFileCallback = null;
\t\t\t}
\t\t}

\t\t// load commands
\t\t\$.each(self.commands, function(name, cmd) {
\t\t\tvar proto = Object.assign({}, cmd.prototype),
\t\t\t\textendsCmd, opts;
\t\t\tif (\$.isFunction(cmd) && !self._commands[name] && (cmd.prototype.forceLoad || \$.inArray(name, self.options.commands) !== -1)) {
\t\t\t\textendsCmd = cmd.prototype.extendsCmd || '';
\t\t\t\tif (extendsCmd) {
\t\t\t\t\tif (\$.isFunction(self.commands[extendsCmd])) {
\t\t\t\t\t\tcmd.prototype = Object.assign({}, base, new self.commands[extendsCmd](), cmd.prototype);
\t\t\t\t\t} else {
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tcmd.prototype = Object.assign({}, base, cmd.prototype);
\t\t\t\t}
\t\t\t\tself._commands[name] = new cmd();
\t\t\t\tcmd.prototype = proto;
\t\t\t\topts = self.options.commandsOptions[name] || {};
\t\t\t\tif (extendsCmd && self.options.commandsOptions[extendsCmd]) {
\t\t\t\t\topts = \$.extend(true, {}, self.options.commandsOptions[extendsCmd], opts);
\t\t\t\t}
\t\t\t\tself._commands[name].setup(name, opts);
\t\t\t\t// setup linked commands
\t\t\t\tif (self._commands[name].linkedCmds.length) {
\t\t\t\t\t\$.each(self._commands[name].linkedCmds, function(i, n) {
\t\t\t\t\t\tvar lcmd = self.commands[n];
\t\t\t\t\t\tif (\$.isFunction(lcmd) && !self._commands[n]) {
\t\t\t\t\t\t\tlcmd.prototype = base;
\t\t\t\t\t\t\tself._commands[n] = new lcmd();
\t\t\t\t\t\t\tself._commands[n].setup(n, self.options.commandsOptions[n]||{});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t});

\t\t/**
\t\t * UI nodes
\t\t *
\t\t * @type Object
\t\t **/
\t\tself.ui = {
\t\t\t// container for nav panel and current folder container
\t\t\tworkzone : \$('<div></div>').appendTo(node).elfinderworkzone(self),
\t\t\t// contaainer for folders tree / places
\t\t\tnavbar : \$('<div></div>').appendTo(node).elfindernavbar(self, self.options.uiOptions.navbar || {}),
\t\t\t// container for for preview etc at below the navbar
\t\t\tnavdock : \$('<div></div>').appendTo(node).elfindernavdock(self, self.options.uiOptions.navdock || {}),
\t\t\t// contextmenu
\t\t\tcontextmenu : \$('<div></div>').appendTo(node).elfindercontextmenu(self),
\t\t\t// overlay
\t\t\toverlay : \$('<div></div>').appendTo(node).elfinderoverlay({
\t\t\t\tshow : function() { self.disable(); },
\t\t\t\thide : function() { prevEnabled && self.enable(); }
\t\t\t}),
\t\t\t// current folder container
\t\t\tcwd : \$('<div></div>').appendTo(node).elfindercwd(self, self.options.uiOptions.cwd || {}),
\t\t\t// notification dialog window
\t\t\tnotify : self.dialog('', {
\t\t\t\tcssClass      : 'elfinder-dialog-notify' + (self.options.notifyDialog.canClose? '' : ' elfinder-titlebar-button-hide'),
\t\t\t\tposition      : self.options.notifyDialog.position,
\t\t\t\tabsolute      : true,
\t\t\t\tresizable     : false,
\t\t\t\tautoOpen      : false,
\t\t\t\tallowMinimize : true,
\t\t\t\tcloseOnEscape : self.options.notifyDialog.canClose? true : false,
\t\t\t\ttitle         : '&nbsp;',
\t\t\t\twidth         : self.options.notifyDialog.width? parseInt(self.options.notifyDialog.width) : null,
\t\t\t\tminHeight     : null,
\t\t\t\tminimize      : function() { self.ui.notify.trigger('minimize'); }
\t\t\t}),
\t\t\tstatusbar : \$('<div class=\"ui-widget-header ui-helper-clearfix ui-corner-bottom elfinder-statusbar\"></div>').hide().appendTo(node),
\t\t\ttoast : \$('<div class=\"elfinder-toast\"></div>').appendTo(node),
\t\t\tbottomtray : \$('<div class=\"elfinder-bottomtray\">').appendTo(node),
\t\t\tprogressbar : \$('<div class=\"elfinder-ui-progressbar\">').appendTo(node)
\t\t};

\t\tself.trigger('uiready');

\t\t// load required ui
\t\t\$.each(self.options.ui || [], function(i, ui) {
\t\t\tvar name = 'elfinder'+ui,
\t\t\t\topts = self.options.uiOptions[ui] || {};
\t
\t\t\tif (!self.ui[ui] && \$.fn[name]) {
\t\t\t\t// regist to self.ui before make instance
\t\t\t\tself.ui[ui] = \$('<'+(opts.tag || 'div')+'/>').appendTo(node);
\t\t\t\tself.ui[ui][name](self, opts);
\t\t\t}
\t\t});

\t\tself.ui.progressbar.appendTo(self.ui.workzone);
\t\tself.ui.notify.prev('.ui-dialog-titlebar').append('<div class=\"elfinder-ui-progressbar\"></div>');

\t\t// update size\t
\t\tself.resize(width, height);
\t\t
\t\t// make node resizable
\t\tif (self.options.resizable) {
\t\t\tnode.resizable({
\t\t\t\tresize    : function(e, ui) {
\t\t\t\t\tself.resize(ui.size.width, ui.size.height);
\t\t\t\t},
\t\t\t\thandles   : 'se',
\t\t\t\tminWidth  : 300,
\t\t\t\tminHeight : 200
\t\t\t});
\t\t\tif (self.UA.Touch) {
\t\t\t\tnode.addClass('touch-punch');
\t\t\t}
\t\t}

\t\t(function() {
\t\t\tvar navbar = self.getUI('navbar'),
\t\t\t\tcwd    = self.getUI('cwd').parent();
\t\t\t
\t\t\tself.autoScroll = {
\t\t\t\tnavbarUp   : function(v) {
\t\t\t\t\tnavbar.scrollTop(Math.max(0, navbar.scrollTop() - v));
\t\t\t\t},
\t\t\t\tnavbarDown : function(v) {
\t\t\t\t\tnavbar.scrollTop(navbar.scrollTop() + v);
\t\t\t\t},
\t\t\t\tcwdUp     : function(v) {
\t\t\t\t\tcwd.scrollTop(Math.max(0, cwd.scrollTop() - v));
\t\t\t\t},
\t\t\t\tcwdDown   : function(v) {
\t\t\t\t\tcwd.scrollTop(cwd.scrollTop() + v);
\t\t\t\t}
\t\t\t};
\t\t})();

\t\t// Swipe on the touch devices to show/hide of toolbar or navbar
\t\tif (self.UA.Touch) {
\t\t\t(function() {
\t\t\t\tvar lastX, lastY, nodeOffset, nodeWidth, nodeTop, navbarW, toolbarH,
\t\t\t\t\tnavbar = self.getUI('navbar'),
\t\t\t\t\ttoolbar = self.getUI('toolbar'),
\t\t\t\t\tmoveEv = 'touchmove.stopscroll',
\t\t\t\t\tmoveTm,
\t\t\t\t\tmoveUpOn = function(e) {
\t\t\t\t\t\tvar touches = e.originalEvent.touches || [{}],
\t\t\t\t\t\t\ty = touches[0].pageY || null;
\t\t\t\t\t\tif (!lastY || y < lastY) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\tmoveTm && clearTimeout(moveTm);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tmoveDownOn = function(e) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tmoveTm && clearTimeout(moveTm);
\t\t\t\t\t},
\t\t\t\t\tmoveOff = function() {
\t\t\t\t\t\tmoveTm = setTimeout(function() {
\t\t\t\t\t\t\tnode.off(moveEv);
\t\t\t\t\t\t}, 100);
\t\t\t\t\t},
\t\t\t\t\thandleW, handleH = 50;

\t\t\t\tnavbar = navbar.children().length? navbar : null;
\t\t\t\ttoolbar = toolbar.length? toolbar : null;
\t\t\t\tnode.on('touchstart touchmove touchend', function(e) {
\t\t\t\t\tif (e.type === 'touchend') {
\t\t\t\t\t\tlastX = false;
\t\t\t\t\t\tlastY = false;
\t\t\t\t\t\tmoveOff();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tvar touches = e.originalEvent.touches || [{}],
\t\t\t\t\t\tx = touches[0].pageX || null,
\t\t\t\t\t\ty = touches[0].pageY || null,
\t\t\t\t\t\tltr = (self.direction === 'ltr'),
\t\t\t\t\t\tnavbarMode, treeWidth, swipeX, moveX, toolbarT, mode;
\t\t\t\t\t
\t\t\t\t\tif (x === null || y === null || (e.type === 'touchstart' && touches.length > 1)) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (e.type === 'touchstart') {
\t\t\t\t\t\tnodeOffset = node.offset();
\t\t\t\t\t\tnodeWidth = node.width();
\t\t\t\t\t\tif (navbar) {
\t\t\t\t\t\t\tlastX = false;
\t\t\t\t\t\t\tif (navbar.is(':hidden')) {
\t\t\t\t\t\t\t\tif (! handleW) {
\t\t\t\t\t\t\t\t\thandleW = Math.max(50, nodeWidth / 10);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif ((ltr? (x - nodeOffset.left) : (nodeWidth + nodeOffset.left - x)) < handleW) {
\t\t\t\t\t\t\t\t\tlastX = x;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else if (! e.originalEvent._preventSwipeX) {
\t\t\t\t\t\t\t\tnavbarW = navbar.width();
\t\t\t\t\t\t\t\tif (ltr) {
\t\t\t\t\t\t\t\t\tswipeX = (x < nodeOffset.left + navbarW);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tswipeX = (x > nodeOffset.left + nodeWidth - navbarW);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (swipeX) {
\t\t\t\t\t\t\t\t\thandleW = Math.max(50, nodeWidth / 10);
\t\t\t\t\t\t\t\t\tlastX = x;
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tlastX = false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (toolbar) {
\t\t\t\t\t\t\tlastY = false;
\t\t\t\t\t\t\tif (! e.originalEvent._preventSwipeY) {
\t\t\t\t\t\t\t\ttoolbarH = toolbar.height();
\t\t\t\t\t\t\t\tnodeTop = nodeOffset.top;
\t\t\t\t\t\t\t\tif (y - nodeTop < (toolbar.is(':hidden')? handleH : (toolbarH + 30))) {
\t\t\t\t\t\t\t\t\tlastY = y;
\t\t\t\t\t\t\t\t\tnode.on(moveEv, toolbar.is(':hidden')? moveDownOn: moveUpOn);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (navbar && lastX !== false) {
\t\t\t\t\t\t\tnavbarMode = (ltr? (lastX > x) : (lastX < x))? 'navhide' : 'navshow';
\t\t\t\t\t\t\tmoveX = Math.abs(lastX - x);
\t\t\t\t\t\t\tif (navbarMode === 'navhide' && moveX > navbarW * 0.6
\t\t\t\t\t\t\t\t|| (moveX > (navbarMode === 'navhide'? navbarW / 3 : 45)
\t\t\t\t\t\t\t\t\t&& (navbarMode === 'navshow'
\t\t\t\t\t\t\t\t\t\t|| (ltr? x < nodeOffset.left + 20 : x > nodeOffset.left + nodeWidth - 20)
\t\t\t\t\t\t\t\t\t))
\t\t\t\t\t\t\t) {
\t\t\t\t\t\t\t\tself.getUI('navbar').trigger(navbarMode, {handleW: handleW});
\t\t\t\t\t\t\t\tlastX = false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (toolbar && lastY !== false ) {
\t\t\t\t\t\t\ttoolbarT = toolbar.offset().top;
\t\t\t\t\t\t\tif (Math.abs(lastY - y) > Math.min(45, toolbarH / 3)) {
\t\t\t\t\t\t\t\tmode = (lastY > y)? 'slideUp' : 'slideDown';
\t\t\t\t\t\t\t\tif (mode === 'slideDown' || toolbarT + 20 > y) {
\t\t\t\t\t\t\t\t\tif (toolbar.is(mode === 'slideDown' ? ':hidden' : ':visible')) {
\t\t\t\t\t\t\t\t\t\ttoolbar.stop(true, true).trigger('toggle', {duration: 100, handleH: handleH});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tlastY = false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t})();
\t\t}

\t\tif (self.dragUpload) {
\t\t\t// add event listener for HTML5 DnD upload
\t\t\t(function() {
\t\t\t\tvar isin = function(e) {
\t\t\t\t\treturn (e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && \$(e.target).closest('div.ui-dialog-content').length === 0);
\t\t\t\t},
\t\t\t\tent       = 'native-drag-enter',
\t\t\t\tdisable   = 'native-drag-disable',
\t\t\t\tc         = 'class',
\t\t\t\tnavdir    = self.res(c, 'navdir'),
\t\t\t\tdroppable = self.res(c, 'droppable'),
\t\t\t\tdropover  = self.res(c, 'adroppable'),
\t\t\t\tarrow     = self.res(c, 'navarrow'),
\t\t\t\tclDropActive = self.res(c, 'adroppable'),
\t\t\t\twz        = self.getUI('workzone'),
\t\t\t\tltr       = (self.direction === 'ltr'),
\t\t\t\tclearTm   = function() {
\t\t\t\t\tautoScrTm && cancelAnimationFrame(autoScrTm);
\t\t\t\t\tautoScrTm = null;
\t\t\t\t},
\t\t\t\twzRect, autoScrFn, autoScrTm;
\t\t\t\t
\t\t\t\tnode.on('dragenter', function(e) {
\t\t\t\t\tclearTm();
\t\t\t\t\tif (isin(e)) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\twzRect = wz.data('rectangle');
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('dragleave', function(e) {
\t\t\t\t\tclearTm();
\t\t\t\t\tif (isin(e)) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('dragover', function(e) {
\t\t\t\t\tvar autoUp;
\t\t\t\t\tif (isin(e)) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.originalEvent.dataTransfer.dropEffect = 'none';
\t\t\t\t\t\tif (! autoScrTm) {
\t\t\t\t\t\t\tautoScrTm = requestAnimationFrame(function() {
\t\t\t\t\t\t\t\tvar wzBottom = wzRect.top + wzRect.height,
\t\t\t\t\t\t\t\t\twzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true),
\t\t\t\t\t\t\t\t\tfn;
\t\t\t\t\t\t\t\tif ((autoUp = e.pageY < wzRect.top) || e.pageY > wzBottom2 ) {
\t\t\t\t\t\t\t\t\tif (wzRect.cwdEdge > e.pageX) {
\t\t\t\t\t\t\t\t\t\tfn = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tfn = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (!autoUp) {
\t\t\t\t\t\t\t\t\t\tif (fn.substr(0, 3) === 'cwd') {
\t\t\t\t\t\t\t\t\t\t\tif (wzBottom < e.pageY) {
\t\t\t\t\t\t\t\t\t\t\t\twzBottom2 = wzBottom;
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tfn = '';
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tfn && self.autoScroll[fn](Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - wzBottom2), 1.3));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tautoScrTm = null;
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tclearTm();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('drop', function(e) {
\t\t\t\t\tclearTm();
\t\t\t\t\tif (isin(e)) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\tnode.on('dragenter', '.native-droppable', function(e){
\t\t\t\t\tif (e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar \$elm = \$(e.currentTarget),
\t\t\t\t\t\t\tid   = e.currentTarget.id || null,
\t\t\t\t\t\t\tcwd  = null,
\t\t\t\t\t\t\telfFrom;
\t\t\t\t\t\tif (!id) { // target is cwd
\t\t\t\t\t\t\tcwd = self.cwd();
\t\t\t\t\t\t\t\$elm.data(disable, false);
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\$.each(e.originalEvent.dataTransfer.types, function(i, v){
\t\t\t\t\t\t\t\t\tif (v.substr(0, 13) === 'elfinderfrom:') {
\t\t\t\t\t\t\t\t\t\telfFrom = v.substr(13).toLowerCase();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!cwd || (cwd.write && (!elfFrom || elfFrom !== (window.location.href + cwd.hash).toLowerCase()))) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\$elm.data(ent, true);
\t\t\t\t\t\t\t\$elm.addClass(clDropActive);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$elm.data(disable, true);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('dragleave', '.native-droppable', function(e){
\t\t\t\t\tif (e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar \$elm = \$(e.currentTarget);
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tif (\$elm.data(ent)) {
\t\t\t\t\t\t\t\$elm.data(ent, false);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$elm.removeClass(clDropActive);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('dragover', '.native-droppable', function(e){
\t\t\t\t\tif (e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar \$elm = \$(e.currentTarget);
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.originalEvent.dataTransfer.dropEffect = \$elm.data(disable)? 'none' : 'copy';
\t\t\t\t\t\t\$elm.data(ent, false);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('drop', '.native-droppable', function(e){
\t\t\t\t\tif (e.originalEvent && e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar \$elm = \$(e.currentTarget),
\t\t\t\t\t\t\tid;
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\$elm.removeClass(clDropActive);
\t\t\t\t\t\tif (e.currentTarget.id) {
\t\t\t\t\t\t\tid = \$elm.hasClass(navdir)? self.navId2Hash(e.currentTarget.id) : self.cwdId2Hash(e.currentTarget.id);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tid = self.cwd().hash;
\t\t\t\t\t\t}
\t\t\t\t\t\te.originalEvent._target = id;
\t\t\t\t\t\tself.exec('upload', {dropEvt: e.originalEvent, target: id}, void 0, id);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t})();
\t\t}

\t\t// trigger event cssloaded if cssAutoLoad disabled
\t\tif (self.cssloaded === false) {
\t\t\tself.cssloaded = true;
\t\t\tself.trigger('cssloaded');
\t\t}

\t\t// calculate elFinder node z-index
\t\tself.zIndexCalc();

\t\t// send initial request and start to pray >_<
\t\tself.trigger('init')
\t\t\t.request({
\t\t\t\tdata        : {cmd : 'open', target : self.startDir(), init : 1, tree : 1}, 
\t\t\t\tpreventDone : true,
\t\t\t\tnotify      : {type : 'open', cnt : 1, hideCnt : true},
\t\t\t\tfreeze      : true
\t\t\t})
\t\t\t.fail(function() {
\t\t\t\tself.trigger('fail').disable().lastDir('');
\t\t\t\tlisteners = {};
\t\t\t\tshortcuts = {};
\t\t\t\t\$(document).add(node).off('.'+namespace);
\t\t\t\tself.trigger = function() { };
\t\t\t})
\t\t\t.done(function(data) {
\t\t\t\tvar trashDisable = function(th) {
\t\t\t\t\t\tvar src = self.file(self.trashes[th]),
\t\t\t\t\t\t\td = self.options.debug,
\t\t\t\t\t\t\terror;
\t\t\t\t\t\t
\t\t\t\t\t\tif (src && src.volumeid) {
\t\t\t\t\t\t\tdelete self.volOptions[src.volumeid].trashHash;
\t\t\t\t\t\t}
\t\t\t\t\t\tself.trashes[th] = false;
\t\t\t\t\t\tself.debug('backend-error', 'Trash hash \"'+th+'\" was not found or not writable.');
\t\t\t\t\t},
\t\t\t\t\ttoChkTh = {};
\t\t\t\t
\t\t\t\t// regist rawStringDecoder
\t\t\t\tif (self.options.rawStringDecoder) {
\t\t\t\t\tself.registRawStringDecoder(self.options.rawStringDecoder);
\t\t\t\t}

\t\t\t\t// re-calculate elFinder node z-index
\t\t\t\tself.zIndexCalc();
\t\t\t\t
\t\t\t\tself.load().debug('api', self.api);
\t\t\t\t// update ui's size after init
\t\t\t\tnode.trigger('resize');
\t\t\t\t// initial open
\t\t\t\topen(data);
\t\t\t\tself.trigger('open', data, false);
\t\t\t\tself.trigger('opendone');
\t\t\t\t
\t\t\t\tif (inFrame && self.options.enableAlways) {
\t\t\t\t\t\$(window).trigger('focus');
\t\t\t\t}
\t\t\t\t
\t\t\t\t// check self.trashes
\t\t\t\t\$.each(self.trashes, function(th) {
\t\t\t\t\tvar dir = self.file(th),
\t\t\t\t\t\tsrc;
\t\t\t\t\tif (! dir) {
\t\t\t\t\t\ttoChkTh[th] = true;
\t\t\t\t\t} else if (dir.mime !== 'directory' || ! dir.write) {
\t\t\t\t\t\ttrashDisable(th);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (Object.keys(toChkTh).length) {
\t\t\t\t\tself.request({
\t\t\t\t\t\tdata : {cmd : 'info', targets : Object.keys(toChkTh)},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\tif (data && data.files) {
\t\t\t\t\t\t\t\$.each(data.files, function(i, dir) {
\t\t\t\t\t\t\t\tif (dir.mime === 'directory' && dir.write) {
\t\t\t\t\t\t\t\t\tdelete toChkTh[dir.hash];
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\$.each(toChkTh, trashDisable);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t// to enable / disable
\t\t\t\tself[self.options.enableAlways? 'enable' : 'disable']();
\t\t\t});
\t\t
\t\t// self.timeEnd('load');
\t\t// End of bootUp()
\t};
\t
\t// call bootCallback function with elFinder instance, extraObject - { dfrdsBeforeBootup: dfrdsBeforeBootup }
\tif (bootCallback && typeof bootCallback === 'function') {
\t\tself.bootCallback = bootCallback;
\t\tbootCallback.call(node.get(0), self, { dfrdsBeforeBootup: dfrdsBeforeBootup });
\t}
\t
\t// call dfrdsBeforeBootup functions then boot up elFinder
\t\$.when.apply(null, dfrdsBeforeBootup).done(function() {
\t\tbootUp();
\t}).fail(function(error) {
\t\tself.error(error);
\t});
};

//register elFinder to global scope
if (typeof toGlobal === 'undefined' || toGlobal) {
\twindow.elFinder = elFinder;
}

/**
 * Prototype
 * 
 * @type  Object
 */
elFinder.prototype = {
\t
\tuniqueid : 0,
\t
\tres : function(type, id) {
\t\treturn this.resources[type] && this.resources[type][id];
\t}, 

\t/**
\t * User os. Required to bind native shortcuts for open/rename
\t *
\t * @type String
\t **/
\tOS : navigator.userAgent.indexOf('Mac') !== -1 ? 'mac' : navigator.userAgent.indexOf('Win') !== -1  ? 'win' : 'other',
\t
\t/**
\t * User browser UA.
\t * jQuery.browser: version deprecated: 1.3, removed: 1.9
\t *
\t * @type Object
\t **/
\tUA : (function(){
\t\tvar self = this,
\t\t\twebkit = !document.unqueID && !window.opera && !window.sidebar && 'localStorage' in window && 'WebkitAppearance' in document.documentElement.style,
\t\t\tchrome = webkit && window.chrome,
\t\t\t/*setRotated = function() {
\t\t\t\tvar a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0;
\t\t\t\tif (a === -90) {
\t\t\t\t\ta = 270;
\t\t\t\t}
\t\t\t\tUA.Angle = a;
\t\t\t\tUA.Rotated = a % 180 === 0? false : true;
\t\t\t},*/
\t\t\tUA = {
\t\t\t\t// Browser IE <= IE 6
\t\t\t\tltIE6   : typeof window.addEventListener == \"undefined\" && typeof document.documentElement.style.maxHeight == \"undefined\",
\t\t\t\t// Browser IE <= IE 7
\t\t\t\tltIE7   : typeof window.addEventListener == \"undefined\" && typeof document.querySelectorAll == \"undefined\",
\t\t\t\t// Browser IE <= IE 8
\t\t\t\tltIE8   : typeof window.addEventListener == \"undefined\" && typeof document.getElementsByClassName == \"undefined\",
\t\t\t\t// Browser IE <= IE 9
\t\t\t\tltIE9  : document.uniqueID && document.documentMode <= 9,
\t\t\t\t// Browser IE <= IE 10
\t\t\t\tltIE10  : document.uniqueID && document.documentMode <= 10,
\t\t\t\t// Browser IE >= IE 11
\t\t\t\tgtIE11  : document.uniqueID && document.documentMode >= 11,
\t\t\t\tIE      : document.uniqueID,
\t\t\t\tFirefox : window.sidebar,
\t\t\t\tOpera   : window.opera,
\t\t\t\tWebkit  : webkit,
\t\t\t\tChrome  : chrome,
\t\t\t\tEdge    : (chrome && window.msCredentials)? true : false,
\t\t\t\tSafari  : webkit && !window.chrome,
\t\t\t\tMobile  : typeof window.orientation != \"undefined\",
\t\t\t\tTouch   : typeof window.ontouchstart != \"undefined\",
\t\t\t\tiOS     : navigator.platform.match(/^iP(?:[ao]d|hone)/),
\t\t\t\tMac     : navigator.platform.match(/^Mac/),
\t\t\t\tFullscreen : (typeof (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen) !== 'undefined'),
\t\t\t\tAngle   : 0,
\t\t\t\tRotated : false,
\t\t\t\tCSS : (function() {
\t\t\t\t\tvar aStyle = document.createElement('a').style,
\t\t\t\t\t\tpStyle = document.createElement('p').style,
\t\t\t\t\t\tcss;
\t\t\t\t\tcss = 'position:sticky;position:-webkit-sticky;';
\t\t\t\t\tcss += 'width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;';
\t\t\t\t\taStyle.cssText = css;
\t\t\t\t\treturn {
\t\t\t\t\t\tpositionSticky : aStyle.position.indexOf('sticky')!==-1,
\t\t\t\t\t\twidthMaxContent : aStyle.width.indexOf('max-content')!==-1,
\t\t\t\t\t\tflex : typeof pStyle.flex !== 'undefined'
\t\t\t\t\t};
\t\t\t\t})()
\t\t\t};
\t\t\treturn UA;
\t})(),
\t
\t/**
\t * Is cookie enabled
\t * 
\t * @type Boolean
\t */
\tcookieEnabled : (function() {
\t\tvar res = false,
\t\t\ttest = 'elftest=';
\t\tdocument.cookie = test + '1';
\t\tres = document.cookie.split(test).length === 2;
\t\tdocument.cookie = test + ';max-age=0';
\t\treturn res;
\t})(),

\t/**
\t * Has RequireJS?
\t * 
\t * @type Boolean
\t */
\thasRequire : (typeof define === 'function' && define.amd),
\t
\t/**
\t * Current request command
\t * 
\t * @type  String
\t */
\tcurrentReqCmd : '',
\t
\t/**
\t * Current keyboard state
\t * 
\t * @type  Object
\t */
\tkeyState : {},
\t
\t/**
\t * Internationalization object
\t * 
\t * @type  Object
\t */
\ti18 : {
\t\ten : {
\t\t\ttranslator      : '',
\t\t\tlanguage        : 'English',
\t\t\tdirection       : 'ltr',
\t\t\tdateFormat      : 'd.m.Y H:i',
\t\t\tfancyDateFormat : '\$1 H:i',
\t\t\tnonameDateFormat : 'ymd-His',
\t\t\tmessages        : {}
\t\t},
\t\tmonths : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
\t\tmonthsShort : ['msJan', 'msFeb', 'msMar', 'msApr', 'msMay', 'msJun', 'msJul', 'msAug', 'msSep', 'msOct', 'msNov', 'msDec'],

\t\tdays : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
\t\tdaysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
\t},
\t
\t/**
\t * File mimetype to kind mapping
\t * 
\t * @type  Object
\t */
\tkinds : \t{
\t\t\t'unknown'                       : 'Unknown',
\t\t\t'directory'                     : 'Folder',
\t\t\t'group'                         : 'Selects',
\t\t\t'symlink'                       : 'Alias',
\t\t\t'symlink-broken'                : 'AliasBroken',
\t\t\t'application/x-empty'           : 'TextPlain',
\t\t\t'application/postscript'        : 'Postscript',
\t\t\t'application/vnd.ms-office'     : 'MsOffice',
\t\t\t'application/msword'            : 'MsWord',
\t\t\t'application/vnd.ms-word'       : 'MsWord',
\t\t\t'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'MsWord',
\t\t\t'application/vnd.ms-word.document.macroEnabled.12'                        : 'MsWord',
\t\t\t'application/vnd.openxmlformats-officedocument.wordprocessingml.template' : 'MsWord',
\t\t\t'application/vnd.ms-word.template.macroEnabled.12'                        : 'MsWord',
\t\t\t'application/vnd.ms-excel'      : 'MsExcel',
\t\t\t'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'       : 'MsExcel',
\t\t\t'application/vnd.ms-excel.sheet.macroEnabled.12'                          : 'MsExcel',
\t\t\t'application/vnd.openxmlformats-officedocument.spreadsheetml.template'    : 'MsExcel',
\t\t\t'application/vnd.ms-excel.template.macroEnabled.12'                       : 'MsExcel',
\t\t\t'application/vnd.ms-excel.sheet.binary.macroEnabled.12'                   : 'MsExcel',
\t\t\t'application/vnd.ms-excel.addin.macroEnabled.12'                          : 'MsExcel',
\t\t\t'application/vnd.ms-powerpoint' : 'MsPP',
\t\t\t'application/vnd.openxmlformats-officedocument.presentationml.presentation' : 'MsPP',
\t\t\t'application/vnd.ms-powerpoint.presentation.macroEnabled.12'              : 'MsPP',
\t\t\t'application/vnd.openxmlformats-officedocument.presentationml.slideshow'  : 'MsPP',
\t\t\t'application/vnd.ms-powerpoint.slideshow.macroEnabled.12'                 : 'MsPP',
\t\t\t'application/vnd.openxmlformats-officedocument.presentationml.template'   : 'MsPP',
\t\t\t'application/vnd.ms-powerpoint.template.macroEnabled.12'                  : 'MsPP',
\t\t\t'application/vnd.ms-powerpoint.addin.macroEnabled.12'                     : 'MsPP',
\t\t\t'application/vnd.openxmlformats-officedocument.presentationml.slide'      : 'MsPP',
\t\t\t'application/vnd.ms-powerpoint.slide.macroEnabled.12'                     : 'MsPP',
\t\t\t'application/pdf'               : 'PDF',
\t\t\t'application/xml'               : 'XML',
\t\t\t'application/vnd.oasis.opendocument.text' : 'OO',
\t\t\t'application/vnd.oasis.opendocument.text-template'         : 'OO',
\t\t\t'application/vnd.oasis.opendocument.text-web'              : 'OO',
\t\t\t'application/vnd.oasis.opendocument.text-master'           : 'OO',
\t\t\t'application/vnd.oasis.opendocument.graphics'              : 'OO',
\t\t\t'application/vnd.oasis.opendocument.graphics-template'     : 'OO',
\t\t\t'application/vnd.oasis.opendocument.presentation'          : 'OO',
\t\t\t'application/vnd.oasis.opendocument.presentation-template' : 'OO',
\t\t\t'application/vnd.oasis.opendocument.spreadsheet'           : 'OO',
\t\t\t'application/vnd.oasis.opendocument.spreadsheet-template'  : 'OO',
\t\t\t'application/vnd.oasis.opendocument.chart'                 : 'OO',
\t\t\t'application/vnd.oasis.opendocument.formula'               : 'OO',
\t\t\t'application/vnd.oasis.opendocument.database'              : 'OO',
\t\t\t'application/vnd.oasis.opendocument.image'                 : 'OO',
\t\t\t'application/vnd.openofficeorg.extension'                  : 'OO',
\t\t\t'application/x-shockwave-flash' : 'AppFlash',
\t\t\t'application/flash-video'       : 'Flash video',
\t\t\t'application/x-bittorrent'      : 'Torrent',
\t\t\t'application/javascript'        : 'JS',
\t\t\t'application/rtf'               : 'RTF',
\t\t\t'application/rtfd'              : 'RTF',
\t\t\t'application/x-font-ttf'        : 'TTF',
\t\t\t'application/x-font-otf'        : 'OTF',
\t\t\t'application/x-rpm'             : 'RPM',
\t\t\t'application/x-web-config'      : 'TextPlain',
\t\t\t'application/xhtml+xml'         : 'HTML',
\t\t\t'application/docbook+xml'       : 'DOCBOOK',
\t\t\t'application/x-awk'             : 'AWK',
\t\t\t'application/x-gzip'            : 'GZIP',
\t\t\t'application/x-bzip2'           : 'BZIP',
\t\t\t'application/x-xz'              : 'XZ',
\t\t\t'application/zip'               : 'ZIP',
\t\t\t'application/x-zip'               : 'ZIP',
\t\t\t'application/x-rar'             : 'RAR',
\t\t\t'application/x-tar'             : 'TAR',
\t\t\t'application/x-7z-compressed'   : '7z',
\t\t\t'application/x-jar'             : 'JAR',
\t\t\t'text/plain'                    : 'TextPlain',
\t\t\t'text/x-php'                    : 'PHP',
\t\t\t'text/html'                     : 'HTML',
\t\t\t'text/javascript'               : 'JS',
\t\t\t'text/css'                      : 'CSS',
\t\t\t'text/rtf'                      : 'RTF',
\t\t\t'text/rtfd'                     : 'RTF',
\t\t\t'text/x-c'                      : 'C',
\t\t\t'text/x-csrc'                   : 'C',
\t\t\t'text/x-chdr'                   : 'CHeader',
\t\t\t'text/x-c++'                    : 'CPP',
\t\t\t'text/x-c++src'                 : 'CPP',
\t\t\t'text/x-c++hdr'                 : 'CPPHeader',
\t\t\t'text/x-shellscript'            : 'Shell',
\t\t\t'application/x-csh'             : 'Shell',
\t\t\t'text/x-python'                 : 'Python',
\t\t\t'text/x-java'                   : 'Java',
\t\t\t'text/x-java-source'            : 'Java',
\t\t\t'text/x-ruby'                   : 'Ruby',
\t\t\t'text/x-perl'                   : 'Perl',
\t\t\t'text/x-sql'                    : 'SQL',
\t\t\t'text/xml'                      : 'XML',
\t\t\t'text/x-comma-separated-values' : 'CSV',
\t\t\t'text/x-markdown'               : 'Markdown',
\t\t\t'image/x-ms-bmp'                : 'BMP',
\t\t\t'image/jpeg'                    : 'JPEG',
\t\t\t'image/gif'                     : 'GIF',
\t\t\t'image/png'                     : 'PNG',
\t\t\t'image/tiff'                    : 'TIFF',
\t\t\t'image/x-targa'                 : 'TGA',
\t\t\t'image/vnd.adobe.photoshop'     : 'PSD',
\t\t\t'image/xbm'                     : 'XBITMAP',
\t\t\t'image/pxm'                     : 'PXM',
\t\t\t'audio/mpeg'                    : 'AudioMPEG',
\t\t\t'audio/midi'                    : 'AudioMIDI',
\t\t\t'audio/ogg'                     : 'AudioOGG',
\t\t\t'audio/mp4'                     : 'AudioMPEG4',
\t\t\t'audio/x-m4a'                   : 'AudioMPEG4',
\t\t\t'audio/wav'                     : 'AudioWAV',
\t\t\t'audio/x-mp3-playlist'          : 'AudioPlaylist',
\t\t\t'video/x-dv'                    : 'VideoDV',
\t\t\t'video/mp4'                     : 'VideoMPEG4',
\t\t\t'video/mpeg'                    : 'VideoMPEG',
\t\t\t'video/x-msvideo'               : 'VideoAVI',
\t\t\t'video/quicktime'               : 'VideoMOV',
\t\t\t'video/x-ms-wmv'                : 'VideoWM',
\t\t\t'video/x-flv'                   : 'VideoFlash',
\t\t\t'video/x-matroska'              : 'VideoMKV',
\t\t\t'video/ogg'                     : 'VideoOGG'
\t\t},
\t
\t/**
\t * File mimetype to file extention mapping
\t * 
\t * @type  Object
\t * @see   elFinder.mimetypes.js
\t */
\tmimeTypes : {},
\t
\t/**
\t * Ajax request data validation rules
\t * 
\t * @type  Object
\t */
\trules : {
\t\tdefaults : function(data) {
\t\t\tif (!data
\t\t\t|| (data.added && !Array.isArray(data.added))
\t\t\t||  (data.removed && !Array.isArray(data.removed))
\t\t\t||  (data.changed && !Array.isArray(data.changed))) {
\t\t\t\treturn false;
\t\t\t}
\t\t\treturn true;
\t\t},
\t\topen    : function(data) { return data && data.cwd && data.files && \$.isPlainObject(data.cwd) && Array.isArray(data.files); },
\t\ttree    : function(data) { return data && data.tree && Array.isArray(data.tree); },
\t\tparents : function(data) { return data && data.tree && Array.isArray(data.tree); },
\t\ttmb     : function(data) { return data && data.images && (\$.isPlainObject(data.images) || Array.isArray(data.images)); },
\t\tupload  : function(data) { return data && (\$.isPlainObject(data.added) || Array.isArray(data.added));},
\t\tsearch  : function(data) { return data && data.files && Array.isArray(data.files); }
\t},
\t
\t/**
\t * Commands costructors
\t *
\t * @type Object
\t */
\tcommands : {},
\t
\t/**
\t * Commands to add the item (space delimited)
\t * 
\t * @type String
\t */
\tcmdsToAdd : 'archive duplicate extract mkdir mkfile paste rm upload',
\t
\tparseUploadData : function(text) {
\t\tvar self = this,
\t\t\tdata;
\t\t
\t\tif (!\$.trim(text)) {
\t\t\treturn {error : ['errResponse', 'errDataEmpty']};
\t\t}
\t\t
\t\ttry {
\t\t\tdata = JSON.parse(text);
\t\t} catch (e) {
\t\t\treturn {error : ['errResponse', 'errDataNotJSON']};
\t\t}
\t\t
\t\tdata = self.normalize(data);
\t\tif (!self.validResponse('upload', data)) {
\t\t\treturn {error : (data.norError || ['errResponse'])};
\t\t}
\t\tdata.removed = \$.merge((data.removed || []), \$.map(data.added || [], function(f) { return self.file(f.hash)? f.hash : null; }));
\t\treturn data;
\t\t
\t},
\t
\tiframeCnt : 0,
\t
\tuploads : {
\t\t// xhr muiti uploading flag
\t\txhrUploading: false,
\t\t
\t\t// Timer of request fail to sync
\t\tfailSyncTm: null,
\t\t
\t\t// current chunkfail requesting chunk
\t\tchunkfailReq: {},
\t\t
\t\t// check file/dir exists
\t\tcheckExists: function(files, target, fm, isDir) {
\t\t\tvar dfrd = \$.Deferred(),
\t\t\t\tnames, renames = [], hashes = {}, chkFiles = [],
\t\t\t\tcancel = function() {
\t\t\t\t\tvar i = files.length;
\t\t\t\t\twhile (--i > -1) {
\t\t\t\t\t\tfiles[i]._remove = true;
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tresolve = function() {
\t\t\t\t\tdfrd.resolve(renames, hashes);
\t\t\t\t},
\t\t\t\tcheck = function() {
\t\t\t\t\tvar existed = [], exists = [], i, c,
\t\t\t\t\t\tpathStr = target !== fm.cwd().hash? fm.path(target, true) + fm.option('separator', target) : '',
\t\t\t\t\t\tconfirm = function(ndx) {
\t\t\t\t\t\t\tvar last = ndx == exists.length-1,
\t\t\t\t\t\t\t\topts = {
\t\t\t\t\t\t\t\t\tcssClass : 'elfinder-confirm-upload',
\t\t\t\t\t\t\t\t\ttitle  : fm.i18n('cmdupload'),
\t\t\t\t\t\t\t\t\ttext   : ['errExists', pathStr + exists[ndx].name, 'confirmRepl'], 
\t\t\t\t\t\t\t\t\tall    : !last,
\t\t\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\t\t\tlabel    : 'btnYes',
\t\t\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t\t\t: resolve();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\treject : {
\t\t\t\t\t\t\t\t\t\tlabel    : 'btnNo',
\t\t\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\t\t\tvar i;
\t\t\t
\t\t\t\t\t\t\t\t\t\t\tif (all) {
\t\t\t\t\t\t\t\t\t\t\t\ti = exists.length;
\t\t\t\t\t\t\t\t\t\t\t\twhile (ndx < i--) {
\t\t\t\t\t\t\t\t\t\t\t\t\tfiles[exists[i].i]._remove = true;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tfiles[exists[ndx].i]._remove = true;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t
\t\t\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t\t\t: resolve();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\tcancel();
\t\t\t\t\t\t\t\t\t\t\tresolve();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tbuttons : [
\t\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\t\tlabel : 'btnBackup',
\t\t\t\t\t\t\t\t\t\t\tcssClass : 'elfinder-confirm-btn-backup',
\t\t\t\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\t\t\t\tvar i;
\t\t\t\t\t\t\t\t\t\t\t\tif (all) {
\t\t\t\t\t\t\t\t\t\t\t\t\ti = exists.length;
\t\t\t\t\t\t\t\t\t\t\t\t\twhile (ndx < i--) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\trenames.push(exists[i].name);
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\trenames.push(exists[ndx].name);
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t\t\t\t: resolve();
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t]
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (!isDir) {
\t\t\t\t\t\t\t\topts.buttons.push({
\t\t\t\t\t\t\t\t\tlabel : 'btnRename' + (last? '' : 'All'),
\t\t\t\t\t\t\t\t\tcssClass : 'elfinder-confirm-btn-rename',
\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\trenames = null;
\t\t\t\t\t\t\t\t\t\tresolve();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (fm.iframeCnt > 0) {
\t\t\t\t\t\t\t\tdelete opts.reject;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tfm.confirm(opts);
\t\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\tif (! fm.file(target).read) {
\t\t\t\t\t\t// for dropbox type
\t\t\t\t\t\tresolve();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tnames = \$.map(files, function(file, i) { return file.name && (!fm.UA.iOS || file.name !== 'image.jpg')? {i: i, name: file.name} : null ;});
\t\t\t\t\t
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'ls', target : target, intersect : \$.map(names, function(item) { return item.name;})},
\t\t\t\t\t\tnotify : {type : 'preupload', cnt : 1, hideCnt : true},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tvar existedArr, cwdItems;
\t\t\t\t\t\tif (data) {
\t\t\t\t\t\t\tif (data.error) {
\t\t\t\t\t\t\t\tcancel();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
\t\t\t\t\t\t\t\t\tif (data.list) {
\t\t\t\t\t\t\t\t\t\tif (Array.isArray(data.list)) {
\t\t\t\t\t\t\t\t\t\t\texisted = data.list || [];
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\texistedArr = [];
\t\t\t\t\t\t\t\t\t\t\texisted = \$.map(data.list, function(n) {
\t\t\t\t\t\t\t\t\t\t\t\tif (typeof n === 'string') {
\t\t\t\t\t\t\t\t\t\t\t\t\treturn n;
\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t// support to >=2.1.11 plugin Normalizer, Sanitizer
\t\t\t\t\t\t\t\t\t\t\t\t\texistedArr = existedArr.concat(n);
\t\t\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\tif (existedArr.length) {
\t\t\t\t\t\t\t\t\t\t\t\texisted = existed.concat(existedArr);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\thashes = data.list;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\texists = \$.grep(names, function(name){
\t\t\t\t\t\t\t\t\t\t\treturn \$.inArray(name.name, existed) !== -1 ? true : false ;
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tif (exists.length && existed.length && target == fm.cwd().hash) {
\t\t\t\t\t\t\t\t\t\t\tcwdItems = \$.map(fm.files(target), function(file) { return file.name; } );
\t\t\t\t\t\t\t\t\t\t\tif (\$.grep(existed, function(n) { 
\t\t\t\t\t\t\t\t\t\t\t\treturn \$.inArray(n, cwdItems) === -1? true : false;
\t\t\t\t\t\t\t\t\t\t\t}).length){
\t\t\t\t\t\t\t\t\t\t\t\tfm.sync();
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (exists.length > 0) {
\t\t\t\t\t\t\tconfirm(0);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tresolve();
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\tcancel();
\t\t\t\t\t\tresolve();
\t\t\t\t\t\terror && fm.error(error);
\t\t\t\t\t});
\t\t\t\t};
\t\t\tif (fm.api >= 2.1 && typeof files[0] == 'object') {
\t\t\t\tcheck();
\t\t\t} else {
\t\t\t\tresolve();
\t\t\t}
\t\t\treturn dfrd;
\t\t},
\t\t
\t\t// check droped contents
\t\tcheckFile : function(data, fm, target) {
\t\t\tif (!!data.checked || data.type == 'files') {
\t\t\t\treturn data.files;
\t\t\t} else if (data.type == 'data') {
\t\t\t\tvar dfrd = \$.Deferred(),
\t\t\t\tscanDfd = \$.Deferred(),
\t\t\t\tfiles = [],
\t\t\t\tpaths = [],
\t\t\t\tdirctorys = [],
\t\t\t\tprocessing = 0,
\t\t\t\titems,
\t\t\t\tmkdirs = [],
\t\t\t\tcancel = false,
\t\t\t\ttoArray = function(list) {
\t\t\t\t\treturn Array.prototype.slice.call(list || [], 0);
\t\t\t\t},
\t\t\t\tdoScan = function(items) {
\t\t\t\t\tvar entry, readEntries,
\t\t\t\t\t\texcludes = fm.options.folderUploadExclude[fm.OS] || null,
\t\t\t\t\t\tlength = items.length,
\t\t\t\t\t\tcheck = function() {
\t\t\t\t\t\t\tif (--processing < 1 && scanDfd.state() === 'pending') {
\t\t\t\t\t\t\t\tscanDfd.resolve();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tpushItem = function(file) {
\t\t\t\t\t\t\tif (! excludes || ! file.name.match(excludes)) {
\t\t\t\t\t\t\t\tpaths.push(entry.fullPath || '');
\t\t\t\t\t\t\t\tfiles.push(file);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tcheck();
\t\t\t\t\t\t},
\t\t\t\t\t\treadEntries = function(dirReader) {
\t\t\t\t\t\t\tvar entries = [],
\t\t\t\t\t\t\t\tread = function() {
\t\t\t\t\t\t\t\t\tdirReader.readEntries(function(results) {
\t\t\t\t\t\t\t\t\t\tif (cancel || !results.length) {
\t\t\t\t\t\t\t\t\t\t\tfor (var i = 0; i < entries.length; i++) {
\t\t\t\t\t\t\t\t\t\t\t\tif (cancel) {
\t\t\t\t\t\t\t\t\t\t\t\t\tscanDfd.reject();
\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\tdoScan([entries[i]]);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\tcheck();
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tentries = entries.concat(toArray(results));
\t\t\t\t\t\t\t\t\t\t\tread();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}, check);
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\tread();
\t\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\tprocessing++;
\t\t\t\t\tfor (var i = 0; i < length; i++) {
\t\t\t\t\t\tif (cancel) {
\t\t\t\t\t\t\tscanDfd.reject();
\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t}
\t\t\t\t\t\tentry = items[i];
\t\t\t\t\t\tif (entry) {
\t\t\t\t\t\t\tif (entry.isFile) {
\t\t\t\t\t\t\t\tprocessing++;
\t\t\t\t\t\t\t\tentry.file(pushItem, check);
\t\t\t\t\t\t\t} else if (entry.isDirectory) {
\t\t\t\t\t\t\t\tif (fm.api >= 2.1) {
\t\t\t\t\t\t\t\t\tprocessing++;
\t\t\t\t\t\t\t\t\tmkdirs.push(entry.fullPath);
\t\t\t\t\t\t\t\t\treadEntries(entry.createReader()); // Start reading dirs.
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tcheck();
\t\t\t\t\treturn scanDfd;
\t\t\t\t}, hasDirs;
\t\t\t\t
\t\t\t\titems = \$.map(data.files.items, function(item){
\t\t\t\t\treturn item.getAsEntry? item.getAsEntry() : item.webkitGetAsEntry();
\t\t\t\t});
\t\t\t\t\$.each(items, function(i, item) {
\t\t\t\t\tif (item.isDirectory) {
\t\t\t\t\t\thasDirs = true;
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (items.length > 0) {
\t\t\t\t\tfm.uploads.checkExists(items, target, fm, hasDirs).done(function(renames, hashes){
\t\t\t\t\t\tvar dfds = [];
\t\t\t\t\t\tif (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
\t\t\t\t\t\t\tif (renames === null) {
\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t\trenames = [];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\titems = \$.grep(items, function(item){
\t\t\t\t\t\t\t\tvar i, bak, hash, dfd, hi;
\t\t\t\t\t\t\t\tif (item.isDirectory && renames.length) {
\t\t\t\t\t\t\t\t\ti = \$.inArray(item.name, renames);
\t\t\t\t\t\t\t\t\tif (i !== -1) {
\t\t\t\t\t\t\t\t\t\trenames.splice(i, 1);
\t\t\t\t\t\t\t\t\t\tbak = fm.uniqueName(item.name + fm.options.backupSuffix , null, '');
\t\t\t\t\t\t\t\t\t\t\$.each(hashes, function(h, name) {
\t\t\t\t\t\t\t\t\t\t\tif (item.name == name) {
\t\t\t\t\t\t\t\t\t\t\t\thash = h;
\t\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tif (! hash) {
\t\t\t\t\t\t\t\t\t\t\thash = fm.fileByName(item.name, target).hash;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tfm.lockfiles({files : [hash]});
\t\t\t\t\t\t\t\t\t\tdfd = fm.request({
\t\t\t\t\t\t\t\t\t\t\tdata   : {cmd : 'rename', target : hash, name : bak},
\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'rename', cnt : 1}
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\t\t\t\titem._remove = true;
\t\t\t\t\t\t\t\t\t\t\tfm.sync();
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\t\t\tfm.unlockfiles({files : [hash]});
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tdfds.push(dfd);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn !item._remove? true : false;
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t\t\$.when.apply(\$, dfds).done(function(){
\t\t\t\t\t\t\tvar notifyto, msg,
\t\t\t\t\t\t\t\tid = +new Date();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (items.length > 0) {
\t\t\t\t\t\t\t\tmsg = fm.escape(items[0].name);
\t\t\t\t\t\t\t\tif (items.length > 1) {
\t\t\t\t\t\t\t\t\tmsg += ' ... ' + items.length + fm.i18n('items');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tnotifyto = setTimeout(function() {
\t\t\t\t\t\t\t\t\tfm.notify({
\t\t\t\t\t\t\t\t\t\ttype : 'readdir',
\t\t\t\t\t\t\t\t\t\tid : id,
\t\t\t\t\t\t\t\t\t\tcnt : 1,
\t\t\t\t\t\t\t\t\t\thideCnt: true,
\t\t\t\t\t\t\t\t\t\tmsg : fm.i18n('ntfreaddir') + ' (' + msg + ')',
\t\t\t\t\t\t\t\t\t\tcancel: function() {
\t\t\t\t\t\t\t\t\t\t\tcancel = true;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}, fm.options.notifyDelay);
\t\t\t\t\t\t\t\tdoScan(items).done(function() {
\t\t\t\t\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\t\t\t\t\tfm.notify({type : 'readdir', id: id, cnt : -1});
\t\t\t\t\t\t\t\t\tif (cancel) {
\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tdfrd.resolve([files, paths, renames, hashes, mkdirs]);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t});
\t\t\t\t\treturn dfrd.promise();
\t\t\t\t} else {
\t\t\t\t\treturn dfrd.reject();
\t\t\t\t}
\t\t\t} else {
\t\t\t\tvar ret = [];
\t\t\t\tvar check = [];
\t\t\t\tvar str = data.files[0];
\t\t\t\tif (data.type == 'html') {
\t\t\t\t\tvar tmp = \$(\"<html></html>\").append(\$.parseHTML(str.replace(/ src=/ig, ' _elfsrc='))),
\t\t\t\t\t\tatag;
\t\t\t\t\t\$('img[_elfsrc]', tmp).each(function(){
\t\t\t\t\t\tvar url, purl,
\t\t\t\t\t\tself = \$(this),
\t\t\t\t\t\tpa = self.closest('a');
\t\t\t\t\t\tif (pa && pa.attr('href') && pa.attr('href').match(/\\.(?:jpe?g|gif|bmp|png)/i)) {
\t\t\t\t\t\t\tpurl = pa.attr('href');
\t\t\t\t\t\t}
\t\t\t\t\t\turl = self.attr('_elfsrc');
\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\tif (purl) {
\t\t\t\t\t\t\t\t\$.inArray(purl, ret) == -1 && ret.push(purl);
\t\t\t\t\t\t\t\t\$.inArray(url, check) == -1 &&  check.push(url);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\$.inArray(url, ret) == -1 && ret.push(url);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t// Probably it's clipboard data
\t\t\t\t\t\tif (ret.length === 1 && ret[0].match(/^data:image\\/png/)) {
\t\t\t\t\t\t\tdata.clipdata = true;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tatag = \$('a[href]', tmp);
\t\t\t\t\tatag.each(function(){
\t\t\t\t\t\tvar text, loc,
\t\t\t\t\t\t\tparseUrl = function(url) {
\t\t\t\t\t\t\t\tvar a = document.createElement('a');
\t\t\t\t\t\t\t\ta.href = url;
\t\t\t\t\t\t\t\treturn a;
\t\t\t\t\t\t\t};
\t\t\t\t\t\tif (text = \$(this).text()) {
\t\t\t\t\t\t\tloc = parseUrl(\$(this).attr('href'));
\t\t\t\t\t\t\tif (loc.href && loc.href.match(/^(?:ht|f)tp/i) && (atag.length === 1 || ! loc.pathname.match(/(?:\\.html?|\\/[^\\/.]*)\$/i) || \$.trim(text).match(/\\.[a-z0-9-]{1,10}\$/i))) {
\t\t\t\t\t\t\t\tif (\$.inArray(loc.href, ret) == -1 && \$.inArray(loc.href, check) == -1) ret.push(loc.href);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tvar regex, m, url;
\t\t\t\t\tregex = /((?:ht|f)tps?:\\/\\/[-_.!~*\\'()a-z0-9;/?:\\@&=+\\\$,%#\\*\\[\\]]+)/ig;
\t\t\t\t\twhile (m = regex.exec(str)) {
\t\t\t\t\t\turl = m[1].replace(/&amp;/g, '&');
\t\t\t\t\t\tif (\$.inArray(url, ret) == -1) ret.push(url);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn ret;
\t\t\t}
\t\t},

\t\t// upload transport using XMLHttpRequest
\t\txhr : function(data, fm) { 
\t\t\tvar self   = fm ? fm : this,
\t\t\t\tnode        = self.getUI(),
\t\t\t\txhr         = new XMLHttpRequest(),
\t\t\t\tnotifyto    = null,
\t\t\t\tnotifyto1   = null,
\t\t\t\tnotifyto2   = null,
\t\t\t\tdataChecked = data.checked,
\t\t\t\tisDataType  = (data.isDataType || data.type == 'data'),
\t\t\t\ttarget      = (data.target || self.cwd().hash),
\t\t\t\tdropEvt     = (data.dropEvt || null),
\t\t\t\textraData   = data.extraData || null,
\t\t\t\tchunkEnable = (self.option('uploadMaxConn', target) != -1),
\t\t\t\tmultiMax    = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))),
\t\t\t\tretryWait   = 10000, // 10 sec
\t\t\t\tretryMax    = 30, // 10 sec * 30 = 300 secs (Max 5 mins)
\t\t\t\tretry       = 0,
\t\t\t\tgetFile     = function(files) {
\t\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\t\tfile;
\t\t\t\t\tif (files.promise) {
\t\t\t\t\t\tfiles.always(function(f) {
\t\t\t\t\t\t\tdfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {});
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {});
\t\t\t\t\t}
\t\t\t\t\treturn dfd;
\t\t\t\t},
\t\t\t\tdfrd   = \$.Deferred()
\t\t\t\t\t.fail(function(err) {
\t\t\t\t\t\tvar error = self.parseError(err),
\t\t\t\t\t\t\tuserAbort;
\t\t\t\t\t\tif (error === 'userabort') {
\t\t\t\t\t\t\tuserAbort = true;
\t\t\t\t\t\t\terror = void 0;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (files && (self.uploads.xhrUploading || userAbort)) {
\t\t\t\t\t\t\t// send request om fail
\t\t\t\t\t\t\tgetFile(files).done(function(file) {
\t\t\t\t\t\t\t\tif (!userAbort) {
\t\t\t\t\t\t\t\t\ttriggerError(error, file);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (! file._cid) {
\t\t\t\t\t\t\t\t\t// send sync request
\t\t\t\t\t\t\t\t\tself.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm);
\t\t\t\t\t\t\t\t\tself.uploads.failSyncTm = setTimeout(function() {
\t\t\t\t\t\t\t\t\t\tself.sync(target);
\t\t\t\t\t\t\t\t\t}, 1000);
\t\t\t\t\t\t\t\t} else if (! self.uploads.chunkfailReq[file._cid]) {
\t\t\t\t\t\t\t\t\t// send chunkfail request
\t\t\t\t\t\t\t\t\tself.uploads.chunkfailReq[file._cid] = true;
\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\tdata : {
\t\t\t\t\t\t\t\t\t\t\t\tcmd: 'upload',
\t\t\t\t\t\t\t\t\t\t\t\ttarget: target,
\t\t\t\t\t\t\t\t\t\t\t\tchunk: file._chunk,
\t\t\t\t\t\t\t\t\t\t\t\tcid: file._cid,
\t\t\t\t\t\t\t\t\t\t\t\tupload: ['chunkfail'],
\t\t\t\t\t\t\t\t\t\t\t\tmimes: 'chunkfail'
\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\toptions : {
\t\t\t\t\t\t\t\t\t\t\t\ttype: 'post',
\t\t\t\t\t\t\t\t\t\t\t\turl: self.uploadURL
\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\tpreventDefault: true
\t\t\t\t\t\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\t\t\t\t\tdelete self.uploads.chunkfailReq[file._chunk];
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}, 1000);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\ttriggerError(error);
\t\t\t\t\t\t}
\t\t\t\t\t\t!userAbort && self.sync();
\t\t\t\t\t\tself.uploads.xhrUploading = false;
\t\t\t\t\t\tfiles = null;
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tself.uploads.xhrUploading = false;
\t\t\t\t\t\tfiles = null;
\t\t\t\t\t\tif (data) {
\t\t\t\t\t\t\tself.currentReqCmd = 'upload';
\t\t\t\t\t\t\tdata.warning && triggerError(data.warning);
\t\t\t\t\t\t\tself.updateCache(data);
\t\t\t\t\t\t\tdata.removed && data.removed.length && self.remove(data);
\t\t\t\t\t\t\tdata.added   && data.added.length   && self.add(data);
\t\t\t\t\t\t\tdata.changed && data.changed.length && self.change(data);
\t\t\t\t\t\t\tself.trigger('upload', data, false);
\t\t\t\t\t\t\tself.trigger('uploaddone');
\t\t\t\t\t\t\tif (data.toasts && Array.isArray(data.toasts)) {
\t\t\t\t\t\t\t\t\$.each(data.toasts, function() {
\t\t\t\t\t\t\t\t\tthis.msg && self.toast(this);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdata.sync && self.sync();
\t\t\t\t\t\t\tif (data.debug) {
\t\t\t\t\t\t\t\tself.responseDebug(data);
\t\t\t\t\t\t\t\tfm.debug('backend-debug', data);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.always(function() {
\t\t\t\t\t\tself.abortXHR(xhr);
\t\t\t\t\t\t// unregist fnAbort function
\t\t\t\t\t\tnode.off('uploadabort', fnAbort);
\t\t\t\t\t\t\$(window).off('unload', fnAbort);
\t\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\t\tnotifyto1 && clearTimeout(notifyto1);
\t\t\t\t\t\tnotifyto2 && clearTimeout(notifyto2);
\t\t\t\t\t\tdataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
\t\t\t\t\t\tnotifyto1 && uploadedNtf && self.notify({type : 'chunkmerge', cnt : -cnt});
\t\t\t\t\t\tchunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1});
\t\t\t\t\t}),
\t\t\t\tformData    = new FormData(),
\t\t\t\tfiles       = data.input ? data.input.files : self.uploads.checkFile(data, self, target), 
\t\t\t\tcnt         = data.checked? (isDataType? files[0].length : files.length) : files.length,
\t\t\t\tisChunked   = false,
\t\t\t\tloaded      = 0,
\t\t\t\tprev        = 0,
\t\t\t\tfilesize    = 0,
\t\t\t\tnotify      = false,
\t\t\t\tnotifyElm   = self.ui.notify,
\t\t\t\tcancelBtn   = true,
\t\t\t\tuploadedNtf = false,
\t\t\t\tabort       = false,
\t\t\t\tcheckNotify = function() {
\t\t\t\t\tif (!notify && (ntfUpload = notifyElm.children('.elfinder-notify-upload')).length) {
\t\t\t\t\t\tnotify = true;
\t\t\t\t\t}
\t\t\t\t\treturn notify;
\t\t\t\t},
\t\t\t\tfnAbort     = function(e, error) {
\t\t\t\t\tabort = true;
\t\t\t\t\tself.abortXHR(xhr, { quiet: true, abort: true });
\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\tif (checkNotify()) {
\t\t\t\t\t\tself.notify({type : 'upload', cnt : ntfUpload.data('cnt') * -1, progress : 0, size : 0});
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcancelToggle = function(show, hasChunk) {
\t\t\t\t\tntfUpload.children('.elfinder-notify-cancel')[show? 'show':'hide']();
\t\t\t\t\tcancelBtn = show;
\t\t\t\t},
\t\t\t\tstartNotify = function(size) {
\t\t\t\t\tif (!size) size = filesize;
\t\t\t\t\treturn setTimeout(function() {
\t\t\t\t\t\tnotify = true;
\t\t\t\t\t\tself.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size,
\t\t\t\t\t\t\tcancel: function() {
\t\t\t\t\t\t\t\tnode.trigger('uploadabort', 'userabort');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tntfUpload = notifyElm.children('.elfinder-notify-upload');
\t\t\t\t\t\tprev = loaded;
\t\t\t\t\t\tif (data.multiupload) {
\t\t\t\t\t\t\tcancelBtn && cancelToggle(true);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcancelToggle(cancelBtn && loaded < size);
\t\t\t\t\t\t}
\t\t\t\t\t}, self.options.notifyDelay);
\t\t\t\t},
\t\t\t\tdoRetry = function() {
\t\t\t\t\tif (retry++ <= retryMax) {
\t\t\t\t\t\tif (checkNotify() && prev) {
\t\t\t\t\t\t\tself.notify({type : 'upload', cnt : 0, progress : 0, size : prev});
\t\t\t\t\t\t}
\t\t\t\t\t\tself.abortXHR(xhr, { quiet: true });
\t\t\t\t\t\tprev = loaded = 0;
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tvar reqId;
\t\t\t\t\t\t\tif (! abort) {
\t\t\t\t\t\t\t\txhr.open('POST', self.uploadURL, true);
\t\t\t\t\t\t\t\tif (self.api >= 2.1029) {
\t\t\t\t\t\t\t\t\treqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
\t\t\t\t\t\t\t\t\t(typeof formData['delete'] === 'function') && formData['delete']('reqid');
\t\t\t\t\t\t\t\t\tformData.append('reqid', reqId);
\t\t\t\t\t\t\t\t\txhr._requestId = reqId;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\txhr.send(formData);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}, retryWait);
\t\t\t\t\t} else {
\t\t\t\t\t\tnode.trigger('uploadabort', ['errAbort', 'errTimeout']);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tprogress = function() {
\t\t\t\t\tvar node;
\t\t\t\t\tif (notify) {
\t\t\t\t\t\tdfrd.notifyWith(ntfUpload, [{
\t\t\t\t\t\t\tcnt: ntfUpload.data('cnt'),
\t\t\t\t\t\t\tprogress: ntfUpload.data('progress'),
\t\t\t\t\t\t\ttotal: ntfUpload.data('total')
\t\t\t\t\t\t}]);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\ttriggerError = function(err, file, unite) {
\t\t\t\t\terr && self.trigger('xhruploadfail', { error: err, file: file });
\t\t\t\t\tif (unite) {
\t\t\t\t\t\tif (err) {
\t\t\t\t\t\t\tif (errCnt < self.options.maxErrorDialogs) {
\t\t\t\t\t\t\t\tif (Array.isArray(err)) {
\t\t\t\t\t\t\t\t\terrors = errors.concat(err);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\terrors.push(err);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\terrCnt++;
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (err) {
\t\t\t\t\t\t\tself.error(err);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (errors.length) {
\t\t\t\t\t\t\t\tif (errCnt >= self.options.maxErrorDialogs) {
\t\t\t\t\t\t\t\t\terrors = errors.concat('moreErrors', errCnt - self.options.maxErrorDialogs);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tself.error(errors);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\terrors = [];
\t\t\t\t\t\t\terrCnt = 0;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\terrors = [],
\t\t\t\terrCnt = 0,
\t\t\t\trenames = (data.renames || null),
\t\t\t\thashes = (data.hashes || null),
\t\t\t\tchunkMerge = false,
\t\t\t\tntfUpload = \$();
\t\t\t
\t\t\t// regist fnAbort function
\t\t\tnode.one('uploadabort', fnAbort);
\t\t\t\$(window).one('unload.' + fm.namespace, fnAbort);
\t\t\t
\t\t\t!chunkMerge && (prev = loaded);
\t\t\t
\t\t\tif (!isDataType && !cnt) {
\t\t\t\treturn dfrd.reject(['errUploadNoFiles']);
\t\t\t}
\t\t\t
\t\t\txhr.addEventListener('error', function() {
\t\t\t\tif (xhr.status == 0) {
\t\t\t\t\tif (abort) {
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t} else {
\t\t\t\t\t\t// ff bug while send zero sized file
\t\t\t\t\t\t// for safari - send directory
\t\t\t\t\t\tif (!isDataType && data.files && \$.grep(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
\t\t\t\t\t\t\tdfrd.reject(['errAbort', 'errFolderUpload']);
\t\t\t\t\t\t} else if (data.input && \$.grep(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
\t\t\t\t\t\t\tdfrd.reject(['errUploadNoFiles']);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdoRetry();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tnode.trigger('uploadabort', 'errConnect');
\t\t\t\t}
\t\t\t}, false);
\t\t\t
\t\t\txhr.addEventListener('load', function(e) {
\t\t\t\tvar status = xhr.status, res, curr = 0, error = '', errData, errObj;
\t\t\t\t
\t\t\t\tself.setCustomHeaderByXhr(xhr);

\t\t\t\tif (status >= 400) {
\t\t\t\t\tif (status > 500) {
\t\t\t\t\t\terror = 'errResponse';
\t\t\t\t\t} else {
\t\t\t\t\t\terror = ['errResponse', 'errServerError'];
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (!xhr.responseText) {
\t\t\t\t\t\terror = ['errResponse', 'errDataEmpty'];
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (error) {
\t\t\t\t\tnode.trigger('uploadabort');
\t\t\t\t\tgetFile(files || {}).done(function(file) {
\t\t\t\t\t\treturn dfrd.reject(file._cid? null : error);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tloaded = filesize;
\t\t\t\t
\t\t\t\tif (checkNotify() && (curr = loaded - prev)) {
\t\t\t\t\tself.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
\t\t\t\t\tprogress();
\t\t\t\t}

\t\t\t\tres = self.parseUploadData(xhr.responseText);
\t\t\t\t
\t\t\t\t// chunked upload commit
\t\t\t\tif (res._chunkmerged) {
\t\t\t\t\tformData = new FormData();
\t\t\t\t\tvar _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}];
\t\t\t\t\tchunkMerge = true;
\t\t\t\t\tnode.off('uploadabort', fnAbort);
\t\t\t\t\tnotifyto2 = setTimeout(function() {
\t\t\t\t\t\tself.notify({type : 'chunkmerge', cnt : 1});
\t\t\t\t\t}, self.options.notifyDelay);
\t\t\t\t\tisDataType? send(_file, files[1]) : send(_file);
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\t
\t\t\t\tres._multiupload = data.multiupload? true : false;
\t\t\t\tif (res.error) {
\t\t\t\t\terrData = {
\t\t\t\t\t\tcmd: 'upload',
\t\t\t\t\t\terr: res,
\t\t\t\t\t\txhr: xhr,
\t\t\t\t\t\trc: xhr.status
\t\t\t\t\t};
\t\t\t\t\tself.trigger('uploadfail', res);
\t\t\t\t\t// trigger \"requestError\" event
\t\t\t\t\tself.trigger('requestError', errData);
\t\t\t\t\tif (errData._getEvent && errData._getEvent().isDefaultPrevented()) {
\t\t\t\t\t\tres.error = '';
\t\t\t\t\t}
\t\t\t\t\tif (res._chunkfailure || res._multiupload) {
\t\t\t\t\t\tabort = true;
\t\t\t\t\t\tself.uploads.xhrUploading = false;
\t\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\t\tif (ntfUpload.length) {
\t\t\t\t\t\t\tself.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
\t\t\t\t\t\t\tdfrd.reject(res);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t// for multi connection
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tdfrd.reject(res);
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tdfrd.resolve(res);
\t\t\t\t}
\t\t\t}, false);
\t\t\t
\t\t\txhr.upload.addEventListener('loadstart', function(e) {
\t\t\t\tif (!chunkMerge && e.lengthComputable) {
\t\t\t\t\tloaded = e.loaded;
\t\t\t\t\tretry && (loaded = 0);
\t\t\t\t\tfilesize = e.total;
\t\t\t\t\tif (!loaded) {
\t\t\t\t\t\tloaded = parseInt(filesize * 0.05);
\t\t\t\t\t}
\t\t\t\t\tif (checkNotify()) {
\t\t\t\t\t\tself.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize});
\t\t\t\t\t\tprev = loaded;
\t\t\t\t\t\tprogress();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}, false);
\t\t\t
\t\t\txhr.upload.addEventListener('progress', function(e) {
\t\t\t\tvar curr;

\t\t\t\tif (e.lengthComputable && !chunkMerge && xhr.readyState < 2) {
\t\t\t\t\t
\t\t\t\t\tloaded = e.loaded;

\t\t\t\t\t// to avoid strange bug in safari (not in chrome) with drag&drop.
\t\t\t\t\t// bug: macos finder opened in any folder,
\t\t\t\t\t// reset safari cache (option+command+e), reload elfinder page,
\t\t\t\t\t// drop file from finder
\t\t\t\t\t// on first attempt request starts (progress callback called ones) but never ends.
\t\t\t\t\t// any next drop - successfull.
\t\t\t\t\tif (!data.checked && loaded > 0 && !notifyto) {
\t\t\t\t\t\tnotifyto = startNotify(xhr._totalSize - loaded);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!filesize) {
\t\t\t\t\t\tfilesize = e.total;
\t\t\t\t\t\tif (!loaded) {
\t\t\t\t\t\t\tloaded = parseInt(filesize * 0.05);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tcurr = loaded - prev;
\t\t\t\t\tif (checkNotify() && (curr/e.total) >= 0.05) {
\t\t\t\t\t\tself.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
\t\t\t\t\t\tprev = loaded;
\t\t\t\t\t\tprogress();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!uploadedNtf && loaded >= filesize && !isChunked) {
\t\t\t\t\t\t// Use \"chunkmerge\" for \"server-in-process\" notification
\t\t\t\t\t\tuploadedNtf = true;
\t\t\t\t\t\tnotifyto1 = setTimeout(function() {
\t\t\t\t\t\t\tself.notify({type : 'chunkmerge', cnt : cnt});
\t\t\t\t\t\t}, self.options.notifyDelay);
\t\t\t\t\t}

\t\t\t\t\tif (cancelBtn && ! data.multiupload && loaded >= filesize) {
\t\t\t\t\t\tcheckNotify() && cancelToggle(false);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}, false);
\t\t\t
\t\t\tvar send = function(files, paths){
\t\t\t\tvar size = 0,
\t\t\t\tfcnt = 1,
\t\t\t\tsfiles = [],
\t\t\t\tc = 0,
\t\t\t\ttotal = cnt,
\t\t\t\tmaxFileSize,
\t\t\t\ttotalSize = 0,
\t\t\t\tchunked = [],
\t\t\t\tchunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system
\t\t\t\tBYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize
\t\t\t\tblobSlice = chunkEnable? false : '',
\t\t\t\tblobSize, blobMtime, blobName, i, start, end, chunks, blob, chunk, added, done, last, failChunk,
\t\t\t\tmulti = function(files, num){
\t\t\t\t\tvar sfiles = [], cid, sfilesLen = 0, cancelChk, hasChunk;
\t\t\t\t\tif (!abort) {
\t\t\t\t\t\twhile(files.length && sfiles.length < num) {
\t\t\t\t\t\t\tsfiles.push(files.shift());
\t\t\t\t\t\t}
\t\t\t\t\t\tsfilesLen = sfiles.length;
\t\t\t\t\t\tif (sfilesLen) {
\t\t\t\t\t\t\tcancelChk = sfilesLen;
\t\t\t\t\t\t\tfor (var i=0; i < sfilesLen; i++) {
\t\t\t\t\t\t\t\tif (abort) {
\t\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tcid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null);
\t\t\t\t\t\t\t\thasChunk = (hasChunk || cid)? true : false;
\t\t\t\t\t\t\t\tif (!!failChunk[cid]) {
\t\t\t\t\t\t\t\t\tlast--;
\t\t\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.exec('upload', {
\t\t\t\t\t\t\t\t\ttype: data.type,
\t\t\t\t\t\t\t\t\tisDataType: isDataType,
\t\t\t\t\t\t\t\t\tfiles: sfiles[i],
\t\t\t\t\t\t\t\t\tchecked: true,
\t\t\t\t\t\t\t\t\ttarget: target,
\t\t\t\t\t\t\t\t\tdropEvt: dropEvt,
\t\t\t\t\t\t\t\t\trenames: renames,
\t\t\t\t\t\t\t\t\thashes: hashes,
\t\t\t\t\t\t\t\t\tmultiupload: true,
\t\t\t\t\t\t\t\t\toverwrite: data.overwrite === 0? 0 : void 0,
\t\t\t\t\t\t\t\t\tclipdata: data.clipdata
\t\t\t\t\t\t\t\t}, void 0, target)
\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\tif (error && error === 'No such command') {
\t\t\t\t\t\t\t\t\t\tabort = true;
\t\t\t\t\t\t\t\t\t\tfm.error(['errUpload', 'errPerm']);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (cid) {\t
\t\t\t\t\t\t\t\t\t\tfailChunk[cid] = true;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.always(function(e) {
\t\t\t\t\t\t\t\t\tif (e && e.added) added = \$.merge(added, e.added);
\t\t\t\t\t\t\t\t\tif (last <= ++done) {
\t\t\t\t\t\t\t\t\t\tfm.trigger('multiupload', {added: added});
\t\t\t\t\t\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\t\t\t\t\t\tif (checkNotify()) {
\t\t\t\t\t\t\t\t\t\t\tself.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (files.length) {
\t\t\t\t\t\t\t\t\t\tmulti(files, 1); // Next one
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tif (--cancelChk <= 1) {
\t\t\t\t\t\t\t\t\t\t\tif (cancelBtn) {
\t\t\t\t\t\t\t\t\t\t\t\tcancelToggle(false, hasChunk);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (sfiles.length < 1 || abort) {
\t\t\t\t\t\tif (abort) {
\t\t\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\t\t\tif (cid) {
\t\t\t\t\t\t\t\tfailChunk[cid] = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\tself.uploads.xhrUploading = false;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcheck = function(){
\t\t\t\t\tif (!self.uploads.xhrUploading) {
\t\t\t\t\t\tself.uploads.xhrUploading = true;
\t\t\t\t\t\tmulti(sfiles, multiMax); // Max connection: 3
\t\t\t\t\t} else {
\t\t\t\t\t\tsetTimeout(check, 100);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\treqId, err;

\t\t\t\tif (! dataChecked && (isDataType || data.type == 'files')) {
\t\t\t\t\tif (! (maxFileSize = fm.option('uploadMaxSize', target))) {
\t\t\t\t\t\tmaxFileSize = 0;
\t\t\t\t\t}
\t\t\t\t\tfor (i=0; i < files.length; i++) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tblob = files[i];
\t\t\t\t\t\t\tblobSize = blob.size;
\t\t\t\t\t\t\tif (blobSlice === false) {
\t\t\t\t\t\t\t\tblobSlice = '';
\t\t\t\t\t\t\t\tif (self.api >= 2.1) {
\t\t\t\t\t\t\t\t\tif ('slice' in blob) {
\t\t\t\t\t\t\t\t\t\tblobSlice = 'slice';
\t\t\t\t\t\t\t\t\t} else if ('mozSlice' in blob) {
\t\t\t\t\t\t\t\t\t\tblobSlice = 'mozSlice';
\t\t\t\t\t\t\t\t\t} else if ('webkitSlice' in blob) {
\t\t\t\t\t\t\t\t\t\tblobSlice = 'webkitSlice';
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tcnt--;
\t\t\t\t\t\t\ttotal--;
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// file size check
\t\t\t\t\t\tif ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) {
\t\t\t\t\t\t\ttriggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true);
\t\t\t\t\t\t\tcnt--;
\t\t\t\t\t\t\ttotal--;
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// file mime check
\t\t\t\t\t\tif (blob.type && ! self.uploadMimeCheck(blob.type, target)) {
\t\t\t\t\t\t\ttriggerError(['errUploadFile', blob.name, 'errUploadMime', '(' + blob.type + ')'], blob, true);
\t\t\t\t\t\t\tcnt--;
\t\t\t\t\t\t\ttotal--;
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (blobSlice && blobSize > BYTES_PER_CHUNK) {
\t\t\t\t\t\t\tstart = 0;
\t\t\t\t\t\t\tend = BYTES_PER_CHUNK;
\t\t\t\t\t\t\tchunks = -1;
\t\t\t\t\t\t\ttotal = Math.floor((blobSize - 1) / BYTES_PER_CHUNK);
\t\t\t\t\t\t\tblobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0;
\t\t\t\t\t\t\tblobName = data.clipdata? fm.date(fm.nonameDateFormat) + '.png' : blob.name;

\t\t\t\t\t\t\ttotalSize += blobSize;
\t\t\t\t\t\t\tchunked[chunkID] = 0;
\t\t\t\t\t\t\twhile(start < blobSize) {
\t\t\t\t\t\t\t\tchunk = blob[blobSlice](start, end);
\t\t\t\t\t\t\t\tchunk._chunk = blobName + '.' + (++chunks) + '_' + total + '.part';
\t\t\t\t\t\t\t\tchunk._cid   = chunkID;
\t\t\t\t\t\t\t\tchunk._range = start + ',' + chunk.size + ',' + blobSize;
\t\t\t\t\t\t\t\tchunk._mtime = blobMtime;
\t\t\t\t\t\t\t\tchunked[chunkID]++;
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (size) {
\t\t\t\t\t\t\t\t\tc++;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (typeof sfiles[c] == 'undefined') {
\t\t\t\t\t\t\t\t\tsfiles[c] = [];
\t\t\t\t\t\t\t\t\tif (isDataType) {
\t\t\t\t\t\t\t\t\t\tsfiles[c][0] = [];
\t\t\t\t\t\t\t\t\t\tsfiles[c][1] = [];
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tsize = BYTES_PER_CHUNK;
\t\t\t\t\t\t\t\tfcnt = 1;
\t\t\t\t\t\t\t\tif (isDataType) {
\t\t\t\t\t\t\t\t\tsfiles[c][0].push(chunk);
\t\t\t\t\t\t\t\t\tsfiles[c][1].push(paths[i]);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tsfiles[c].push(chunk);
\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\tstart = end;
\t\t\t\t\t\t\t\tend = start + BYTES_PER_CHUNK;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (chunk == null) {
\t\t\t\t\t\t\t\ttriggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true);
\t\t\t\t\t\t\t\tcnt--;
\t\t\t\t\t\t\t\ttotal--;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\ttotal += chunks;
\t\t\t\t\t\t\t\tsize = 0;
\t\t\t\t\t\t\t\tfcnt = 1;
\t\t\t\t\t\t\t\tc++;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\tif ((fm.uplMaxSize && size + blobSize > fm.uplMaxSize) || fcnt > fm.uplMaxFile) {
\t\t\t\t\t\t\tsize = 0;
\t\t\t\t\t\t\tfcnt = 1;
\t\t\t\t\t\t\tc++;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (typeof sfiles[c] == 'undefined') {
\t\t\t\t\t\t\tsfiles[c] = [];
\t\t\t\t\t\t\tif (isDataType) {
\t\t\t\t\t\t\t\tsfiles[c][0] = [];
\t\t\t\t\t\t\t\tsfiles[c][1] = [];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (isDataType) {
\t\t\t\t\t\t\tsfiles[c][0].push(blob);
\t\t\t\t\t\t\tsfiles[c][1].push(paths[i]);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tsfiles[c].push(blob);
\t\t\t\t\t\t}
\t\t\t\t\t\tsize += blobSize;
\t\t\t\t\t\ttotalSize += blobSize;
\t\t\t\t\t\tfcnt++;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (errors.length) {
\t\t\t\t\t\ttriggerError();
\t\t\t\t\t}

\t\t\t\t\tif (sfiles.length == 0) {
\t\t\t\t\t\t// no data
\t\t\t\t\t\tdata.checked = true;
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (sfiles.length > 1) {
\t\t\t\t\t\t// multi upload
\t\t\t\t\t\tnotifyto = startNotify(totalSize);
\t\t\t\t\t\tadded = [];
\t\t\t\t\t\tdone = 0;
\t\t\t\t\t\tlast = sfiles.length;
\t\t\t\t\t\tfailChunk = [];
\t\t\t\t\t\tcheck();
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// single upload
\t\t\t\t\tif (isDataType) {
\t\t\t\t\t\tfiles = sfiles[0][0];
\t\t\t\t\t\tpaths = sfiles[0][1];
\t\t\t\t\t} else {
\t\t\t\t\t\tfiles = sfiles[0];
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (!dataChecked) {
\t\t\t\t\tif (!fm.UA.Safari || !data.files) {
\t\t\t\t\t\tnotifyto = startNotify(totalSize);
\t\t\t\t\t} else {
\t\t\t\t\t\txhr._totalSize = totalSize;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tdataChecked = true;
\t\t\t\t
\t\t\t\tif (! files.length) {
\t\t\t\t\tdfrd.reject(['errUploadNoFiles']);
\t\t\t\t}
\t\t\t\t
\t\t\t\txhr.open('POST', self.uploadURL, true);
\t\t\t\t
\t\t\t\t// set request headers
\t\t\t\tif (fm.customHeaders) {
\t\t\t\t\t\$.each(fm.customHeaders, function(key) {
\t\t\t\t\t\txhr.setRequestHeader(key, this);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\t// set xhrFields
\t\t\t\tif (fm.xhrFields) {
\t\t\t\t\t\$.each(fm.xhrFields, function(key) {
\t\t\t\t\t\tif (key in xhr) {
\t\t\t\t\t\t\txhr[key] = this;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}

\t\t\t\tif (self.api >= 2.1029) {
\t\t\t\t\t// request ID
\t\t\t\t\treqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
\t\t\t\t\tformData.append('reqid', reqId);
\t\t\t\t\txhr._requestId = reqId;
\t\t\t\t}
\t\t\t\tformData.append('cmd', 'upload');
\t\t\t\tformData.append(self.newAPI ? 'target' : 'current', target);
\t\t\t\tif (renames && renames.length) {
\t\t\t\t\t\$.each(renames, function(i, v) {
\t\t\t\t\t\tformData.append('renames[]', v);
\t\t\t\t\t});
\t\t\t\t\tformData.append('suffix', fm.options.backupSuffix);
\t\t\t\t}
\t\t\t\tif (hashes) {
\t\t\t\t\t\$.each(hashes, function(i, v) {
\t\t\t\t\t\tformData.append('hashes['+ i +']', v);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t\$.each(self.customData, function(key, val) {
\t\t\t\t\tformData.append(key, val);
\t\t\t\t});
\t\t\t\t\$.each(self.options.onlyMimes, function(i, mime) {
\t\t\t\t\tformData.append('mimes[]', mime);
\t\t\t\t});
\t\t\t\t
\t\t\t\t\$.each(files, function(i, file) {
\t\t\t\t\tvar name, relpath;
\t\t\t\t\tif (file._chunkmerged) {
\t\t\t\t\t\tformData.append('chunk', file._chunkmerged);
\t\t\t\t\t\tformData.append('upload[]', file._name);
\t\t\t\t\t\tformData.append('mtime[]', file._mtime);
\t\t\t\t\t\tdata.clipdata && formData.append('overwrite', 0);
\t\t\t\t\t\tisChunked = true;
\t\t\t\t\t} else {
\t\t\t\t\t\tif (file._chunkfail) {
\t\t\t\t\t\t\tformData.append('upload[]', 'chunkfail');
\t\t\t\t\t\t\tformData.append('mimes', 'chunkfail');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (data.clipdata) {
\t\t\t\t\t\t\t\tif (!file._chunk) {
\t\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t\t\tname = fm.date(fm.nonameDateFormat) + '.png';
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (file.name) {
\t\t\t\t\t\t\t\t\tname = file.name;
\t\t\t\t\t\t\t\t\tif (fm.UA.iOS) {
\t\t\t\t\t\t\t\t\t\tif (name.match(/^image\\.jpe?g\$/i)) {
\t\t\t\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t\t\t\t\tname = fm.date(fm.nonameDateFormat) + '.jpg';
\t\t\t\t\t\t\t\t\t\t} else if (name.match(/^capturedvideo\\.mov\$/i)) {
\t\t\t\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t\t\t\t\tname = fm.date(fm.nonameDateFormat) + '.mov';
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\trelpath = (file.webkitRelativePath || file.relativePath || file._relativePath || '').replace(/[^\\/]+\$/, '');
\t\t\t\t\t\t\t\t\tname = relpath + name;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tname? formData.append('upload[]', file, name) : formData.append('upload[]', file);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (file._chunk) {
\t\t\t\t\t\t\tformData.append('chunk', file._chunk);
\t\t\t\t\t\t\tformData.append('cid'  , file._cid);
\t\t\t\t\t\t\tformData.append('range', file._range);
\t\t\t\t\t\t\tformData.append('mtime[]', file._mtime);
\t\t\t\t\t\t\tisChunked = true;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tformData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\tif (isDataType) {
\t\t\t\t\t\$.each(paths, function(i, path) {
\t\t\t\t\t\tformData.append('upload_path[]', path);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (data.overwrite === 0) {
\t\t\t\t\tformData.append('overwrite', 0);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// send int value that which meta key was pressed when dropped  as `dropWith`
\t\t\t\tif (dropEvt) {
\t\t\t\t\tformData.append('dropWith', parseInt(
\t\t\t\t\t\t(dropEvt.altKey  ? '1' : '0')+
\t\t\t\t\t\t(dropEvt.ctrlKey ? '1' : '0')+
\t\t\t\t\t\t(dropEvt.metaKey ? '1' : '0')+
\t\t\t\t\t\t(dropEvt.shiftKey? '1' : '0'), 2));
\t\t\t\t}
\t\t\t\t
\t\t\t\t// set extraData on current request
\t\t\t\tif (extraData) {
\t\t\t\t\t\$.each(extraData, function(key, val) {
\t\t\t\t\t\tformData.append(key, val);
\t\t\t\t\t});
\t\t\t\t}

\t\t\t\txhr.send(formData);
\t\t\t\t
\t\t\t\treturn true;
\t\t\t};
\t\t\t
\t\t\tif (! isDataType) {
\t\t\t\tif (files.length > 0) {
\t\t\t\t\tif (! data.clipdata && renames == null) {
\t\t\t\t\t\tvar mkdirs = [],
\t\t\t\t\t\t\tpaths = [],
\t\t\t\t\t\t\texcludes = fm.options.folderUploadExclude[fm.OS] || null;
\t\t\t\t\t\t\$.each(files, function(i, file) {
\t\t\t\t\t\t\tvar relPath = file.webkitRelativePath || file.relativePath || '',
\t\t\t\t\t\t\t\tidx, rootDir;
\t\t\t\t\t\t\tif (! relPath) {
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (excludes && file.name.match(excludes)) {
\t\t\t\t\t\t\t\tfile._remove = true;
\t\t\t\t\t\t\t\trelPath = void(0);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t// add '/' as prefix to make same to folder uploading with DnD, see #2607
\t\t\t\t\t\t\t\trelPath = '/' + relPath.replace(/\\/[^\\/]*\$/, '').replace(/^\\//, '');
\t\t\t\t\t\t\t\tif (relPath && \$.inArray(relPath, mkdirs) === -1) {
\t\t\t\t\t\t\t\t\tmkdirs.push(relPath);
\t\t\t\t\t\t\t\t\t// checking the root directory to supports <input type=\"file\" webkitdirectory> see #2378
\t\t\t\t\t\t\t\t\tidx = relPath.substr(1).indexOf('/');
\t\t\t\t\t\t\t\t\tif (idx !== -1 && (rootDir = relPath.substr(0, idx + 1)) && \$.inArray(rootDir, mkdirs) === -1) {
\t\t\t\t\t\t\t\t\t\tmkdirs.unshift(rootDir);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tpaths.push(relPath);
\t\t\t\t\t\t});
\t\t\t\t\t\trenames = [];
\t\t\t\t\t\thashes = {};
\t\t\t\t\t\tif (mkdirs.length) {
\t\t\t\t\t\t\t(function() {
\t\t\t\t\t\t\t\tvar checkDirs = \$.map(mkdirs, function(name) { return name.substr(1).indexOf('/') === -1 ? {name: name.substr(1)} : null;}),
\t\t\t\t\t\t\t\t\tcancelDirs = [];
\t\t\t\t\t\t\t\tfm.uploads.checkExists(checkDirs, target, fm, true).done(
\t\t\t\t\t\t\t\t\tfunction(res, res2) {
\t\t\t\t\t\t\t\t\t\tvar dfds = [], dfd, bak, hash;
\t\t\t\t\t\t\t\t\t\tif (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
\t\t\t\t\t\t\t\t\t\t\tcancelDirs = \$.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} );
\t\t\t\t\t\t\t\t\t\t\tcheckDirs = \$.grep(checkDirs, function(dir) { return !dir._remove? true : false ;} );
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tif (cancelDirs.length) {
\t\t\t\t\t\t\t\t\t\t\t\$.each(paths.concat(), function(i, path) {
\t\t\t\t\t\t\t\t\t\t\t\tif (\$.inArray(path, cancelDirs) === 0) {
\t\t\t\t\t\t\t\t\t\t\t\t\tfiles[i]._remove = true;
\t\t\t\t\t\t\t\t\t\t\t\t\tpaths[i] = void(0);
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tfiles = \$.grep(files, function(file) { return file._remove? false : true; });
\t\t\t\t\t\t\t\t\t\tpaths = \$.grep(paths, function(path) { return path === void 0 ? false : true; });
\t\t\t\t\t\t\t\t\t\tif (checkDirs.length) {
\t\t\t\t\t\t\t\t\t\t\tdfd = \$.Deferred();
\t\t\t\t\t\t\t\t\t\t\tif (res.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\$.each(res, function(i, existName) {
\t\t\t\t\t\t\t\t\t\t\t\t\t// backup
\t\t\t\t\t\t\t\t\t\t\t\t\tbak = fm.uniqueName(existName + fm.options.backupSuffix , null, '');
\t\t\t\t\t\t\t\t\t\t\t\t\t\$.each(res2, function(h, name) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (res[0] == name) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thash = h;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\t\tif (! hash) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\thash = fm.fileByName(res[0], target).hash;
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.lockfiles({files : [hash]});
\t\t\t\t\t\t\t\t\t\t\t\t\tdfds.push(
\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata   : {cmd : 'rename', target : hash, name : bak},
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'rename', cnt : 1}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.sync();
\t\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.unlockfiles({files : [hash]});
\t\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tdfds.push(null);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\t\t\t\$.when.apply(\$, dfds).done(function() {
\t\t\t\t\t\t\t\t\t\t\t\t// ensure directories
\t\t\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\tdata   : {cmd : 'mkdir', target : target, dirs : mkdirs},
\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'mkdir', cnt : mkdirs.length},
\t\t\t\t\t\t\t\t\t\t\t\t\tpreventFail: true
\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\t\t\t\t\terror = error || ['errUnknown'];
\t\t\t\t\t\t\t\t\t\t\t\t\tif (error[0] === 'errCmdParams') {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tmultiMax = 1;
\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tmultiMax = 0;
\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\t\t\t\tvar rm = false;
\t\t\t\t\t\t\t\t\t\t\t\t\tif (!data.hashes) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata.hashes = {};
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\tpaths = \$.map(paths.concat(), function(p, i) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (p === '/') {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn target;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (data.hashes[p]) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn data.hashes[p];
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trm = true;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfiles[i]._remove = true;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn null;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\t\tif (rm) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tfiles = \$.grep(files, function(file) { return file._remove? false : true; });
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\t\t\t\t\t\tif (multiMax) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tisDataType = true;
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (! send(files, paths)) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t})();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.uploads.checkExists(files, target, fm).done(
\t\t\t\t\t\t\t\tfunction(res, res2){
\t\t\t\t\t\t\t\t\tif (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
\t\t\t\t\t\t\t\t\t\thashes = res2;
\t\t\t\t\t\t\t\t\t\tif (res === null) {
\t\t\t\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\trenames = res;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tfiles = \$.grep(files, function(file){return !file._remove? true : false ;});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tcnt = files.length;
\t\t\t\t\t\t\t\t\tif (cnt > 0) {
\t\t\t\t\t\t\t\t\t\tif (! send(files)) {
\t\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (! send(files)) {
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tdfrd.reject();
\t\t\t\t}
\t\t\t} else {
\t\t\t\tif (dataChecked) {
\t\t\t\t\tsend(files[0], files[1]);
\t\t\t\t} else {
\t\t\t\t\tfiles.done(function(result) { // result: [files, paths, renames, hashes, mkdirs]
\t\t\t\t\t\trenames = [];
\t\t\t\t\t\tcnt = result[0].length;
\t\t\t\t\t\tif (cnt) {
\t\t\t\t\t\t\tif (result[4] && result[4].length) {
\t\t\t\t\t\t\t\t// ensure directories
\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\tdata   : {cmd : 'mkdir', target : target, dirs : result[4]},
\t\t\t\t\t\t\t\t\tnotify : {type : 'mkdir', cnt : result[4].length},
\t\t\t\t\t\t\t\t\tpreventFail: true
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\terror = error || ['errUnknown'];
\t\t\t\t\t\t\t\t\tif (error[0] === 'errCmdParams') {
\t\t\t\t\t\t\t\t\t\tmultiMax = 1;
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tmultiMax = 0;
\t\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\tvar rm = false;
\t\t\t\t\t\t\t\t\tif (!data.hashes) {
\t\t\t\t\t\t\t\t\t\tdata.hashes = {};
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tresult[1] = \$.map(result[1], function(p, i) {
\t\t\t\t\t\t\t\t\t\tresult[0][i]._relativePath = p.replace(/^\\//, '');
\t\t\t\t\t\t\t\t\t\tp = p.replace(/\\/[^\\/]*\$/, '');
\t\t\t\t\t\t\t\t\t\tif (p === '') {
\t\t\t\t\t\t\t\t\t\t\treturn target;
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tif (data.hashes[p]) {
\t\t\t\t\t\t\t\t\t\t\t\treturn data.hashes[p];
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\trm = true;
\t\t\t\t\t\t\t\t\t\t\t\tresult[0][i]._remove = true;
\t\t\t\t\t\t\t\t\t\t\t\treturn null;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tif (rm) {
\t\t\t\t\t\t\t\t\t\tresult[0] = \$.grep(result[0], function(file) { return file._remove? false : true; });
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\t\tif (multiMax) {
\t\t\t\t\t\t\t\t\t\trenames = result[2];
\t\t\t\t\t\t\t\t\t\thashes = result[3];
\t\t\t\t\t\t\t\t\t\tsend(result[0], result[1]);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tresult[1] = \$.map(result[1], function() { return target; });
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\trenames = result[2];
\t\t\t\t\t\t\thashes = result[3];
\t\t\t\t\t\t\tsend(result[0], result[1]);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdfrd.reject(['errUploadNoFiles']);
\t\t\t\t\t\t}
\t\t\t\t\t}).fail(function(){
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}

\t\t\treturn dfrd;
\t\t},
\t\t
\t\t// upload transport using iframe
\t\tiframe : function(data, fm) { 
\t\t\tvar self   = fm ? fm : this,
\t\t\t\tinput  = data.input? data.input : false,
\t\t\t\tfiles  = !input ? self.uploads.checkFile(data, self) : false,
\t\t\t\tdfrd   = \$.Deferred()
\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\terror && self.error(error);
\t\t\t\t\t}),
\t\t\t\tname = 'iframe-'+fm.namespace+(++self.iframeCnt),
\t\t\t\tform = \$('<form action=\"'+self.uploadURL+'\" method=\"post\" enctype=\"multipart/form-data\" encoding=\"multipart/form-data\" target=\"'+name+'\" style=\"display:none\"><input type=\"hidden\" name=\"cmd\" value=\"upload\" /></form>'),
\t\t\t\tmsie = this.UA.IE,
\t\t\t\t// clear timeouts, close notification dialog, remove form/iframe
\t\t\t\tonload = function() {
\t\t\t\t\tabortto  && clearTimeout(abortto);
\t\t\t\t\tnotifyto && clearTimeout(notifyto);
\t\t\t\t\tnotify   && self.notify({type : 'upload', cnt : -cnt});
\t\t\t\t\t
\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\tmsie && \$('<iframe src=\"javascript:false;\"></iframe>').appendTo(form);
\t\t\t\t\t\tform.remove();
\t\t\t\t\t\tiframe.remove();
\t\t\t\t\t}, 100);
\t\t\t\t},
\t\t\t\tiframe = \$('<iframe src=\"'+(msie ? 'javascript:false;' : 'about:blank')+'\" name=\"'+name+'\" style=\"position:absolute;left:-1000px;top:-1000px\" ></iframe>')
\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\tiframe.off('load')
\t\t\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\t\t\tonload();
\t\t\t\t\t\t\t\t// data will be processed in callback response or window onmessage
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// notify dialog
\t\t\t\t\t\t\tnotifyto = setTimeout(function() {
\t\t\t\t\t\t\t\tnotify = true;
\t\t\t\t\t\t\t\tself.notify({type : 'upload', cnt : cnt});
\t\t\t\t\t\t\t}, self.options.notifyDelay);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// emulate abort on timeout
\t\t\t\t\t\t\tif (self.options.iframeTimeout > 0) {
\t\t\t\t\t\t\t\tabortto = setTimeout(function() {
\t\t\t\t\t\t\t\t\tonload();
\t\t\t\t\t\t\t\t\tdfrd.reject(['errConnect', 'errTimeout']);
\t\t\t\t\t\t\t\t}, self.options.iframeTimeout);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tform.submit();
\t\t\t\t\t}),
\t\t\t\ttarget  = (data.target || self.cwd().hash),
\t\t\t\tnames   = [],
\t\t\t\tdfds    = [],
\t\t\t\trenames = [],
\t\t\t\thashes  = {},
\t\t\t\tcnt, notify, notifyto, abortto;

\t\t\tif (files && files.length) {
\t\t\t\t\$.each(files, function(i, val) {
\t\t\t\t\tform.append('<input type=\"hidden\" name=\"upload[]\" value=\"'+val+'\"/>');
\t\t\t\t});
\t\t\t\tcnt = 1;
\t\t\t} else if (input && \$(input).is(':file') && \$(input).val()) {
\t\t\t\tif (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
\t\t\t\t\tnames = input.files? input.files : [{ name: \$(input).val().replace(/^(?:.+[\\\\\\/])?([^\\\\\\/]+)\$/, '\$1') }];
\t\t\t\t\t//names = \$.map(names, function(file){return file.name? { name: file.name } : null ;});
\t\t\t\t\tdfds.push(self.uploads.checkExists(names, target, self).done(
\t\t\t\t\t\tfunction(res, res2){
\t\t\t\t\t\t\thashes = res2;
\t\t\t\t\t\t\tif (res === null) {
\t\t\t\t\t\t\t\tdata.overwrite = 0;
\t\t\t\t\t\t\t} else{
\t\t\t\t\t\t\t\trenames = res;
\t\t\t\t\t\t\t\tcnt = \$.grep(names, function(file){return !file._remove? true : false ;}).length;
\t\t\t\t\t\t\t\tif (cnt != names.length) {
\t\t\t\t\t\t\t\t\tcnt = 0;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t));
\t\t\t\t}
\t\t\t\tcnt = input.files ? input.files.length : 1;
\t\t\t\tform.append(input);
\t\t\t} else {
\t\t\t\treturn dfrd.reject();
\t\t\t}
\t\t\t
\t\t\t\$.when.apply(\$, dfds).done(function() {
\t\t\t\tif (cnt < 1) {
\t\t\t\t\treturn dfrd.reject();
\t\t\t\t}
\t\t\t\tform.append('<input type=\"hidden\" name=\"'+(self.newAPI ? 'target' : 'current')+'\" value=\"'+target+'\"/>')
\t\t\t\t\t.append('<input type=\"hidden\" name=\"html\" value=\"1\"/>')
\t\t\t\t\t.append('<input type=\"hidden\" name=\"node\" value=\"'+self.id+'\"/>')
\t\t\t\t\t.append(\$(input).attr('name', 'upload[]'));
\t\t\t\t
\t\t\t\tif (renames.length > 0) {
\t\t\t\t\t\$.each(renames, function(i, rename) {
\t\t\t\t\t\tform.append('<input type=\"hidden\" name=\"renames[]\" value=\"'+self.escape(rename)+'\"/>');
\t\t\t\t\t});
\t\t\t\t\tform.append('<input type=\"hidden\" name=\"suffix\" value=\"'+fm.options.backupSuffix+'\"/>');
\t\t\t\t}
\t\t\t\tif (hashes) {
\t\t\t\t\t\$.each(renames, function(i, v) {
\t\t\t\t\t\tform.append('<input type=\"hidden\" name=\"['+i+']\" value=\"'+self.escape(v)+'\"/>');
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (data.overwrite === 0) {
\t\t\t\t\tform.append('<input type=\"hidden\" name=\"overwrite\" value=\"0\"/>');
\t\t\t\t}
\t\t\t\t
\t\t\t\t\$.each(self.options.onlyMimes||[], function(i, mime) {
\t\t\t\t\tform.append('<input type=\"hidden\" name=\"mimes[]\" value=\"'+self.escape(mime)+'\"/>');
\t\t\t\t});
\t\t\t\t
\t\t\t\t\$.each(self.customData, function(key, val) {
\t\t\t\t\tform.append('<input type=\"hidden\" name=\"'+key+'\" value=\"'+self.escape(val)+'\"/>');
\t\t\t\t});
\t\t\t\t
\t\t\t\tform.appendTo('body');
\t\t\t\tiframe.appendTo('body');
\t\t\t});
\t\t\t
\t\t\treturn dfrd;
\t\t}
\t},
\t
\t
\t/**
\t * Bind callback to event(s) The callback is executed at most once per event.
\t * To bind to multiply events at once, separate events names by space
\t *
\t * @param  String    event name
\t * @param  Function  callback
\t * @param  Boolan    priority first
\t * @return elFinder
\t */
\tone : function(ev, callback, priorityFirst) {
\t\tvar self  = this,
\t\t\tevent = ev.toLowerCase(),
\t\t\th     = function(e, f) {
\t\t\t\tif (!self.toUnbindEvents[event]) {
\t\t\t\t\tself.toUnbindEvents[event] = [];
\t\t\t\t}
\t\t\t\tself.toUnbindEvents[event].push({
\t\t\t\t\ttype: event,
\t\t\t\t\tcallback: h
\t\t\t\t});
\t\t\t\treturn (callback.done? callback.done : callback).apply(this, arguments);
\t\t\t};
\t\tif (callback.done) {
\t\t\th = {done: h};
\t\t}
\t\treturn this.bind(event, h, priorityFirst);
\t},
\t
\t/**
\t * Set/get data into/from localStorage
\t *
\t * @param  String       key
\t * @param  String|void  value
\t * @return String|null
\t */
\tlocalStorage : function(key, val) {
\t\tvar self   = this,
\t\t\ts      = window.localStorage,
\t\t\toldkey = 'elfinder-'+(key || '')+this.id, // old key of elFinder < 2.1.6
\t\t\tprefix = window.location.pathname+'-elfinder-',
\t\t\tsuffix = this.id,
\t\t\tclrs   = [],
\t\t\tretval, oldval, t, precnt, sufcnt;

\t\t// reset this node data
\t\tif (typeof(key) === 'undefined') {
\t\t\tprecnt = prefix.length;
\t\t\tsufcnt = suffix.length * -1;
\t\t\t\$.each(s, function(key) {
\t\t\t\tif (key.substr(0, precnt) === prefix && key.substr(sufcnt) === suffix) {
\t\t\t\t\tclrs.push(key);
\t\t\t\t}
\t\t\t});
\t\t\t\$.each(clrs, function(i, key) {
\t\t\t\ts.removeItem(key);
\t\t\t});
\t\t\treturn true;
\t\t}
\t\t
\t\t// new key of elFinder >= 2.1.6
\t\tkey = prefix+key+suffix;
\t\t
\t\tif (val === null) {
\t\t\treturn s.removeItem(key);
\t\t}
\t\t
\t\tif (val === void(0) && !(retval = s.getItem(key)) && (oldval = s.getItem(oldkey))) {
\t\t\tval = oldval;
\t\t\ts.removeItem(oldkey);
\t\t}
\t\t
\t\tif (val !== void(0)) {
\t\t\tt = typeof val;
\t\t\tif (t !== 'string' && t !== 'number') {
\t\t\t\tval = JSON.stringify(val);
\t\t\t}
\t\t\ttry {
\t\t\t\ts.setItem(key, val);
\t\t\t} catch (e) {
\t\t\t\ttry {
\t\t\t\t\ts.clear();
\t\t\t\t\ts.setItem(key, val);
\t\t\t\t} catch (e) {
\t\t\t\t\tself.debug('error', e.toString());
\t\t\t\t}
\t\t\t}
\t\t\tretval = s.getItem(key);
\t\t}

\t\tif (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) {
\t\t\ttry {
\t\t\t\treturn JSON.parse(retval);
\t\t\t} catch(e) {}
\t\t}
\t\treturn retval;
\t},

\t/**
\t * Set/get data into/from sessionStorage
\t *
\t * @param  String       key
\t * @param  String|void  value
\t * @return String|null
\t */
\tsessionStorage : function(key, val) {
\t\tvar self   = this,
\t\t\ts, retval, t;

\t\ttry {
\t\t\ts = window.sessionStorage;
\t\t} catch(e) {}

\t\tif (!s) {
\t\t\treturn;
\t\t}

\t\tif (val === null) {
\t\t\treturn s.removeItem(key);
\t\t}

\t\tif (val !== void(0)) {
\t\t\tt = typeof val;
\t\t\tif (t !== 'string' && t !== 'number') {
\t\t\t\tval = JSON.stringify(val);
\t\t\t}
\t\t\ttry {
\t\t\t\ts.setItem(key, val);
\t\t\t} catch (e) {
\t\t\t\ttry {
\t\t\t\t\ts.clear();
\t\t\t\t\ts.setItem(key, val);
\t\t\t\t} catch (e) {
\t\t\t\t\tself.debug('error', e.toString());
\t\t\t\t}
\t\t\t}
\t\t}
\t\tretval = s.getItem(key);

\t\tif (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) {
\t\t\ttry {
\t\t\t\treturn JSON.parse(retval);
\t\t\t} catch(e) {}
\t\t}
\t\treturn retval;
\t},

\t/**
\t * Get/set cookie
\t *
\t * @param  String       cookie name
\t * @param  String|void  cookie value
\t * @return String|null
\t */
\tcookie : function(name, value) {
\t\tvar d, o, c, i, retval, t;

\t\tname = 'elfinder-'+name+this.id;

\t\tif (value === void(0)) {
\t\t\tif (this.cookieEnabled && document.cookie && document.cookie != '') {
\t\t\t\tc = document.cookie.split(';');
\t\t\t\tname += '=';
\t\t\t\tfor (i=0; i<c.length; i++) {
\t\t\t\t\tc[i] = \$.trim(c[i]);
\t\t\t\t\tif (c[i].substring(0, name.length) == name) {
\t\t\t\t\t\tretval = decodeURIComponent(c[i].substring(name.length));
\t\t\t\t\t\tif (retval.substr(0,1) === '{' || retval.substr(0,1) === '[') {
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\treturn JSON.parse(retval);
\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn retval;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\treturn null;
\t\t}

\t\tif (!this.cookieEnabled) {
\t\t\treturn '';
\t\t}

\t\to = Object.assign({}, this.options.cookie);
\t\tif (value === null) {
\t\t\tvalue = '';
\t\t\to.expires = -1;
\t\t} else {
\t\t\tt = typeof value;
\t\t\tif (t !== 'string' && t !== 'number') {
\t\t\t\tvalue = JSON.stringify(value);
\t\t\t}
\t\t}
\t\tif (typeof(o.expires) == 'number') {
\t\t\td = new Date();
\t\t\td.setTime(d.getTime()+(o.expires * 86400000));
\t\t\to.expires = d;
\t\t}
\t\tdocument.cookie = name+'='+encodeURIComponent(value)+'; expires='+o.expires.toUTCString()+(o.path ? '; path='+o.path : '')+(o.domain ? '; domain='+o.domain : '')+(o.secure ? '; secure' : '');
\t\tif (value && (value.substr(0,1) === '{' || value.substr(0,1) === '[')) {
\t\t\ttry {
\t\t\t\treturn JSON.parse(value);
\t\t\t} catch(e) {}
\t\t}
\t\treturn value;
\t},
\t
\t/**
\t * Get start directory (by location.hash or last opened directory)
\t * 
\t * @return String
\t */
\tstartDir : function() {
\t\tvar locHash = window.location.hash;
\t\tif (locHash && locHash.match(/^#elf_/)) {
\t\t\treturn locHash.replace(/^#elf_/, '');
\t\t} else if (this.options.startPathHash) {
\t\t\treturn this.options.startPathHash;
\t\t} else {
\t\t\treturn this.lastDir();
\t\t}
\t},
\t
\t/**
\t * Get/set last opened directory
\t * 
\t * @param  String|undefined  dir hash
\t * @return String
\t */
\tlastDir : function(hash) { 
\t\treturn this.options.rememberLastDir ? this.storage('lastdir', hash) : '';
\t},
\t
\t/**
\t * Node for escape html entities in texts
\t * 
\t * @type jQuery
\t */
\t_node : \$('<span></c.length;>'),
\t
\t/**
\t * Replace not html-safe symbols to html entities
\t * 
\t * @param  String  text to escape
\t * @return String
\t */
\tescape : function(name) {
\t\treturn this._node.text(name).html().replace(/\"/g, '&quot;').replace(/'/g, '&#039;');
\t},
\t
\t/**
\t * Cleanup ajax data.
\t * For old api convert data into new api format
\t * 
\t * @param  String  command name
\t * @param  Object  data from backend
\t * @return Object
\t */
\tnormalize : function(data) {
\t\tvar self   = this,
\t\t\tfileFilter = (function() {
\t\t\t\tvar func, filter;
\t\t\t\tif (filter = self.options.fileFilter) {
\t\t\t\t\tif (typeof filter === 'function') {
\t\t\t\t\t\tfunc = function(file) {
\t\t\t\t\t\t\treturn filter.call(self, file);
\t\t\t\t\t\t};
\t\t\t\t\t} else if (filter instanceof RegExp) {
\t\t\t\t\t\tfunc = function(file) {
\t\t\t\t\t\t\treturn filter.test(file.name);
\t\t\t\t\t\t};
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn func? func : null;
\t\t\t})(),
\t\t\tchkCmdMap = function(opts) {
\t\t\t\t// Disable command to replace with other command
\t\t\t\tvar disabled;
\t\t\t\tif (opts.uiCmdMap) {
\t\t\t\t\tif (\$.isPlainObject(opts.uiCmdMap) && Object.keys(opts.uiCmdMap).length) {
\t\t\t\t\t\tif (!opts.disabledFlip) {
\t\t\t\t\t\t\topts.disabledFlip = {};
\t\t\t\t\t\t}
\t\t\t\t\t\tdisabled = opts.disabledFlip;
\t\t\t\t\t\t\$.each(opts.uiCmdMap, function(f, t) {
\t\t\t\t\t\t\tif (t === 'hidden' && !disabled[f]) {
\t\t\t\t\t\t\t\topts.disabled.push(f);
\t\t\t\t\t\t\t\topts.disabledFlip[f] = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdelete opts.uiCmdMap;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tnormalizeOptions = function(opts) {
\t\t\t\tvar getType = function(v) {
\t\t\t\t\t\tvar type = typeof v;
\t\t\t\t\t\tif (type === 'object' && Array.isArray(v)) {
\t\t\t\t\t\t\ttype = 'array';
\t\t\t\t\t\t}
\t\t\t\t\t\treturn type;
\t\t\t\t\t};
\t\t\t\t\$.each(self.optionProperties, function(k, empty) {
\t\t\t\t\tif (empty !== void(0)) {
\t\t\t\t\t\tif (opts[k] && getType(opts[k]) !== getType(empty)) {
\t\t\t\t\t\t\topts[k] = empty;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (opts.disabled) {
\t\t\t\t\topts.disabledFlip = self.arrayFlip(opts.disabled, true);
\t\t\t\t\t\$.each(self.options.disabledCmdsRels, function(com, rels) {
\t\t\t\t\t\tvar m, flg;
\t\t\t\t\t\tif (opts.disabledFlip[com]) {
\t\t\t\t\t\t\tflg = true;
\t\t\t\t\t\t} else if (m = com.match(/^([^&]+)&([^=]+)=(.*)\$/)) {
\t\t\t\t\t\t\tif (opts.disabledFlip[m[1]] && opts[m[2]] == m[3]) {
\t\t\t\t\t\t\t\tflg = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (flg) {
\t\t\t\t\t\t\t\$.each(rels, function(i, rel) {
\t\t\t\t\t\t\t\tif (!opts.disabledFlip[rel]) {
\t\t\t\t\t\t\t\t\topts.disabledFlip[rel] = true;
\t\t\t\t\t\t\t\t\topts.disabled.push(rel);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\topts.disabledFlip = {};
\t\t\t\t}
\t\t\t\treturn opts;
\t\t\t},
\t\t\tfilter = function(file, asMap, type) { 
\t\t\t\tvar res = asMap? file : true,
\t\t\t\t\tign = asMap? null : false,
\t\t\t\t\tvid, targetOptions, isRoot, rootNames;
\t\t\t\t
\t\t\t\tif (file && file.hash && file.name && file.mime) {
\t\t\t\t\tif (file.mime === 'application/x-empty') {
\t\t\t\t\t\tfile.mime = 'text/plain';
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tisRoot = self.isRoot(file);
\t\t\t\t\tif (isRoot && ! file.volumeid) {
\t\t\t\t\t\tself.debug('warning', 'The volume root statuses requires `volumeid` property.');
\t\t\t\t\t}
\t\t\t\t\tif (isRoot || file.mime === 'directory') {
\t\t\t\t\t\t// Prevention of circular reference
\t\t\t\t\t\tif (file.phash) {
\t\t\t\t\t\t\tif (file.phash === file.hash) {
\t\t\t\t\t\t\t\terror = error.concat(['Parent folder of \"\$1\" is itself.', file.name]);
\t\t\t\t\t\t\t\treturn ign;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (isRoot && file.volumeid && file.phash.indexOf(file.volumeid) === 0) {
\t\t\t\t\t\t\t\terror = error.concat(['Parent folder of \"\$1\" is inner itself.', file.name]);
\t\t\t\t\t\t\t\treturn ign;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// set options, tmbUrls for each volume
\t\t\t\t\t\tif (file.volumeid) {
\t\t\t\t\t\t\tvid = file.volumeid;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (isRoot) {
\t\t\t\t\t\t\t\t// make or update of leaf roots cache
\t\t\t\t\t\t\t\tif (file.phash) {
\t\t\t\t\t\t\t\t\tif (! self.leafRoots[file.phash]) {
\t\t\t\t\t\t\t\t\t\tself.leafRoots[file.phash] = [ file.hash ];
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tif (\$.inArray(file.hash, self.leafRoots[file.phash]) === -1) {
\t\t\t\t\t\t\t\t\t\t\tself.leafRoots[file.phash].push(file.hash);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\tself.hasVolOptions = true;
\t\t\t\t\t\t\t\tif (! self.volOptions[vid]) {
\t\t\t\t\t\t\t\t\tself.volOptions[vid] = {
\t\t\t\t\t\t\t\t\t\t// set dispInlineRegex
\t\t\t\t\t\t\t\t\t\tdispInlineRegex: self.options.dispInlineRegex
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\ttargetOptions = self.volOptions[vid];
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (file.options) {
\t\t\t\t\t\t\t\t\t// >= v.2.1.14 has file.options
\t\t\t\t\t\t\t\t\tObject.assign(targetOptions, file.options);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t// for compat <= v2.1.13
\t\t\t\t\t\t\t\tif (file.disabled) {
\t\t\t\t\t\t\t\t\ttargetOptions.disabled = file.disabled;
\t\t\t\t\t\t\t\t\ttargetOptions.disabledFlip = self.arrayFlip(file.disabled, true);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (file.tmbUrl) {
\t\t\t\t\t\t\t\t\ttargetOptions.tmbUrl = file.tmbUrl;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t// '/' required at the end of url
\t\t\t\t\t\t\t\tif (targetOptions.url && targetOptions.url.substr(-1) !== '/') {
\t\t\t\t\t\t\t\t\ttargetOptions.url += '/';
\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\t// check uiCmdMap
\t\t\t\t\t\t\t\tchkCmdMap(targetOptions);
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t// check trash bin hash
\t\t\t\t\t\t\t\tif (targetOptions.trashHash) {
\t\t\t\t\t\t\t\t\tif (self.trashes[targetOptions.trashHash] === false) {
\t\t\t\t\t\t\t\t\t\tdelete targetOptions.trashHash;
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tself.trashes[targetOptions.trashHash] = file.hash;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t// set immediate properties
\t\t\t\t\t\t\t\t\$.each(self.optionProperties, function(k) {
\t\t\t\t\t\t\t\t\tif (targetOptions[k]) {
\t\t\t\t\t\t\t\t\t\tfile[k] = targetOptions[k];
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});

\t\t\t\t\t\t\t\t// regist fm.roots
\t\t\t\t\t\t\t\tif (type !== 'cwd') {
\t\t\t\t\t\t\t\t\tself.roots[vid] = file.hash;
\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\t// regist fm.volumeExpires
\t\t\t\t\t\t\t\tif (file.expires) {
\t\t\t\t\t\t\t\t\tself.volumeExpires[vid] = file.expires;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (prevId !== vid) {
\t\t\t\t\t\t\t\tprevId = vid;
\t\t\t\t\t\t\t\ti18nFolderName = self.option('i18nFolderName', vid);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// volume root i18n name
\t\t\t\t\t\tif (isRoot && ! file.i18) {
\t\t\t\t\t\t\tname = 'volume_' + file.name,
\t\t\t\t\t\t\ti18 = self.i18n(false, name);
\t
\t\t\t\t\t\t\tif (name !== i18) {
\t\t\t\t\t\t\t\tfile.i18 = i18;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// i18nFolderName
\t\t\t\t\t\tif (i18nFolderName && ! file.i18) {
\t\t\t\t\t\t\tname = 'folder_' + file.name,
\t\t\t\t\t\t\ti18 = self.i18n(false, name);
\t
\t\t\t\t\t\t\tif (name !== i18) {
\t\t\t\t\t\t\t\tfile.i18 = i18;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (isRoot) {
\t\t\t\t\t\t\tif (rootNames = self.storage('rootNames')) {
\t\t\t\t\t\t\t\tif (rootNames[file.hash]) {
\t\t\t\t\t\t\t\t\tfile._name = file.name;
\t\t\t\t\t\t\t\t\tfile._i18 = file.i18;
\t\t\t\t\t\t\t\t\tfile.name = rootNames[file.hash] = rootNames[file.hash];
\t\t\t\t\t\t\t\t\tdelete file.i18;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tself.storage('rootNames', rootNames);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}

\t\t\t\t\t\t// lock trash bins holder
\t\t\t\t\t\tif (self.trashes[file.hash]) {
\t\t\t\t\t\t\tfile.locked = true;
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (fileFilter) {
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tif (! fileFilter(file)) {
\t\t\t\t\t\t\t\t\treturn ign;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tself.debug(e);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (file.size == 0) {
\t\t\t\t\t\t\tfile.mime = self.getMimetype(file.name, file.mime);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (file.options) {
\t\t\t\t\t\tself.optionsByHashes[file.hash] = normalizeOptions(file.options);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tdelete file.options;
\t\t\t\t\t
\t\t\t\t\treturn res;
\t\t\t\t}
\t\t\t\treturn ign;
\t\t\t},
\t\t\tgetDescendants = function(hashes) {
\t\t\t\tvar res = [];
\t\t\t\t\$.each(self.files(), function(h, f) {
\t\t\t\t\t\$.each(self.parents(h), function(i, ph) {
\t\t\t\t\t\tif (\$.inArray(ph, hashes) !== -1 && \$.inArray(h, hashes) === -1) {
\t\t\t\t\t\t\tres.push(h);
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t});
\t\t\t\treturn res;
\t\t\t},
\t\t\tapplyLeafRootStats = function(dataArr, type) {
\t\t\t\t\$.each(dataArr, function(i, f) {
\t\t\t\t\tvar pfile, done;
\t\t\t\t\tif (self.leafRoots[f.hash]) {
\t\t\t\t\t\tself.applyLeafRootStats(f);
\t\t\t\t\t}
\t\t\t\t\t// update leaf root parent stat
\t\t\t\t\tif (type !== 'change' && f.phash && self.isRoot(f) && (pfile = self.file(f.phash))) {
\t\t\t\t\t\tself.applyLeafRootStats(pfile);
\t\t\t\t\t\t// add to data.changed
\t\t\t\t\t\tif (!data.changed) {
\t\t\t\t\t\t\tdata.changed = [pfile];
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$.each(data.changed, function(i, f) {
\t\t\t\t\t\t\t\tif (f.hash === pfile.hash) {
\t\t\t\t\t\t\t\t\tdata.changed[i] = pfile;
\t\t\t\t\t\t\t\t\tdone = true;
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tif (!done) {
\t\t\t\t\t\t\t\tdata.changed.push(pfile);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\terror = [],
\t\t\tname, i18, i18nFolderName, prevId, cData;
\t\t
\t\t// set cunstom data
\t\tif (data.customData && (!self.prevCustomData || (JSON.stringify(data.customData) !== JSON.stringify(self.prevCustomData)))) {
\t\t\tself.prevCustomData = data.customData;
\t\t\ttry {
\t\t\t\tcData = JSON.parse(data.customData);
\t\t\t\tif (\$.isPlainObject(cData)) {
\t\t\t\t\tself.prevCustomData = cData;
\t\t\t\t\t\$.each(Object.keys(cData), function(i, key) {
\t\t\t\t\t\tif (cData[key] === null) {
\t\t\t\t\t\t\tdelete cData[key];
\t\t\t\t\t\t\tdelete self.optsCustomData[key];
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tself.customData = Object.assign({}, self.optsCustomData, cData);
\t\t\t\t}
\t\t\t} catch(e) {}
\t\t}

\t\tif (data.options) {
\t\t\tnormalizeOptions(data.options);
\t\t}
\t\t
\t\tif (data.cwd) {
\t\t\tif (data.cwd.volumeid && data.options && Object.keys(data.options).length && self.isRoot(data.cwd)) {
\t\t\t\tself.hasVolOptions = true;
\t\t\t\tself.volOptions[data.cwd.volumeid] = data.options;
\t\t\t}
\t\t\tdata.cwd = filter(data.cwd, true, 'cwd');
\t\t}
\t\tif (data.files) {
\t\t\tdata.files = \$.grep(data.files, filter);
\t\t} 
\t\tif (data.tree) {
\t\t\tdata.tree = \$.grep(data.tree, filter);
\t\t}
\t\tif (data.added) {
\t\t\tdata.added = \$.grep(data.added, filter);
\t\t}
\t\tif (data.changed) {
\t\t\tdata.changed = \$.grep(data.changed, filter);
\t\t}
\t\tif (data.removed && data.removed.length && self.searchStatus.state === 2) {
\t\t\tdata.removed = data.removed.concat(getDescendants(data.removed));
\t\t}
\t\tif (data.api) {
\t\t\tdata.init = true;
\t\t}

\t\tif (Object.keys(self.leafRoots).length) {
\t\t\tdata.files && applyLeafRootStats(data.files);
\t\t\tdata.tree && applyLeafRootStats(data.tree);
\t\t\tdata.added && applyLeafRootStats(data.added);
\t\t\tdata.changed && applyLeafRootStats(data.changed, 'change');
\t\t}

\t\t// merge options that apply only to cwd
\t\tif (data.cwd && data.cwd.options && data.options) {
\t\t\tObject.assign(data.options, normalizeOptions(data.cwd.options));
\t\t}

\t\t// '/' required at the end of url
\t\tif (data.options && data.options.url && data.options.url.substr(-1) !== '/') {
\t\t\tdata.options.url += '/';
\t\t}
\t\t
\t\t// check error
\t\tif (error.length) {
\t\t\tdata.norError = ['errResponse'].concat(error);
\t\t}
\t\t
\t\treturn data;
\t},
\t
\t/**
\t * Update sort options
\t *
\t * @param {String} sort type
\t * @param {String} sort order
\t * @param {Boolean} show folder first
\t */
\tsetSort : function(type, order, stickFolders, alsoTreeview) {
\t\tthis.storage('sortType', (this.sortType = this.sortRules[type] ? type : 'name'));
\t\tthis.storage('sortOrder', (this.sortOrder = /asc|desc/.test(order) ? order : 'asc'));
\t\tthis.storage('sortStickFolders', (this.sortStickFolders = !!stickFolders) ? 1 : '');
\t\tthis.storage('sortAlsoTreeview', (this.sortAlsoTreeview = !!alsoTreeview) ? 1 : '');
\t\tthis.trigger('sortchange');
\t},
\t
\t_sortRules : {
\t\tname : function(file1, file2) {
\t\t\treturn elFinder.prototype.naturalCompare(file1.i18 || file1.name, file2.i18 || file2.name);
\t\t},
\t\tsize : function(file1, file2) { 
\t\t\tvar size1 = parseInt(file1.size) || 0,
\t\t\t\tsize2 = parseInt(file2.size) || 0;
\t\t\t\t
\t\t\treturn size1 === size2 ? 0 : size1 > size2 ? 1 : -1;
\t\t},
\t\tkind : function(file1, file2) {
\t\t\treturn elFinder.prototype.naturalCompare(file1.mime, file2.mime);
\t\t},
\t\tdate : function(file1, file2) { 
\t\t\tvar date1 = file1.ts || file1.date || 0,
\t\t\t\tdate2 = file2.ts || file2.date || 0;

\t\t\treturn date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
\t\t},
\t\tperm : function(file1, file2) { 
\t\t\tvar val = function(file) { return (file.write? 2 : 0) + (file.read? 1 : 0); },
\t\t\t\tv1  = val(file1),
\t\t\t\tv2  = val(file2);
\t\t\treturn v1 === v2 ? 0 : v1 > v2 ? 1 : -1;
\t\t},
\t\tmode : function(file1, file2) { 
\t\t\tvar v1 = file1.mode || (file1.perm || ''),
\t\t\t\tv2 = file2.mode || (file2.perm || '');
\t\t\treturn elFinder.prototype.naturalCompare(v1, v2);
\t\t},
\t\towner : function(file1, file2) { 
\t\t\tvar v1 = file1.owner || '',
\t\t\t\tv2 = file2.owner || '';
\t\t\treturn elFinder.prototype.naturalCompare(v1, v2);
\t\t},
\t\tgroup : function(file1, file2) { 
\t\t\tvar v1 = file1.group || '',
\t\t\t\tv2 = file2.group || '';
\t\t\treturn elFinder.prototype.naturalCompare(v1, v2);
\t\t}
\t},
\t
\t/**
\t * Valid sort rule names
\t * 
\t * @type Object
\t */
\tsorters : {},
\t
\t/**
\t * Compare strings for natural sort
\t *
\t * @param  String
\t * @param  String
\t * @return Number
\t */
\tnaturalCompare : function(a, b) {
\t\tvar self = elFinder.prototype.naturalCompare;
\t\tif (typeof self.loc == 'undefined') {
\t\t\tself.loc = (navigator.userLanguage || navigator.browserLanguage || navigator.language || 'en-US');
\t\t}
\t\tif (typeof self.sort == 'undefined') {
\t\t\tif ('11'.localeCompare('2', self.loc, {numeric: true}) > 0) {
\t\t\t\t// Native support
\t\t\t\tif (window.Intl && window.Intl.Collator) {
\t\t\t\t\tself.sort = new Intl.Collator(self.loc, {numeric: true}).compare;
\t\t\t\t} else {
\t\t\t\t\tself.sort = function(a, b) {
\t\t\t\t\t\treturn a.localeCompare(b, self.loc, {numeric: true});
\t\t\t\t\t};
\t\t\t\t}
\t\t\t} else {
\t\t\t\t/*
\t\t\t\t * Edited for elFinder (emulates localeCompare() by numeric) by Naoki Sawada aka nao-pon
\t\t\t\t */
\t\t\t\t/*
\t\t\t\t * Huddle/javascript-natural-sort (https://github.com/Huddle/javascript-natural-sort)
\t\t\t\t */
\t\t\t\t/*
\t\t\t\t * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
\t\t\t\t * Author: Jim Palmer (based on chunking idea from Dave Koelle)
\t\t\t\t * http://opensource.org/licenses/mit-license.php
\t\t\t\t */
\t\t\t\tself.sort = function(a, b) {
\t\t\t\t\tvar re = /(^-?[0-9]+(\\.?[0-9]*)[df]?e?[0-9]?\$|^0x[0-9a-f]+\$|[0-9]+)/gi,
\t\t\t\t\tsre = /(^[ ]*|[ ]*\$)/g,
\t\t\t\t\tdre = /(^([\\w ]+,?[\\w ]+)?[\\w ]+,?[\\w ]+\\d+:\\d+(:\\d+)?[\\w ]?|^\\d{1,4}[\\/\\-]\\d{1,4}[\\/\\-]\\d{1,4}|^\\w+, \\w+ \\d+, \\d{4})/,
\t\t\t\t\thre = /^0x[0-9a-f]+\$/i,
\t\t\t\t\tore = /^0/,
\t\t\t\t\tsyre = /^[\\x01\\x21-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7e]/, // symbol first - (Naoki Sawada)
\t\t\t\t\ti = function(s) { return self.sort.insensitive && (''+s).toLowerCase() || ''+s; },
\t\t\t\t\t// convert all to strings strip whitespace
\t\t\t\t\t// first character is \"_\", it's smallest - (Naoki Sawada)
\t\t\t\t\tx = i(a).replace(sre, '').replace(/^_/, \"\\x01\") || '',
\t\t\t\t\ty = i(b).replace(sre, '').replace(/^_/, \"\\x01\") || '',
\t\t\t\t\t// chunk/tokenize
\t\t\t\t\txN = x.replace(re, '\\0\$1\\0').replace(/\\0\$/,'').replace(/^\\0/,'').split('\\0'),
\t\t\t\t\tyN = y.replace(re, '\\0\$1\\0').replace(/\\0\$/,'').replace(/^\\0/,'').split('\\0'),
\t\t\t\t\t// numeric, hex or date detection
\t\t\t\t\txD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
\t\t\t\t\tyD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
\t\t\t\t\toFxNcL, oFyNcL,
\t\t\t\t\tlocRes = 0;

\t\t\t\t\t// first try and sort Hex codes or Dates
\t\t\t\t\tif (yD) {
\t\t\t\t\t\tif ( xD < yD ) return -1;
\t\t\t\t\t\telse if ( xD > yD ) return 1;
\t\t\t\t\t}
\t\t\t\t\t// natural sorting through split numeric strings and default strings
\t\t\t\t\tfor(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {

\t\t\t\t\t\t// find floats not starting with '0', string or 0 if not defined (Clint Priest)
\t\t\t\t\t\toFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
\t\t\t\t\t\toFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;

\t\t\t\t\t\t// handle numeric vs string comparison - number < string - (Kyle Adams)
\t\t\t\t\t\t// but symbol first < number - (Naoki Sawada)
\t\t\t\t\t\tif (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
\t\t\t\t\t\t\tif (isNaN(oFxNcL) && (typeof oFxNcL !== 'string' || ! oFxNcL.match(syre))) {
\t\t\t\t\t\t\t\treturn 1;
\t\t\t\t\t\t\t} else if (typeof oFyNcL !== 'string' || ! oFyNcL.match(syre)) {
\t\t\t\t\t\t\t\treturn -1;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}

\t\t\t\t\t\t// use decimal number comparison if either value is string zero
\t\t\t\t\t\tif (parseInt(oFxNcL, 10) === 0) oFxNcL = 0;
\t\t\t\t\t\tif (parseInt(oFyNcL, 10) === 0) oFyNcL = 0;

\t\t\t\t\t\t// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
\t\t\t\t\t\tif (typeof oFxNcL !== typeof oFyNcL) {
\t\t\t\t\t\t\toFxNcL += '';
\t\t\t\t\t\t\toFyNcL += '';
\t\t\t\t\t\t}

\t\t\t\t\t\t// use locale sensitive sort for strings when case insensitive
\t\t\t\t\t\t// note: localeCompare interleaves uppercase with lowercase (e.g. A,a,B,b)
\t\t\t\t\t\tif (self.sort.insensitive && typeof oFxNcL === 'string' && typeof oFyNcL === 'string') {
\t\t\t\t\t\t\tlocRes = oFxNcL.localeCompare(oFyNcL, self.loc);
\t\t\t\t\t\t\tif (locRes !== 0) return locRes;
\t\t\t\t\t\t}

\t\t\t\t\t\tif (oFxNcL < oFyNcL) return -1;
\t\t\t\t\t\tif (oFxNcL > oFyNcL) return 1;
\t\t\t\t\t}
\t\t\t\t\treturn 0;
\t\t\t\t};
\t\t\t\tself.sort.insensitive = true;
\t\t\t}
\t\t}
\t\treturn self.sort(a, b);
\t},
\t
\t/**
\t * Compare files based on elFinder.sort
\t *
\t * @param  Object  file
\t * @param  Object  file
\t * @return Number
\t */
\tcompare : function(file1, file2) {
\t\tvar self  = this,
\t\t\ttype  = self.sortType,
\t\t\tasc   = self.sortOrder == 'asc',
\t\t\tstick = self.sortStickFolders,
\t\t\trules = self.sortRules,
\t\t\tsort  = rules[type],
\t\t\td1    = file1.mime == 'directory',
\t\t\td2    = file2.mime == 'directory',
\t\t\tres;
\t\t\t
\t\tif (stick) {
\t\t\tif (d1 && !d2) {
\t\t\t\treturn -1;
\t\t\t} else if (!d1 && d2) {
\t\t\t\treturn 1;
\t\t\t}
\t\t}
\t\t
\t\tres = asc ? sort(file1, file2) : sort(file2, file1);
\t\t
\t\treturn type !== 'name' && res === 0
\t\t\t? res = asc ? rules.name(file1, file2) : rules.name(file2, file1)
\t\t\t: res;
\t},
\t
\t/**
\t * Sort files based on config
\t *
\t * @param  Array  files
\t * @return Array
\t */
\tsortFiles : function(files) {
\t\treturn files.sort(this.compare);
\t},
\t
\t/**
\t * Open notification dialog 
\t * and append/update message for required notification type.
\t *
\t * @param  Object  options
\t * @example  
\t * this.notify({
\t *    type : 'copy',
\t *    msg : 'Copy files', // not required for known types @see this.notifyType
\t *    cnt : 3,
\t *    hideCnt  : false,   // true for not show count
\t *    progress : 10,      // progress bar percents (use cnt : 0 to update progress bar)
\t *    cancel   : callback // callback function for cancel button
\t * })
\t * @return elFinder
\t */
\tnotify : function(opts) {
\t\tvar self     = this,
\t\t\ttype     = opts.type,
\t\t\tid       = opts.id? 'elfinder-notify-'+opts.id : '',
\t\t\tmsg      = this.i18n((typeof opts.msg !== 'undefined')? opts.msg : (this.messages['ntf'+type] ? 'ntf'+type : 'ntfsmth')),
\t\t\thiddens  = this.arrayFlip(this.options.notifyDialog.hiddens || []),
\t\t\tndialog  = this.ui.notify,
\t\t\tdialog   = ndialog.closest('.ui-dialog'),
\t\t\tnotify   = ndialog.children('.elfinder-notify-'+type+(id? ('.'+id) : '')),
\t\t\tbutton   = notify.children('div.elfinder-notify-cancel').children('button'),
\t\t\tntpl     = '<div class=\"elfinder-notify elfinder-notify-{type}'+(id? (' '+id) : '')+'\"><span class=\"elfinder-dialog-icon elfinder-dialog-icon-{type}\"></span><span class=\"elfinder-notify-msg\">{msg}</span> <span class=\"elfinder-notify-cnt\"></span><div class=\"elfinder-notify-progressbar\"><div class=\"elfinder-notify-progress\"></div></div><div class=\"elfinder-notify-cancel\"></div></div>',
\t\t\tdelta    = opts.cnt + 0,
\t\t\tsize     = (typeof opts.size != 'undefined')? parseInt(opts.size) : null,
\t\t\tprogress = (typeof opts.progress != 'undefined' && opts.progress >= 0) ? opts.progress : null,
\t\t\tfakeint  = opts.fakeinterval || 200,
\t\t\tcancel   = opts.cancel,
\t\t\tclhover  = 'ui-state-hover',
\t\t\tclose    = function() {
\t\t\t\tvar prog = notify.find('.elfinder-notify-progress'),
\t\t\t\t\trm = function() {
\t\t\t\t\t\tnotify.remove();
\t\t\t\t\t\tif (!ndialog.children(dialog.data('minimized')? void(0) : ':visible').length) {
\t\t\t\t\t\t\tif (dialog.data('minimized')) {
\t\t\t\t\t\t\t\tdialog.data('minimized').hide();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tndialog.elfinderdialog('close');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tsetProgressbar();
\t\t\t\t\t};
\t\t\t\tnotify._esc && \$(document).off('keydown', notify._esc);
\t\t\t\tif (notify.data('cur') < 100) {
\t\t\t\t\tprog.animate({
\t\t\t\t\t\twidth : '100%'
\t\t\t\t\t}, 50, function() { requestAnimationFrame(function() { rm(); }); });
\t\t\t\t} else {
\t\t\t\t\trm();
\t\t\t\t}
\t\t\t},
\t\t\tfakeUp = function(interval) {
\t\t\t\tvar cur;
\t\t\t\tif (notify.length) {
\t\t\t\t\tcur = notify.data('cur') + 1;
\t\t\t\t\tif (cur <= 98) {
\t\t\t\t\t\tnotify.find('.elfinder-notify-progress').width(cur + '%');
\t\t\t\t\t\tnotify.data('cur', cur);
\t\t\t\t\t\tsetProgressbar();
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tinterval *= 1.05; 
\t\t\t\t\t\t\tfakeUp(interval);
\t\t\t\t\t\t}, interval);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tsetProgressbar = function() {
\t\t\t\tvar cnt = 0,
\t\t\t\t\tval = 0,
\t\t\t\t\tntfs = ndialog.children('.elfinder-notify'),
\t\t\t\t\tw;
\t\t\t\tif (ntfs.length) {
\t\t\t\t\tntfs.each(function() {
\t\t\t\t\t\tcnt++;
\t\t\t\t\t\tval += Math.min(\$(this).data('cur'), 100);
\t\t\t\t\t});
\t\t\t\t\tw = cnt? Math.floor(val / (cnt * 100) * 100) + '%' : 0;
\t\t\t\t\tself.ui.progressbar.width(w);
\t\t\t\t\tif (dialog.data('minimized')) {
\t\t\t\t\t\tdialog.data('minimized').title(w);
\t\t\t\t\t\tdialog.data('minimized').dialog().children('.ui-dialog-titlebar').children('.elfinder-ui-progressbar').width(w);
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tself.ui.progressbar.width(0);
\t\t\t\t\tdialog.data('minimized') && dialog.data('minimized').hide();
\t\t\t\t}
\t\t\t},
\t\t\tcnt, total, prc;

\t\tif (!type) {
\t\t\treturn this;
\t\t}
\t\t
\t\tif (!notify.length) {
\t\t\tnotify = \$(ntpl.replace(/\\{type\\}/g, type).replace(/\\{msg\\}/g, msg));
\t\t\tif (hiddens[type]) {
\t\t\t\tnotify.hide();
\t\t\t} else {
\t\t\t\tndialog.on('minimize', function(e) {
\t\t\t\t\tdialog.data('minimized') && setProgressbar();
\t\t\t\t});
\t\t\t}
\t\t\tnotify.appendTo(ndialog).data('cnt', 0);

\t\t\tif (progress != null) {
\t\t\t\tnotify.data({progress : 0, total : 0, cur : 0});
\t\t\t} else {
\t\t\t\tnotify.data({cur : 0});
\t\t\t\tfakeUp(fakeint);
\t\t\t}

\t\t\tif (cancel) {
\t\t\t\tbutton = \$('<span class=\"elfinder-notify-button ui-icon ui-icon-close\" title=\"'+this.i18n('btnCancel')+'\"></span>')
\t\t\t\t\t.on('mouseenter mouseleave', function(e) { 
\t\t\t\t\t\t\$(this).toggleClass(clhover, e.type === 'mouseenter');
\t\t\t\t\t});
\t\t\t\tnotify.children('div.elfinder-notify-cancel').append(button);
\t\t\t}
\t\t\tndialog.trigger('resize');
\t\t} else if (typeof opts.msg !== 'undefined') {
\t\t\tnotify.children('span.elfinder-notify-msg').html(msg);
\t\t}

\t\tcnt = delta + parseInt(notify.data('cnt'));
\t\t
\t\tif (cnt > 0) {
\t\t\tif (cancel && button.length) {
\t\t\t\tif (\$.isFunction(cancel) || (typeof cancel === 'object' && cancel.promise)) {
\t\t\t\t\tnotify._esc = function(e) {
\t\t\t\t\t\tif (e.type == 'keydown' && e.keyCode != \$.ui.keyCode.ESCAPE) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tclose();
\t\t\t\t\t\tif (cancel.promise) {
\t\t\t\t\t\t\tcancel.reject(0); // 0 is canceling flag
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcancel(e);
\t\t\t\t\t\t}
\t\t\t\t\t};
\t\t\t\t\tbutton.on('click', function(e) {
\t\t\t\t\t\tnotify._esc(e);
\t\t\t\t\t});
\t\t\t\t\t\$(document).on('keydown.' + this.namespace, notify._esc);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t!opts.hideCnt && notify.children('.elfinder-notify-cnt').text('('+cnt+')');
\t\t\tif (delta > 0 && ndialog.is(':hidden') && !hiddens[type]) {
\t\t\t\tif (dialog.data('minimized')) {
\t\t\t\t\tdialog.data('minimized').show();
\t\t\t\t} else {
\t\t\t\t\tndialog.elfinderdialog('open', this).height('auto');
\t\t\t\t}
\t\t\t}
\t\t\tnotify.data('cnt', cnt);
\t\t\t
\t\t\tif ((progress != null)
\t\t\t&& (total = notify.data('total')) >= 0
\t\t\t&& (prc = notify.data('progress')) >= 0) {

\t\t\t\ttotal += size != null? size : delta;
\t\t\t\tprc   += progress;
\t\t\t\t(size == null && delta < 0) && (prc += delta * 100);
\t\t\t\tnotify.data({progress : prc, total : total});
\t\t\t\tif (size != null) {
\t\t\t\t\tprc *= 100;
\t\t\t\t\ttotal = Math.max(1, total);
\t\t\t\t}
\t\t\t\tprogress = Math.min(parseInt(prc/total), 100);
\t\t\t\t
\t\t\t\tnotify.find('.elfinder-notify-progress')
\t\t\t\t\t.animate({
\t\t\t\t\t\twidth : (progress < 100 ? progress : 100)+'%'
\t\t\t\t\t}, 20, function() {
\t\t\t\t\t\tnotify.data('cur', progress);
\t\t\t\t\t\tsetProgressbar();
\t\t\t\t\t});
\t\t\t}
\t\t\t
\t\t} else {
\t\t\tclose();
\t\t}
\t\t
\t\treturn this;
\t},
\t
\t/**
\t * Open confirmation dialog 
\t *
\t * @param  Object  options
\t * @example  
\t * this.confirm({
\t *    cssClass : 'elfinder-confirm-mydialog',
\t *    title : 'Remove files',
\t *    text  : 'Here is question text',
\t *    accept : {  // accept callback - required
\t *      label : 'Continue',
\t *      callback : function(applyToAll) { fm.log('Ok') }
\t *    },
\t *    cancel : { // cancel callback - required
\t *      label : 'Cancel',
\t *      callback : function() { fm.log('Cancel')}
\t *    },
\t *    reject : { // reject callback - optionally
\t *      label : 'No',
\t *      callback : function(applyToAll) { fm.log('No')}
\t *    },
\t *    buttons : [ // additional buttons callback - optionally
\t *      {
\t *        label : 'Btn1',
\t *        callback : function(applyToAll) { fm.log('Btn1')}
\t *      }
\t *    ],
\t *    all : true  // display checkbox \"Apply to all\"
\t * })
\t * @return elFinder
\t */
\tconfirm : function(opts) {
\t\tvar self     = this,
\t\t\tcomplete = false,
\t\t\toptions = {
\t\t\t\tcssClass  : 'elfinder-dialog-confirm',
\t\t\t\tmodal     : true,
\t\t\t\tresizable : false,
\t\t\t\ttitle     : this.i18n(opts.title || 'confirmReq'),
\t\t\t\tbuttons   : {},
\t\t\t\tclose     : function() { 
\t\t\t\t\t!complete && opts.cancel.callback();
\t\t\t\t\t\$(this).elfinderdialog('destroy');
\t\t\t\t}
\t\t\t},
\t\t\tapply = this.i18n('apllyAll'),
\t\t\tlabel, checkbox, btnNum;

\t\tif (opts.cssClass) {
\t\t\toptions.cssClass += ' ' + opts.cssClass;
\t\t}
\t\toptions.buttons[this.i18n(opts.accept.label)] = function() {
\t\t\topts.accept.callback(!!(checkbox && checkbox.prop('checked')));
\t\t\tcomplete = true;
\t\t\t\$(this).elfinderdialog('close');
\t\t};
\t\toptions.buttons[this.i18n(opts.accept.label)]._cssClass = 'elfinder-confirm-accept';
\t\t
\t\tif (opts.reject) {
\t\t\toptions.buttons[this.i18n(opts.reject.label)] = function() {
\t\t\t\topts.reject.callback(!!(checkbox && checkbox.prop('checked')));
\t\t\t\tcomplete = true;
\t\t\t\t\$(this).elfinderdialog('close');
\t\t\t};
\t\t\toptions.buttons[this.i18n(opts.reject.label)]._cssClass = 'elfinder-confirm-reject';
\t\t}
\t\t
\t\tif (opts.buttons && opts.buttons.length > 0) {
\t\t\tbtnNum = 1;
\t\t\t\$.each(opts.buttons, function(i, v){
\t\t\t\toptions.buttons[self.i18n(v.label)] = function() {
\t\t\t\t\tv.callback(!!(checkbox && checkbox.prop('checked')));
\t\t\t\t\tcomplete = true;
\t\t\t\t\t\$(this).elfinderdialog('close');
\t\t\t\t};
\t\t\t\toptions.buttons[self.i18n(v.label)]._cssClass = 'elfinder-confirm-extbtn' + (btnNum++);
\t\t\t\tif (v.cssClass) {
\t\t\t\t\toptions.buttons[self.i18n(v.label)]._cssClass += ' ' + v.cssClass;
\t\t\t\t}
\t\t\t});
\t\t}
\t\t
\t\toptions.buttons[this.i18n(opts.cancel.label)] = function() {
\t\t\t\$(this).elfinderdialog('close');
\t\t};
\t\toptions.buttons[this.i18n(opts.cancel.label)]._cssClass = 'elfinder-confirm-cancel';
\t\t
\t\tif (opts.all) {
\t\t\toptions.create = function() {
\t\t\t\tvar base = \$('<div class=\"elfinder-dialog-confirm-applyall\"></div>');
\t\t\t\tcheckbox = \$('<input type=\"checkbox\" />');
\t\t\t\t\$(this).next().find('.ui-dialog-buttonset')
\t\t\t\t\t.prepend(base.append(\$('<label>'+apply+'</label>').prepend(checkbox)));
\t\t\t};
\t\t}
\t\t
\t\tif (opts.optionsCallback && \$.isFunction(opts.optionsCallback)) {
\t\t\topts.optionsCallback(options);
\t\t}
\t\t
\t\treturn this.dialog('<span class=\"elfinder-dialog-icon elfinder-dialog-icon-confirm\"></span>' + this.i18n(opts.text), options);
\t},
\t
\t/**
\t * Create unique file name in required dir
\t * 
\t * @param  String  file name
\t * @param  String  parent dir hash
\t * @param  String  glue
\t * @return String
\t */
\tuniqueName : function(prefix, phash, glue) {
\t\tvar i = 0, ext = '', p, name;
\t\t
\t\tprefix = this.i18n(false, prefix);
\t\tphash = phash || this.cwd().hash;
\t\tglue = (typeof glue === 'undefined')? ' ' : glue;

\t\tif (p = prefix.match(/^(.+)(\\.[^.]+)\$/)) {
\t\t\text    = p[2];
\t\t\tprefix = p[1];
\t\t}
\t\t
\t\tname   = prefix+ext;
\t\t
\t\tif (!this.fileByName(name, phash)) {
\t\t\treturn name;
\t\t}
\t\twhile (i < 10000) {
\t\t\tname = prefix + glue + (++i) + ext;
\t\t\tif (!this.fileByName(name, phash)) {
\t\t\t\treturn name;
\t\t\t}
\t\t}
\t\treturn prefix + Math.random() + ext;
\t},
\t
\t/**
\t * Return message translated onto current language
\t * Allowed accept HTML element that was wrapped in jQuery object
\t * To be careful to XSS vulnerability of HTML element Ex. You should use `fm.escape(file.name)`
\t *
\t * @param  String|Array  message[s]|Object jQuery
\t * @return String
\t **/
\ti18n : function() {
\t\tvar self = this,
\t\t\tmessages = this.messages, 
\t\t\tinput    = [],
\t\t\tignore   = [], 
\t\t\tmessage = function(m) {
\t\t\t\tvar file;
\t\t\t\tif (m.indexOf('#') === 0) {
\t\t\t\t\tif ((file = self.file(m.substr(1)))) {
\t\t\t\t\t\treturn file.name;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn m;
\t\t\t},
\t\t\ti, j, m, escFunc, start = 0, isErr;
\t\t
\t\tif (arguments.length && arguments[0] === false) {
\t\t\tescFunc = function(m){ return m; };
\t\t\tstart = 1;
\t\t}
\t\tfor (i = start; i< arguments.length; i++) {
\t\t\tm = arguments[i];
\t\t\t
\t\t\tif (Array.isArray(m)) {
\t\t\t\tfor (j = 0; j < m.length; j++) {
\t\t\t\t\tif (m[j] instanceof jQuery) {
\t\t\t\t\t\t// jQuery object is HTML element
\t\t\t\t\t\tinput.push(m[j]);
\t\t\t\t\t} else if (typeof m[j] !== 'undefined'){
\t\t\t\t\t\tinput.push(message('' + m[j]));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t} else if (m instanceof jQuery) {
\t\t\t\t// jQuery object is HTML element
\t\t\t\tinput.push(m[j]);
\t\t\t} else if (typeof m !== 'undefined'){
\t\t\t\tinput.push(message('' + m));
\t\t\t}
\t\t}
\t\t
\t\tfor (i = 0; i < input.length; i++) {
\t\t\t// dont translate placeholders
\t\t\tif (\$.inArray(i, ignore) !== -1) {
\t\t\t\tcontinue;
\t\t\t}
\t\t\tm = input[i];
\t\t\tif (typeof m == 'string') {
\t\t\t\tisErr = !!(messages[m] && m.match(/^err/));
\t\t\t\t// translate message
\t\t\t\tm = messages[m] || (escFunc? escFunc(m) : self.escape(m));
\t\t\t\t// replace placeholders in message
\t\t\t\tm = m.replace(/\\\$(\\d+)/g, function(match, placeholder) {
\t\t\t\t\tvar res;
\t\t\t\t\tplaceholder = i + parseInt(placeholder);
\t\t\t\t\tif (placeholder > 0 && input[placeholder]) {
\t\t\t\t\t\tignore.push(placeholder);
\t\t\t\t\t}
\t\t\t\t\tres = escFunc? escFunc(input[placeholder]) : self.escape(input[placeholder]);
\t\t\t\t\tif (isErr) {
\t\t\t\t\t\tres = '<span class=\"elfinder-err-var elfinder-err-var' + placeholder + '\">' + res + '</span>';
\t\t\t\t\t}
\t\t\t\t\treturn res;
\t\t\t\t});
\t\t\t} else {
\t\t\t\t// get HTML from jQuery object
\t\t\t\tm = m.get(0).outerHTML;
\t\t\t}

\t\t\tinput[i] = m;
\t\t}

\t\treturn \$.grep(input, function(m, i) { return \$.inArray(i, ignore) === -1 ? true : false; }).join('<br>');
\t},
\t
\t/**
\t * Get icon style from file.icon
\t * 
\t * @param  Object  elFinder file object
\t * @return String|Object
\t */
\tgetIconStyle : function(file, asObject) {
\t\tvar self = this,
\t\t\ttemplate = {
\t\t\t\t'background' : 'url(\\'{url}\\') 0 0 no-repeat',
\t\t\t\t'background-size' : 'contain'
\t\t\t},
\t\t\tstyle = '',
\t\t\tcssObj = {},
\t\t\ti = 0;
\t\tif (file.icon) {
\t\t\tstyle = 'style=\"';
\t\t\t\$.each(template, function(k, v) {
\t\t\t\tif (i++ === 0) {
\t\t\t\t\tv = v.replace('{url}', self.escape(file.icon));
\t\t\t\t}
\t\t\t\tif (asObject) {
\t\t\t\t\tcssObj[k] = v;
\t\t\t\t} else {
\t\t\t\t\tstyle += k+':'+v+';';
\t\t\t\t}
\t\t\t});
\t\t\tstyle += '\"';
\t\t}
\t\treturn asObject? cssObj : style;
\t},
\t
\t/**
\t * Convert mimetype into css classes
\t * 
\t * @param  String  file mimetype
\t * @return String
\t */
\tmime2class : function(mimeType) {
\t\tvar prefix = 'elfinder-cwd-icon-',
\t\t\tmime   = mimeType.toLowerCase(),
\t\t\tisText = this.textMimes[mime];
\t\t
\t\tmime = mime.split('/');
\t\tif (isText) {
\t\t\tmime[0] += ' ' + prefix + 'text';
\t\t} else if (mime[1] && mime[1].match(/\\+xml\$/)) {
\t\t\tmime[0] += ' ' + prefix + 'xml';
\t\t}
\t\t
\t\treturn prefix + mime[0] + (mime[1] ? ' ' + prefix + mime[1].replace(/(\\.|\\+)/g, '-') : '');
\t},
\t
\t/**
\t * Return localized kind of file
\t * 
\t * @param  Object|String  file or file mimetype
\t * @return String
\t */
\tmime2kind : function(f) {
\t\tvar isObj = typeof(f) == 'object' ? true : false,
\t\t\tmime  = isObj ? f.mime : f,
\t\t\tkind;
\t\t

\t\tif (isObj && f.alias && mime != 'symlink-broken') {
\t\t\tkind = 'Alias';
\t\t} else if (this.kinds[mime]) {
\t\t\tif (isObj && mime === 'directory' && (! f.phash || f.isroot)) {
\t\t\t\tkind = 'Root';
\t\t\t} else {
\t\t\t\tkind = this.kinds[mime];
\t\t\t}
\t\t}
\t\tif (! kind) {
\t\t\tif (mime.indexOf('text') === 0) {
\t\t\t\tkind = 'Text';
\t\t\t} else if (mime.indexOf('image') === 0) {
\t\t\t\tkind = 'Image';
\t\t\t} else if (mime.indexOf('audio') === 0) {
\t\t\t\tkind = 'Audio';
\t\t\t} else if (mime.indexOf('video') === 0) {
\t\t\t\tkind = 'Video';
\t\t\t} else if (mime.indexOf('application') === 0) {
\t\t\t\tkind = 'App';
\t\t\t} else {
\t\t\t\tkind = mime;
\t\t\t}
\t\t}
\t\t
\t\treturn this.messages['kind'+kind] ? this.i18n('kind'+kind) : mime;
\t},
\t
\t/**
\t * Return boolean Is mime-type text file
\t * 
\t * @param  String  mime-type
\t * @return Boolean
\t */
\tmimeIsText : function(mime) {
\t\treturn (this.textMimes[mime.toLowerCase()] || (mime.indexOf('text/') === 0 && mime.substr(5, 3) !== 'rtf') || mime.match(/^application\\/.+\\+xml\$/))? true : false;
\t},
\t
\t/**
\t * Returns a date string formatted according to the given format string
\t * 
\t * @param  String  format string
\t * @param  Object  Date object
\t * @return String
\t */
\tdate : function(format, date) {
\t\tvar self = this,
\t\t\toutput, d, dw, m, y, h, g, i, s;
\t\t
\t\tif (! date) {
\t\t\tdate = new Date();
\t\t}
\t\t
\t\th  = date[self.getHours]();
\t\tg  = h > 12 ? h - 12 : h;
\t\ti  = date[self.getMinutes]();
\t\ts  = date[self.getSeconds]();
\t\td  = date[self.getDate]();
\t\tdw = date[self.getDay]();
\t\tm  = date[self.getMonth]() + 1;
\t\ty  = date[self.getFullYear]();
\t\t
\t\toutput = format.replace(/[a-z]/gi, function(val) {
\t\t\tswitch (val) {
\t\t\t\tcase 'd': return d > 9 ? d : '0'+d;
\t\t\t\tcase 'j': return d;
\t\t\t\tcase 'D': return self.i18n(self.i18.daysShort[dw]);
\t\t\t\tcase 'l': return self.i18n(self.i18.days[dw]);
\t\t\t\tcase 'm': return m > 9 ? m : '0'+m;
\t\t\t\tcase 'n': return m;
\t\t\t\tcase 'M': return self.i18n(self.i18.monthsShort[m-1]);
\t\t\t\tcase 'F': return self.i18n(self.i18.months[m-1]);
\t\t\t\tcase 'Y': return y;
\t\t\t\tcase 'y': return (''+y).substr(2);
\t\t\t\tcase 'H': return h > 9 ? h : '0'+h;
\t\t\t\tcase 'G': return h;
\t\t\t\tcase 'g': return g;
\t\t\t\tcase 'h': return g > 9 ? g : '0'+g;
\t\t\t\tcase 'a': return h >= 12 ? 'pm' : 'am';
\t\t\t\tcase 'A': return h >= 12 ? 'PM' : 'AM';
\t\t\t\tcase 'i': return i > 9 ? i : '0'+i;
\t\t\t\tcase 's': return s > 9 ? s : '0'+s;
\t\t\t}
\t\t\treturn val;
\t\t});
\t\t
\t\treturn output;
\t},
\t
\t/**
\t * Return localized date
\t * 
\t * @param  Object  file object
\t * @return String
\t */
\tformatDate : function(file, t) {
\t\tvar self = this, 
\t\t\tts   = t || file.ts, 
\t\t\ti18  = self.i18,
\t\t\tdate, format, output, d, dw, m, y, h, g, i, s;

\t\tif (self.options.clientFormatDate && ts > 0) {

\t\t\tdate = new Date(ts*1000);
\t\t\tformat = ts >= this.yesterday 
\t\t\t\t? this.fancyFormat 
\t\t\t\t: this.dateFormat;

\t\t\toutput = self.date(format, date);
\t\t\t
\t\t\treturn ts >= this.yesterday
\t\t\t\t? output.replace('\$1', this.i18n(ts >= this.today ? 'Today' : 'Yesterday'))
\t\t\t\t: output;
\t\t} else if (file.date) {
\t\t\treturn file.date.replace(/([a-z]+)\\s/i, function(a1, a2) { return self.i18n(a2)+' '; });
\t\t}
\t\t
\t\treturn self.i18n('dateUnknown');
\t},
\t
\t/**
\t * Return localized number string
\t * 
\t * @param  Number
\t * @return String
\t */
\ttoLocaleString : function(num) {
\t\tvar v = new Number(num);
\t\tif (v) {
\t\t\tif (v.toLocaleString) {
\t\t\t\treturn v.toLocaleString();
\t\t\t} else {
\t\t\t\treturn String(num).replace( /(\\d)(?=(\\d\\d\\d)+(?!\\d))/g, '\$1,');
\t\t\t}
\t\t}
\t\treturn num;
\t},
\t
\t/**
\t * Return css class marks file permissions
\t * 
\t * @param  Object  file 
\t * @return String
\t */
\tperms2class : function(o) {
\t\tvar c = '';
\t\t
\t\tif (!o.read && !o.write) {
\t\t\tc = 'elfinder-na';
\t\t} else if (!o.read) {
\t\t\tc = 'elfinder-wo';
\t\t} else if (!o.write) {
\t\t\tc = 'elfinder-ro';
\t\t}
\t\t
\t\tif (o.type) {
\t\t\tc += ' elfinder-' + this.escape(o.type);
\t\t}
\t\t
\t\treturn c;
\t},
\t
\t/**
\t * Return localized string with file permissions
\t * 
\t * @param  Object  file
\t * @return String
\t */
\tformatPermissions : function(f) {
\t\tvar p  = [];
\t\t\t
\t\tf.read && p.push(this.i18n('read'));
\t\tf.write && p.push(this.i18n('write'));\t

\t\treturn p.length ? p.join(' '+this.i18n('and')+' ') : this.i18n('noaccess');
\t},
\t
\t/**
\t * Return formated file size
\t * 
\t * @param  Number  file size
\t * @return String
\t */
\tformatSize : function(s) {
\t\tvar n = 1, u = 'b';
\t\t
\t\tif (s == 'unknown') {
\t\t\treturn this.i18n('unknown');
\t\t}
\t\t
\t\tif (s > 1073741824) {
\t\t\tn = 1073741824;
\t\t\tu = 'GB';
\t\t} else if (s > 1048576) {
\t\t\tn = 1048576;
\t\t\tu = 'MB';
\t\t} else if (s > 1024) {
\t\t\tn = 1024;
\t\t\tu = 'KB';
\t\t}
\t\ts = s/n;
\t\treturn (s > 0 ? n >= 1048576 ? s.toFixed(2) : Math.round(s) : 0) +' '+u;
\t},
\t
\t/**
\t * Return formated file mode by options.fileModeStyle
\t * 
\t * @param  String  file mode
\t * @param  String  format style
\t * @return String
\t */
\tformatFileMode : function(p, style) {
\t\tvar i, o, s, b, sticy, suid, sgid, str, oct;
\t\t
\t\tif (!style) {
\t\t\tstyle = this.options.fileModeStyle.toLowerCase();
\t\t}
\t\tp = \$.trim(p);
\t\tif (p.match(/[rwxs-]{9}\$/i)) {
\t\t\tstr = p = p.substr(-9);
\t\t\tif (style == 'string') {
\t\t\t\treturn str;
\t\t\t}
\t\t\toct = '';
\t\t\ts = 0;
\t\t\tfor (i=0; i<7; i=i+3) {
\t\t\t\to = p.substr(i, 3);
\t\t\t\tb = 0;
\t\t\t\tif (o.match(/[r]/i)) {
\t\t\t\t\tb += 4;
\t\t\t\t}
\t\t\t\tif (o.match(/[w]/i)) {
\t\t\t\t\tb += 2;
\t\t\t\t}
\t\t\t\tif (o.match(/[xs]/i)) {
\t\t\t\t\tif (o.match(/[xs]/)) {
\t\t\t\t\t\tb += 1;
\t\t\t\t\t}
\t\t\t\t\tif (o.match(/[s]/i)) {
\t\t\t\t\t\tif (i == 0) {
\t\t\t\t\t\t\ts += 4;
\t\t\t\t\t\t} else if (i == 3) {
\t\t\t\t\t\t\ts += 2;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\toct += b.toString(8);
\t\t\t}
\t\t\tif (s) {
\t\t\t\toct = s.toString(8) + oct;
\t\t\t}
\t\t} else {
\t\t\tp = parseInt(p, 8);
\t\t\toct = p? p.toString(8) : '';
\t\t\tif (!p || style == 'octal') {
\t\t\t\treturn oct;
\t\t\t}
\t\t\to = p.toString(8);
\t\t\ts = 0;
\t\t\tif (o.length > 3) {
\t\t\t\to = o.substr(-4);
\t\t\t\ts = parseInt(o.substr(0, 1), 8);
\t\t\t\to = o.substr(1);
\t\t\t}
\t\t\tsticy = ((s & 1) == 1); // not support
\t\t\tsgid = ((s & 2) == 2);
\t\t\tsuid = ((s & 4) == 4);
\t\t\tstr = '';
\t\t\tfor(i=0; i<3; i++) {
\t\t\t\tif ((parseInt(o.substr(i, 1), 8) & 4) == 4) {
\t\t\t\t\tstr += 'r';
\t\t\t\t} else {
\t\t\t\t\tstr += '-';
\t\t\t\t}
\t\t\t\tif ((parseInt(o.substr(i, 1), 8) & 2) == 2) {
\t\t\t\t\tstr += 'w';
\t\t\t\t} else {
\t\t\t\t\tstr += '-';
\t\t\t\t}
\t\t\t\tif ((parseInt(o.substr(i, 1), 8) & 1) == 1) {
\t\t\t\t\tstr += ((i==0 && suid)||(i==1 && sgid))? 's' : 'x';
\t\t\t\t} else {
\t\t\t\t\tstr += '-';
\t\t\t\t}
\t\t\t}
\t\t}
\t\tif (style == 'both') {
\t\t\treturn str + ' (' + oct + ')';
\t\t} else if (style == 'string') {
\t\t\treturn str;
\t\t} else {
\t\t\treturn oct;
\t\t}
\t},
\t
\t/**
\t * Regist this.decodeRawString function
\t * 
\t * @return void
\t */
\tregistRawStringDecoder : function(rawStringDecoder) {
\t\tif (\$.isFunction(rawStringDecoder)) {
\t\t\tthis.decodeRawString = this.options.rawStringDecoder = rawStringDecoder;
\t\t}
\t},
\t
\t/**
\t * Return boolean that uploadable MIME type into target folder
\t * 
\t * @param  String  mime    MIME type
\t * @param  String  target  target folder hash
\t * @return Bool
\t */
\tuploadMimeCheck : function(mime, target) {
\t\ttarget = target || this.cwd().hash;
\t\tvar res   = true, // default is allow
\t\t\tmimeChecker = this.option('uploadMime', target),
\t\t\tallow,
\t\t\tdeny,
\t\t\tcheck = function(checker) {
\t\t\t\tvar ret = false;
\t\t\t\tif (typeof checker === 'string' && checker.toLowerCase() === 'all') {
\t\t\t\t\tret = true;
\t\t\t\t} else if (Array.isArray(checker) && checker.length) {
\t\t\t\t\t\$.each(checker, function(i, v) {
\t\t\t\t\t\tv = v.toLowerCase();
\t\t\t\t\t\tif (v === 'all' || mime.indexOf(v) === 0) {
\t\t\t\t\t\t\tret = true;
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\treturn ret;
\t\t\t};
\t\tif (mime && \$.isPlainObject(mimeChecker)) {
\t\t\tmime = mime.toLowerCase();
\t\t\tallow = check(mimeChecker.allow);
\t\t\tdeny = check(mimeChecker.deny);
\t\t\tif (mimeChecker.firstOrder === 'allow') {
\t\t\t\tres = false; // default is deny
\t\t\t\tif (! deny && allow === true) { // match only allow
\t\t\t\t\tres = true;
\t\t\t\t}
\t\t\t} else {
\t\t\t\tres = true; // default is allow
\t\t\t\tif (deny === true && ! allow) { // match only deny
\t\t\t\t\tres = false;
\t\t\t\t}
\t\t\t}
\t\t}
\t\treturn res;
\t},
\t
\t/**
\t * call chained sequence of async deferred functions
\t * 
\t * @param  Array   tasks async functions
\t * @return Object  jQuery.Deferred
\t */
\tsequence : function(tasks) {
\t\tvar l = tasks.length,
\t\t\tchain = function(task, idx) {
\t\t\t\t++idx;
\t\t\t\tif (tasks[idx]) {
\t\t\t\t\treturn chain(task.then(tasks[idx]), idx);
\t\t\t\t} else {
\t\t\t\t\treturn task;
\t\t\t\t}
\t\t\t};
\t\tif (l > 1) {
\t\t\treturn chain(tasks[0](), 0);
\t\t} else {
\t\t\treturn tasks[0]();
\t\t}
\t},
\t
\t/**
\t * Reload contents of target URL for clear browser cache
\t * 
\t * @param  String  url target URL
\t * @return Object  jQuery.Deferred
\t */
\treloadContents : function(url) {
\t\tvar dfd = \$.Deferred(),
\t\t\tifm;
\t\ttry {
\t\t\tifm = \$('<iframe width=\"1\" height=\"1\" scrolling=\"no\" frameborder=\"no\" style=\"position:absolute; top:-1px; left:-1px\" crossorigin=\"use-credentials\">')
\t\t\t\t.attr('src', url)
\t\t\t\t.one('load', function() {
\t\t\t\t\tvar ifm = \$(this);
\t\t\t\t\ttry {
\t\t\t\t\t\tthis.contentDocument.location.reload(true);
\t\t\t\t\t\tifm.one('load', function() {
\t\t\t\t\t\t\tifm.remove();
\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t});
\t\t\t\t\t} catch(e) {
\t\t\t\t\t\tifm.attr('src', '').attr('src', url).one('load', function() {
\t\t\t\t\t\t\tifm.remove();
\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.appendTo('body');
\t\t} catch(e) {
\t\t\tifm && ifm.remove();
\t\t\tdfd.reject();
\t\t}
\t\treturn dfd;
\t},
\t
\t/**
\t * Make netmount option for OAuth2
\t * 
\t * @param  String   protocol
\t * @param  String   name
\t * @param  String   host
\t * @param  Object   opts  Default {noOffline: false, root: 'root', pathI18n: 'folderId', folders: true}
\t\t\t}
\t * 
\t * @return Object
\t */
\tmakeNetmountOptionOauth : function(protocol, name, host, opt) {
\t\tvar noOffline = typeof opt === 'boolean'? opt : null, // for backward compat
\t\t\topts = Object.assign({
\t\t\t\tnoOffline : false,
\t\t\t\troot      : 'root',
\t\t\t\tpathI18n  : 'folderId',
\t\t\t\tfolders   : true
\t\t\t}, (noOffline === null? (opt || {}) : {noOffline : noOffline})),
\t\t\taddFolders = function(fm, bro, folders) {
\t\t\t\tvar self = this,
\t\t\t\t\tcnt  = Object.keys(\$.isPlainObject(folders)? folders : {}).length,
\t\t\t\t\tselect;
\t\t\t\t
\t\t\t\tbro.next().remove();
\t\t\t\tif (cnt) {
\t\t\t\t\tselect = \$('<select class=\"ui-corner-all elfinder-tabstop\" style=\"max-width:200px;\">').append(
\t\t\t\t\t\t\$(\$.map(folders, function(n,i){return '<option value=\"'+fm.escape((i+'').trim())+'\">'+fm.escape(n)+'</option>';}).join(''))
\t\t\t\t\t).on('change click', function(e){
\t\t\t\t\t\tvar node = \$(this),
\t\t\t\t\t\t\tpath = node.val(),
\t\t\t\t\t\t\tspn;
\t\t\t\t\t\tself.inputs.path.val(path);
\t\t\t\t\t\tif (opts.folders && (e.type === 'change' || node.data('current') !== path)) {
\t\t\t\t\t\t\tnode.next().remove();
\t\t\t\t\t\t\tnode.data('current', path);
\t\t\t\t\t\t\tif (path != opts.root) {
\t\t\t\t\t\t\t\tspn = spinner();
\t\t\t\t\t\t\t\tif (xhr && xhr.state() === 'pending') {
\t\t\t\t\t\t\t\t\tfm.abortXHR(xhr, { quiet: true , abort: true });
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tnode.after(spn);
\t\t\t\t\t\t\t\txhr = fm.request({
\t\t\t\t\t\t\t\t\tdata : {cmd : 'netmount', protocol: protocol, host: host, user: 'init', path: path, pass: 'folders'},
\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t}).done(function(data){
\t\t\t\t\t\t\t\t\taddFolders.call(self, fm, node, data.folders);
\t\t\t\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\t\t\tfm.abortXHR(xhr, { quiet: true });
\t\t\t\t\t\t\t\t\tspn.remove();
\t\t\t\t\t\t\t\t}).xhr;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tbro.after(\$('<div></div>').append(select))
\t\t\t\t\t\t.closest('.ui-dialog').trigger('tabstopsInit');
\t\t\t\t\tselect.trigger('focus');
\t\t\t\t}
\t\t\t},
\t\t\tspinner = function() {
\t\t\t\treturn \$('<div class=\"elfinder-netmount-spinner\"></div>').append('<span class=\"elfinder-spinner\"></span>');
\t\t\t},
\t\t\txhr;
\t\treturn {
\t\t\tvars : {},
\t\t\tname : name,
\t\t\tinputs: {
\t\t\t\toffline  : \$('<input type=\"checkbox\"/>').on('change', function() {
\t\t\t\t\t\$(this).parents('table.elfinder-netmount-tb').find('select:first').trigger('change', 'reset');
\t\t\t\t}),
\t\t\t\thost     : \$('<span><span class=\"elfinder-spinner\"></span></span><input type=\"hidden\"/>'),
\t\t\t\tpath     : \$('<input type=\"text\" value=\"'+opts.root+'\"/>'),
\t\t\t\tuser     : \$('<input type=\"hidden\"/>'),
\t\t\t\tpass     : \$('<input type=\"hidden\"/>'),
\t\t\t\tmnt2res  : \$('<input type=\"hidden\"/>')
\t\t\t},
\t\t\tselect: function(fm, ev, d){
\t\t\t\tvar f = this.inputs,
\t\t\t\t\toline = f.offline,
\t\t\t\t\tf0 = \$(f.host[0]),
\t\t\t\t\tdata = d || null;
\t\t\t\tthis.vars.mbtn = f.host.closest('.ui-dialog').children('.ui-dialog-buttonpane:first').find('button.elfinder-btncnt-0');
\t\t\t\tif (! f0.data('inrequest')
\t\t\t\t\t\t&& (f0.find('span.elfinder-spinner').length
\t\t\t\t\t\t\t|| data === 'reset'
\t\t\t\t\t\t\t|| (data === 'winfocus' && ! f0.siblings('span.elfinder-button-icon-reload').length))
\t\t\t\t\t\t\t)
\t\t\t\t{
\t\t\t\t\tif (oline.parent().children().length === 1) {
\t\t\t\t\t\tf.path.parent().prev().html(fm.i18n(opts.pathI18n));
\t\t\t\t\t\toline.attr('title', fm.i18n('offlineAccess'));
\t\t\t\t\t\toline.uniqueId().after(\$('<label></label>').attr('for', oline.attr('id')).html(' '+fm.i18n('offlineAccess')));
\t\t\t\t\t}
\t\t\t\t\tf0.data('inrequest', true).empty().addClass('elfinder-spinner')
\t\t\t\t\t\t.parent().find('span.elfinder-button-icon').remove();
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'netmount', protocol: protocol, host: host, user: 'init', options: {id: fm.id, offline: oline.prop('checked')? 1:0, pass: f.host[1].value}},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t}).done(function(data){
\t\t\t\t\t\tf0.removeClass(\"elfinder-spinner\").html(data.body.replace(/\\{msg:([^}]+)\\}/g, function(whole,s1){return fm.i18n(s1, host);}));
\t\t\t\t\t});
\t\t\t\t\topts.noOffline && oline.closest('tr').hide();
\t\t\t\t} else {
\t\t\t\t\toline.closest('tr')[(opts.noOffline || f.user.val())? 'hide':'show']();
\t\t\t\t\tf0.data('funcexpup') && f0.data('funcexpup')();
\t\t\t\t}
\t\t\t\tthis.vars.mbtn[\$(f.host[1]).val()? 'show':'hide']();
\t\t\t},
\t\t\tdone: function(fm, data){
\t\t\t\tvar f = this.inputs,
\t\t\t\t\tp = this.protocol,
\t\t\t\t\tf0 = \$(f.host[0]),
\t\t\t\t\tf1 = \$(f.host[1]),
\t\t\t\t\texpires = '&nbsp;',
\t\t\t\t\tvars = this.vars,
\t\t\t\t\tchk = function() {
\t\t\t\t\t\tif (vars.oauthW && !document.hasFocus() && --vars.chkCnt) {
\t\t\t\t\t\t\tp.trigger('change', 'winfocus');
\t\t\t\t\t\t\tvars.tm = setTimeout(chk, 3000);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tbtn;
\t\t\t\t
\t\t\t\topts.noOffline && f.offline.closest('tr').hide();
\t\t\t\tif (data.mode == 'makebtn') {
\t\t\t\t\tf0.removeClass('elfinder-spinner').removeData('expires').removeData('funcexpup');
\t\t\t\t\tbtn = f.host.find('input').on('mouseenter mouseleave', function(){\$(this).toggleClass('ui-state-hover');});
\t\t\t\t\tif (data.url) {
\t\t\t\t\t\tbtn.on('click', function() {
\t\t\t\t\t\t\tvars.tm && clearTimeout(vars.tm);
\t\t\t\t\t\t\tvars.oauthW = window.open(data.url);
\t\t\t\t\t\t\t// To correspond to safari, authentication tab sometimes not closing in CORS environment.
\t\t\t\t\t\t\t// This may be a safari bug and may improve in the future.
\t\t\t\t\t\t\tif ((fm.UA.iOS || fm.UA.Mac) && fm.isCORS && !vars.chkdone) {
\t\t\t\t\t\t\t\tvars.chkCnt = 60;
\t\t\t\t\t\t\t\tvars.tm = setTimeout(chk, 5000);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tf1.val('');
\t\t\t\t\tf.path.val(opts.root).next().remove();
\t\t\t\t\tf.user.val('');
\t\t\t\t\tf.pass.val('');
\t\t\t\t\t! opts.noOffline && f.offline.closest('tr').show();
\t\t\t\t\tvars.mbtn.hide();
\t\t\t\t} else if (data.mode == 'folders') {
\t\t\t\t\tif (data.folders) {
\t\t\t\t\t\taddFolders.call(this, fm, f.path.nextAll(':last'), data.folders);
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (vars.oauthW) {
\t\t\t\t\t\tvars.tm && clearTimeout(vars.tm);
\t\t\t\t\t\tvars.oauthW.close();
\t\t\t\t\t\tdelete vars.oauthW;
\t\t\t\t\t\t// The problem that Safari's authentication tab doesn't close only affects the first time.
\t\t\t\t\t\tvars.chkdone = true;
\t\t\t\t\t}
\t\t\t\t\tif (data.expires) {
\t\t\t\t\t\texpires = '()';
\t\t\t\t\t\tf0.data('expires', data.expires);
\t\t\t\t\t}
\t\t\t\t\tf0.html(host + expires).removeClass('elfinder-spinner');
\t\t\t\t\tif (data.expires) {
\t\t\t\t\t\tf0.data('funcexpup', function() {
\t\t\t\t\t\t\tvar rem = Math.floor((f0.data('expires') - (+new Date()) / 1000) / 60);
\t\t\t\t\t\t\tif (rem < 3) {
\t\t\t\t\t\t\t\tf0.parent().children('.elfinder-button-icon-reload').click();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tf0.text(f0.text().replace(/\\(.*\\)/, '('+fm.i18n(['minsLeft', rem])+')'));
\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\tif (f0.is(':visible')) {
\t\t\t\t\t\t\t\t\t\tf0.data('funcexpup')();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}, 60000);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tf0.data('funcexpup')();
\t\t\t\t\t}
\t\t\t\t\tif (data.reset) {
\t\t\t\t\t\tp.trigger('change', 'reset');
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tf0.parent().append(\$('<span class=\"elfinder-button-icon elfinder-button-icon-reload\" title=\"'+fm.i18n('reAuth')+'\">')
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tf1.val('reauth');
\t\t\t\t\t\t\tp.trigger('change', 'reset');
\t\t\t\t\t\t}));
\t\t\t\t\tf1.val(protocol);
\t\t\t\t\tvars.mbtn.show();
\t\t\t\t\tif (data.folders) {
\t\t\t\t\t\taddFolders.call(this, fm, f.path, data.folders);
\t\t\t\t\t}
\t\t\t\t\tif (data.mnt2res) {
\t\t\t\t\t\tf.mnt2res.val('1');
\t\t\t\t\t}
\t\t\t\t\tf.user.val('done');
\t\t\t\t\tf.pass.val('done');
\t\t\t\t\tf.offline.closest('tr').hide();
\t\t\t\t}
\t\t\t\tf0.removeData('inrequest');
\t\t\t},
\t\t\tfail: function(fm, err){
\t\t\t\t\$(this.inputs.host[0]).removeData('inrequest');
\t\t\t\tthis.protocol.trigger('change', 'reset');
\t\t\t},
\t\t\tintegrateInfo: opts.integrate
\t\t};
\t},
\t
\t/**
\t * Find cwd's nodes from files
\t * 
\t * @param  Array    files
\t * @param  Object   opts   {firstOnly: true|false}
\t */
\tfindCwdNodes : function(files, opts) {
\t\tvar self    = this,
\t\t\tcwd     = this.getUI('cwd'),
\t\t\tcwdHash = this.cwd().hash,
\t\t\tnewItem = \$();
\t\t
\t\topts = opts || {};
\t\t
\t\t\$.each(files, function(i, f) {
\t\t\tif (f.phash === cwdHash || self.searchStatus.state > 1) {
\t\t\t\tnewItem = newItem.add(self.cwdHash2Elm(f.hash));
\t\t\t\tif (opts.firstOnly) {
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\treturn newItem;
\t},
\t
\t/**
\t * Convert from relative URL to abstract URL based on current URL
\t * 
\t * @param  String  URL
\t * @return String
\t */
\tconvAbsUrl : function(url) {
\t\tif (url.match(/^http/i)) {
\t\t\treturn url;
\t\t}
\t\tif (url.substr(0,2) === '//') {
\t\t\treturn window.location.protocol + url;
\t\t}
\t\tvar root = window.location.protocol + '//' + window.location.host,
\t\t\treg  = /[^\\/]+\\/\\.\\.\\//,
\t\t\tret;
\t\tif (url.substr(0, 1) === '/') {
\t\t\tret = root + url;
\t\t} else {
\t\t\tret = root + window.location.pathname.replace(/\\/[^\\/]+\$/, '/') + url;
\t\t}
\t\tret = ret.replace('/./', '/');
\t\twhile(reg.test(ret)) {
\t\t\tret = ret.replace(reg, '');
\t\t}
\t\treturn ret;
\t},
\t
\t/**
\t * Is same origin to current site
\t * 
\t * @param  String  check url
\t * @return Boolean
\t */
\tisSameOrigin : function (checkUrl) {
\t\tvar url;
\t\tcheckUrl = this.convAbsUrl(checkUrl);
\t\tif (location.origin && window.URL) {
\t\t\ttry {
\t\t\t\turl = new URL(checkUrl);
\t\t\t\treturn location.origin === url.origin;
\t\t\t} catch(e) {}
\t\t}
\t\turl = document.createElement('a');
\t\turl.href = checkUrl;
\t\treturn location.protocol === url.protocol && location.host === url.host && location.port && url.port;
\t},
\t
\tnavHash2Id : function(hash) {
\t\treturn this.navPrefix + hash;
\t},
\t
\tnavId2Hash : function(id) {
\t\treturn typeof(id) == 'string' ? id.substr(this.navPrefix.length) : false;
\t},
\t
\tcwdHash2Id : function(hash) {
\t\treturn this.cwdPrefix + hash;
\t},
\t
\tcwdId2Hash : function(id) {
\t\treturn typeof(id) == 'string' ? id.substr(this.cwdPrefix.length) : false;
\t},
\t
\t/**
\t * navHash to jQuery element object
\t *
\t * @param      String  hash    nav hash
\t * @return     Object  jQuery element object
\t */
\tnavHash2Elm : function(hash) {
\t\treturn \$(document.getElementById(this.navHash2Id(hash)));
\t},

\t/**
\t * cwdHash to jQuery element object
\t *
\t * @param      String  hash    cwd hash
\t * @return     Object  jQuery element object
\t */
\tcwdHash2Elm : function(hash) {
\t\treturn \$(document.getElementById(this.cwdHash2Id(hash)));
\t},

\tisInWindow : function(elem, nochkHide) {
\t\tvar elm, rect;
\t\tif (! (elm = elem.get(0))) {
\t\t\treturn false;
\t\t}
\t\tif (! nochkHide && elm.offsetParent === null) {
\t\t\treturn false;
\t\t}
\t\trect = elm.getBoundingClientRect();
\t\treturn document.elementFromPoint(rect.left, rect.top)? true : false;
\t},
\t
\t/**
\t * calculate elFinder node z-index
\t * 
\t * @return void
\t */
\tzIndexCalc : function() {
\t\tvar self = this,
\t\t\tnode = this.getUI(),
\t\t\tni = node.css('z-index');
\t\tif (ni && ni !== 'auto' && ni !== 'inherit') {
\t\t\tself.zIndex = ni;
\t\t} else {
\t\t\tnode.parents().each(function(i, n) {
\t\t\t\tvar z = \$(n).css('z-index');
\t\t\t\tif (z !== 'auto' && z !== 'inherit' && (z = parseInt(z))) {
\t\t\t\t\tself.zIndex = z;
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t});
\t\t}
\t},
\t
\t/**
\t * Load JavaScript files
\t * 
\t * @param  Array    urls      to load JavaScript file URLs
\t * @param  Function callback  call back function on script loaded
\t * @param  Object   opts      Additional options to \$.ajax OR {loadType: 'tag'} to load by script tag
\t * @param  Object   check     { obj: (Object)ParentObject, name: (String)\"Attribute name\", timeout: (Integer)milliseconds }
\t * @return elFinder
\t */
\tloadScript : function(urls, callback, opts, check) {
\t\tvar defOpts = {
\t\t\t\tdataType : 'script',
\t\t\t\tcache    : true
\t\t\t},
\t\t\tsuccess, cnt, scripts = {}, results = {};
\t\t
\t\topts = opts || {};
\t\tif (opts.tryRequire && this.hasRequire) {
\t\t\trequire(urls, callback, opts.error);
\t\t} else {
\t\t\tsuccess = function() {
\t\t\t\tvar cnt, fi, hasError;
\t\t\t\t\$.each(results, function(i, status) {
\t\t\t\t\tif (status !== 'success' && status !== 'notmodified') {
\t\t\t\t\t\thasError = true;
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (!hasError) {
\t\t\t\t\tif (\$.isFunction(callback)) {
\t\t\t\t\t\tif (check) {
\t\t\t\t\t\t\tif (typeof check.obj[check.name] === 'undefined') {
\t\t\t\t\t\t\t\tcnt = check.timeout? (check.timeout / 10) : 1;
\t\t\t\t\t\t\t\tfi = setInterval(function() {
\t\t\t\t\t\t\t\t\tif (--cnt < 0 || typeof check.obj[check.name] !== 'undefined') {
\t\t\t\t\t\t\t\t\t\tclearInterval(fi);
\t\t\t\t\t\t\t\t\t\tcallback();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}, 10);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tcallback();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcallback();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (opts.error && \$.isFunction(opts.error)) {
\t\t\t\t\t\topts.error({ loadResults: results });
\t\t\t\t\t}
\t\t\t\t}
\t\t\t};

\t\t\tif (opts.loadType === 'tag') {
\t\t\t\t\$('head > script').each(function() {
\t\t\t\t\tscripts[this.src] = this;
\t\t\t\t});
\t\t\t\tcnt = urls.length;
\t\t\t\t\$.each(urls, function(i, url) {
\t\t\t\t\tvar done = false,
\t\t\t\t\t\tscript;
\t\t\t\t\t
\t\t\t\t\tif (scripts[url]) {
\t\t\t\t\t\tresults[i] = scripts[url]._error || 'success';
\t\t\t\t\t\t(--cnt < 1) && success();
\t\t\t\t\t} else {
\t\t\t\t\t\tscript = document.createElement('script');
\t\t\t\t\t\tscript.charset = opts.charset || 'UTF-8';
\t\t\t\t\t\t\$('head').append(script);
\t\t\t\t\t\tscript.onload = script.onreadystatechange = function() {
\t\t\t\t\t\t\tif ( !done && (!this.readyState ||
\t\t\t\t\t\t\t\t\tthis.readyState === 'loaded' || this.readyState === 'complete') ) {
\t\t\t\t\t\t\t\tdone = true;
\t\t\t\t\t\t\t\tresults[i] = 'success';
\t\t\t\t\t\t\t\t(--cnt < 1) && success();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t\tscript.onerror = function(err) {
\t\t\t\t\t\t\tresults[i] = script._error = (err && err.type)? err.type : 'error';
\t\t\t\t\t\t\t(--cnt < 1) && success();
\t\t\t\t\t\t};
\t\t\t\t\t\tscript.src = url;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t} else {
\t\t\t\topts = \$.isPlainObject(opts)? Object.assign(defOpts, opts) : defOpts;
\t\t\t\tcnt = 0;
\t\t\t\t(function appendScript(d, status) {
\t\t\t\t\tif (d !== void(0)) {
\t\t\t\t\t\tresults[cnt++] = status;
\t\t\t\t\t}
\t\t\t\t\tif (urls.length) {
\t\t\t\t\t\t\$.ajax(Object.assign({}, opts, {
\t\t\t\t\t\t\turl: urls.shift(),
\t\t\t\t\t\t\tsuccess: appendScript,
\t\t\t\t\t\t\terror: appendScript
\t\t\t\t\t\t}));
\t\t\t\t\t} else {
\t\t\t\t\t\tsuccess();
\t\t\t\t\t}
\t\t\t\t})();
\t\t\t}
\t\t}
\t\treturn this;
\t},
\t
\t/**
\t * Load CSS files
\t * 
\t * @param  Array    to load CSS file URLs
\t * @param  Object   options
\t * @return elFinder
\t */
\tloadCss : function(urls, opts) {
\t\tvar self = this,
\t\t\tclName, dfds;
\t\tif (typeof urls === 'string') {
\t\t\turls = [ urls ];
\t\t}
\t\tif (opts) {
\t\t\tif (opts.className) {
\t\t\t\tclName = opts.className;
\t\t\t}
\t\t\tif (opts.dfd && opts.dfd.promise) {
\t\t\t\tdfds = [];
\t\t\t}
\t\t}
\t\t\$.each(urls, function(i, url) {
\t\t\tvar link, df;
\t\t\turl = self.convAbsUrl(url).replace(/^https?:/i, '');
\t\t\tif (dfds) {
\t\t\t\tdfds[i] = \$.Deferred();
\t\t\t}
\t\t\tif (! \$('head > link[href=\"' + self.escape(url) + '\"]').length) {
\t\t\t\tlink = document.createElement('link');
\t\t\t\tlink.type = 'text/css';
\t\t\t\tlink.rel = 'stylesheet';
\t\t\t\tlink.href = url;
\t\t\t\tif (clName) {
\t\t\t\t\tlink.className = clName;
\t\t\t\t}
\t\t\t\tif (dfds) {
\t\t\t\t\tlink.onload = function() {
\t\t\t\t\t\tdfds[i].resolve();
\t\t\t\t\t};
\t\t\t\t\tlink.onerror = function() {
\t\t\t\t\t\tdfds[i].reject();
\t\t\t\t\t};
\t\t\t\t}
\t\t\t\t\$('head').append(link);
\t\t\t} else {
\t\t\t\tdfds && dfds[i].resolve();
\t\t\t}
\t\t});
\t\tif (dfds) {
\t\t\t\$.when.apply(null, dfds).done(function() {
\t\t\t\topts.dfd.resolve();
\t\t\t}).fail(function() {
\t\t\t\topts.dfd.reject();
\t\t\t});
\t\t}
\t\treturn this;
\t},
\t
\t/**
\t * Abortable async job performer
\t * 
\t * @param func Function
\t * @param arr  Array
\t * @param opts Object
\t * 
\t * @return Object \$.Deferred that has an extended method _abort()
\t */
\tasyncJob : function(func, arr, opts) {
\t\tvar dfrd = \$.Deferred(),
\t\t\tabortFlg = false,
\t\t\tparms = Object.assign({
\t\t\t\tinterval : 0,
\t\t\t\tnumPerOnce : 1
\t\t\t}, opts || {}),
\t\t\tresArr = [],
\t\t\tvars =[],
\t\t\tcurVars = [],
\t\t\texec,
\t\t\ttm;
\t\t
\t\tdfrd._abort = function(resolve) {
\t\t\ttm && clearTimeout(tm);
\t\t\tvars = [];
\t\t\tabortFlg = true;
\t\t\tif (dfrd.state() === 'pending') {
\t\t\t\tdfrd[resolve? 'resolve' : 'reject'](resArr);
\t\t\t}
\t\t};
\t\t
\t\tdfrd.fail(function() {
\t\t\tdfrd._abort();
\t\t}).always(function() {
\t\t\tdfrd._abort = function() {};
\t\t});

\t\tif (typeof func === 'function' && Array.isArray(arr)) {
\t\t\tvars = arr.concat();
\t\t\texec = function() {
\t\t\t\tvar i, len, res;
\t\t\t\tif (abortFlg) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tcurVars = vars.splice(0, parms.numPerOnce);
\t\t\t\tlen = curVars.length;
\t\t\t\tfor (i = 0; i < len; i++) {
\t\t\t\t\tif (abortFlg) {
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t\tres = func(curVars[i]);
\t\t\t\t\t(res !== null) && resArr.push(res);
\t\t\t\t}
\t\t\t\tif (abortFlg) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tif (vars.length) {
\t\t\t\t\ttm = setTimeout(exec, parms.interval);
\t\t\t\t} else {
\t\t\t\t\tdfrd.resolve(resArr);
\t\t\t\t}
\t\t\t};
\t\t\tif (vars.length) {
\t\t\t\ttm = setTimeout(exec, 0);
\t\t\t} else {
\t\t\t\tdfrd.resolve(resArr);
\t\t\t}
\t\t} else {
\t\t\tdfrd.reject();
\t\t}
\t\treturn dfrd;
\t},
\t
\tgetSize : function(targets) {
\t\tvar self = this,
\t\t\treqs = [],
\t\t\ttgtlen = targets.length,
\t\t\tdfrd = \$.Deferred().fail(function() {
\t\t\t\t\$.each(reqs, function(i, req) {
\t\t\t\t\tif (req) {
\t\t\t\t\t\treq.syncOnFail && req.syncOnFail(false);
\t\t\t\t\t\treq.reject();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}),
\t\t\tgetLeafRoots = function(file) {
\t\t\t\tvar targets = [];
\t\t\t\tif (file.mime === 'directory') {
\t\t\t\t\t\$.each(self.leafRoots, function(hash, roots) {
\t\t\t\t\t\tvar phash;
\t\t\t\t\t\tif (hash === file.hash) {
\t\t\t\t\t\t\ttargets.push.apply(targets, roots);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tphash = (self.file(hash) || {}).phash;
\t\t\t\t\t\t\twhile(phash) {
\t\t\t\t\t\t\t\tif (phash === file.hash) {
\t\t\t\t\t\t\t\t\ttargets.push.apply(targets, roots);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tphash = (self.file(phash) || {}).phash;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\treturn targets;
\t\t\t},
\t\t\tcheckPhash = function(hash) {
\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\tdir = self.file(hash),
\t\t\t\t\ttarget = dir? dir.phash : hash;
\t\t\t\tif (target && ! self.file(target)) {
\t\t\t\t\tself.request({
\t\t\t\t\t\tdata : {
\t\t\t\t\t\t\tcmd    : 'parents',
\t\t\t\t\t\t\ttarget : target
\t\t\t\t\t\t},
\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t}).done(function() {
\t\t\t\t\t\tself.one('parentsdone', function() {
\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t});
\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}
\t\t\t\treturn dfd;
\t\t\t},
\t\t\tcache = function() {
\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\tcnt = Object.keys(self.leafRoots).length;
\t\t\t\t
\t\t\t\tif (cnt > 0) {
\t\t\t\t\t\$.each(self.leafRoots, function(hash) {
\t\t\t\t\t\tcheckPhash(hash).done(function() {
\t\t\t\t\t\t\t--cnt;
\t\t\t\t\t\t\tif (cnt < 1) {
\t\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}
\t\t\t\treturn dfd;
\t\t\t};

\t\tself.autoSync('stop');
\t\tcache().done(function() {
\t\t\tvar files = [], grps = {}, dfds = [], cache = [], singles = {};
\t\t\t
\t\t\t\$.each(targets, function() {
\t\t\t\tfiles.push.apply(files, getLeafRoots(self.file(this)));
\t\t\t});
\t\t\ttargets.push.apply(targets, files);
\t\t\t
\t\t\t\$.each(targets, function() {
\t\t\t\tvar root = self.root(this),
\t\t\t\t\tfile = self.file(this);
\t\t\t\tif (file && (file.sizeInfo || file.mime !== 'directory')) {
\t\t\t\t\tcache.push(\$.Deferred().resolve(file.sizeInfo? file.sizeInfo : {size: file.size, dirCnt: 0, fileCnt : 1}));
\t\t\t\t} else {
\t\t\t\t\tif (! grps[root]) {
\t\t\t\t\t\tgrps[root] = [ this.toString() ];
\t\t\t\t\t} else {
\t\t\t\t\t\tgrps[root].push(this.toString());
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\t\$.each(grps, function() {
\t\t\t\tvar idx = dfds.length;
\t\t\t\tif (this.length === 1) {
\t\t\t\t\tsingles[idx] = this[0];
\t\t\t\t}
\t\t\t\tdfds.push(self.request({
\t\t\t\t\tdata : {cmd : 'size', targets : this},
\t\t\t\t\tpreventDefault : true
\t\t\t\t}));
\t\t\t});
\t\t\treqs.push.apply(reqs, dfds);
\t\t\tdfds.push.apply(dfds, cache);
\t\t\t
\t\t\t\$.when.apply(\$, dfds).fail(function() {
\t\t\t\tdfrd.reject();
\t\t\t}).done(function() {
\t\t\t\tvar cache = function(h, data) {
\t\t\t\t\t\tvar file;
\t\t\t\t\t\tif (file = self.file(h)) {
\t\t\t\t\t\t\tfile.sizeInfo = { isCache: true };
\t\t\t\t\t\t\t\$.each(['size', 'dirCnt', 'fileCnt'], function() {
\t\t\t\t\t\t\t\tfile.sizeInfo[this] = data[this] || 0;
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tfile.size = parseInt(file.sizeInfo.size);
\t\t\t\t\t\t\tchanged.push(file);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsize = 0,
\t\t\t\t\tfileCnt = 0,
\t\t\t\t\tdirCnt = 0,
\t\t\t\t\targLen = arguments.length,
\t\t\t\t\tcnts = [],
\t\t\t\t\tcntsTxt = '',
\t\t\t\t\tchanged = [],
\t\t\t\t\ti, file, data;
\t\t\t\t
\t\t\t\tfor (i = 0; i < argLen; i++) {
\t\t\t\t\tdata = arguments[i];
\t\t\t\t\tfile = null;
\t\t\t\t\tif (!data.isCache) {
\t\t\t\t\t\tif (singles[i] && (file = self.file(singles[i]))) {
\t\t\t\t\t\t\tcache(singles[i], data);
\t\t\t\t\t\t} else if (data.sizes && \$.isPlainObject(data.sizes)) {
\t\t\t\t\t\t\t\$.each(data.sizes, function(h, sizeInfo) {
\t\t\t\t\t\t\t\tcache(h, sizeInfo);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tsize += parseInt(data.size);
\t\t\t\t\tif (fileCnt !== false) {
\t\t\t\t\t\tif (typeof data.fileCnt === 'undefined') {
\t\t\t\t\t\t\tfileCnt = false;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfileCnt += parseInt(data.fileCnt || 0);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (dirCnt !== false) {
\t\t\t\t\t\tif (typeof data.dirCnt === 'undefined') {
\t\t\t\t\t\t\tdirCnt = false;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdirCnt += parseInt(data.dirCnt || 0);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tchanged.length && self.change({changed: changed});
\t\t\t\t
\t\t\t\tif (dirCnt !== false){
\t\t\t\t\tcnts.push(self.i18n('folders') + ': ' + (dirCnt - (tgtlen > 1? 0 : 1)));
\t\t\t\t}
\t\t\t\tif (fileCnt !== false){
\t\t\t\t\tcnts.push(self.i18n('files') + ': ' + fileCnt);
\t\t\t\t}
\t\t\t\tif (cnts.length) {
\t\t\t\t\tcntsTxt = '<br>' + cnts.join(', ');
\t\t\t\t}
\t\t\t\tdfrd.resolve({
\t\t\t\t\tsize: size,
\t\t\t\t\tfileCnt: fileCnt,
\t\t\t\t\tdirCnt: dirCnt,
\t\t\t\t\tformated: (size >= 0 ? self.formatSize(size) : self.i18n('unknown')) + cntsTxt
\t\t\t\t});
\t\t\t});
\t\t\t
\t\t\tself.autoSync();
\t\t});
\t\t
\t\treturn dfrd;
\t},

\t/**
\t * Worker Object URL for Blob URL of getWorker()
\t */
\twkObjUrl : null,

\t/**
\t * Gets the web worker.
\t *
\t * @param      {Object}  options  The options
\t * @return     {Worker}  The worker.
\t */
\tgetWorker : function(options){
\t\t// for to make blob URL
\t\tfunction woker() {
\t\t\tself.onmessage = function(e) {
\t\t\t\tvar d = e.data;
\t\t\t\ttry {
\t\t\t\t\tself.data = d.data;
\t\t\t\t\tif (d.scripts) {
\t\t\t\t\t\tfor(var i = 0; i < d.scripts.length; i++) {
\t\t\t\t\t\t\timportScripts(d.scripts[i]);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tself.postMessage(self.res);
\t\t\t\t} catch (e) {
\t\t\t\t\tself.postMessage({error: e.toString()});
\t\t\t\t}
\t\t\t};
\t\t}
\t\t// get woker
\t\tvar wk;
\t\ttry {
\t\t\tif (!this.wkObjUrl) {
\t\t\t\tthis.wkObjUrl = (window.URL || window.webkitURL).createObjectURL(new Blob(
\t\t\t\t\t[woker.toString().replace(/\\s+/g, ' ').replace(/ *([^\\w]) */g, '\$1').replace(/^function\\b.+?\\{|\\}\$/g, '')],
\t\t\t\t\t{ type:'text/javascript' }
\t\t\t\t));
\t\t\t}
\t\t\twk = new Worker(this.wkObjUrl, options);
\t\t} catch(e) {
\t\t\tthis.debug('error', e.toString());
\t\t}
\t\treturn wk;
\t},

\t/**
\t * Get worker absolute URL by filename
\t *
\t * @param      {string}  filename  The filename
\t * @return     {<type>}  The worker url.
\t */
\tgetWorkerUrl : function(filename) {
\t\treturn this.convAbsUrl(this.baseUrl + 'js/worker/' + filename);
\t},

\t/**
\t * Gets the theme object by settings of options.themes
\t *
\t * @param  String  themeid  The themeid
\t * @return Object  jQuery.Deferred
\t */
\tgetTheme : function(themeid) {
\t\tvar self = this,
\t\t\tdfd = \$.Deferred(),
\t\t\tabsUrl = function(url, base) {
\t\t\t\tif (!base) {
\t\t\t\t\tbase = self.convAbsUrl(self.baseUrl);
\t\t\t\t}
\t\t\t\tif (Array.isArray(url)) {
\t\t\t\t\treturn \$.map(url, function(v) {
\t\t\t\t\t\treturn absUrl(v, base);
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\treturn url.match(/^(?:http|\\/\\/)/i)? url : base + url.replace(/^(?:\\.\\/|\\/)/, '');
\t\t\t\t}
\t\t\t},
\t\t\tthemeObj, m;
\t\tif (themeid && (themeObj = self.options.themes[themeid])) {
\t\t\tif (typeof themeObj === 'string') {
\t\t\t\turl = absUrl(themeObj);
\t\t\t\tif (m = url.match(/^(.+\\/)[^/]+\\.json\$/i)) {
\t\t\t\t\t\$.getJSON(url).done(function(data) {
\t\t\t\t\t\tthemeObj = data;
\t\t\t\t\t\tthemeObj.id = themeid;
\t\t\t\t\t\tif (themeObj.cssurls) {
\t\t\t\t\t\t\tthemeObj.cssurls = absUrl(themeObj.cssurls, m[1]);
\t\t\t\t\t\t}
\t\t\t\t\t\tdfd.resolve(themeObj);
\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdfd.resolve({
\t\t\t\t\t\tid: themeid,
\t\t\t\t\t\tname: themeid,
\t\t\t\t\t\tcssurls: [url]
\t\t\t\t\t});
\t\t\t\t}
\t\t\t} else if (\$.isPlainObject(themeObj) && themeObj.cssurls) {
\t\t\t\tthemeObj.id = themeid;
\t\t\t\tthemeObj.cssurls = absUrl(themeObj.cssurls);
\t\t\t\tif (!Array.isArray(themeObj.cssurls)) {
\t\t\t\t\tthemeObj.cssurls = [themeObj.cssurls];
\t\t\t\t}
\t\t\t\tif (!themeObj.name) {
\t\t\t\t\tthemeObj.name = themeid;
\t\t\t\t}
\t\t\t\tdfd.resolve(themeObj);
\t\t\t} else {
\t\t\t\tdfd.reject();
\t\t\t}
\t\t} else {
\t\t\tdfd.reject();
\t\t}
\t\treturn dfd;
\t},

\t/**
\t * Change current theme
\t *
\t * @param  String  themeid  The themeid
\t * @return Object  this elFinder instance
\t */
\tchangeTheme : function(themeid) {
\t\tvar self = this;
\t\tif (themeid) {
\t\t\tif (self.options.themes[themeid] && (!self.theme || self.theme.id !== themeid)) {
\t\t\t\tself.getTheme(themeid).done(function(themeObj) {
\t\t\t\t\tif (themeObj.cssurls) {
\t\t\t\t\t\t\$('head>link.elfinder-theme-ext').remove();
\t\t\t\t\t\tself.loadCss(themeObj.cssurls, {
\t\t\t\t\t\t\tclassName: 'elfinder-theme-ext',
\t\t\t\t\t\t\tdfd: \$.Deferred().done(function() {
\t\t\t\t\t\t\t\tself.theme = themeObj;
\t\t\t\t\t\t\t\tself.trigger && self.trigger('themechange');
\t\t\t\t\t\t\t})
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t} else if (themeid === 'default' && self.theme && self.theme.id !== 'default') {
\t\t\t\t\$('head>link.elfinder-theme-ext').remove();
\t\t\t\tself.theme = null;
\t\t\t\tself.trigger && self.trigger('themechange');
\t\t\t}
\t\t}
\t\treturn this;
\t},

\t/**
\t * Apply leaf root stats to target directory
\t *
\t * @param      object     dir     object of target directory
\t * @param      boolean    update  is force update
\t * 
\t * @return     boolean    dir object was chenged 
\t */
\tapplyLeafRootStats : function(dir, update) {
\t\tvar self = this,
\t\t\tprev = update? dir : (self.file(dir.hash) || dir),
\t\t\tprevTs = prev.ts,
\t\t\tchange = false;
\t\t// backup original stats
\t\tif (update || !dir._realStats) {
\t\t\tdir._realStats = {
\t\t\t\tlocked: dir.locked || 0,
\t\t\t\tdirs: dir.dirs || 0,
\t\t\t\tts: dir.ts
\t\t\t};
\t\t}
\t\t// set lock
\t\tdir.locked = 1;
\t\tif (!prev.locked) {
\t\t\tchange = true;
\t\t}
\t\t// has leaf root to `dirs: 1`
\t\tdir.dirs = 1;
\t\tif (!prev.dirs) {
\t\t\tchange = true;
\t\t}
\t\t// set ts
\t\t\$.each(self.leafRoots[dir.hash], function() {
\t\t\tvar f = self.file(this);
\t\t\tif (f && f.ts && (dir.ts || 0) < f.ts) {
\t\t\t\tdir.ts = f.ts;
\t\t\t}
\t\t});
\t\tif (prevTs !== dir.ts) {
\t\t\tchange = true;
\t\t}

\t\treturn change;
\t},

\t/**
\t * To aborted XHR object
\t * 
\t * @param Object xhr
\t * @param Object opts
\t * 
\t * @return void
\t */
\tabortXHR : function(xhr, o) {
\t\tvar opts = o || {};
\t\t
\t\tif (xhr) {
\t\t\topts.quiet && (xhr.quiet = true);
\t\t\tif (opts.abort && xhr._requestId) {
\t\t\t\tthis.request({
\t\t\t\t\tdata: {
\t\t\t\t\t\tcmd: 'abort',
\t\t\t\t\t\tid: xhr._requestId
\t\t\t\t\t},
\t\t\t\t\tpreventDefault: true
\t\t\t\t});
\t\t\t}
\t\t\txhr.abort();
\t\t\txhr = void 0;
\t\t}
\t},

\t/**
\t * Sets the custom header by xhr response header with options.parrotHeaders
\t *
\t * @param Object xhr
\t * 
\t * @return void
\t */
\tsetCustomHeaderByXhr : function(xhr) {
\t\tvar self = this;
\t\tif (xhr.getResponseHeader && self.parrotHeaders && self.parrotHeaders.length) {
\t\t\t\$.each(self.parrotHeaders, function(i, h) {
\t\t\t\tvar val = xhr.getResponseHeader(h);
\t\t\t\tif (val) {
\t\t\t\t\tself.customHeaders[h] = val;
\t\t\t\t\tself.sessionStorage('core-ph:'+h, val);
\t\t\t\t} else if (typeof val === 'string') {
\t\t\t\t\tdelete self.customHeaders[h];
\t\t\t\t\tself.sessionStorage('core-ph:'+h, null);
\t\t\t\t}
\t\t\t});
\t\t}
\t},

\t/**
\t * Determines if parrot headers.
\t *
\t * @return     {boolean}  True if parrot headers, False otherwise.
\t */
\thasParrotHeaders : function() {
\t\tvar res = false,
\t\t\tphs = this.parrotHeaders;
\t\tif (Object.keys(this.customHeaders).length) {
\t\t\tfor (var i = 0; i < phs.length; i++) {
\t\t\t\tif (this.customHeaders[phs[i]]) {
\t\t\t\t\tres = true;
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t}
\t\t}
\t\treturn res;
\t},

\t/**
\t * Gets the request identifier
\t *
\t * @return  String  The request identifier.
\t */
\tgetRequestId : function() {
\t\treturn (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
\t},
\t
\t/**
\t * Flip key and value of array or object
\t * 
\t * @param  Array | Object  { a: 1, b: 1, c: 2 }
\t * @param  Mixed           Static value
\t * @return Object          { 1: \"b\", 2: \"c\" }
\t */
\tarrayFlip : function (trans, val) {
\t\tvar key,
\t\t\ttmpArr = {},
\t\t\tisArr = \$.isArray(trans);
\t\tfor (key in trans) {
\t\t\tif (isArr || trans.hasOwnProperty(key)) {
\t\t\t\ttmpArr[trans[key]] = val || key;
\t\t\t}
\t\t}
\t\treturn tmpArr;
\t},
\t
\t/**
\t * Return array [\"name without extention\", \"extention\"]
\t * 
\t * @param String name
\t * 
\t * @return Array
\t * 
\t */
\tsplitFileExtention : function(name) {
\t\tvar m;
\t\tif (m = name.match(/^(.+?)?\\.((?:tar\\.(?:gz|bz|bz2|z|lzo))|cpio\\.gz|ps\\.gz|xcf\\.(?:gz|bz2)|[a-z0-9]{1,10})\$/i)) {
\t\t\tif (typeof m[1] === 'undefined') {
\t\t\t\tm[1] = '';
\t\t\t}
\t\t\treturn [m[1], m[2]];
\t\t} else {
\t\t\treturn [name, ''];
\t\t}
\t},
\t
\t/**
\t * Slice the ArrayBuffer by sliceSize
\t *
\t * @param      arraybuffer  arrayBuffer  The array buffer
\t * @param      Number       sliceSize    The slice size
\t * @return     Array   Array of sleced arraybuffer
\t */
\tsliceArrayBuffer : function(arrayBuffer, sliceSize) {
\t\tvar segments= [],
\t\t\tfi = 0;
\t\twhile(fi * sliceSize < arrayBuffer.byteLength){
\t\t\tsegments.push(arrayBuffer.slice(fi * sliceSize, (fi + 1) * sliceSize));
\t\t\tfi++;
\t\t}
\t\treturn segments;
\t},

\tarrayBufferToBase64 : function(ab) {
\t\tif (!window.btoa) {
\t\t\treturn '';
\t\t}
\t\tvar dView = new Uint8Array(ab), // Get a byte view
\t\t\tarr = Array.prototype.slice.call(dView), // Create a normal array
\t\t\tarr1 = arr.map(function(item) {
\t\t\t\treturn String.fromCharCode(item); // Convert
\t\t\t});
\t    return window.btoa(arr1.join('')); // Form a string
\t},

\tlog : function(m) { window.console && window.console.log && window.console.log(m); return this; },
\t
\tdebug : function(type, m) {
\t\tvar self = this,
\t\t\td = this.options.debug,
\t\t\ttb = this.options.toastBackendWarn,
\t\t\ttbOpts, showlog;

\t\tif (type === 'backend-error') {
\t\t\tif (! this.cwd().hash || (d && (d === 'all' || d['backend-error']))) {
\t\t\t\tm = Array.isArray(m)? m : [ m ];
\t\t\t\tthis.error(m);
\t\t\t}
\t\t} else if (type === 'backend-warning') {
\t\t\tshowlog = true;
\t\t\tif (tb) {
\t\t\t\ttbOpts = \$.isPlainObject(tb)? tb : {};
\t\t\t\t\$.each(Array.isArray(m)? m : [ m ], function(i, m) {
\t\t\t\t\tself.toast(Object.assign({
\t\t\t\t\t\tmode : 'warning',
\t\t\t\t\t\tmsg: m
\t\t\t\t\t}, tbOpts));
\t\t\t\t});
\t\t\t}
\t\t} else if (type === 'backend-debug') {
\t\t\tthis.trigger('backenddebug', m);
\t\t}
\t\t
\t\tif (showlog || (d && (d === 'all' || d[type]))) {
\t\t\twindow.console && window.console.log && window.console.log('elfinder debug: ['+type+'] ['+this.id+']', m);
\t\t}

\t\treturn this;
\t},

\t/**
\t * Parse response.debug and trigger debug
\t *
\t * @param      Object  response  The response
\t */
\tresponseDebug : function(response) {
\t\tvar rd = response.debug,
\t\t\td;
\t\tif (rd) {
\t\t\t// set options.debug
\t\t\td = this.options.debug;
\t\t\tif (!d || d !== 'all') {
\t\t\t\tif (!d) {
\t\t\t\t\td = this.options.debug = {};
\t\t\t\t}
\t\t\t\td['backend-error'] = true;
\t\t\t\td['warning'] = true;
\t\t\t}
\t\t\tif (rd.mountErrors && (typeof rd.mountErrors === 'string' || (Array.isArray(rd.mountErrors) && rd.mountErrors.length))) {
\t\t\t\tthis.debug('backend-error', rd.mountErrors);
\t\t\t}
\t\t\tif (rd.backendErrors && (typeof rd.backendErrors === 'string' || (Array.isArray(rd.backendErrors) && rd.backendErrors.length))) {
\t\t\t\tthis.debug('backend-warning', rd.backendErrors);
\t\t\t}
\t\t}
\t},

\ttime : function(l) { window.console && window.console.time && window.console.time(l); },
\ttimeEnd : function(l) { window.console && window.console.timeEnd && window.console.timeEnd(l); }
\t

};

/**
 * for conpat ex. ie8...
 *
 * Object.keys() - JavaScript | MDN
 * https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
 */
if (!Object.keys) {
\tObject.keys = (function () {
\t\tvar hasOwnProperty = Object.prototype.hasOwnProperty,
\t\t\t\thasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
\t\t\t\tdontEnums = [
\t\t\t\t\t'toString',
\t\t\t\t\t'toLocaleString',
\t\t\t\t\t'valueOf',
\t\t\t\t\t'hasOwnProperty',
\t\t\t\t\t'isPrototypeOf',
\t\t\t\t\t'propertyIsEnumerable',
\t\t\t\t\t'constructor'
\t\t\t\t],
\t\t\t\tdontEnumsLength = dontEnums.length;

\t\treturn function (obj) {
\t\t\tif (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

\t\t\tvar result = [];

\t\t\tfor (var prop in obj) {
\t\t\t\tif (hasOwnProperty.call(obj, prop)) result.push(prop);
\t\t\t}

\t\t\tif (hasDontEnumBug) {
\t\t\t\tfor (var i=0; i < dontEnumsLength; i++) {
\t\t\t\t\tif (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
\t\t\t\t}
\t\t\t}
\t\t\treturn result;
\t\t};
\t})();
}
// Array.isArray
if (!Array.isArray) {
\tArray.isArray = function(arr) {
\t\treturn jQuery.isArray(arr);
\t};
}
// Object.assign
if (!Object.assign) {
\tObject.assign = function() {
\t\treturn jQuery.extend.apply(null, arguments);
\t};
}
// String.repeat
if (!String.prototype.repeat) {
\tString.prototype.repeat = function(count) {
\t\t'use strict';
\t\tif (this == null) {
\t\t\tthrow new TypeError('can\\'t convert ' + this + ' to object');
\t\t}
\t\tvar str = '' + this;
\t\tcount = +count;
\t\tif (count != count) {
\t\t\tcount = 0;
\t\t}
\t\tif (count < 0) {
\t\t\tthrow new RangeError('repeat count must be non-negative');
\t\t}
\t\tif (count == Infinity) {
\t\t\tthrow new RangeError('repeat count must be less than infinity');
\t\t}
\t\tcount = Math.floor(count);
\t\tif (str.length == 0 || count == 0) {
\t\t\treturn '';
\t\t}
\t\t// Ensuring count is a 31-bit integer allows us to heavily optimize the
\t\t// main part. But anyway, most current (August 2014) browsers can't handle
\t\t// strings 1 << 28 chars or longer, so:
\t\tif (str.length * count >= 1 << 28) {
\t\t\tthrow new RangeError('repeat count must not overflow maximum string size');
\t\t}
\t\tvar rpt = '';
\t\tfor (var i = 0; i < count; i++) {
\t\t\trpt += str;
\t\t}
\t\treturn rpt;
\t};
}
// String.trim
if (!String.prototype.trim) {
\tString.prototype.trim = function() {
\t\treturn this.replace(/^\\s+|\\s+\$/g, '');
\t};
}
// Array.apply
(function () {
\ttry {
\t\tArray.apply(null, {});
\t\treturn;
\t} catch (e) { }

\tvar toString = Object.prototype.toString,
\t\tarrayType = '[object Array]',
\t\t_apply = Function.prototype.apply,
\t\tslice = /*@cc_on @if (@_jscript_version <= 5.8)
\t\t\tfunction () {
\t\t\t\tvar a = [], i = this.length;
\t\t\t\twhile (i-- > 0) a[i] = this[i];
\t\t\t\treturn a;
\t\t\t}@else@*/Array.prototype.slice/*@end@*/;

\tFunction.prototype.apply = function apply(thisArg, argArray) {
\t\treturn _apply.call(this, thisArg,
\t\t\ttoString.call(argArray) === arrayType ? argArray : slice.call(argArray));
\t};
})();
// Array.from
if (!Array.from) {
\tArray.from = function(obj) {
\t\treturn obj.length === 1 ? [obj[0]] : Array.apply(null, obj);
\t};
}
// window.requestAnimationFrame and window.cancelAnimationFrame
if (!window.cancelAnimationFrame) {
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 
                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
    }
 
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
 
    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());
}


/*
 * File: /js/elFinder.version.js
 */

/**
 * Application version
 *
 * @type String
 **/
elFinder.prototype.version = '2.1.57';



/*
 * File: /js/jquery.elfinder.js
 */

/*** jQuery UI droppable performance tune for elFinder ***/
(function(){
if (\$.ui) {
\tif (\$.ui.ddmanager) {
\t\tvar origin = \$.ui.ddmanager.prepareOffsets;
\t\t\$.ui.ddmanager.prepareOffsets = function( t, event ) {
\t\t\tvar isOutView = function(elem) {
\t\t\t\tif (elem.is(':hidden')) {
\t\t\t\t\treturn true;
\t\t\t\t}
\t\t\t\tvar rect = elem[0].getBoundingClientRect();
\t\t\t\treturn document.elementFromPoint(rect.left, rect.top) || document.elementFromPoint(rect.left + rect.width, rect.top + rect.height)? false : true;
\t\t\t};
\t\t\t
\t\t\tif (event.type === 'mousedown' || t.options.elfRefresh) {
\t\t\t\tvar i, d,
\t\t\t\tm = \$.ui.ddmanager.droppables[ t.options.scope ] || [],
\t\t\t\tl = m.length;
\t\t\t\tfor ( i = 0; i < l; i++ ) {
\t\t\t\t\td = m[ i ];
\t\t\t\t\tif (d.options.autoDisable && (!d.options.disabled || d.options.autoDisable > 1)) {
\t\t\t\t\t\td.options.disabled = isOutView(d.element);
\t\t\t\t\t\td.options.autoDisable = d.options.disabled? 2 : 1;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// call origin function
\t\t\treturn origin( t, event );
\t\t};
\t}
}
})();

 /**
 *
 * jquery.binarytransport
 *
 * @description. jQuery ajax transport for making binary data type requests.
 *
 */

(function(\$, undefined) {
\t
\t// use this transport for \"binary\" data type
\t\$.ajaxTransport(\"+binary\", function(options, originalOptions, jqXHR) {
\t\t// check for conditions and support for blob / arraybuffer response type
\t\tif (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob))))) {
\t\t\tvar callback;

\t\t\t// Cross domain only allowed if supported through XMLHttpRequest
\t\t\treturn {
\t\t\t\tsend: function( headers, complete ) {
\t\t\t\t\tvar i,
\t\t\t\t\t\tdataType = options.responseType || \"blob\",
\t\t\t\t\t\txhr = options.xhr();

\t\t\t\t\txhr.open(
\t\t\t\t\t\toptions.type,
\t\t\t\t\t\toptions.url,
\t\t\t\t\t\toptions.async,
\t\t\t\t\t\toptions.username,
\t\t\t\t\t\toptions.password
\t\t\t\t\t);

\t\t\t\t\t// Apply custom fields if provided
\t\t\t\t\tif ( options.xhrFields ) {
\t\t\t\t\t\tfor ( i in options.xhrFields ) {
\t\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\t// Override mime type if needed
\t\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {
\t\t\t\t\t\txhr.overrideMimeType( options.mimeType );
\t\t\t\t\t}

\t\t\t\t\t// X-Requested-With header
\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are
\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.
\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)
\t\t\t\t\t// For same-domain requests, won't change header if already provided.
\t\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {
\t\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";
\t\t\t\t\t}

\t\t\t\t\t// Set headers
\t\t\t\t\tfor ( i in headers ) {
\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );
\t\t\t\t\t}

\t\t\t\t\t// Callback
\t\t\t\t\tcallback = function( type ) {
\t\t\t\t\t\treturn function() {
\t\t\t\t\t\t\tif ( callback ) {
\t\t\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = null;

\t\t\t\t\t\t\t\tif ( type === \"abort\" ) {
\t\t\t\t\t\t\t\t\txhr.abort();
\t\t\t\t\t\t\t\t} else if ( type === \"error\" ) {
\t\t\t\t\t\t\t\t\tcomplete(
\t\t\t\t\t\t\t\t\t\txhr.status,
\t\t\t\t\t\t\t\t\t\txhr.statusText
\t\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tvar data = {};
\t\t\t\t\t\t\t\t\tdata[options.dataType] = xhr.response;
\t\t\t\t\t\t\t\t\tcomplete(
\t\t\t\t\t\t\t\t\t\txhr.status,
\t\t\t\t\t\t\t\t\t\txhr.statusText,
\t\t\t\t\t\t\t\t\t\tdata,
\t\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()
\t\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t};

\t\t\t\t\t// Listen to events
\t\t\t\t\txhr.onload = callback();
\t\t\t\t\txhr.onabort = xhr.onerror = xhr.ontimeout = callback( \"error\" );

\t\t\t\t\t// Create the abort callback
\t\t\t\t\tcallback = callback( \"abort\" );

\t\t\t\t\ttry {
\t\t\t\t\t\txhr.responseType = dataType;
\t\t\t\t\t\t// Do send the request (this may raise an exception)
\t\t\t\t\t\txhr.send( options.data || null );
\t\t\t\t\t} catch ( e ) {
\t\t\t\t\t\tif ( callback ) {
\t\t\t\t\t\t\tthrow e;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},

\t\t\t\tabort: function() {
\t\t\t\t\tif ( callback ) {
\t\t\t\t\t\tcallback();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t};
\t\t}
\t});
})(window.jQuery);

/*!
 * jQuery UI Touch Punch 0.2.3
 *
 * Copyright 2011–2014, Dave Furfero
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * Depends:
 *\tjquery.ui.widget.js
 *\tjquery.ui.mouse.js
 */
(function (\$) {

  // Detect touch support
  \$.support.touch = 'ontouchend' in document;

  // Ignore browsers without touch support
  if (!\$.support.touch) {
\treturn;
  }

  var mouseProto = \$.ui.mouse.prototype,
\t  _mouseInit = mouseProto._mouseInit,
\t  _mouseDestroy = mouseProto._mouseDestroy,
\t  touchHandled,
\t  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) {

\t// Ignore multi-touch events
\tif (event.originalEvent.touches.length > 1) {
\t  return;
\t}

\tif (! \$(event.currentTarget).hasClass('touch-punch-keep-default')) {
\t\tevent.preventDefault();
\t}

\tvar touch = event.originalEvent.changedTouches[0],
\t\tsimulatedEvent = document.createEvent('MouseEvents');
\t
\t// Initialize the simulated mouse event using the touch event's coordinates
\tsimulatedEvent.initMouseEvent(
\t  simulatedType,\t// type
\t  true,\t\t\t\t// bubbles\t\t\t\t\t  
\t  true,\t\t\t\t// cancelable\t\t\t\t  
\t  window,\t\t\t// view\t\t\t\t\t\t  
\t  1,\t\t\t\t// detail\t\t\t\t\t  
\t  touch.screenX,\t// screenX\t\t\t\t\t  
\t  touch.screenY,\t// screenY\t\t\t\t\t  
\t  touch.clientX,\t// clientX\t\t\t\t\t  
\t  touch.clientY,\t// clientY\t\t\t\t\t  
\t  false,\t\t\t// ctrlKey\t\t\t\t\t  
\t  false,\t\t\t// altKey\t\t\t\t\t  
\t  false,\t\t\t// shiftKey\t\t\t\t\t  
\t  false,\t\t\t// metaKey\t\t\t\t\t  
\t  0,\t\t\t\t// button\t\t\t\t\t  
\t  null\t\t\t\t// relatedTarget\t\t\t  
\t);

\t// Dispatch the simulated event to the target element
\tevent.target.dispatchEvent(simulatedEvent);
  }

  /**
   * Handle the jQuery UI widget's touchstart events
   * @param {Object} event The widget element's touchstart event
   */
  mouseProto._touchStart = function (event) {

\tvar self = this;

\t// Ignore the event if another widget is already being handled
\tif (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
\t  return;
\t}

\t// Track element position to avoid \"false\" move
\tposX = event.originalEvent.changedTouches[0].screenX.toFixed(0);
\tposY = event.originalEvent.changedTouches[0].screenY.toFixed(0);

\t// Set the flag to prevent other widgets from inheriting the touch event
\ttouchHandled = true;

\t// Track movement to determine if interaction was a click
\tself._touchMoved = false;

\t// Simulate the mouseover event
\tsimulateMouseEvent(event, 'mouseover');

\t// Simulate the mousemove event
\tsimulateMouseEvent(event, 'mousemove');

\t// Simulate the mousedown event
\tsimulateMouseEvent(event, 'mousedown');
  };

  /**
   * Handle the jQuery UI widget's touchmove events
   * @param {Object} event The document's touchmove event
   */
  mouseProto._touchMove = function (event) {

\t// Ignore event if not handled
\tif (!touchHandled) {
\t  return;
\t}

\t// Ignore if it's a \"false\" move (position not changed)
\tvar x = event.originalEvent.changedTouches[0].screenX.toFixed(0);
\tvar y = event.originalEvent.changedTouches[0].screenY.toFixed(0);
\t// Ignore if it's a \"false\" move (position not changed)
\tif (Math.abs(posX - x) <= 4 && Math.abs(posY - y) <= 4) {
\t\treturn;
\t}

\t// Interaction was not a click
\tthis._touchMoved = true;

\t// Simulate the mousemove event
\tsimulateMouseEvent(event, 'mousemove');
  };

  /**
   * Handle the jQuery UI widget's touchend events
   * @param {Object} event The document's touchend event
   */
  mouseProto._touchEnd = function (event) {

\t// Ignore event if not handled
\tif (!touchHandled) {
\t  return;
\t}

\t// Simulate the mouseup event
\tsimulateMouseEvent(event, 'mouseup');

\t// Simulate the mouseout event
\tsimulateMouseEvent(event, 'mouseout');

\t// If the touch interaction did not move, it should trigger a click
\tif (!this._touchMoved) {

\t  // Simulate the click event
\t  simulateMouseEvent(event, 'click');
\t}

\t// Unset the flag to allow other widgets to inherit the touch event
\ttouchHandled = false;
\tthis._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 () {
\t
\tvar self = this;

\tif (self.element.hasClass('touch-punch')) {
\t\t// Delegate the touch handlers to the widget's element
\t\tself.element.on({
\t\t  touchstart: \$.proxy(self, '_touchStart'),
\t\t  touchmove: \$.proxy(self, '_touchMove'),
\t\t  touchend: \$.proxy(self, '_touchEnd')
\t\t});
\t}

\t// Call the original \$.ui.mouse init method
\t_mouseInit.call(self);
  };

  /**
   * Remove the touch event handlers
   */
  mouseProto._mouseDestroy = function () {
\t
\tvar self = this;

\tif (self.element.hasClass('touch-punch')) {
\t\t// Delegate the touch handlers to the widget's element
\t\tself.element.off({
\t\t  touchstart: \$.proxy(self, '_touchStart'),
\t\t  touchmove: \$.proxy(self, '_touchMove'),
\t\t  touchend: \$.proxy(self, '_touchEnd')
\t\t});
\t}

\t// Call the original \$.ui.mouse destroy method
\t_mouseDestroy.call(self);
  };

})(jQuery);

\$.fn.elfinder = function(o, o2) {
\t
\tif (o === 'instance') {
\t\treturn this.getElFinder();
\t} else if (o === 'ondemand') {

\t}
\t
\treturn this.each(function() {
\t\t
\t\tvar cmd          = typeof o  === 'string'  ? o  : '',
\t\t\tbootCallback = typeof o2 === 'function'? o2 : void(0),
\t\t\telfinder     = this.elfinder,
\t\t\topts, reloadCallback;
\t\t
\t\tif (!elfinder) {
\t\t\tif (\$.isPlainObject(o)) {
\t\t\t\tnew elFinder(this, o, bootCallback);
\t\t\t}
\t\t} else {
\t\t\tswitch(cmd) {
\t\t\t\tcase 'close':
\t\t\t\tcase 'hide':
\t\t\t\t\telfinder.hide();
\t\t\t\t\tbreak;
\t\t\t\t\t
\t\t\t\tcase 'open':
\t\t\t\tcase 'show':
\t\t\t\t\telfinder.show();
\t\t\t\t\tbreak;
\t\t\t\t\t
\t\t\t\tcase 'destroy':
\t\t\t\t\telfinder.destroy();
\t\t\t\t\tbreak;
\t\t\t\t
\t\t\t\tcase 'reload':
\t\t\t\tcase 'restart':
\t\t\t\t\tif (elfinder) {
\t\t\t\t\t\topts = \$.extend(true, elfinder.options, \$.isPlainObject(o2)? o2 : {});
\t\t\t\t\t\tbootCallback = elfinder.bootCallback;
\t\t\t\t\t\tif (elfinder.reloadCallback && \$.isFunction(elfinder.reloadCallback)) {
\t\t\t\t\t\t\telfinder.reloadCallback(opts, bootCallback);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\telfinder.destroy();
\t\t\t\t\t\t\tnew elFinder(this, opts, bootCallback);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tbreak;
\t\t\t}
\t\t}
\t});
};

\$.fn.getElFinder = function() {
\tvar instance;
\t
\tthis.each(function() {
\t\tif (this.elfinder) {
\t\t\tinstance = this.elfinder;
\t\t\treturn false;
\t\t}
\t});
\t
\treturn instance;
};

\$.fn.elfUiWidgetInstance = function(name) {
\ttry {
\t\treturn this[name]('instance');
\t} catch(e) {
\t\t// fallback for jQuery UI < 1.11
\t\tvar data = this.data('ui-' + name);
\t\tif (data && typeof data === 'object' && data.widgetFullName === 'ui-' + name) {
\t\t\treturn data;
\t\t}
\t\treturn null;
\t}
};

// function scrollRight
if (! \$.fn.scrollRight) {
\t\$.fn.extend({
\t\tscrollRight: function (val) {
\t\t\tvar node = this.get(0);
\t\t\tif (val === undefined) {
\t\t\t\treturn Math.max(0, node.scrollWidth - (node.scrollLeft + node.clientWidth));
\t\t\t}
\t\t\treturn this.scrollLeft(node.scrollWidth - node.clientWidth - val);
\t\t}
\t});
}

// function scrollBottom
if (! \$.fn.scrollBottom) {
\t\$.fn.extend({
\t\tscrollBottom: function(val) { 
\t\t\tvar node = this.get(0);
\t\t\tif (val === undefined) {
\t\t\t\treturn Math.max(0, node.scrollHeight - (node.scrollTop + node.clientHeight));
\t\t\t}
\t\t\treturn this.scrollTop(node.scrollHeight - node.clientHeight - val);
\t\t}
\t});
}


/*
 * File: /js/elFinder.mimetypes.js
 */

elFinder.prototype.mimeTypes = {\"application\\/x-executable\":\"exe\",\"application\\/x-jar\":\"jar\",\"application\\/x-gzip\":\"gz\",\"application\\/x-bzip2\":\"tbz\",\"application\\/x-rar\":\"rar\",\"text\\/x-php\":\"php\",\"text\\/javascript\":\"js\",\"application\\/rtfd\":\"rtfd\",\"text\\/x-python\":\"py\",\"text\\/x-ruby\":\"rb\",\"text\\/x-shellscript\":\"sh\",\"text\\/x-perl\":\"pl\",\"text\\/xml\":\"xml\",\"text\\/x-csrc\":\"c\",\"text\\/x-chdr\":\"h\",\"text\\/x-c++src\":\"cpp\",\"text\\/x-c++hdr\":\"hh\",\"text\\/x-markdown\":\"md\",\"text\\/x-yaml\":\"yml\",\"image\\/x-ms-bmp\":\"bmp\",\"image\\/x-targa\":\"tga\",\"image\\/xbm\":\"xbm\",\"image\\/pxm\":\"pxm\",\"audio\\/wav\":\"wav\",\"video\\/x-dv\":\"dv\",\"video\\/x-ms-wmv\":\"wm\",\"video\\/ogg\":\"ogm\",\"video\\/MP2T\":\"m2ts\",\"application\\/x-mpegURL\":\"m3u8\",\"application\\/dash+xml\":\"mpd\",\"application\\/andrew-inset\":\"ez\",\"application\\/applixware\":\"aw\",\"application\\/atom+xml\":\"atom\",\"application\\/atomcat+xml\":\"atomcat\",\"application\\/atomsvc+xml\":\"atomsvc\",\"application\\/ccxml+xml\":\"ccxml\",\"application\\/cdmi-capability\":\"cdmia\",\"application\\/cdmi-container\":\"cdmic\",\"application\\/cdmi-domain\":\"cdmid\",\"application\\/cdmi-object\":\"cdmio\",\"application\\/cdmi-queue\":\"cdmiq\",\"application\\/cu-seeme\":\"cu\",\"application\\/davmount+xml\":\"davmount\",\"application\\/docbook+xml\":\"dbk\",\"application\\/dssc+der\":\"dssc\",\"application\\/dssc+xml\":\"xdssc\",\"application\\/ecmascript\":\"ecma\",\"application\\/emma+xml\":\"emma\",\"application\\/epub+zip\":\"epub\",\"application\\/exi\":\"exi\",\"application\\/font-tdpfr\":\"pfr\",\"application\\/gml+xml\":\"gml\",\"application\\/gpx+xml\":\"gpx\",\"application\\/gxf\":\"gxf\",\"application\\/hyperstudio\":\"stk\",\"application\\/inkml+xml\":\"ink\",\"application\\/ipfix\":\"ipfix\",\"application\\/java-serialized-object\":\"ser\",\"application\\/java-vm\":\"class\",\"application\\/json\":\"json\",\"application\\/jsonml+json\":\"jsonml\",\"application\\/lost+xml\":\"lostxml\",\"application\\/mac-binhex40\":\"hqx\",\"application\\/mac-compactpro\":\"cpt\",\"application\\/mads+xml\":\"mads\",\"application\\/marc\":\"mrc\",\"application\\/marcxml+xml\":\"mrcx\",\"application\\/mathematica\":\"ma\",\"application\\/mathml+xml\":\"mathml\",\"application\\/mbox\":\"mbox\",\"application\\/mediaservercontrol+xml\":\"mscml\",\"application\\/metalink+xml\":\"metalink\",\"application\\/metalink4+xml\":\"meta4\",\"application\\/mets+xml\":\"mets\",\"application\\/mods+xml\":\"mods\",\"application\\/mp21\":\"m21\",\"application\\/mp4\":\"mp4s\",\"application\\/msword\":\"doc\",\"application\\/mxf\":\"mxf\",\"application\\/octet-stream\":\"bin\",\"application\\/oda\":\"oda\",\"application\\/oebps-package+xml\":\"opf\",\"application\\/ogg\":\"ogx\",\"application\\/omdoc+xml\":\"omdoc\",\"application\\/onenote\":\"onetoc\",\"application\\/oxps\":\"oxps\",\"application\\/patch-ops-error+xml\":\"xer\",\"application\\/pdf\":\"pdf\",\"application\\/pgp-encrypted\":\"pgp\",\"application\\/pgp-signature\":\"asc\",\"application\\/pics-rules\":\"prf\",\"application\\/pkcs10\":\"p10\",\"application\\/pkcs7-mime\":\"p7m\",\"application\\/pkcs7-signature\":\"p7s\",\"application\\/pkcs8\":\"p8\",\"application\\/pkix-attr-cert\":\"ac\",\"application\\/pkix-cert\":\"cer\",\"application\\/pkix-crl\":\"crl\",\"application\\/pkix-pkipath\":\"pkipath\",\"application\\/pkixcmp\":\"pki\",\"application\\/pls+xml\":\"pls\",\"application\\/postscript\":\"ai\",\"application\\/prs.cww\":\"cww\",\"application\\/pskc+xml\":\"pskcxml\",\"application\\/rdf+xml\":\"rdf\",\"application\\/reginfo+xml\":\"rif\",\"application\\/relax-ng-compact-syntax\":\"rnc\",\"application\\/resource-lists+xml\":\"rl\",\"application\\/resource-lists-diff+xml\":\"rld\",\"application\\/rls-services+xml\":\"rs\",\"application\\/rpki-ghostbusters\":\"gbr\",\"application\\/rpki-manifest\":\"mft\",\"application\\/rpki-roa\":\"roa\",\"application\\/rsd+xml\":\"rsd\",\"application\\/rss+xml\":\"rss\",\"application\\/rtf\":\"rtf\",\"application\\/sbml+xml\":\"sbml\",\"application\\/scvp-cv-request\":\"scq\",\"application\\/scvp-cv-response\":\"scs\",\"application\\/scvp-vp-request\":\"spq\",\"application\\/scvp-vp-response\":\"spp\",\"application\\/sdp\":\"sdp\",\"application\\/set-payment-initiation\":\"setpay\",\"application\\/set-registration-initiation\":\"setreg\",\"application\\/shf+xml\":\"shf\",\"application\\/smil+xml\":\"smi\",\"application\\/sparql-query\":\"rq\",\"application\\/sparql-results+xml\":\"srx\",\"application\\/srgs\":\"gram\",\"application\\/srgs+xml\":\"grxml\",\"application\\/sru+xml\":\"sru\",\"application\\/ssdl+xml\":\"ssdl\",\"application\\/ssml+xml\":\"ssml\",\"application\\/tei+xml\":\"tei\",\"application\\/thraud+xml\":\"tfi\",\"application\\/timestamped-data\":\"tsd\",\"application\\/vnd.3gpp.pic-bw-large\":\"plb\",\"application\\/vnd.3gpp.pic-bw-small\":\"psb\",\"application\\/vnd.3gpp.pic-bw-var\":\"pvb\",\"application\\/vnd.3gpp2.tcap\":\"tcap\",\"application\\/vnd.3m.post-it-notes\":\"pwn\",\"application\\/vnd.accpac.simply.aso\":\"aso\",\"application\\/vnd.accpac.simply.imp\":\"imp\",\"application\\/vnd.acucobol\":\"acu\",\"application\\/vnd.acucorp\":\"atc\",\"application\\/vnd.adobe.air-application-installer-package+zip\":\"air\",\"application\\/vnd.adobe.formscentral.fcdt\":\"fcdt\",\"application\\/vnd.adobe.fxp\":\"fxp\",\"application\\/vnd.adobe.xdp+xml\":\"xdp\",\"application\\/vnd.adobe.xfdf\":\"xfdf\",\"application\\/vnd.ahead.space\":\"ahead\",\"application\\/vnd.airzip.filesecure.azf\":\"azf\",\"application\\/vnd.airzip.filesecure.azs\":\"azs\",\"application\\/vnd.amazon.ebook\":\"azw\",\"application\\/vnd.americandynamics.acc\":\"acc\",\"application\\/vnd.amiga.ami\":\"ami\",\"application\\/vnd.android.package-archive\":\"apk\",\"application\\/vnd.anser-web-certificate-issue-initiation\":\"cii\",\"application\\/vnd.anser-web-funds-transfer-initiation\":\"fti\",\"application\\/vnd.antix.game-component\":\"atx\",\"application\\/vnd.apple.installer+xml\":\"mpkg\",\"application\\/vnd.aristanetworks.swi\":\"swi\",\"application\\/vnd.astraea-software.iota\":\"iota\",\"application\\/vnd.audiograph\":\"aep\",\"application\\/vnd.blueice.multipass\":\"mpm\",\"application\\/vnd.bmi\":\"bmi\",\"application\\/vnd.businessobjects\":\"rep\",\"application\\/vnd.chemdraw+xml\":\"cdxml\",\"application\\/vnd.chipnuts.karaoke-mmd\":\"mmd\",\"application\\/vnd.cinderella\":\"cdy\",\"application\\/vnd.claymore\":\"cla\",\"application\\/vnd.cloanto.rp9\":\"rp9\",\"application\\/vnd.clonk.c4group\":\"c4g\",\"application\\/vnd.cluetrust.cartomobile-config\":\"c11amc\",\"application\\/vnd.cluetrust.cartomobile-config-pkg\":\"c11amz\",\"application\\/vnd.commonspace\":\"csp\",\"application\\/vnd.contact.cmsg\":\"cdbcmsg\",\"application\\/vnd.cosmocaller\":\"cmc\",\"application\\/vnd.crick.clicker\":\"clkx\",\"application\\/vnd.crick.clicker.keyboard\":\"clkk\",\"application\\/vnd.crick.clicker.palette\":\"clkp\",\"application\\/vnd.crick.clicker.template\":\"clkt\",\"application\\/vnd.crick.clicker.wordbank\":\"clkw\",\"application\\/vnd.criticaltools.wbs+xml\":\"wbs\",\"application\\/vnd.ctc-posml\":\"pml\",\"application\\/vnd.cups-ppd\":\"ppd\",\"application\\/vnd.curl.car\":\"car\",\"application\\/vnd.curl.pcurl\":\"pcurl\",\"application\\/vnd.dart\":\"dart\",\"application\\/vnd.data-vision.rdz\":\"rdz\",\"application\\/vnd.dece.data\":\"uvf\",\"application\\/vnd.dece.ttml+xml\":\"uvt\",\"application\\/vnd.dece.unspecified\":\"uvx\",\"application\\/vnd.dece.zip\":\"uvz\",\"application\\/vnd.denovo.fcselayout-link\":\"fe_launch\",\"application\\/vnd.dna\":\"dna\",\"application\\/vnd.dolby.mlp\":\"mlp\",\"application\\/vnd.dpgraph\":\"dpg\",\"application\\/vnd.dreamfactory\":\"dfac\",\"application\\/vnd.ds-keypoint\":\"kpxx\",\"application\\/vnd.dvb.ait\":\"ait\",\"application\\/vnd.dvb.service\":\"svc\",\"application\\/vnd.dynageo\":\"geo\",\"application\\/vnd.ecowin.chart\":\"mag\",\"application\\/vnd.enliven\":\"nml\",\"application\\/vnd.epson.esf\":\"esf\",\"application\\/vnd.epson.msf\":\"msf\",\"application\\/vnd.epson.quickanime\":\"qam\",\"application\\/vnd.epson.salt\":\"slt\",\"application\\/vnd.epson.ssf\":\"ssf\",\"application\\/vnd.eszigno3+xml\":\"es3\",\"application\\/vnd.ezpix-album\":\"ez2\",\"application\\/vnd.ezpix-package\":\"ez3\",\"application\\/vnd.fdf\":\"fdf\",\"application\\/vnd.fdsn.mseed\":\"mseed\",\"application\\/vnd.fdsn.seed\":\"seed\",\"application\\/vnd.flographit\":\"gph\",\"application\\/vnd.fluxtime.clip\":\"ftc\",\"application\\/vnd.framemaker\":\"fm\",\"application\\/vnd.frogans.fnc\":\"fnc\",\"application\\/vnd.frogans.ltf\":\"ltf\",\"application\\/vnd.fsc.weblaunch\":\"fsc\",\"application\\/vnd.fujitsu.oasys\":\"oas\",\"application\\/vnd.fujitsu.oasys2\":\"oa2\",\"application\\/vnd.fujitsu.oasys3\":\"oa3\",\"application\\/vnd.fujitsu.oasysgp\":\"fg5\",\"application\\/vnd.fujitsu.oasysprs\":\"bh2\",\"application\\/vnd.fujixerox.ddd\":\"ddd\",\"application\\/vnd.fujixerox.docuworks\":\"xdw\",\"application\\/vnd.fujixerox.docuworks.binder\":\"xbd\",\"application\\/vnd.fuzzysheet\":\"fzs\",\"application\\/vnd.genomatix.tuxedo\":\"txd\",\"application\\/vnd.geogebra.file\":\"ggb\",\"application\\/vnd.geogebra.tool\":\"ggt\",\"application\\/vnd.geometry-explorer\":\"gex\",\"application\\/vnd.geonext\":\"gxt\",\"application\\/vnd.geoplan\":\"g2w\",\"application\\/vnd.geospace\":\"g3w\",\"application\\/vnd.gmx\":\"gmx\",\"application\\/vnd.google-earth.kml+xml\":\"kml\",\"application\\/vnd.google-earth.kmz\":\"kmz\",\"application\\/vnd.grafeq\":\"gqf\",\"application\\/vnd.groove-account\":\"gac\",\"application\\/vnd.groove-help\":\"ghf\",\"application\\/vnd.groove-identity-message\":\"gim\",\"application\\/vnd.groove-injector\":\"grv\",\"application\\/vnd.groove-tool-message\":\"gtm\",\"application\\/vnd.groove-tool-template\":\"tpl\",\"application\\/vnd.groove-vcard\":\"vcg\",\"application\\/vnd.hal+xml\":\"hal\",\"application\\/vnd.handheld-entertainment+xml\":\"zmm\",\"application\\/vnd.hbci\":\"hbci\",\"application\\/vnd.hhe.lesson-player\":\"les\",\"application\\/vnd.hp-hpgl\":\"hpgl\",\"application\\/vnd.hp-hpid\":\"hpid\",\"application\\/vnd.hp-hps\":\"hps\",\"application\\/vnd.hp-jlyt\":\"jlt\",\"application\\/vnd.hp-pcl\":\"pcl\",\"application\\/vnd.hp-pclxl\":\"pclxl\",\"application\\/vnd.hydrostatix.sof-data\":\"sfd-hdstx\",\"application\\/vnd.ibm.minipay\":\"mpy\",\"application\\/vnd.ibm.modcap\":\"afp\",\"application\\/vnd.ibm.rights-management\":\"irm\",\"application\\/vnd.ibm.secure-container\":\"sc\",\"application\\/vnd.iccprofile\":\"icc\",\"application\\/vnd.igloader\":\"igl\",\"application\\/vnd.immervision-ivp\":\"ivp\",\"application\\/vnd.immervision-ivu\":\"ivu\",\"application\\/vnd.insors.igm\":\"igm\",\"application\\/vnd.intercon.formnet\":\"xpw\",\"application\\/vnd.intergeo\":\"i2g\",\"application\\/vnd.intu.qbo\":\"qbo\",\"application\\/vnd.intu.qfx\":\"qfx\",\"application\\/vnd.ipunplugged.rcprofile\":\"rcprofile\",\"application\\/vnd.irepository.package+xml\":\"irp\",\"application\\/vnd.is-xpr\":\"xpr\",\"application\\/vnd.isac.fcs\":\"fcs\",\"application\\/vnd.jam\":\"jam\",\"application\\/vnd.jcp.javame.midlet-rms\":\"rms\",\"application\\/vnd.jisp\":\"jisp\",\"application\\/vnd.joost.joda-archive\":\"joda\",\"application\\/vnd.kahootz\":\"ktz\",\"application\\/vnd.kde.karbon\":\"karbon\",\"application\\/vnd.kde.kchart\":\"chrt\",\"application\\/vnd.kde.kformula\":\"kfo\",\"application\\/vnd.kde.kivio\":\"flw\",\"application\\/vnd.kde.kontour\":\"kon\",\"application\\/vnd.kde.kpresenter\":\"kpr\",\"application\\/vnd.kde.kspread\":\"ksp\",\"application\\/vnd.kde.kword\":\"kwd\",\"application\\/vnd.kenameaapp\":\"htke\",\"application\\/vnd.kidspiration\":\"kia\",\"application\\/vnd.kinar\":\"kne\",\"application\\/vnd.koan\":\"skp\",\"application\\/vnd.kodak-descriptor\":\"sse\",\"application\\/vnd.las.las+xml\":\"lasxml\",\"application\\/vnd.llamagraphics.life-balance.desktop\":\"lbd\",\"application\\/vnd.llamagraphics.life-balance.exchange+xml\":\"lbe\",\"application\\/vnd.lotus-1-2-3\":123,\"application\\/vnd.lotus-approach\":\"apr\",\"application\\/vnd.lotus-freelance\":\"pre\",\"application\\/vnd.lotus-notes\":\"nsf\",\"application\\/vnd.lotus-organizer\":\"org\",\"application\\/vnd.lotus-screencam\":\"scm\",\"application\\/vnd.lotus-wordpro\":\"lwp\",\"application\\/vnd.macports.portpkg\":\"portpkg\",\"application\\/vnd.mcd\":\"mcd\",\"application\\/vnd.medcalcdata\":\"mc1\",\"application\\/vnd.mediastation.cdkey\":\"cdkey\",\"application\\/vnd.mfer\":\"mwf\",\"application\\/vnd.mfmp\":\"mfm\",\"application\\/vnd.micrografx.flo\":\"flo\",\"application\\/vnd.micrografx.igx\":\"igx\",\"application\\/vnd.mif\":\"mif\",\"application\\/vnd.mobius.daf\":\"daf\",\"application\\/vnd.mobius.dis\":\"dis\",\"application\\/vnd.mobius.mbk\":\"mbk\",\"application\\/vnd.mobius.mqy\":\"mqy\",\"application\\/vnd.mobius.msl\":\"msl\",\"application\\/vnd.mobius.plc\":\"plc\",\"application\\/vnd.mobius.txf\":\"txf\",\"application\\/vnd.mophun.application\":\"mpn\",\"application\\/vnd.mophun.certificate\":\"mpc\",\"application\\/vnd.mozilla.xul+xml\":\"xul\",\"application\\/vnd.ms-artgalry\":\"cil\",\"application\\/vnd.ms-cab-compressed\":\"cab\",\"application\\/vnd.ms-excel\":\"xls\",\"application\\/vnd.ms-excel.addin.macroenabled.12\":\"xlam\",\"application\\/vnd.ms-excel.sheet.binary.macroenabled.12\":\"xlsb\",\"application\\/vnd.ms-excel.sheet.macroenabled.12\":\"xlsm\",\"application\\/vnd.ms-excel.template.macroenabled.12\":\"xltm\",\"application\\/vnd.ms-fontobject\":\"eot\",\"application\\/vnd.ms-htmlhelp\":\"chm\",\"application\\/vnd.ms-ims\":\"ims\",\"application\\/vnd.ms-lrm\":\"lrm\",\"application\\/vnd.ms-officetheme\":\"thmx\",\"application\\/vnd.ms-pki.seccat\":\"cat\",\"application\\/vnd.ms-pki.stl\":\"stl\",\"application\\/vnd.ms-powerpoint\":\"ppt\",\"application\\/vnd.ms-powerpoint.addin.macroenabled.12\":\"ppam\",\"application\\/vnd.ms-powerpoint.presentation.macroenabled.12\":\"pptm\",\"application\\/vnd.ms-powerpoint.slide.macroenabled.12\":\"sldm\",\"application\\/vnd.ms-powerpoint.slideshow.macroenabled.12\":\"ppsm\",\"application\\/vnd.ms-powerpoint.template.macroenabled.12\":\"potm\",\"application\\/vnd.ms-project\":\"mpp\",\"application\\/vnd.ms-word.document.macroenabled.12\":\"docm\",\"application\\/vnd.ms-word.template.macroenabled.12\":\"dotm\",\"application\\/vnd.ms-works\":\"wps\",\"application\\/vnd.ms-wpl\":\"wpl\",\"application\\/vnd.ms-xpsdocument\":\"xps\",\"application\\/vnd.mseq\":\"mseq\",\"application\\/vnd.musician\":\"mus\",\"application\\/vnd.muvee.style\":\"msty\",\"application\\/vnd.mynfc\":\"taglet\",\"application\\/vnd.neurolanguage.nlu\":\"nlu\",\"application\\/vnd.nitf\":\"ntf\",\"application\\/vnd.noblenet-directory\":\"nnd\",\"application\\/vnd.noblenet-sealer\":\"nns\",\"application\\/vnd.noblenet-web\":\"nnw\",\"application\\/vnd.nokia.n-gage.data\":\"ngdat\",\"application\\/vnd.nokia.n-gage.symbian.install\":\"n-gage\",\"application\\/vnd.nokia.radio-preset\":\"rpst\",\"application\\/vnd.nokia.radio-presets\":\"rpss\",\"application\\/vnd.novadigm.edm\":\"edm\",\"application\\/vnd.novadigm.edx\":\"edx\",\"application\\/vnd.novadigm.ext\":\"ext\",\"application\\/vnd.oasis.opendocument.chart\":\"odc\",\"application\\/vnd.oasis.opendocument.chart-template\":\"otc\",\"application\\/vnd.oasis.opendocument.database\":\"odb\",\"application\\/vnd.oasis.opendocument.formula\":\"odf\",\"application\\/vnd.oasis.opendocument.formula-template\":\"odft\",\"application\\/vnd.oasis.opendocument.graphics\":\"odg\",\"application\\/vnd.oasis.opendocument.graphics-template\":\"otg\",\"application\\/vnd.oasis.opendocument.image\":\"odi\",\"application\\/vnd.oasis.opendocument.image-template\":\"oti\",\"application\\/vnd.oasis.opendocument.presentation\":\"odp\",\"application\\/vnd.oasis.opendocument.presentation-template\":\"otp\",\"application\\/vnd.oasis.opendocument.spreadsheet\":\"ods\",\"application\\/vnd.oasis.opendocument.spreadsheet-template\":\"ots\",\"application\\/vnd.oasis.opendocument.text\":\"odt\",\"application\\/vnd.oasis.opendocument.text-master\":\"odm\",\"application\\/vnd.oasis.opendocument.text-template\":\"ott\",\"application\\/vnd.oasis.opendocument.text-web\":\"oth\",\"application\\/vnd.olpc-sugar\":\"xo\",\"application\\/vnd.oma.dd2+xml\":\"dd2\",\"application\\/vnd.openofficeorg.extension\":\"oxt\",\"application\\/vnd.openxmlformats-officedocument.presentationml.presentation\":\"pptx\",\"application\\/vnd.openxmlformats-officedocument.presentationml.slide\":\"sldx\",\"application\\/vnd.openxmlformats-officedocument.presentationml.slideshow\":\"ppsx\",\"application\\/vnd.openxmlformats-officedocument.presentationml.template\":\"potx\",\"application\\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\":\"xlsx\",\"application\\/vnd.openxmlformats-officedocument.spreadsheetml.template\":\"xltx\",\"application\\/vnd.openxmlformats-officedocument.wordprocessingml.document\":\"docx\",\"application\\/vnd.openxmlformats-officedocument.wordprocessingml.template\":\"dotx\",\"application\\/vnd.osgeo.mapguide.package\":\"mgp\",\"application\\/vnd.osgi.dp\":\"dp\",\"application\\/vnd.osgi.subsystem\":\"esa\",\"application\\/vnd.palm\":\"pdb\",\"application\\/vnd.pawaafile\":\"paw\",\"application\\/vnd.pg.format\":\"str\",\"application\\/vnd.pg.osasli\":\"ei6\",\"application\\/vnd.picsel\":\"efif\",\"application\\/vnd.pmi.widget\":\"wg\",\"application\\/vnd.pocketlearn\":\"plf\",\"application\\/vnd.powerbuilder6\":\"pbd\",\"application\\/vnd.previewsystems.box\":\"box\",\"application\\/vnd.proteus.magazine\":\"mgz\",\"application\\/vnd.publishare-delta-tree\":\"qps\",\"application\\/vnd.pvi.ptid1\":\"ptid\",\"application\\/vnd.quark.quarkxpress\":\"qxd\",\"application\\/vnd.realvnc.bed\":\"bed\",\"application\\/vnd.recordare.musicxml\":\"mxl\",\"application\\/vnd.recordare.musicxml+xml\":\"musicxml\",\"application\\/vnd.rig.cryptonote\":\"cryptonote\",\"application\\/vnd.rim.cod\":\"cod\",\"application\\/vnd.rn-realmedia\":\"rm\",\"application\\/vnd.rn-realmedia-vbr\":\"rmvb\",\"application\\/vnd.route66.link66+xml\":\"link66\",\"application\\/vnd.sailingtracker.track\":\"st\",\"application\\/vnd.seemail\":\"see\",\"application\\/vnd.sema\":\"sema\",\"application\\/vnd.semd\":\"semd\",\"application\\/vnd.semf\":\"semf\",\"application\\/vnd.shana.informed.formdata\":\"ifm\",\"application\\/vnd.shana.informed.formtemplate\":\"itp\",\"application\\/vnd.shana.informed.interchange\":\"iif\",\"application\\/vnd.shana.informed.package\":\"ipk\",\"application\\/vnd.simtech-mindmapper\":\"twd\",\"application\\/vnd.smaf\":\"mmf\",\"application\\/vnd.smart.teacher\":\"teacher\",\"application\\/vnd.solent.sdkm+xml\":\"sdkm\",\"application\\/vnd.spotfire.dxp\":\"dxp\",\"application\\/vnd.spotfire.sfs\":\"sfs\",\"application\\/vnd.stardivision.calc\":\"sdc\",\"application\\/vnd.stardivision.draw\":\"sda\",\"application\\/vnd.stardivision.impress\":\"sdd\",\"application\\/vnd.stardivision.math\":\"smf\",\"application\\/vnd.stardivision.writer\":\"sdw\",\"application\\/vnd.stardivision.writer-global\":\"sgl\",\"application\\/vnd.stepmania.package\":\"smzip\",\"application\\/vnd.stepmania.stepchart\":\"sm\",\"application\\/vnd.sun.xml.calc\":\"sxc\",\"application\\/vnd.sun.xml.calc.template\":\"stc\",\"application\\/vnd.sun.xml.draw\":\"sxd\",\"application\\/vnd.sun.xml.draw.template\":\"std\",\"application\\/vnd.sun.xml.impress\":\"sxi\",\"application\\/vnd.sun.xml.impress.template\":\"sti\",\"application\\/vnd.sun.xml.math\":\"sxm\",\"application\\/vnd.sun.xml.writer\":\"sxw\",\"application\\/vnd.sun.xml.writer.global\":\"sxg\",\"application\\/vnd.sun.xml.writer.template\":\"stw\",\"application\\/vnd.sus-calendar\":\"sus\",\"application\\/vnd.svd\":\"svd\",\"application\\/vnd.symbian.install\":\"sis\",\"application\\/vnd.syncml+xml\":\"xsm\",\"application\\/vnd.syncml.dm+wbxml\":\"bdm\",\"application\\/vnd.syncml.dm+xml\":\"xdm\",\"application\\/vnd.tao.intent-module-archive\":\"tao\",\"application\\/vnd.tcpdump.pcap\":\"pcap\",\"application\\/vnd.tmobile-livetv\":\"tmo\",\"application\\/vnd.trid.tpt\":\"tpt\",\"application\\/vnd.triscape.mxs\":\"mxs\",\"application\\/vnd.trueapp\":\"tra\",\"application\\/vnd.ufdl\":\"ufd\",\"application\\/vnd.uiq.theme\":\"utz\",\"application\\/vnd.umajin\":\"umj\",\"application\\/vnd.unity\":\"unityweb\",\"application\\/vnd.uoml+xml\":\"uoml\",\"application\\/vnd.vcx\":\"vcx\",\"application\\/vnd.visio\":\"vsd\",\"application\\/vnd.visionary\":\"vis\",\"application\\/vnd.vsf\":\"vsf\",\"application\\/vnd.wap.wbxml\":\"wbxml\",\"application\\/vnd.wap.wmlc\":\"wmlc\",\"application\\/vnd.wap.wmlscriptc\":\"wmlsc\",\"application\\/vnd.webturbo\":\"wtb\",\"application\\/vnd.wolfram.player\":\"nbp\",\"application\\/vnd.wordperfect\":\"wpd\",\"application\\/vnd.wqd\":\"wqd\",\"application\\/vnd.wt.stf\":\"stf\",\"application\\/vnd.xara\":\"xar\",\"application\\/vnd.xfdl\":\"xfdl\",\"application\\/vnd.yamaha.hv-dic\":\"hvd\",\"application\\/vnd.yamaha.hv-script\":\"hvs\",\"application\\/vnd.yamaha.hv-voice\":\"hvp\",\"application\\/vnd.yamaha.openscoreformat\":\"osf\",\"application\\/vnd.yamaha.openscoreformat.osfpvg+xml\":\"osfpvg\",\"application\\/vnd.yamaha.smaf-audio\":\"saf\",\"application\\/vnd.yamaha.smaf-phrase\":\"spf\",\"application\\/vnd.yellowriver-custom-menu\":\"cmp\",\"application\\/vnd.zul\":\"zir\",\"application\\/vnd.zzazz.deck+xml\":\"zaz\",\"application\\/voicexml+xml\":\"vxml\",\"application\\/widget\":\"wgt\",\"application\\/winhlp\":\"hlp\",\"application\\/wsdl+xml\":\"wsdl\",\"application\\/wspolicy+xml\":\"wspolicy\",\"application\\/x-7z-compressed\":\"7z\",\"application\\/x-abiword\":\"abw\",\"application\\/x-ace-compressed\":\"ace\",\"application\\/x-apple-diskimage\":\"dmg\",\"application\\/x-authorware-bin\":\"aab\",\"application\\/x-authorware-map\":\"aam\",\"application\\/x-authorware-seg\":\"aas\",\"application\\/x-bcpio\":\"bcpio\",\"application\\/x-bittorrent\":\"torrent\",\"application\\/x-blorb\":\"blb\",\"application\\/x-bzip\":\"bz\",\"application\\/x-cbr\":\"cbr\",\"application\\/x-cdlink\":\"vcd\",\"application\\/x-cfs-compressed\":\"cfs\",\"application\\/x-chat\":\"chat\",\"application\\/x-chess-pgn\":\"pgn\",\"application\\/x-conference\":\"nsc\",\"application\\/x-cpio\":\"cpio\",\"application\\/x-csh\":\"csh\",\"application\\/x-debian-package\":\"deb\",\"application\\/x-dgc-compressed\":\"dgc\",\"application\\/x-director\":\"dir\",\"application\\/x-doom\":\"wad\",\"application\\/x-dtbncx+xml\":\"ncx\",\"application\\/x-dtbook+xml\":\"dtb\",\"application\\/x-dtbresource+xml\":\"res\",\"application\\/x-dvi\":\"dvi\",\"application\\/x-envoy\":\"evy\",\"application\\/x-eva\":\"eva\",\"application\\/x-font-bdf\":\"bdf\",\"application\\/x-font-ghostscript\":\"gsf\",\"application\\/x-font-linux-psf\":\"psf\",\"application\\/x-font-pcf\":\"pcf\",\"application\\/x-font-snf\":\"snf\",\"application\\/x-font-type1\":\"pfa\",\"application\\/x-freearc\":\"arc\",\"application\\/x-futuresplash\":\"spl\",\"application\\/x-gca-compressed\":\"gca\",\"application\\/x-glulx\":\"ulx\",\"application\\/x-gnumeric\":\"gnumeric\",\"application\\/x-gramps-xml\":\"gramps\",\"application\\/x-gtar\":\"gtar\",\"application\\/x-hdf\":\"hdf\",\"application\\/x-install-instructions\":\"install\",\"application\\/x-iso9660-image\":\"iso\",\"application\\/x-java-jnlp-file\":\"jnlp\",\"application\\/x-latex\":\"latex\",\"application\\/x-lzh-compressed\":\"lzh\",\"application\\/x-mie\":\"mie\",\"application\\/x-mobipocket-ebook\":\"prc\",\"application\\/x-ms-application\":\"application\",\"application\\/x-ms-shortcut\":\"lnk\",\"application\\/x-ms-wmd\":\"wmd\",\"application\\/x-ms-wmz\":\"wmz\",\"application\\/x-ms-xbap\":\"xbap\",\"application\\/x-msaccess\":\"mdb\",\"application\\/x-msbinder\":\"obd\",\"application\\/x-mscardfile\":\"crd\",\"application\\/x-msclip\":\"clp\",\"application\\/x-msdownload\":\"dll\",\"application\\/x-msmediaview\":\"mvb\",\"application\\/x-msmetafile\":\"wmf\",\"application\\/x-msmoney\":\"mny\",\"application\\/x-mspublisher\":\"pub\",\"application\\/x-msschedule\":\"scd\",\"application\\/x-msterminal\":\"trm\",\"application\\/x-mswrite\":\"wri\",\"application\\/x-netcdf\":\"nc\",\"application\\/x-nzb\":\"nzb\",\"application\\/x-pkcs12\":\"p12\",\"application\\/x-pkcs7-certificates\":\"p7b\",\"application\\/x-pkcs7-certreqresp\":\"p7r\",\"application\\/x-research-info-systems\":\"ris\",\"application\\/x-shar\":\"shar\",\"application\\/x-shockwave-flash\":\"swf\",\"application\\/x-silverlight-app\":\"xap\",\"application\\/x-sql\":\"sql\",\"application\\/x-stuffit\":\"sit\",\"application\\/x-stuffitx\":\"sitx\",\"application\\/x-subrip\":\"srt\",\"application\\/x-sv4cpio\":\"sv4cpio\",\"application\\/x-sv4crc\":\"sv4crc\",\"application\\/x-t3vm-image\":\"t3\",\"application\\/x-tads\":\"gam\",\"application\\/x-tar\":\"tar\",\"application\\/x-tcl\":\"tcl\",\"application\\/x-tex\":\"tex\",\"application\\/x-tex-tfm\":\"tfm\",\"application\\/x-texinfo\":\"texinfo\",\"application\\/x-tgif\":\"obj\",\"application\\/x-ustar\":\"ustar\",\"application\\/x-wais-source\":\"src\",\"application\\/x-x509-ca-cert\":\"der\",\"application\\/x-xfig\":\"fig\",\"application\\/x-xliff+xml\":\"xlf\",\"application\\/x-xpinstall\":\"xpi\",\"application\\/x-xz\":\"xz\",\"application\\/x-zmachine\":\"z1\",\"application\\/xaml+xml\":\"xaml\",\"application\\/xcap-diff+xml\":\"xdf\",\"application\\/xenc+xml\":\"xenc\",\"application\\/xhtml+xml\":\"xhtml\",\"application\\/xml\":\"xsl\",\"application\\/xml-dtd\":\"dtd\",\"application\\/xop+xml\":\"xop\",\"application\\/xproc+xml\":\"xpl\",\"application\\/xslt+xml\":\"xslt\",\"application\\/xspf+xml\":\"xspf\",\"application\\/xv+xml\":\"mxml\",\"application\\/yang\":\"yang\",\"application\\/yin+xml\":\"yin\",\"application\\/zip\":\"zip\",\"audio\\/adpcm\":\"adp\",\"audio\\/basic\":\"au\",\"audio\\/midi\":\"mid\",\"audio\\/mp4\":\"m4a\",\"audio\\/mpeg\":\"mpga\",\"audio\\/ogg\":\"oga\",\"audio\\/s3m\":\"s3m\",\"audio\\/silk\":\"sil\",\"audio\\/vnd.dece.audio\":\"uva\",\"audio\\/vnd.digital-winds\":\"eol\",\"audio\\/vnd.dra\":\"dra\",\"audio\\/vnd.dts\":\"dts\",\"audio\\/vnd.dts.hd\":\"dtshd\",\"audio\\/vnd.lucent.voice\":\"lvp\",\"audio\\/vnd.ms-playready.media.pya\":\"pya\",\"audio\\/vnd.nuera.ecelp4800\":\"ecelp4800\",\"audio\\/vnd.nuera.ecelp7470\":\"ecelp7470\",\"audio\\/vnd.nuera.ecelp9600\":\"ecelp9600\",\"audio\\/vnd.rip\":\"rip\",\"audio\\/webm\":\"weba\",\"audio\\/x-aac\":\"aac\",\"audio\\/x-aiff\":\"aif\",\"audio\\/x-caf\":\"caf\",\"audio\\/x-flac\":\"flac\",\"audio\\/x-matroska\":\"mka\",\"audio\\/x-mpegurl\":\"m3u\",\"audio\\/x-ms-wax\":\"wax\",\"audio\\/x-ms-wma\":\"wma\",\"audio\\/x-pn-realaudio\":\"ram\",\"audio\\/x-pn-realaudio-plugin\":\"rmp\",\"audio\\/xm\":\"xm\",\"chemical\\/x-cdx\":\"cdx\",\"chemical\\/x-cif\":\"cif\",\"chemical\\/x-cmdf\":\"cmdf\",\"chemical\\/x-cml\":\"cml\",\"chemical\\/x-csml\":\"csml\",\"chemical\\/x-xyz\":\"xyz\",\"font\\/collection\":\"ttc\",\"font\\/otf\":\"otf\",\"font\\/ttf\":\"ttf\",\"font\\/woff\":\"woff\",\"font\\/woff2\":\"woff2\",\"image\\/cgm\":\"cgm\",\"image\\/g3fax\":\"g3\",\"image\\/gif\":\"gif\",\"image\\/ief\":\"ief\",\"image\\/jpeg\":\"jpeg\",\"image\\/ktx\":\"ktx\",\"image\\/png\":\"png\",\"image\\/prs.btif\":\"btif\",\"image\\/sgi\":\"sgi\",\"image\\/svg+xml\":\"svg\",\"image\\/tiff\":\"tiff\",\"image\\/vnd.adobe.photoshop\":\"psd\",\"image\\/vnd.dece.graphic\":\"uvi\",\"image\\/vnd.djvu\":\"djvu\",\"image\\/vnd.dvb.subtitle\":\"sub\",\"image\\/vnd.dwg\":\"dwg\",\"image\\/vnd.dxf\":\"dxf\",\"image\\/vnd.fastbidsheet\":\"fbs\",\"image\\/vnd.fpx\":\"fpx\",\"image\\/vnd.fst\":\"fst\",\"image\\/vnd.fujixerox.edmics-mmr\":\"mmr\",\"image\\/vnd.fujixerox.edmics-rlc\":\"rlc\",\"image\\/vnd.ms-modi\":\"mdi\",\"image\\/vnd.ms-photo\":\"wdp\",\"image\\/vnd.net-fpx\":\"npx\",\"image\\/vnd.wap.wbmp\":\"wbmp\",\"image\\/vnd.xiff\":\"xif\",\"image\\/webp\":\"webp\",\"image\\/x-3ds\":\"3ds\",\"image\\/x-cmu-raster\":\"ras\",\"image\\/x-cmx\":\"cmx\",\"image\\/x-freehand\":\"fh\",\"image\\/x-icon\":\"ico\",\"image\\/x-mrsid-image\":\"sid\",\"image\\/x-pcx\":\"pcx\",\"image\\/x-pict\":\"pic\",\"image\\/x-portable-anymap\":\"pnm\",\"image\\/x-portable-bitmap\":\"pbm\",\"image\\/x-portable-graymap\":\"pgm\",\"image\\/x-portable-pixmap\":\"ppm\",\"image\\/x-rgb\":\"rgb\",\"image\\/x-xpixmap\":\"xpm\",\"image\\/x-xwindowdump\":\"xwd\",\"message\\/rfc822\":\"eml\",\"model\\/iges\":\"igs\",\"model\\/mesh\":\"msh\",\"model\\/vnd.collada+xml\":\"dae\",\"model\\/vnd.dwf\":\"dwf\",\"model\\/vnd.gdl\":\"gdl\",\"model\\/vnd.gtw\":\"gtw\",\"model\\/vnd.vtu\":\"vtu\",\"model\\/vrml\":\"wrl\",\"model\\/x3d+binary\":\"x3db\",\"model\\/x3d+vrml\":\"x3dv\",\"model\\/x3d+xml\":\"x3d\",\"text\\/cache-manifest\":\"appcache\",\"text\\/calendar\":\"ics\",\"text\\/css\":\"css\",\"text\\/csv\":\"csv\",\"text\\/html\":\"html\",\"text\\/n3\":\"n3\",\"text\\/plain\":\"txt\",\"text\\/prs.lines.tag\":\"dsc\",\"text\\/richtext\":\"rtx\",\"text\\/sgml\":\"sgml\",\"text\\/tab-separated-values\":\"tsv\",\"text\\/troff\":\"t\",\"text\\/turtle\":\"ttl\",\"text\\/uri-list\":\"uri\",\"text\\/vcard\":\"vcard\",\"text\\/vnd.curl\":\"curl\",\"text\\/vnd.curl.dcurl\":\"dcurl\",\"text\\/vnd.curl.mcurl\":\"mcurl\",\"text\\/vnd.curl.scurl\":\"scurl\",\"text\\/vnd.fly\":\"fly\",\"text\\/vnd.fmi.flexstor\":\"flx\",\"text\\/vnd.graphviz\":\"gv\",\"text\\/vnd.in3d.3dml\":\"3dml\",\"text\\/vnd.in3d.spot\":\"spot\",\"text\\/vnd.sun.j2me.app-descriptor\":\"jad\",\"text\\/vnd.wap.wml\":\"wml\",\"text\\/vnd.wap.wmlscript\":\"wmls\",\"text\\/x-asm\":\"s\",\"text\\/x-c\":\"cc\",\"text\\/x-fortran\":\"f\",\"text\\/x-java-source\":\"java\",\"text\\/x-nfo\":\"nfo\",\"text\\/x-opml\":\"opml\",\"text\\/x-pascal\":\"p\",\"text\\/x-setext\":\"etx\",\"text\\/x-sfv\":\"sfv\",\"text\\/x-uuencode\":\"uu\",\"text\\/x-vcalendar\":\"vcs\",\"text\\/x-vcard\":\"vcf\",\"video\\/3gpp\":\"3gp\",\"video\\/3gpp2\":\"3g2\",\"video\\/h261\":\"h261\",\"video\\/h263\":\"h263\",\"video\\/h264\":\"h264\",\"video\\/jpeg\":\"jpgv\",\"video\\/jpm\":\"jpm\",\"video\\/mj2\":\"mj2\",\"video\\/mp4\":\"mp4\",\"video\\/mpeg\":\"mpeg\",\"video\\/quicktime\":\"qt\",\"video\\/vnd.dece.hd\":\"uvh\",\"video\\/vnd.dece.mobile\":\"uvm\",\"video\\/vnd.dece.pd\":\"uvp\",\"video\\/vnd.dece.sd\":\"uvs\",\"video\\/vnd.dece.video\":\"uvv\",\"video\\/vnd.dvb.file\":\"dvb\",\"video\\/vnd.fvt\":\"fvt\",\"video\\/vnd.mpegurl\":\"mxu\",\"video\\/vnd.ms-playready.media.pyv\":\"pyv\",\"video\\/vnd.uvvu.mp4\":\"uvu\",\"video\\/vnd.vivo\":\"viv\",\"video\\/webm\":\"webm\",\"video\\/x-f4v\":\"f4v\",\"video\\/x-fli\":\"fli\",\"video\\/x-flv\":\"flv\",\"video\\/x-m4v\":\"m4v\",\"video\\/x-matroska\":\"mkv\",\"video\\/x-mng\":\"mng\",\"video\\/x-ms-asf\":\"asf\",\"video\\/x-ms-vob\":\"vob\",\"video\\/x-ms-wmx\":\"wmx\",\"video\\/x-ms-wvx\":\"wvx\",\"video\\/x-msvideo\":\"avi\",\"video\\/x-sgi-movie\":\"movie\",\"video\\/x-smv\":\"smv\",\"x-conference\\/x-cooltalk\":\"ice\",\"text\\/x-sql\":\"sql\",\"image\\/x-pixlr-data\":\"pxd\",\"image\\/x-adobe-dng\":\"dng\",\"image\\/x-sketch\":\"sketch\",\"image\\/x-xcf\":\"xcf\",\"audio\\/amr\":\"amr\",\"image\\/vnd-ms.dds\":\"dds\",\"application\\/plt\":\"plt\",\"application\\/sat\":\"sat\",\"application\\/step\":\"step\",\"text\\/x-httpd-cgi\":\"cgi\",\"text\\/x-asap\":\"asp\",\"text\\/x-jsp\":\"jsp\"};

/*
 * File: /js/elFinder.options.js
 */

/**
 * Default elFinder config
 *
 * @type  Object
 * @autor Dmitry (dio) Levashov
 */
elFinder.prototype._options = {
\t/**
\t * URLs of 3rd party libraries CDN
\t * 
\t * @type Object
\t */
\tcdns : {
\t\t// for editor etc.
\t\tace        : 'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.8',
\t\tcodemirror : 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2',
\t\tckeditor   : 'https://cdnjs.cloudflare.com/ajax/libs/ckeditor/4.12.1',
\t\tckeditor5  : 'https://cdn.ckeditor.com/ckeditor5/17.0.0',
\t\ttinymce    : 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.2.0',
\t\tsimplemde  : 'https://cdnjs.cloudflare.com/ajax/libs/simplemde/1.11.2',
\t\tfabric     : 'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2',
\t\tfabric16   : 'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.7',
\t\ttui        : 'https://uicdn.toast.com',
\t\t// for quicklook etc.
\t\thls        : 'https://cdnjs.cloudflare.com/ajax/libs/hls.js/0.13.2/hls.min.js',
\t\tdash       : 'https://cdnjs.cloudflare.com/ajax/libs/dashjs/3.0.3/dash.all.min.js',
\t\tflv        : 'https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.5.0/flv.min.js',
\t\tvideojs    : 'https://cdnjs.cloudflare.com/ajax/libs/video.js/7.7.5',
\t\tprettify   : 'https://cdn.jsdelivr.net/gh/google/code-prettify@f1c3473acd1e8ea8c8c1a60c56e89f5cdd06f915/loader/run_prettify.js',
\t\tpsd        : 'https://cdnjs.cloudflare.com/ajax/libs/psd.js/3.2.0/psd.min.js',
\t\trar        : 'https://cdn.jsdelivr.net/gh/nao-pon/rar.js@6cef13ec66dd67992fc7f3ea22f132d770ebaf8b/rar.min.js',
\t\tzlibUnzip  : 'https://cdn.jsdelivr.net/gh/imaya/zlib.js@0.3.1/bin/unzip.min.js', // need check unzipFiles() in quicklook.plugins.js when update
\t\tzlibGunzip : 'https://cdn.jsdelivr.net/gh/imaya/zlib.js@0.3.1/bin/gunzip.min.js',
\t\tbzip2      : 'https://cdn.jsdelivr.net/gh/nao-pon/bzip2.js@0.8.0/bzip2.js',
\t\tmarked     : 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.7.0/marked.min.js',
\t\tsparkmd5   : 'https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.min.js',
\t\tjssha      : 'https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.3.1/sha.js',
\t\tamr        : 'https://cdn.jsdelivr.net/gh/yxl/opencore-amr-js@dcf3d2b5f384a1d9ded2a54e4c137a81747b222b/js/amrnb.js',
\t\ttiff       : 'https://cdn.jsdelivr.net/gh/seikichi/tiff.js@545ede3ee46b5a5bc5f06d65954e775aa2a64017/tiff.min.js'
\t},
\t
\t/**
\t * Connector url. Required!
\t *
\t * @type String
\t */
\turl : '',

\t/**
\t * Ajax request type.
\t *
\t * @type String
\t * @default \"get\"
\t */
\trequestType : 'get',
\t
\t/**
\t * Use CORS to connector url
\t * 
\t * @type Boolean|null  true|false|null(Auto detect)
\t */
\tcors : null,

\t/**
\t * Array of header names to return parrot out in HTTP headers received from the server
\t * 
\t * @type Array
\t */
\tparrotHeaders : [],

\t/**
\t * Maximum number of concurrent connections on request
\t * 
\t * @type Number
\t * @default 3
\t */
\trequestMaxConn : 3,

\t/**
\t * Transport to send request to backend.
\t * Required for future extensions using websockets/webdav etc.
\t * Must be an object with \"send\" method.
\t * transport.send must return \$.Deferred() object
\t *
\t * @type Object
\t * @default null
\t * @example
\t *  transport : {
\t *    init : function(elfinderInstance) { },
\t *    send : function(options) {
\t *      var dfrd = \$.Deferred();
\t *      // connect to backend ...
\t *      return dfrd;
\t *    },
\t *    upload : function(data) {
\t *      var dfrd = \$.Deferred();
\t *      // upload ...
\t *      return dfrd;
\t *    }
\t *    
\t *  }
\t **/
\ttransport : {},

\t/**
\t * URL to upload file to.
\t * If not set - connector URL will be used
\t *
\t * @type String
\t * @default  ''
\t */
\turlUpload : '',

\t/**
\t * Allow to drag and drop to upload files
\t *
\t * @type Boolean|String
\t * @default  'auto'
\t */
\tdragUploadAllow : 'auto',
\t
\t/**
\t * Confirmation dialog displayed at the time of overwriting upload
\t * 
\t * @type Boolean
\t * @default true
\t */
\toverwriteUploadConfirm : true,
\t
\t/**
\t * Max size of chunked data of file upload
\t * 
\t * @type Number
\t * @default  10485760(10MB)
\t */
\tuploadMaxChunkSize : 10485760,
\t
\t/**
\t * Regular expression of file name to exclude when uploading folder
\t * 
\t * @type Object
\t * @default { win: /^(?:desktop\\.ini|thumbs\\.db)\$/i, mac: /^\\.ds_store\$/i }
\t */
\tfolderUploadExclude : {
\t\twin: /^(?:desktop\\.ini|thumbs\\.db)\$/i,
\t\tmac: /^\\.ds_store\$/i
\t},
\t
\t/**
\t * Timeout for upload using iframe
\t *
\t * @type Number
\t * @default  0 - no timeout
\t */
\tiframeTimeout : 0,
\t
\t/**
\t * Data to append to all requests and to upload files
\t *
\t * @type Object
\t * @default  {}
\t */
\tcustomData : {},
\t
\t/**
\t * Event listeners to bind on elFinder init
\t *
\t * @type Object
\t * @default  {}
\t */
\thandlers : {},

\t/**
\t * Any custom headers to send across every ajax request
\t *
\t * @type Object
\t * @default {}
\t */
\tcustomHeaders : {},

\t/**
\t * Any custom xhrFields to send across every ajax request
\t *
\t * @type Object
\t * @default {}
\t */
\txhrFields : {},

\t/**
\t * Interface language
\t *
\t * @type String
\t * @default \"en\"
\t */
\tlang : 'en',

\t/**
\t * Base URL of elfFinder library starting from Manager HTML
\t * Auto detect when empty value
\t * 
\t * @type String
\t * @default \"\"
\t */
\tbaseUrl : '',

\t/**
\t * Base URL of i18n js files
\t * baseUrl + \"js/i18n/\" when empty value
\t * 
\t * @type String
\t * @default \"\"
\t */
\ti18nBaseUrl : '',
\t
\t/**
\t * Auto load required CSS
\t * `false` to disable this function or
\t * CSS URL Array to load additional CSS files
\t * 
\t * @type Boolean|Array
\t * @default true
\t */
\tcssAutoLoad : true,

\t/**
\t * Theme to load
\t * {\"themeid\" : \"Theme CSS URL\"} or
\t * {\"themeid\" : \"Theme manifesto.json URL\"} or
\t * Theme manifesto.json Object
\t * {
\t *   \"themeid\" : {
\t *     \"name\":\"Theme Name\",
\t *     \"cssurls\":\"Theme CSS URL\",
\t *     \"author\":\"Author Name\",
\t *     \"email\":\"Author Email\",
\t *     \"license\":\"License\",
\t *     \"link\":\"Web Site URL\",
\t *     \"image\":\"Screen Shot URL\",
\t *     \"description\":\"Description\"
\t *   }
\t * }
\t * 
\t * @type Object
\t */
\tthemes : {},

\t/**
\t * Theme id to initial theme
\t * 
\t * @type String|Null
\t */
\ttheme : null,

\t/**
\t * Maximum value of error dialog open at the same time
\t * 
\t * @type Number
\t */
\tmaxErrorDialogs : 5,

\t/**
\t * Additional css class for filemanager node.
\t *
\t * @type String
\t */
\tcssClass : '',

\t/**
\t * Active commands list. '*' means all of the commands that have been load.
\t * If some required commands will be missed here, elFinder will add its
\t *
\t * @type Array
\t */
\tcommands : ['*'],
\t// Available commands list
\t//commands : [
\t//\t'archive', 'back', 'chmod', 'colwidth', 'copy', 'cut', 'download', 'duplicate', 'edit', 'extract',
\t//\t'forward', 'fullscreen', 'getfile', 'help', 'home', 'info', 'mkdir', 'mkfile', 'netmount', 'netunmount',
\t//\t'open', 'opendir', 'paste', 'places', 'quicklook', 'reload', 'rename', 'resize', 'restore', 'rm',
\t//\t'search', 'sort', 'up', 'upload', 'view', 'zipdl'
\t//],
\t
\t/**
\t * Commands options.
\t *
\t * @type Object
\t **/
\tcommandsOptions : {
\t\t// // configure shortcuts of any command
\t\t// // add `shortcuts` property into each command
\t\t// any_command_name : {
\t\t// \tshortcuts : [] // for disable this command's shortcuts
\t\t// },
\t\t// any_command_name : {
\t\t// \tshortcuts : function(fm, shortcuts) {
\t\t// \t\t// for add `CTRL + E` for this command action
\t\t// \t\tshortcuts[0]['pattern'] += ' ctrl+e';
\t\t// \t\treturn shortcuts;
\t\t// \t}
\t\t// },
\t\t// any_command_name : {
\t\t// \tshortcuts : function(fm, shortcuts) {
\t\t// \t\t// for full customize of this command's shortcuts
\t\t// \t\treturn [ { pattern: 'ctrl+e ctrl+down numpad_enter' + (fm.OS != 'mac' && ' enter') } ];
\t\t// \t}
\t\t// },
\t\t// \"getfile\" command options.
\t\tgetfile : {
\t\t\tonlyURL  : false,
\t\t\t// allow to return multiple files info
\t\t\tmultiple : false,
\t\t\t// allow to return filers info
\t\t\tfolders  : false,
\t\t\t// action after callback (\"\"/\"close\"/\"destroy\")
\t\t\toncomplete : '',
\t\t\t// action when callback is fail (\"\"/\"close\"/\"destroy\")
\t\t\tonerror : '',
\t\t\t// get path before callback call
\t\t\tgetPath    : true, 
\t\t\t// get image sizes before callback call
\t\t\tgetImgSize : false
\t\t},
\t\topen : {
\t\t\t// HTTP method that request to the connector when item URL is not valid URL.
\t\t\t// If you set to \"get\" will be displayed request parameter in the browser's location field
\t\t\t// so if you want to conceal its parameters should be given \"post\".
\t\t\t// Nevertheless, please specify \"get\" if you want to enable the partial request by HTTP Range header.
\t\t\tmethod : 'post',
\t\t\t// Where to open into : 'window'(default), 'tab' or 'tabs'
\t\t\t// 'tabs' opens in each tabs
\t\t\tinto   : 'window',
\t\t\t// Default command list of action when select file
\t\t\t// String value that is 'Command Name' or 'Command Name1/CommandName2...'
\t\t\tselectAction : 'open'
\t\t},
\t\topennew : {
\t\t\t// URL of to open elFinder manager
\t\t\t// Default '' : Origin URL
\t\t\turl : '',
\t\t\t// Use search query of origin URL
\t\t\tuseOriginQuery : true
\t\t},
\t\t// \"upload\" command options.
\t\tupload : {
\t\t\t// Open elFinder upload dialog: 'button' OR Open system OS upload dialog: 'uploadbutton'
\t\t\tui : 'button'
\t\t},
\t\t// \"download\" command options.
\t\tdownload : {
\t\t\t// max request to download files when zipdl disabled
\t\t\tmaxRequests : 10,
\t\t\t// minimum count of files to use zipdl
\t\t\tminFilesZipdl : 2
\t\t},
\t\t// \"quicklook\" command options.
\t\tquicklook : {
\t\t\tautoplay : true,
\t\t\twidth    : 450,
\t\t\theight   : 300,
\t\t\t// ControlsList of HTML5 audio/video preview
\t\t\t// see https://googlechrome.github.io/samples/media/controlslist.html
\t\t\tmediaControlsList : '', // e.g. 'nodownload nofullscreen noremoteplayback'
\t\t\t// Show toolbar of PDF preview (with <embed> tag)
\t\t\tpdfToolbar : true,
\t\t\t// Maximum lines to preview at initial
\t\t\ttextInitialLines : 100,
\t\t\t// Maximum lines to preview by prettify
\t\t\tprettifyMaxLines : 300,
\t\t\t// quicklook window must be contained in elFinder node on window open (true|false)
\t\t\tcontain : false,
\t\t\t// preview window into NavDock (0 : undocked | 1 : docked(show) | 2 : docked(hide))
\t\t\tdocked   : 0,
\t\t\t// Docked preview height ('auto' or Number of pixel) 'auto' is setted to the Navbar width
\t\t\tdockHeight : 'auto',
\t\t\t// media auto play when docked
\t\t\tdockAutoplay : false,
\t\t\t// Google Maps API key (Require Maps JavaScript API)
\t\t\tgoogleMapsApiKey : '',
\t\t\t// Google Maps API Options
\t\t\tgoogleMapsOpts : {
\t\t\t\tmaps : {},
\t\t\t\tkml : {
\t\t\t\t\tsuppressInfoWindows : false,
\t\t\t\t\tpreserveViewport : false
\t\t\t\t}
\t\t\t},
\t\t\t// ViewerJS (https://viewerjs.org/) Options
\t\t\t// To enable this you need to place ViewerJS on the same server as elFinder and specify that URL in `url`.
\t\t\tviewerjs : {
\t\t\t\turl: '', // Example '/ViewerJS/index.html'
\t\t\t\tmimes: ['application/pdf', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation'],
\t\t\t\tpdfNative: true // Use Native PDF Viewer first
\t\t\t},
\t\t\t// MIME types to CAD-Files and 3D-Models online viewer on sharecad.org
\t\t\t// Example ['image/vnd.dwg', 'image/vnd.dxf', 'model/vnd.dwf', 'application/vnd.hp-hpgl', 'application/plt', 'application/step', 'model/iges', 'application/vnd.ms-pki.stl', 'application/sat', 'image/cgm', 'application/x-msmetafile']
\t\t\tsharecadMimes : [],
\t\t\t// MIME types to use Google Docs online viewer
\t\t\t// Example ['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', 'application/postscript', 'application/rtf']
\t\t\tgoogleDocsMimes : [],
\t\t\t// MIME types to use Microsoft Office Online viewer
\t\t\t// Example ['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', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']
\t\t\t// These MIME types override \"googleDocsMimes\"
\t\t\tofficeOnlineMimes : [],
\t\t\t// File size threshold when using the dim command for obtain the image size necessary to image preview
\t\t\tgetDimThreshold : '200K',
\t\t\t// Max filesize to show filenames of the zip/tar/gzip/bzip file 
\t\t\tunzipMaxSize : '50M',
\t\t\t// MIME-Type regular expression that does not check empty files
\t\t\tmimeRegexNotEmptyCheck : /^application\\/vnd\\.google-apps\\./
\t\t},
\t\t// \"edit\" command options.
\t\tedit : {
\t\t\t// dialog width, integer(px) or integer+'%' (example: 650, '80%' ...)
\t\t\tdialogWidth : void(0),
\t\t\t// dialog height, integer(px) or integer+'%' (example: 650, '80%' ...)
\t\t\tdialogHeight : void(0),
\t\t\t// list of allowed mimetypes to edit of text files
\t\t\t// if empty - any text files can be edited
\t\t\tmimes : [],
\t\t\t// MIME-types to unselected as default of \"File types to enable with \"New file\"\" in preferences
\t\t\tmkfileHideMimes : [],
\t\t\t// MIME-types of text file to make empty file
\t\t\tmakeTextMimes : ['text/plain', 'text/css', 'text/html'],
\t\t\t// Use the editor stored in the browser
\t\t\t// This value allowd overwrite with user preferences
\t\t\tuseStoredEditor : false,
\t\t\t// Open the maximized editor window
\t\t\t// This value allowd overwrite with user preferences
\t\t\teditorMaximized : false,
\t\t\t// edit files in wysisyg's
\t\t\teditors : [
\t\t\t\t// {
\t\t\t\t// \t/**
\t\t\t\t// \t * editor info
\t\t\t\t// \t * @type  Object
\t\t\t\t// \t */
\t\t\t\t// \tinfo : { name: 'Editor Name' },
\t\t\t\t// \t/**
\t\t\t\t// \t * files mimetypes allowed to edit in current wysisyg
\t\t\t\t// \t * @type  Array
\t\t\t\t// \t */
\t\t\t\t// \tmimes : ['text/html'], 
\t\t\t\t// \t/**
\t\t\t\t// \t * HTML element for editing area (optional for text editor)
\t\t\t\t// \t * @type  String
\t\t\t\t// \t */
\t\t\t\t// \thtml : '<textarea></textarea>', 
\t\t\t\t// \t/**
\t\t\t\t// \t * Initialize editing area node (optional for text editor)
\t\t\t\t// \t * 
\t\t\t\t// \t * @param  String  dialog DOM id
\t\t\t\t// \t * @param  Object  target file object
\t\t\t\t// \t * @param  String  target file content (text or Data URI Scheme(binary file))
\t\t\t\t// \t * @param  Object  elFinder instance
\t\t\t\t// \t * @type  Function
\t\t\t\t// \t */
\t\t\t\t// \tinit : function(id, file, content, fm) {
\t\t\t\t// \t\t\$(this).attr('id', id + '-text').val(content);
\t\t\t\t// \t},
\t\t\t\t// \t/**
\t\t\t\t// \t * Get edited contents (optional for text editor)
\t\t\t\t// \t * @type  Function
\t\t\t\t// \t */
\t\t\t\t// \tgetContent : function() {
\t\t\t\t// \t\treturn \$(this).val();
\t\t\t\t// \t},
\t\t\t\t// \t/**
\t\t\t\t// \t * Called when \"edit\" dialog loaded.
\t\t\t\t// \t * Place to init wysisyg.
\t\t\t\t// \t * Can return wysisyg instance
\t\t\t\t// \t *
\t\t\t\t// \t * @param  DOMElement  textarea node
\t\t\t\t// \t * @return Object      editor instance|jQuery.Deferred(return instance on resolve())
\t\t\t\t// \t */
\t\t\t\t// \tload : function(textarea) { },
\t\t\t\t// \t/**
\t\t\t\t// \t * Called before \"edit\" dialog closed.
\t\t\t\t// \t * Place to destroy wysisyg instance.
\t\t\t\t// \t *
\t\t\t\t// \t * @param  DOMElement  textarea node
\t\t\t\t// \t * @param  Object      wysisyg instance (if was returned by \"load\" callback)
\t\t\t\t// \t * @return void
\t\t\t\t// \t */
\t\t\t\t// \tclose : function(textarea, instance) { },
\t\t\t\t// \t/**
\t\t\t\t// \t * Called before file content send to backend.
\t\t\t\t// \t * Place to update textarea content if needed.
\t\t\t\t// \t *
\t\t\t\t// \t * @param  DOMElement  textarea node
\t\t\t\t// \t * @param  Object      wysisyg instance (if was returned by \"load\" callback)
\t\t\t\t// \t * @return void
\t\t\t\t// \t */
\t\t\t\t// \tsave : function(textarea, instance) {},
\t\t\t\t// \t/**
\t\t\t\t// \t * Called after load() or save().
\t\t\t\t// \t * Set focus to wysisyg editor.
\t\t\t\t// \t *
\t\t\t\t// \t * @param  DOMElement  textarea node
\t\t\t\t// \t * @param  Object      wysisyg instance (if was returned by \"load\" callback)
\t\t\t\t// \t * @return void
\t\t\t\t// \t */
\t\t\t\t// \tfocus : function(textarea, instance) {}
\t\t\t\t// \t/**
\t\t\t\t// \t * Called after dialog resized..
\t\t\t\t// \t *
\t\t\t\t// \t * @param  DOMElement  textarea node
\t\t\t\t// \t * @param  Object      wysisyg instance (if was returned by \"load\" callback)
\t\t\t\t// \t * @param  Object      resize event object
\t\t\t\t// \t * @param  Object      data object
\t\t\t\t// \t * @return void
\t\t\t\t// \t */
\t\t\t\t// \tresize : function(textarea, instance, event, data) {}
\t\t\t\t// 
\t\t\t\t// }
\t\t\t],
\t\t\t// Character encodings of select box
\t\t\tencodings : ['Big5', 'Big5-HKSCS', 'Cp437', 'Cp737', 'Cp775', 'Cp850', 'Cp852', 'Cp855', 'Cp857', 'Cp858', 
\t\t\t\t'Cp862', 'Cp866', 'Cp874', 'EUC-CN', 'EUC-JP', 'EUC-KR', 'GB18030', 'ISO-2022-CN', 'ISO-2022-JP', 'ISO-2022-KR', 
\t\t\t\t'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 
\t\t\t\t'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-13', 'ISO-8859-15', 'KOI8-R', 'KOI8-U', 'Shift-JIS', 
\t\t\t\t'Windows-1250', 'Windows-1251', 'Windows-1252', 'Windows-1253', 'Windows-1254', 'Windows-1257'],
\t\t\t// options for extra editors
\t\t\textraOptions : {
\t\t\t\t// upload command options
\t\t\t\tuploadOpts : {},
\t\t\t\t// TUI Image Editor's options
\t\t\t\ttuiImgEditOpts : {
\t\t\t\t\t// Path prefix of icon-a.svg, icon-b.svg, icon-c.svg and icon-d.svg in the Theme. 
\t\t\t\t\t// `iconsPath` MUST follow the same origin policy.
\t\t\t\t\ticonsPath : void(0), // default is \"./img/tui-\"
\t\t\t\t\t// Theme object
\t\t\t\t\ttheme : {}
\t\t\t\t},
\t\t\t\t// Pixo image editor constructor options - https://pixoeditor.com/
\t\t\t\t// Require 'apikey' to enable it
\t\t\t\tpixo: {
\t\t\t\t\tapikey: ''
\t\t\t\t},
\t\t\t\t// Browsing manager URL for CKEditor, TinyMCE
\t\t\t\t// Uses self location with the empty value or not defined.
\t\t\t\t//managerUrl : 'elfinder.html'
\t\t\t\tmanagerUrl : null,
\t\t\t\t// CKEditor editor options
\t\t\t\tckeditor: {},
\t\t\t\t// CKEditor 5 editor options
\t\t\t\tckeditor5: {
\t\t\t\t\t// builds mode - 'classic', 'inline', 'balloon', 'balloon-block' or 'decoupled-document'
\t\t\t\t\tmode: 'decoupled-document'
\t\t\t\t},
\t\t\t\t// TinyMCE editor options
\t\t\t\ttinymce : {},
\t\t\t\t// Setting for Online-Convert.com
\t\t\t\tonlineConvert : {
\t\t\t\t\tmaxSize  : 100, // (MB) Max 100MB on free account
\t\t\t\t\tshowLink : true // It must be enabled with free account
\t\t\t\t}
\t\t\t}
\t\t},
\t\tfullscreen : {
\t\t\t// fullscreen mode 'screen'(When the browser supports it) or 'window'
\t\t\tmode: 'screen' // 'screen' or 'window'
\t\t},
\t\tsearch : {
\t\t\t// Incremental search from the current view
\t\t\tincsearch : {
\t\t\t\tenable : true, // is enable true or false
\t\t\t\tminlen : 1,    // minimum number of characters
\t\t\t\twait   : 500   // wait milliseconds
\t\t\t},
\t\t\t// Additional search types
\t\t\tsearchTypes : {
\t\t\t\t// \"SearchMime\" is implemented in default
\t\t\t\tSearchMime : {           // The key is search type that send to the connector
\t\t\t\t\tname : 'btnMime',    // Button text to be processed in i18n()
\t\t\t\t\ttitle : 'searchMime',// Button title to be processed in i18n()
\t\t\t\t\tincsearch : 'mime'   // Incremental search target filed name of the file object
\t\t\t\t\t// Or Callable function
\t\t\t\t\t/* incsearch function example
\t\t\t\t\tfunction(queryObject, cwdHashes, elFinderInstance) {
\t\t\t\t\t\tvar q = queryObject.val;
\t\t\t\t\t\tvar regex = queryObject.regex;
\t\t\t\t\t\tvar matchedHashes = \$.grep(cwdHashes, function(hash) {
\t\t\t\t\t\t\tvar file = elFinderInstance.file(hash);
\t\t\t\t\t\t\treturn (file && file.mime && file.mime.match(regex))? true : false;
\t\t\t\t\t\t});
\t\t\t\t\t\treturn matchedHashes;
\t\t\t\t\t}
\t\t\t\t\t*/
\t\t\t\t}
\t\t\t}
\t\t},
\t\t// \"info\" command options.
\t\tinfo : {
\t\t\t// If the URL of the Directory is null,
\t\t\t// it is assumed that the link destination is a URL to open the folder in elFinder
\t\t\tnullUrlDirLinkSelf : true,
\t\t\t// Information items to be hidden by default
\t\t\t// These name are 'size', 'aliasfor', 'path', 'link', 'dim', 'modify', 'perms', 'locked', 'owner', 'group', 'perm' and your custom info items label
\t\t\thideItems : [],
\t\t\t// Maximum file size (byte) to get file contents hash (md5, sha256 ...)
\t\t\tshowHashMaxsize : 104857600, // 100 MB
\t\t\t// Array of hash algorisms to show on info dialog
\t\t\t// These name are 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'shake128' and 'shake256'
\t\t\tshowHashAlgorisms : ['md5', 'sha256'],
\t\t\t// Options for fm.getContentsHashes()
\t\t\tshowHashOpts : {
\t\t\t\tshake128len : 256,
\t\t\t\tshake256len : 512
\t\t\t},
\t\t\tcustom : {
\t\t\t\t// /**
\t\t\t\t//  * Example of custom info `desc`
\t\t\t\t//  */
\t\t\t\t// desc : {
\t\t\t\t// \t/**
\t\t\t\t// \t * Lable (require)
\t\t\t\t// \t * It is filtered by the `fm.i18n()`
\t\t\t\t// \t * 
\t\t\t\t// \t * @type String
\t\t\t\t// \t */
\t\t\t\t// \tlabel : 'Description',
\t\t\t\t// \t
\t\t\t\t// \t/**
\t\t\t\t// \t * Template (require)
\t\t\t\t// \t * `{id}` is replaced in dialog.id
\t\t\t\t// \t * 
\t\t\t\t// \t * @type String
\t\t\t\t// \t */
\t\t\t\t// \ttpl : '<div class=\"elfinder-info-desc\"><span class=\"elfinder-spinner\"></span></div>',
\t\t\t\t// \t
\t\t\t\t// \t/**
\t\t\t\t// \t * Restricts to mimetypes (optional)
\t\t\t\t// \t * Exact match or category match
\t\t\t\t// \t * 
\t\t\t\t// \t * @type Array
\t\t\t\t// \t */
\t\t\t\t// \tmimes : ['text', 'image/jpeg', 'directory'],
\t\t\t\t// \t
\t\t\t\t// \t/**
\t\t\t\t// \t * Restricts to file.hash (optional)
\t\t\t\t// \t * 
\t\t\t\t// \t * @ type Regex
\t\t\t\t// \t */
\t\t\t\t// \thashRegex : /^l\\d+_/,
\t\t\t\t// 
\t\t\t\t// \t/**
\t\t\t\t// \t * Request that asks for the description and sets the field (optional)
\t\t\t\t// \t * 
\t\t\t\t// \t * @type Function
\t\t\t\t// \t */
\t\t\t\t// \taction : function(file, fm, dialog) {
\t\t\t\t// \t\tfm.request({
\t\t\t\t// \t\tdata : { cmd : 'desc', target: file.hash },
\t\t\t\t// \t\t\tpreventDefault: true,
\t\t\t\t// \t\t})
\t\t\t\t// \t\t.fail(function() {
\t\t\t\t// \t\t\tdialog.find('div.elfinder-info-desc').html(fm.i18n('unknown'));
\t\t\t\t// \t\t})
\t\t\t\t// \t\t.done(function(data) {
\t\t\t\t// \t\t\tdialog.find('div.elfinder-info-desc').html(data.desc);
\t\t\t\t// \t\t});
\t\t\t\t// \t}
\t\t\t\t// }
\t\t\t}
\t\t},
\t\tmkdir: {
\t\t\t// Enable automatic switching function [\"New Folder\" / \"Into New Folder\"] of toolbar buttton
\t\t\tintoNewFolderToolbtn: false
\t\t},
\t\tresize: {
\t\t\t// defalt status of snap to 8px grid of the jpeg image (\"enable\" or \"disable\")
\t\t\tgrid8px : 'disable',
\t\t\t// Preset size array [width, height]
\t\t\tpresetSize : [[320, 240], [400, 400], [640, 480], [800,600]],
\t\t\t// File size (bytes) threshold when using the `dim` command for obtain the image size necessary to start editing
\t\t\tgetDimThreshold : 204800,
\t\t\t// File size (bytes) to request to get substitute image (400px) with the `dim` command
\t\t\tdimSubImgSize : 307200
\t\t},
\t\trm: {
\t\t\t// If trash is valid, items moves immediately to the trash holder without confirm.
\t\t\tquickTrash : true,
\t\t\t// Maximum wait seconds when checking the number of items to into the trash
\t\t\tinfoCheckWait : 10,
\t\t\t// Maximum number of items that can be placed into the Trash at one time
\t\t\ttoTrashMaxItems : 1000
\t\t},
\t\tpaste : {
\t\t\tmoveConfirm : false // Display confirmation dialog when moving items
\t\t},
\t\thelp : {
\t\t\t// Tabs to show
\t\t\tview : ['about', 'shortcuts', 'help', 'integrations', 'debug'],
\t\t\t// HTML source URL of the heip tab
\t\t\thelpSource : ''
\t\t},
\t\tpreference : {
\t\t\t// dialog width
\t\t\twidth: 600,
\t\t\t// dialog height
\t\t\theight: 400,
\t\t\t// tabs setting see preference.js : build()
\t\t\tcategories: null,
\t\t\t// preference setting see preference.js : build()
\t\t\tprefs: null,
\t\t\t// language setting  see preference.js : build()
\t\t\tlangs: null,
\t\t\t// Command list of action when select file
\t\t\t// Array value are 'Command Name' or 'Command Name1/CommandName2...'
\t\t\tselectActions : ['open', 'edit/download', 'resize/edit/download', 'download', 'quicklook']
\t\t}
\t},
\t
\t/**
\t * Disabled commands relationship
\t * 
\t * @type Object
\t */
\tdisabledCmdsRels : {
\t\t'get'       : ['edit'],
\t\t'rm'        : ['cut', 'empty'],
\t\t'file&url=' : ['download', 'zipdl'] // file command and volume options url is empty
\t},

\t/**
\t * Callback for prepare boot up
\t * 
\t * - The this object in the function is an elFinder node
\t * - The first parameter is elFinder Instance
\t * - The second parameter is an object of other parameters
\t *   For now it can use `dfrdsBeforeBootup` Array
\t * 
\t * @type Function
\t * @default null
\t * @return void
\t */
\tbootCallback : null,
\t
\t/**
\t * Callback for \"getfile\" commands.
\t * Required to use elFinder with WYSIWYG editors etc..
\t *
\t * @type Function
\t * @default null (command not active)
\t */
\tgetFileCallback : null,
\t
\t/**
\t * Default directory view. icons/list
\t *
\t * @type String
\t * @default \"icons\"
\t */
\tdefaultView : 'icons',
\t
\t/**
\t * Hash of default directory path to open
\t * 
\t * NOTE: This setting will be disabled if the target folder is specified in location.hash.
\t * 
\t * If you want to find the hash in Javascript
\t * can be obtained with the following code. (In the case of a standard hashing method)
\t * 
\t * var volumeId = 'l1_'; // volume id
\t * var path = 'path/to/target'; // without root path
\t * //var path = 'path\\\\to\\\\target'; // use \\ on windows server
\t * var hash = volumeId + btoa(path).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '.').replace(/\\.+\$/, '');
\t * 
\t * @type String
\t * @default \"\"
\t */
\tstartPathHash : '',

\t/**
\t * Emit a sound when a file is deleted
\t * Sounds are in sounds/ folder
\t * 
\t * @type Boolean
\t * @default true
\t */
\tsound : true,
\t
\t/**
\t * UI plugins to load.
\t * Current dir ui and dialogs loads always.
\t * Here set not required plugins as folders tree/toolbar/statusbar etc.
\t *
\t * @type Array
\t * @default ['toolbar', 'places', 'tree', 'path', 'stat']
\t * @full ['toolbar', 'places', 'tree', 'path', 'stat']
\t */
\tui : ['toolbar', 'places', 'tree', 'path', 'stat'],
\t
\t/**
\t * Some UI plugins options.
\t * @type Object
\t */
\tuiOptions : {
\t\t// toolbar configuration
\t\ttoolbar : [
\t\t\t['home', 'back', 'forward', 'up', 'reload'],
\t\t\t['netmount'],
\t\t\t['mkdir', 'mkfile', 'upload'],
\t\t\t['open', 'download', 'getfile'],
\t\t\t['undo', 'redo'],
\t\t\t['copy', 'cut', 'paste', 'rm', 'empty', 'hide'],
\t\t\t['duplicate', 'rename', 'edit', 'resize', 'chmod'],
\t\t\t['selectall', 'selectnone', 'selectinvert'],
\t\t\t['quicklook', 'info'],
\t\t\t['extract', 'archive'],
\t\t\t['search'],
\t\t\t['view', 'sort'],
\t\t\t['preference', 'help'],
\t\t\t['fullscreen']
\t\t],
\t\t// toolbar extra options
\t\ttoolbarExtra : {
\t\t\t// also displays the text label on the button (true / false / 'none')
\t\t\tdisplayTextLabel: false,
\t\t\t// Exclude `displayTextLabel` setting UA type
\t\t\tlabelExcludeUA: ['Mobile'],
\t\t\t// auto hide on initial open
\t\t\tautoHideUA: ['Mobile'],
\t\t\t// Initial setting value of hide button in toolbar setting
\t\t\tdefaultHides: ['home', 'reload'],
\t\t\t// show Preference button ('none', 'auto', 'always')
\t\t\t// If you do not include 'preference' in the context menu you should specify 'auto' or 'always'
\t\t\tshowPreferenceButton: 'none',
\t\t\t// show Preference button into contextmenu of the toolbar (true / false)
\t\t\tpreferenceInContextmenu: true
\t\t},
\t\t// directories tree options
\t\ttree : {
\t\t\t// set path info to attr title
\t\t\tattrTitle : true,
\t\t\t// expand current root on init
\t\t\topenRootOnLoad : true,
\t\t\t// expand current work directory on open
\t\t\topenCwdOnOpen  : true,
\t\t\t// auto loading current directory parents and do expand their node.
\t\t\tsyncTree : true,
\t\t\t// Maximum number of display of each child trees
\t\t\t// The tree of directories with children exceeding this number will be split
\t\t\tsubTreeMax : 100,
\t\t\t// Numbar of max connctions of subdirs request
\t\t\tsubdirsMaxConn : 2,
\t\t\t// Number of max simultaneous processing directory of subdirs
\t\t\tsubdirsAtOnce : 5,
\t\t\t// Durations of each animations
\t\t\tdurations : {
\t\t\t\tslideUpDown : 'fast',
\t\t\t\tautoScroll : 'fast'
\t\t\t}
\t\t\t// ,
\t\t\t// /**
\t\t\t//  * Add CSS class name to navbar directories (optional)
\t\t\t//  * see: https://github.com/Studio-42/elFinder/pull/1061,
\t\t\t//  *      https://github.com/Studio-42/elFinder/issues/1231
\t\t\t//  * 
\t\t\t//  * @type Function
\t\t\t//  */
\t\t\t// getClass: function(dir) {
\t\t\t// \t// e.g. This adds the directory's name (lowercase) with prefix as a CSS class
\t\t\t// \treturn 'elfinder-tree-' + dir.name.replace(/[ \"]/g, '').toLowerCase();
\t\t\t// }
\t\t},
\t\t// navbar options
\t\tnavbar : {
\t\t\tminWidth : 150,
\t\t\tmaxWidth : 500,
\t\t\t// auto hide on initial open
\t\t\tautoHideUA: [] // e.g. ['Mobile']
\t\t},
\t\tnavdock : {
\t\t\t// disabled navdock ui
\t\t\tdisabled : false,
\t\t\t// percentage of initial maximum height to work zone
\t\t\tinitMaxHeight : '50%',
\t\t\t// percentage of maximum height to work zone by user resize action
\t\t\tmaxHeight : '90%'
\t\t},
\t\tcwd : {
\t\t\t// display parent folder with \"..\" name :)
\t\t\toldSchool : false,
\t\t\t
\t\t\t// fm.UA types array to show item select checkboxes e.g. ['All'] or ['Mobile'] etc. default: ['Touch']
\t\t\tshowSelectCheckboxUA : ['Touch'],

\t\t\t// Enable dragout by dragstart with Alt key or Shift key
\t\t\tmetakeyDragout : true,
\t\t\t
\t\t\t// file info columns displayed
\t\t\tlistView : {
\t\t\t\t// name is always displayed, cols are ordered
\t\t\t\t// e.g. ['perm', 'date', 'size', 'kind', 'owner', 'group', 'mode']
\t\t\t\t// mode: 'mode'(by `fileModeStyle` setting), 'modestr'(rwxr-xr-x) , 'modeoct'(755), 'modeboth'(rwxr-xr-x (755))
\t\t\t\t// 'owner', 'group' and 'mode', It's necessary set volume driver option \"statOwner\" to `true`
\t\t\t\t// for custom, characters that can be used in the name is `a-z0-9_`
\t\t\t\tcolumns : ['perm', 'date', 'size', 'kind'],
\t\t\t\t// override this if you want custom columns name
\t\t\t\t// example
\t\t\t\t// columnsCustomName : {
\t\t\t\t//\t\tdate : 'Last modification',
\t\t\t\t// \t\tkind : 'Mime type'
\t\t\t\t// }
\t\t\t\tcolumnsCustomName : {},
\t\t\t\t// fixed list header colmun
\t\t\t\tfixedHeader : true
\t\t\t},

\t\t\t// icons view setting
\t\t\ticonsView : {
\t\t\t\t// default icon size (0-3 in default CSS (cwd.css - elfinder-cwd-size[number]))
\t\t\t\tsize: 0,
\t\t\t\t// number of maximum size (3 in default CSS (cwd.css - elfinder-cwd-size[number]))
\t\t\t\t// uses in preference.js
\t\t\t\tsizeMax: 3,
\t\t\t\t// Name of each size
\t\t\t\tsizeNames: {
\t\t\t\t\t0: 'viewSmall',
\t\t\t\t\t1: 'viewMedium',
\t\t\t\t\t2: 'viewLarge',
\t\t\t\t\t3: 'viewExtraLarge' 
\t\t\t\t}
\t\t\t},

\t\t\t// /**
\t\t\t//  * Add CSS class name to cwd directories (optional)
\t\t\t//  * see: https://github.com/Studio-42/elFinder/pull/1061,
\t\t\t//  *      https://github.com/Studio-42/elFinder/issues/1231
\t\t\t//  * 
\t\t\t//  * @type Function
\t\t\t//  */
\t\t\t// ,
\t\t\t// getClass: function(file) {
\t\t\t// \t// e.g. This adds the directory's name (lowercase) with prefix as a CSS class
\t\t\t// \treturn 'elfinder-cwd-' + file.name.replace(/[ \"]/g, '').toLowerCase();
\t\t\t//}
\t\t\t
\t\t\t//,
\t\t\t//// Template placeholders replacement rules for overwrite. see ui/cwd.js replacement
\t\t\t//replacement : {
\t\t\t//\ttooltip : function(f, fm) {
\t\t\t//\t\tvar list = fm.viewType == 'list', // current view type
\t\t\t//\t\t\tquery = fm.searchStatus.state == 2, // is in search results
\t\t\t//\t\t\ttitle = fm.formatDate(f) + (f.size > 0 ? ' ('+fm.formatSize(f.size)+')' : ''),
\t\t\t//\t\t\tinfo  = '';
\t\t\t//\t\tif (query && f.path) {
\t\t\t//\t\t\tinfo = fm.escape(f.path.replace(/\\/[^\\/]*\$/, ''));
\t\t\t//\t\t} else {
\t\t\t//\t\t\tinfo = f.tooltip? fm.escape(f.tooltip).replace(/\\r/g, '&#13;') : '';
\t\t\t//\t\t}
\t\t\t//\t\tif (list) {
\t\t\t//\t\t\tinfo += (info? '&#13;' : '') + fm.escape(f.name);
\t\t\t//\t\t}
\t\t\t//\t\treturn info? info + '&#13;' + title : title;
\t\t\t//\t}
\t\t\t//}
\t\t},
\t\tpath : {
\t\t\t// Move to head of work zone without UI navbar
\t\t\ttoWorkzoneWithoutNavbar : true
\t\t},
\t\tdialog : {
\t\t\t// Enable to auto focusing on mouse over in the target form element
\t\t\tfocusOnMouseOver : true
\t\t},
\t\ttoast : {
\t\t\tanimate : {
\t\t\t\t// to show
\t\t\t\tshowMethod: 'fadeIn', // fadeIn, slideDown, and show are built into jQuery
\t\t\t\tshowDuration: 300,    // milliseconds
\t\t\t\tshowEasing: 'swing',  // swing and linear are built into jQuery
\t\t\t\t// timeout to hide
\t\t\t\ttimeOut: 3000,
\t\t\t\t// to hide
\t\t\t\thideMethod: 'fadeOut',
\t\t\t\thideDuration: 1500,
\t\t\t\thideEasing: 'swing'
\t\t\t}
\t\t}
\t},

\t/**
\t * MIME regex of send HTTP header \"Content-Disposition: inline\" or allow preview in quicklook
\t * This option will overwrite by connector configuration
\t * 
\t * @type String
\t * @default '^(?:(?:image|video|audio)|text/plain|application/pdf\$)'
\t * @example
\t *  dispInlineRegex : '.',  // is allow inline of all of MIME types
\t *  dispInlineRegex : '\$^', // is not allow inline of all of MIME types
\t */
\tdispInlineRegex : '^(?:(?:image|video|audio)|application/(?:x-mpegURL|dash\\+xml)|(?:text/plain|application/pdf)\$)',

\t/**
\t * Display only required files by types
\t *
\t * @type Array
\t * @default []
\t * @example
\t *  onlyMimes : [\"image\"] - display all images
\t *  onlyMimes : [\"image/png\", \"application/x-shockwave-flash\"] - display png and flash
\t */
\tonlyMimes : [],

\t/**
\t * Custom files sort rules.
\t * All default rules (name/size/kind/date/perm/mode/owner/group) set in elFinder._sortRules
\t *
\t * @type {Object}
\t * @example
\t * sortRules : {
\t *   name : function(file1, file2) { return file1.name.toLowerCase().localeCompare(file2.name.toLowerCase()); }
\t * }
\t */
\tsortRules : {},

\t/**
\t * Default sort type.
\t *
\t * @type {String}
\t */
\tsortType : 'name',
\t
\t/**
\t * Default sort order.
\t *
\t * @type {String}
\t * @default \"asc\"
\t */
\tsortOrder : 'asc',
\t
\t/**
\t * Display folders first?
\t *
\t * @type {Boolean}
\t * @default true
\t */
\tsortStickFolders : true,
\t
\t/**
\t * Sort also applies to the treeview (null: disable this feature)
\t *
\t * @type Boolean|null
\t * @default false
\t */
\tsortAlsoTreeview : false,
\t
\t/**
\t * If true - elFinder will formating dates itself, 
\t * otherwise - backend date will be used.
\t *
\t * @type Boolean
\t */
\tclientFormatDate : true,
\t
\t/**
\t * Show UTC dates.
\t * Required set clientFormatDate to true
\t *
\t * @type Boolean
\t */
\tUTCDate : false,
\t
\t/**
\t * File modification datetime format.
\t * Value from selected language data  is used by default.
\t * Set format here to overwrite it.
\t *
\t * @type String
\t * @default  \"\"
\t */
\tdateFormat : '',
\t
\t/**
\t * File modification datetime format in form \"Yesterday 12:23:01\".
\t * Value from selected language data is used by default.
\t * Set format here to overwrite it.
\t * Use \$1 for \"Today\"/\"Yesterday\" placeholder
\t *
\t * @type String
\t * @default  \"\"
\t * @example \"\$1 H:m:i\"
\t */
\tfancyDateFormat : '',
\t
\t/**
\t * Style of file mode at cwd-list, info dialog
\t * 'string' (ex. rwxr-xr-x) or 'octal' (ex. 755) or 'both' (ex. rwxr-xr-x (755))
\t * 
\t * @type {String}
\t * @default 'both'
\t */
\tfileModeStyle : 'both',
\t
\t/**
\t * elFinder width
\t *
\t * @type String|Number
\t * @default  \"auto\"
\t */
\twidth : 'auto',
\t
\t/**
\t * elFinder node height
\t * Number: pixcel or String: Number + \"%\"
\t *
\t * @type Number | String
\t * @default  400
\t */
\theight : 400,
\t
\t/**
\t * Base node object or selector
\t * Element which is the reference of the height percentage
\t *
\t * @type Object|String
\t * @default null | \$(window) (if height is percentage)
\t **/
\theightBase : null,
\t
\t/**
\t * Make elFinder resizable if jquery ui resizable available
\t *
\t * @type Boolean
\t * @default  true
\t */
\tresizable : true,
\t
\t/**
\t * Timeout before open notifications dialogs
\t *
\t * @type Number
\t * @default  500 (.5 sec)
\t */
\tnotifyDelay : 500,
\t
\t/**
\t * Position CSS, Width of notifications dialogs
\t *
\t * @type Object
\t * @default {position: {}, width : null} - Apply CSS definition
\t * position: CSS object | null (null: position center & middle)
\t */
\tnotifyDialog : {position : {}, width : null, canClose : false, hiddens : ['open']},
\t
\t/**
\t * Dialog contained in the elFinder node
\t * 
\t * @type Boolean
\t * @default false
\t */
\tdialogContained : false,
\t
\t/**
\t * Allow shortcuts
\t *
\t * @type Boolean
\t * @default  true
\t */
\tallowShortcuts : true,
\t
\t/**
\t * Remeber last opened dir to open it after reload or in next session
\t *
\t * @type Boolean
\t * @default  true
\t */
\trememberLastDir : true,
\t
\t/**
\t * Clear historys(elFinder) on reload(not browser) function
\t * Historys was cleared on Reload function on elFinder 2.0 (value is true)
\t * 
\t * @type Boolean
\t * @default  false
\t */
\treloadClearHistory : false,
\t
\t/**
\t * Use browser native history with supported browsers
\t *
\t * @type Boolean
\t * @default  true
\t */
\tuseBrowserHistory : true,
\t
\t/**
\t * Lazy load config.
\t * How many files display at once?
\t *
\t * @type Number
\t * @default  50
\t */
\tshowFiles : 50,
\t
\t/**
\t * Lazy load config.
\t * Distance in px to cwd bottom edge to start display files
\t *
\t * @type Number
\t * @default  50
\t */
\tshowThreshold : 50,
\t
\t/**
\t * Additional rule to valid new file name.
\t * By default not allowed empty names or '..'
\t * This setting does not have a sense of security.
\t *
\t * @type false|RegExp|function
\t * @default  false
\t * @example
\t *  disable names with spaces:
\t *  validName : /^[^\\s]+\$/,
\t */
\tvalidName : false,
\t
\t/**
\t * Additional rule to filtering for browsing.
\t * This setting does not have a sense of security.
\t * 
\t * The object `this` is elFinder instance object in this function
\t *
\t * @type false|RegExp|function
\t * @default  false
\t * @example
\t *  show only png and jpg files:
\t *  fileFilter : /.*\\.(png|jpg)\$/i,
\t *  
\t *  show only image type files:
\t *  fileFilter : function(file) { return file.mime && file.mime.match(/^image\\//i); },
\t */
\tfileFilter : false,
\t
\t/**
\t * Backup name suffix.
\t *
\t * @type String
\t * @default  \"~\"
\t */
\tbackupSuffix : '~',
\t
\t/**
\t * Sync content interval
\t *
\t * @type Number
\t * @default  0 (do not sync)
\t */
\tsync : 0,
\t
\t/**
\t * Sync start on load if sync value >= 1000
\t *
\t * @type     Bool
\t * @default  true
\t */
\tsyncStart : true,
\t
\t/**
\t * How many thumbnails create in one request
\t *
\t * @type Number
\t * @default  5
\t */
\tloadTmbs : 5,
\t
\t/**
\t * Cookie option for browsersdoes not suppot localStorage
\t *
\t * @type Object
\t */
\tcookie         : {
\t\texpires : 30,
\t\tdomain  : '',
\t\tpath    : '/',
\t\tsecure  : false
\t},
\t
\t/**
\t * Contextmenu config
\t *
\t * @type Object
\t */
\tcontextmenu : {
\t\t// navbarfolder menu
\t\tnavbar : ['open', 'opennew', 'download', '|', 'upload', 'mkdir', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', 'empty', 'hide', '|', 'rename', '|', 'archive', '|', 'places', 'info', 'chmod', 'netunmount'],
\t\t// current directory menu
\t\tcwd    : ['undo', 'redo', '|', 'back', 'up', 'reload', '|', 'upload', 'mkdir', 'mkfile', 'paste', '|', 'empty', 'hide', '|', 'view', 'sort', 'selectall', 'colwidth', '|', 'places', 'info', 'chmod', 'netunmount', '|', 'fullscreen', '|', 'preference'],
\t\t// current directory file menu
\t\tfiles  : ['getfile', '|' ,'open', 'opennew', 'download', 'opendir', 'quicklook', '|', 'upload', 'mkdir', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', 'empty', 'hide', '|', 'rename', 'edit', 'resize', '|', 'archive', 'extract', '|', 'selectall', 'selectinvert', '|', 'places', 'info', 'chmod', 'netunmount']
\t},

\t/**
\t * elFinder node enable always
\t * This value will set to `true` if <body> has elFinder node only
\t * 
\t * @type     Bool
\t * @default  false
\t */
\tenableAlways : false,
\t
\t/**
\t * elFinder node enable by mouse over
\t * 
\t * @type     Bool
\t * @default  true
\t */
\tenableByMouseOver : true,

\t/**
\t * Show window close confirm dialog
\t * Value is which state to show
\t * 'hasNotifyDialog', 'editingFile', 'hasSelectedItem' and 'hasClipboardData'
\t * 
\t * @type     Array
\t * @default  ['hasNotifyDialog', 'editingFile']
\t */
\twindowCloseConfirm : ['hasNotifyDialog', 'editingFile'],

\t/**
\t * Function decoding 'raw' string converted to unicode
\t * It is used instead of fm.decodeRawString(str)
\t * 
\t * @type Null|Function
\t */
\trawStringDecoder : typeof Encoding === 'object' && \$.isFunction(Encoding.convert)? function(str) {
\t\treturn Encoding.convert(str, {
\t\t\tto: 'UNICODE',
\t\t\ttype: 'string'
\t\t});
\t} : null,

\t/**
\t * Debug config
\t *
\t * @type Array|String('auto')|Boolean(true|false)
\t */
\tdebug : ['error', 'warning', 'event-destroy'],

\t/**
\t * Show toast messeges of backend warning (if found data `debug.backendErrors` in backend results)
\t *
\t * @type Boolean|Object (toast options)
\t */
\ttoastBackendWarn : true
};


/*
 * File: /js/elFinder.options.netmount.js
 */

/**
 * Default elFinder config of commandsOptions.netmount
 *
 * @type  Object
 */

elFinder.prototype._options.commandsOptions.netmount = {
\tftp: {
\t\tname : 'FTP',
\t\tinputs: {
\t\t\thost     : \$('<input type=\"text\"/>'),
\t\t\tport     : \$('<input type=\"number\" placeholder=\"21\" class=\"elfinder-input-optional\"/>'),
\t\t\tpath     : \$('<input type=\"text\" value=\"/\"/>'),
\t\t\tuser     : \$('<input type=\"text\"/>'),
\t\t\tpass     : \$('<input type=\"password\" autocomplete=\"new-password\"/>'),
\t\t\tFTPS     : \$('<input type=\"checkbox\" value=\"1\" title=\"File Transfer Protocol over SSL/TLS\"/>'),
\t\t\tencoding : \$('<input type=\"text\" placeholder=\"Optional\" class=\"elfinder-input-optional\"/>'),
\t\t\tlocale   : \$('<input type=\"text\" placeholder=\"Optional\" class=\"elfinder-input-optional\"/>')
\t\t}
\t},
\tdropbox2: elFinder.prototype.makeNetmountOptionOauth('dropbox2', 'Dropbox', 'Dropbox', {noOffline : true,
\t\troot : '/',
\t\tpathI18n : 'path',
\t\tintegrate : {
\t\t\ttitle: 'Dropbox.com',
\t\t\tlink: 'https://www.dropbox.com'
\t\t}
\t}),
\tgoogledrive: elFinder.prototype.makeNetmountOptionOauth('googledrive', 'Google Drive', 'Google', {
\t\tintegrate : {
\t\t\ttitle: 'Google Drive',
\t\t\tlink: 'https://www.google.com/drive/'
\t\t}
\t}),
\tonedrive: elFinder.prototype.makeNetmountOptionOauth('onedrive', 'One Drive', 'OneDrive', {
\t\tintegrate : {
\t\t\ttitle: 'Microsoft OneDrive',
\t\t\tlink: 'https://onedrive.live.com'
\t\t}
\t}),
\tbox: elFinder.prototype.makeNetmountOptionOauth('box', 'Box', 'Box', {
\t\tnoOffline : true,
\t\tintegrate : {
\t\t\ttitle: 'Box.com',
\t\t\tlink: 'https://www.box.com'
\t\t}
\t})
};


/*
 * File: /js/elFinder.history.js
 */

/**
 * @class elFinder.history
 * Store visited folders
 * and provide \"back\" and \"forward\" methods
 *
 * @author Dmitry (dio) Levashov
 */
elFinder.prototype.history = function(fm) {
\t\tvar self = this,
\t\t/**
\t\t * Update history on \"open\" event?
\t\t *
\t\t * @type Boolean
\t\t */
\t\tupdate = true,
\t\t/**
\t\t * Directories hashes storage
\t\t *
\t\t * @type Array
\t\t */
\t\thistory = [],
\t\t/**
\t\t * Current directory index in history
\t\t *
\t\t * @type Number
\t\t */
\t\tcurrent,
\t\t/**
\t\t * Clear history
\t\t *
\t\t * @return void
\t\t */
\t\treset = function() {
\t\t\thistory = [fm.cwd().hash];
\t\t\tcurrent = 0;
\t\t\tupdate  = true;
\t\t},
\t\t/**
\t\t * Browser native history object
\t\t */
\t\tnativeHistory = (fm.options.useBrowserHistory && window.history && window.history.pushState)? window.history : null,
\t\t/**
\t\t * Open prev/next folder
\t\t *
\t\t * @Boolen  open next folder?
\t\t * @return jQuery.Deferred
\t\t */
\t\tgo = function(fwd) {
\t\t\tif ((fwd && self.canForward()) || (!fwd && self.canBack())) {
\t\t\t\tupdate = false;
\t\t\t\treturn fm.exec('open', history[fwd ? ++current : --current]).fail(reset);
\t\t\t}
\t\t\treturn \$.Deferred().reject();
\t\t},
\t\t/**
\t\t * Sets the native history.
\t\t *
\t\t * @param String thash target hash
\t\t */
\t\tsetNativeHistory = function(thash) {
\t\t\tif (nativeHistory && (! nativeHistory.state || nativeHistory.state.thash !== thash)) {
\t\t\t\tnativeHistory.pushState({thash: thash}, null, location.pathname + location.search + (thash? '#elf_' + thash : ''));
\t\t\t}
\t\t};
\t
\t/**
\t * Return true if there is previous visited directories
\t *
\t * @return Boolen
\t */
\tthis.canBack = function() {
\t\treturn current > 0;
\t};
\t
\t/**
\t * Return true if can go forward
\t *
\t * @return Boolen
\t */
\tthis.canForward = function() {
\t\treturn current < history.length - 1;
\t};
\t
\t/**
\t * Go back
\t *
\t * @return void
\t */
\tthis.back = go;
\t
\t/**
\t * Go forward
\t *
\t * @return void
\t */
\tthis.forward = function() {
\t\treturn go(true);
\t};
\t
\t// bind to elfinder events
\tfm.bind('init', function() {
\t\tif (nativeHistory && !nativeHistory.state) {
\t\t\tsetNativeHistory(fm.startDir());
\t\t}
\t})
\t.open(function() {
\t\tvar l = history.length,
\t\t\tcwd = fm.cwd().hash;

\t\tif (update) {
\t\t\tcurrent >= 0 && l > current + 1 && history.splice(current+1);
\t\t\thistory[history.length-1] != cwd && history.push(cwd);
\t\t\tcurrent = history.length - 1;
\t\t}
\t\tupdate = true;

\t\tsetNativeHistory(cwd);
\t})
\t.reload(fm.options.reloadClearHistory && reset);
\t
};


/*
 * File: /js/elFinder.command.js
 */

/**
 * elFinder command prototype
 *
 * @type  elFinder.command
 * @author  Dmitry (dio) Levashov
 */
elFinder.prototype.command = function(fm) {
\t\t/**
\t * elFinder instance
\t *
\t * @type  elFinder
\t */
\tthis.fm = fm;
\t
\t/**
\t * Command name, same as class name
\t *
\t * @type  String
\t */
\tthis.name = '';
\t
\t/**
\t * Dialog class name
\t *
\t * @type  String
\t */
\tthis.dialogClass = '';

\t/**
\t * Command icon class name with out 'elfinder-button-icon-'
\t * Use this.name if it is empty
\t *
\t * @type  String
\t */
\tthis.className = '';

\t/**
\t * Short command description
\t *
\t * @type  String
\t */
\tthis.title = '';
\t
\t/**
\t * Linked(Child) commands name
\t * They are loaded together when tthis command is loaded.
\t * 
\t * @type  Array
\t */
\tthis.linkedCmds = [];
\t
\t/**
\t * Current command state
\t *
\t * @example
\t * this.state = -1; // command disabled
\t * this.state = 0;  // command enabled
\t * this.state = 1;  // command active (for example \"fullscreen\" command while elfinder in fullscreen mode)
\t * @default -1
\t * @type  Number
\t */
\tthis.state = -1;
\t
\t/**
\t * If true, command can not be disabled by connector.
\t * @see this.update()
\t *
\t * @type  Boolen
\t */
\tthis.alwaysEnabled = false;
\t
\t/**
\t * Do not change dirctory on removed current work directory
\t * 
\t * @type  Boolen
\t */
\tthis.noChangeDirOnRemovedCwd = false;
\t
\t/**
\t * If true, this means command was disabled by connector.
\t * @see this.update()
\t *
\t * @type  Boolen
\t */
\tthis._disabled = false;
\t
\t/**
\t * If true, this command is disabled on serach results
\t * 
\t * @type  Boolean
\t */
\tthis.disableOnSearch = false;
\t
\t/**
\t * Call update() when event select fired
\t * 
\t * @type  Boolean
\t */
\tthis.updateOnSelect = true;
\t
\t/**
\t * Sync toolbar button title on change
\t * 
\t * @type  Boolean
\t */
\tthis.syncTitleOnChange = false;

\t/**
\t * Keep display of the context menu when command execution
\t * 
\t * @type  Boolean
\t */
\tthis.keepContextmenu = false;
\t
\t/**
\t * elFinder events defaults handlers.
\t * Inside handlers \"this\" is current command object
\t *
\t * @type  Object
\t */
\tthis._handlers = {
\t\tenable  : function() { this.update(void(0), this.value); },
\t\tdisable : function() { this.update(-1, this.value); },
\t\t'open reload load sync'    : function() { 
\t\t\tthis._disabled = !(this.alwaysEnabled || this.fm.isCommandEnabled(this.name));
\t\t\tthis.update(void(0), this.value);
\t\t\tthis.change(); 
\t\t}
\t};
\t
\t/**
\t * elFinder events handlers.
\t * Inside handlers \"this\" is current command object
\t *
\t * @type  Object
\t */
\tthis.handlers = {};
\t
\t/**
\t * Shortcuts
\t *
\t * @type  Array
\t */
\tthis.shortcuts = [];
\t
\t/**
\t * Command options
\t *
\t * @type  Object
\t */
\tthis.options = {ui : 'button'};
\t
\t/**
\t * Callback functions on `change` event
\t * 
\t * @type  Array
\t */
\tthis.listeners = [];

\t/**
\t * Prepare object -
\t * bind events and shortcuts
\t *
\t * @return void
\t */
\tthis.setup = function(name, opts) {
\t\tvar self = this,
\t\t\tfm   = this.fm,
\t\t\tsetCallback = function(s) {
\t\t\t\tvar cb = s.callback || function(e) {
\t\t\t\t\t\t\tfm.exec(self.name, void(0), {
\t\t\t\t\t\t\t_userAction: true,
\t\t\t\t\t\t\t_currentType: 'shortcut'
\t\t\t\t\t\t});
\t\t\t\t\t};
\t\t\t\ts.callback = function(e) {
\t\t\t\t\tvar enabled, checks = {};
\t\t\t\t\tif (self.enabled()) {
\t\t\t\t\t\tif (fm.searchStatus.state < 2) {
\t\t\t\t\t\t\tenabled = fm.isCommandEnabled(self.name);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$.each(fm.selected(), function(i, h) {
\t\t\t\t\t\t\t\tif (fm.optionsByHashes[h]) {
\t\t\t\t\t\t\t\t\tchecks[h] = true;
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\$.each(fm.volOptions, function(id) {
\t\t\t\t\t\t\t\t\t\tif (!checks[id] && h.indexOf(id) === 0) {
\t\t\t\t\t\t\t\t\t\t\tchecks[id] = true;
\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\$.each(checks, function(h) {
\t\t\t\t\t\t\t\tenabled = fm.isCommandEnabled(self.name, h);
\t\t\t\t\t\t\t\tif (! enabled) {
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t\tif (enabled) {
\t\t\t\t\t\t\tself.event = e;
\t\t\t\t\t\t\tcb.call(self);
\t\t\t\t\t\t\tdelete self.event;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t};
\t\t\t},
\t\t\ti, s, sc;

\t\tthis.name      = name;
\t\tthis.title     = fm.messages['cmd'+name] ? fm.i18n('cmd'+name)
\t\t               : ((this.extendsCmd && fm.messages['cmd'+this.extendsCmd]) ? fm.i18n('cmd'+this.extendsCmd) : name);
\t\tthis.options   = Object.assign({}, this.options, opts);
\t\tthis.listeners = [];
\t\tthis.dialogClass = 'elfinder-dialog-' + name;

\t\tif (opts.shortcuts) {
\t\t\tif (typeof opts.shortcuts === 'function') {
\t\t\t\tsc = opts.shortcuts(this.fm, this.shortcuts);
\t\t\t} else if (Array.isArray(opts.shortcuts)) {
\t\t\t\tsc = opts.shortcuts;
\t\t\t}
\t\t\tthis.shortcuts = sc || [];
\t\t}

\t\tif (this.updateOnSelect) {
\t\t\tthis._handlers.select = function() { this.update(void(0), this.value); };
\t\t}

\t\t\$.each(Object.assign({}, self._handlers, self.handlers), function(cmd, handler) {
\t\t\tfm.bind(cmd, \$.proxy(handler, self));
\t\t});

\t\tfor (i = 0; i < this.shortcuts.length; i++) {
\t\t\ts = this.shortcuts[i];
\t\t\tsetCallback(s);
\t\t\t!s.description && (s.description = this.title);
\t\t\tfm.shortcut(s);
\t\t}

\t\tif (this.disableOnSearch) {
\t\t\tfm.bind('search searchend', function() {
\t\t\t\tself._disabled = this.type === 'search'? true : ! (this.alwaysEnabled || fm.isCommandEnabled(name));
\t\t\t\tself.update(void(0), self.value);
\t\t\t});
\t\t}

\t\tthis.init();
\t};

\t/**
\t * Command specific init stuffs
\t *
\t * @return void
\t */
\tthis.init = function() {};

\t/**
\t * Exec command
\t *
\t * @param  Array         target files hashes
\t * @param  Array|Object  command value
\t * @return \$.Deferred
\t */
\tthis.exec = function(files, opts) { 
\t\treturn \$.Deferred().reject(); 
\t};
\t
\tthis.getUndo = function(opts, resData) {
\t\treturn false;
\t};
\t
\t/**
\t * Return true if command disabled.
\t *
\t * @return Boolen
\t */
\tthis.disabled = function() {
\t\treturn this.state < 0;
\t};
\t
\t/**
\t * Return true if command enabled.
\t *
\t * @return Boolen
\t */
\tthis.enabled = function() {
\t\treturn this.state > -1;
\t};
\t
\t/**
\t * Return true if command active.
\t *
\t * @return Boolen
\t */
\tthis.active = function() {
\t\treturn this.state > 0;
\t};
\t
\t/**
\t * Return current command state.
\t * Must be overloaded in most commands
\t *
\t * @return Number
\t */
\tthis.getstate = function() {
\t\treturn -1;
\t};
\t
\t/**
\t * Update command state/value
\t * and rize 'change' event if smth changed
\t *
\t * @param  Number  new state or undefined to auto update state
\t * @param  mixed   new value
\t * @return void
\t */
\tthis.update = function(s, v) {
\t\tvar state = this.state,
\t\t\tvalue = this.value;

\t\tif (this._disabled && this.fm.searchStatus === 0) {
\t\t\tthis.state = -1;
\t\t} else {
\t\t\tthis.state = s !== void(0) ? s : this.getstate();
\t\t}

\t\tthis.value = v;
\t\t
\t\tif (state != this.state || value != this.value) {
\t\t\tthis.change();
\t\t}
\t};
\t
\t/**
\t * Bind handler / fire 'change' event.
\t *
\t * @param  Function|undefined  event callback
\t * @return void
\t */
\tthis.change = function(c) {
\t\tvar cmd, i;
\t\t
\t\tif (typeof(c) === 'function') {
\t\t\tthis.listeners.push(c);\t\t\t
\t\t} else {
\t\t\tfor (i = 0; i < this.listeners.length; i++) {
\t\t\t\tcmd = this.listeners[i];
\t\t\t\ttry {
\t\t\t\t\tcmd(this.state, this.value);
\t\t\t\t} catch (e) {
\t\t\t\t\tthis.fm.debug('error', e);
\t\t\t\t}
\t\t\t}
\t\t}
\t\treturn this;
\t};
\t

\t/**
\t * With argument check given files hashes and return list of existed files hashes.
\t * Without argument return selected files hashes.
\t *
\t * @param  Array|String|void  hashes
\t * @return Array
\t */
\tthis.hashes = function(hashes) {
\t\treturn hashes
\t\t\t? \$.grep(Array.isArray(hashes) ? hashes : [hashes], function(hash) { return fm.file(hash) ? true : false; })
\t\t\t: fm.selected();
\t};
\t
\t/**
\t * Return only existed files from given fils hashes | selected files
\t *
\t * @param  Array|String|void  hashes
\t * @return Array
\t */
\tthis.files = function(hashes) {
\t\tvar fm = this.fm;
\t\t
\t\treturn hashes
\t\t\t? \$.map(Array.isArray(hashes) ? hashes : [hashes], function(hash) { return fm.file(hash) || null; })
\t\t\t: fm.selectedFiles();
\t};

\t/**
\t * Wrapper to fm.dialog()
\t *
\t * @param  String|DOMElement  content
\t * @param  Object             options
\t * @return Object             jQuery element object
\t */
\tthis.fmDialog = function(content, options) {
\t\tif (options.cssClass) {
\t\t\toptions.cssClass += ' ' + this.dialogClass;
\t\t} else {
\t\t\toptions.cssClass = this.dialogClass;
\t\t}
\t\treturn this.fm.dialog(content, options);
\t};
};


/*
 * File: /js/elFinder.resources.js
 */

/**
 * elFinder resources registry.
 * Store shared data
 *
 * @type Object
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.resources = {
\t'class' : {
\t\thover       : 'ui-state-hover',
\t\tactive      : 'ui-state-active',
\t\tdisabled    : 'ui-state-disabled',
\t\tdraggable   : 'ui-draggable',
\t\tdroppable   : 'ui-droppable',
\t\tadroppable  : 'elfinder-droppable-active',
\t\tcwdfile     : 'elfinder-cwd-file',
\t\tcwd         : 'elfinder-cwd',
\t\ttree        : 'elfinder-tree',
\t\ttreeroot    : 'elfinder-navbar-root',
\t\tnavdir      : 'elfinder-navbar-dir',
\t\tnavdirwrap  : 'elfinder-navbar-dir-wrapper',
\t\tnavarrow    : 'elfinder-navbar-arrow',
\t\tnavsubtree  : 'elfinder-navbar-subtree',
\t\tnavcollapse : 'elfinder-navbar-collapsed',
\t\tnavexpand   : 'elfinder-navbar-expanded',
\t\ttreedir     : 'elfinder-tree-dir',
\t\tplacedir    : 'elfinder-place-dir',
\t\tsearchbtn   : 'elfinder-button-search',
\t\tediting     : 'elfinder-to-editing',
\t\tpreventback : 'elfinder-prevent-back',
\t\ttabstab     : 'ui-state-default ui-tabs-tab ui-corner-top ui-tab',
\t\ttabsactive  : 'ui-tabs-active ui-state-active'
\t},
\ttpl : {
\t\tperms      : '<span class=\"elfinder-perms\"></span>',
\t\tlock       : '<span class=\"elfinder-lock\"></span>',
\t\tsymlink    : '<span class=\"elfinder-symlink\"></span>',
\t\tnavicon    : '<span class=\"elfinder-nav-icon\"></span>',
\t\tnavspinner : '<span class=\"elfinder-spinner elfinder-navbar-spinner\"></span>',
\t\tnavdir     : '<div class=\"elfinder-navbar-wrapper{root}\"><span id=\"{id}\" class=\"ui-corner-all elfinder-navbar-dir {cssclass}\"{title}><span class=\"elfinder-navbar-arrow\"></span><span class=\"elfinder-navbar-icon\" {style}></span>{symlink}{permissions}{name}</span><div class=\"elfinder-navbar-subtree\" style=\"display:none\"></div></div>',
\t\tplacedir   : '<div class=\"elfinder-navbar-wrapper\"><span id=\"{id}\" class=\"ui-corner-all elfinder-navbar-dir {cssclass}\"{title}><span class=\"elfinder-navbar-arrow\"></span><span class=\"elfinder-navbar-icon\" {style}></span>{symlink}{permissions}{name}</span><div class=\"elfinder-navbar-subtree\" style=\"display:none\"></div></div>'
\t\t
\t},
\t// mimes.text will be overwritten with connector config if `textMimes` is included in initial response
\t// @see php/elFInder.class.php `public static \$textMimes`
\tmimes : {
\t\ttext : [
\t\t\t'application/dash+xml',
\t\t\t'application/docbook+xml',
\t\t\t'application/javascript',
\t\t\t'application/json',
\t\t\t'application/plt',
\t\t\t'application/sat',
\t\t\t'application/sql',
\t\t\t'application/step',
\t\t\t'application/vnd.hp-hpgl',
\t\t\t'application/x-awk',
\t\t\t'application/x-config',
\t\t\t'application/x-csh',
\t\t\t'application/x-empty',
\t\t\t'application/x-mpegurl',
\t\t\t'application/x-perl',
\t\t\t'application/x-php',
\t\t\t'application/x-web-config',
\t\t\t'application/xhtml+xml',
\t\t\t'application/xml',
\t\t\t'audio/x-mp3-playlist',
\t\t\t'image/cgm',
\t\t\t'image/svg+xml',
\t\t\t'image/vnd.dxf',
\t\t\t'model/iges'
\t\t]
\t},
\t
\tmixin : {
\t\tmake : function() {
\t\t\t\t\t\tvar self = this,
\t\t\t\tfm   = this.fm,
\t\t\t\tcmd  = this.name,
\t\t\t\treq  = this.requestCmd || cmd,
\t\t\t\twz   = fm.getUI('workzone'),
\t\t\t\torg  = (this.origin && this.origin === 'navbar')? 'tree' : 'cwd',
\t\t\t\ttree = (org === 'tree'),
\t\t\t\tfind = tree? 'navHash2Elm' : 'cwdHash2Elm',
\t\t\t\ttarea= (! tree && fm.storage('view') != 'list'),
\t\t\t\tsel  = fm.selected(),
\t\t\t\tmove = this.move || false,
\t\t\t\tempty= wz.hasClass('elfinder-cwd-wrapper-empty'),
\t\t\t\tunselect = function() {
\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\tinput && input.trigger('blur');
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\trest = function(){
\t\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\t\toverlay.elfinderoverlay('hide').off('click close', cancel);
\t\t\t\t\t}
\t\t\t\t\tif (nnode) {
\t\t\t\t\t\tpnode.removeClass('ui-front')
\t\t\t\t\t\t\t.css('position', '')
\t\t\t\t\t\t\t.off('unselect.'+fm.namespace, unselect);
\t\t\t\t\t\tif (tarea) {
\t\t\t\t\t\t\tnnode && nnode.css('max-height', '');
\t\t\t\t\t\t} else if (!tree) {
\t\t\t\t\t\t\tpnode.css('width', '')
\t\t\t\t\t\t\t\t.parent('td').css('overflow', '');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}, colwidth,
\t\t\t\tdfrd = \$.Deferred()
\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\tdstCls && dst.attr('class', dstCls);
\t\t\t\t\t\tempty && wz.addClass('elfinder-cwd-wrapper-empty');
\t\t\t\t\t\tif (sel) {
\t\t\t\t\t\t\tmove && fm.trigger('unlockfiles', {files: sel});
\t\t\t\t\t\t\tfm.clipboard([]);
\t\t\t\t\t\t\tfm.trigger('selectfiles', { files: sel });
\t\t\t\t\t\t}
\t\t\t\t\t\terror && fm.error(error);
\t\t\t\t\t})
\t\t\t\t\t.always(function() {
\t\t\t\t\t\trest();
\t\t\t\t\t\tcleanup();
\t\t\t\t\t\tfm.enable().unbind('open', openCallback).trigger('resMixinMake');
\t\t\t\t\t}),
\t\t\t\tid    = 'tmp_'+parseInt(Math.random()*100000),
\t\t\t\tphash = this.data && this.data.target? this.data.target : (tree? fm.file(sel[0]).hash : fm.cwd().hash),
\t\t\t\tdate = new Date(),
\t\t\t\tfile   = {
\t\t\t\t\thash  : id,
\t\t\t\t\tphash : phash,
\t\t\t\t\tname  : fm.uniqueName(this.prefix, phash),
\t\t\t\t\tmime  : this.mime,
\t\t\t\t\tread  : true,
\t\t\t\t\twrite : true,
\t\t\t\t\tdate  : 'Today '+date.getHours()+':'+date.getMinutes(),
\t\t\t\t\tmove  : move
\t\t\t\t},
\t\t\t\tdum = fm.getUI(org).trigger('create.'+fm.namespace, file),
\t\t\t\tdata = this.data || {},
\t\t\t\tnode = fm[find](id),
\t\t\t\tnnode, pnode,
\t\t\t\toverlay = fm.getUI('overlay'),
\t\t\t\tcleanup = function() {
\t\t\t\t\tif (node && node.length) {
\t\t\t\t\t\tinput.off();
\t\t\t\t\t\tnode.hide();
\t\t\t\t\t\tfm.unselectfiles({files : [id]}).unbind('resize', resize);
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\tif (tree) {
\t\t\t\t\t\t\t\tnode.closest('.elfinder-navbar-wrapper').remove();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcancel = function(e) { 
\t\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\t\tpnode.css('z-index', '');
\t\t\t\t\t}
\t\t\t\t\tif (! inError) {
\t\t\t\t\t\tcleanup();
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\tif (e) {
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tinput = \$(tarea? '<textarea></textarea>' : '<input type=\"text\"/>')
\t\t\t\t\t.on('keyup text', function(){
\t\t\t\t\t\tif (tarea) {
\t\t\t\t\t\t\tthis.style.height = '1px';
\t\t\t\t\t\t\tthis.style.height = this.scrollHeight + 'px';
\t\t\t\t\t\t} else if (colwidth) {
\t\t\t\t\t\t\tthis.style.width = colwidth + 'px';
\t\t\t\t\t\t\tif (this.scrollWidth > colwidth) {
\t\t\t\t\t\t\t\tthis.style.width = this.scrollWidth + 10 + 'px';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('keydown', function(e) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tif (e.keyCode == \$.ui.keyCode.ESCAPE) {
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t} else if (e.keyCode == \$.ui.keyCode.ENTER) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\tinput.trigger('blur');
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('mousedown click dblclick', function(e) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tif (e.type === 'dblclick') {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('blur', function() {
\t\t\t\t\t\tvar name   = \$.trim(input.val()),
\t\t\t\t\t\t\tparent = input.parent(),
\t\t\t\t\t\t\tvalid  = true,
\t\t\t\t\t\t\tcut;

\t\t\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\t\t\tpnode.css('z-index', '');
\t\t\t\t\t\t}
\t\t\t\t\t\tif (name === '') {
\t\t\t\t\t\t\treturn cancel();
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!inError && parent.length) {

\t\t\t\t\t\t\tif (fm.options.validName && fm.options.validName.test) {
\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\tvalid = fm.options.validName.test(name);
\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\tvalid = false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (!name || name === '.' || name === '..' || !valid) {
\t\t\t\t\t\t\t\tinError = true;
\t\t\t\t\t\t\t\tfm.error(file.mime === 'directory'? 'errInvDirname' : 'errInvName', {modal: true, close: function(){setTimeout(select, 120);}});
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (fm.fileByName(name, phash)) {
\t\t\t\t\t\t\t\tinError = true;
\t\t\t\t\t\t\t\tfm.error(['errExists', name], {modal: true, close: function(){setTimeout(select, 120);}});
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}

\t\t\t\t\t\t\tcut = (sel && move)? fm.exec('cut', sel) : null;

\t\t\t\t\t\t\t\$.when(cut)
\t\t\t\t\t\t\t.done(function() {
\t\t\t\t\t\t\t\tvar toast   = {},
\t\t\t\t\t\t\t\t\tnextAct = {};
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\trest();
\t\t\t\t\t\t\t\tinput.hide().before(\$('<span>').text(name));

\t\t\t\t\t\t\t\tfm.lockfiles({files : [id]});

\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\tdata        : Object.assign({cmd : req, name : name, target : phash}, data || {}), 
\t\t\t\t\t\t\t\t\t\tnotify      : {type : req, cnt : 1},
\t\t\t\t\t\t\t\t\t\tpreventFail : true,
\t\t\t\t\t\t\t\t\t\tsyncOnFail  : true,
\t\t\t\t\t\t\t\t\t\tnavigate    : {toast : toast},
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\t\tfm.unlockfiles({files : [id]});
\t\t\t\t\t\t\t\t\t\tinError = true;
\t\t\t\t\t\t\t\t\t\tinput.show().prev().remove();
\t\t\t\t\t\t\t\t\t\tfm.error(error, {
\t\t\t\t\t\t\t\t\t\t\tmodal: true,
\t\t\t\t\t\t\t\t\t\t\tclose: function() {
\t\t\t\t\t\t\t\t\t\t\t\tif (Array.isArray(error) && \$.inArray('errUploadMime', error) !== -1) {
\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.notify('errUploadMime').reject();
\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\tsetTimeout(select, 120);
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\tif (data && data.added && data.added[0]) {
\t\t\t\t\t\t\t\t\t\t\tvar item    = data.added[0],
\t\t\t\t\t\t\t\t\t\t\t\tdirhash = item.hash,
\t\t\t\t\t\t\t\t\t\t\t\tnewItem = fm[find](dirhash),
\t\t\t\t\t\t\t\t\t\t\t\tacts    = {
\t\t\t\t\t\t\t\t\t\t\t\t\t'directory' : { cmd: 'open', msg: 'cmdopendir' },
\t\t\t\t\t\t\t\t\t\t\t\t\t'text'      : { cmd: 'edit', msg: 'cmdedit' },
\t\t\t\t\t\t\t\t\t\t\t\t\t'default'   : { cmd: 'open', msg: 'cmdopen' }
\t\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\t\ttmpMimes;
\t\t\t\t\t\t\t\t\t\t\tif (sel && move) {
\t\t\t\t\t\t\t\t\t\t\t\tfm.one(req+'done', function() {
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('paste', dirhash);
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\tif (!move) {
\t\t\t\t\t\t\t\t\t\t\t\tif (fm.mimeIsText(item.mime) && !fm.mimesCanMakeEmpty[item.mime] && fm.mimeTypes[item.mime]) {
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.trigger('canMakeEmptyFile', {mimes: [item.mime], unshift: true});
\t\t\t\t\t\t\t\t\t\t\t\t\ttmpMimes = {};
\t\t\t\t\t\t\t\t\t\t\t\t\ttmpMimes[item.mime] = fm.mimeTypes[item.mime];
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.storage('mkfileTextMimes', Object.assign(tmpMimes, fm.storage('mkfileTextMimes') || {}));
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\tObject.assign(nextAct, nextAction || acts[item.mime] || acts[item.mime.split('/')[0]] || acts[(fm.mimesCanMakeEmpty[item.mime] || \$.inArray(item.mime, fm.resources.mimes.text) !== -1) ? 'text' : 'none'] || acts['default']);
\t\t\t\t\t\t\t\t\t\t\t\tObject.assign(toast, nextAct.cmd ? {
\t\t\t\t\t\t\t\t\t\t\t\t\tincwd    : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)]), action: nextAct},
\t\t\t\t\t\t\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)]), action: nextAct}
\t\t\t\t\t\t\t\t\t\t\t\t} : {
\t\t\t\t\t\t\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd'+cmd)])}
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tdfrd.resolve(data);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('dragenter dragleave dragover drop', function(e) {
\t\t\t\t\t\t// stop bubbling to prevent upload with native drop event
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t}),
\t\t\t\tselect = function() {
\t\t\t\t\tvar name = fm.splitFileExtention(input.val())[0];
\t\t\t\t\tif (!inError && fm.UA.Mobile && !fm.UA.iOS) { // since iOS has a bug? (z-index not effect) so disable it
\t\t\t\t\t\toverlay.on('click close', cancel).elfinderoverlay('show');
\t\t\t\t\t\tpnode.css('z-index', overlay.css('z-index') + 1);
\t\t\t\t\t}
\t\t\t\t\tinError = false;
\t\t\t\t\t! fm.enabled() && fm.enable();
\t\t\t\t\tinput.trigger('focus').trigger('select');
\t\t\t\t\tinput[0].setSelectionRange && input[0].setSelectionRange(0, name.length);
\t\t\t\t},
\t\t\t\tresize = function() {
\t\t\t\t\tnode.trigger('scrolltoview', {blink : false});
\t\t\t\t},
\t\t\t\topenCallback = function() {
\t\t\t\t\tdfrd && (dfrd.state() === 'pending') && dfrd.reject();
\t\t\t\t},
\t\t\t\tinError = false,
\t\t\t\tnextAction,
\t\t\t\t// for tree
\t\t\t\tdst, dstCls, collapsed, expanded, arrow, subtree;

\t\t\tif (!fm.isCommandEnabled(req, phash) || !node.length) {
\t\t\t\treturn dfrd.reject();
\t\t\t}

\t\t\tif (\$.isPlainObject(self.nextAction)){
\t\t\t\tnextAction = Object.assign({}, self.nextAction);
\t\t\t}
\t\t\t
\t\t\tif (tree) {
\t\t\t\tdst = fm[find](phash);
\t\t\t\tcollapsed = fm.res('class', 'navcollapse');
\t\t\t\texpanded  = fm.res('class', 'navexpand');
\t\t\t\tarrow = fm.res('class', 'navarrow');
\t\t\t\tsubtree = fm.res('class', 'navsubtree');
\t\t\t\t
\t\t\t\tnode.closest('.'+subtree).show();
\t\t\t\tif (! dst.hasClass(collapsed)) {
\t\t\t\t\tdstCls = dst.attr('class');
\t\t\t\t\tdst.addClass(collapsed+' '+expanded+' elfinder-subtree-loaded');
\t\t\t\t}
\t\t\t\tif (dst.is('.'+collapsed+':not(.'+expanded+')')) {
\t\t\t\t\tdst.children('.'+arrow).trigger('click').data('dfrd').done(function() {
\t\t\t\t\t\tif (input.val() === file.name) {
\t\t\t\t\t\t\tinput.val(fm.uniqueName(self.prefix, phash)).trigger('select').trigger('focus');
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tnnode = node.contents().filter(function(){ return this.nodeType==3 && \$(this).parent().attr('id') === fm.navHash2Id(file.hash); });
\t\t\t\tpnode = nnode.parent();
\t\t\t\tnnode.replaceWith(input.val(file.name));
\t\t\t} else {
\t\t\t\tempty && wz.removeClass('elfinder-cwd-wrapper-empty');
\t\t\t\tnnode = node.find('.elfinder-cwd-filename');
\t\t\t\tpnode = nnode.parent();
\t\t\t\tif (tarea) {
\t\t\t\t\tnnode.css('max-height', 'none');
\t\t\t\t} else {
\t\t\t\t\tcolwidth = pnode.width();
\t\t\t\t\tpnode.width(colwidth - 15)
\t\t\t\t\t\t.parent('td').css('overflow', 'visible');
\t\t\t\t}
\t\t\t\tnnode.empty().append(input.val(file.name));
\t\t\t}
\t\t\tpnode.addClass('ui-front')
\t\t\t\t.css('position', 'relative')
\t\t\t\t.on('unselect.'+fm.namespace, unselect);
\t\t\t
\t\t\tfm.bind('resize', resize).one('open', openCallback);
\t\t\t
\t\t\tinput.trigger('keyup');
\t\t\tselect();

\t\t\treturn dfrd;

\t\t}
\t},
\tblink: function(elm, mode) {
\t\t\t\tvar acts = {
\t\t\tslowonce : function(){elm.hide().delay(250).fadeIn(750).delay(500).fadeOut(3500);},
\t\t\tlookme   : function(){elm.show().fadeOut(500).fadeIn(750);}
\t\t}, func;
\t\tmode = mode || 'slowonce';
\t\t
\t\tfunc = acts[mode] || acts['lookme'];
\t\t
\t\telm.stop(true, true);
\t\tfunc();
\t}
};


/*
 * File: /js/jquery.dialogelfinder.js
 */

/**
 * @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, opts2) {
\t\tvar position = 'elfinderPosition',
\t\tdestroy  = 'elfinderDestroyOnClose',
\t\tnode, pos;

\tif (\$.isPlainObject(opts)) {
\t\tthis.not('.elfinder').each(function() {

\t\t\topts.handlers = opts.handlers || {};

\t\t\tvar node    = \$(this),
\t\t\t\tdoc     = \$(document),
\t\t\t\ttoolbar = \$('<div class=\"ui-widget-header dialogelfinder-drag ui-corner-top\">'+(opts.title || 'Files')+'</div>'),
\t\t\t\tbutton  = \$('<a href=\"#\" class=\"dialogelfinder-drag-close ui-corner-all\"><span class=\"ui-icon ui-icon-closethick\"> </span></a>')
\t\t\t\t\t.appendTo(toolbar)
\t\t\t\t\t.on('click', function(e) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tnode.dialogelfinder('close');
\t\t\t\t\t}),
\t\t\t\tinit    = opts.handlers.init,
\t\t\t\telfinder;

\t\t\topts.handlers.init = function(e, fm) {
\t\t\t\tnode.prepend(toolbar);
\t\t\t\tinit && init(e, fm);
\t\t\t};

\t\t\telfinder = node.addClass('elfinder dialogelfinder touch-punch')
\t\t\t\t.css('position', 'absolute')
\t\t\t\t.hide()
\t\t\t\t.appendTo('body')
\t\t\t\t.draggable({
\t\t\t\t\thandle : '.dialogelfinder-drag',
\t\t\t\t\tcontainment : 'window',
\t\t\t\t\tstop : function() {
\t\t\t\t\t\tnode.trigger('resize');
\t\t\t\t\t\telfinder.trigger('resize');
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.elfinder(opts, opts2)
\t\t\t\t.elfinder('instance');
\t\t\t
\t\t\telfinder.reloadCallback = function(o, o2) {
\t\t\t\telfinder.destroy();
\t\t\t\to.handlers.init = init;
\t\t\t\tnode.dialogelfinder(o, o2).dialogelfinder('open');
\t\t\t};
\t\t\t
\t\t\tnode.width(parseInt(node.width()) || 840) // fix width if set to \"auto\"
\t\t\t\t.data(destroy, !!opts.destroyOnClose)
\t\t\t\t.find('.elfinder-toolbar').removeClass('ui-corner-top');
\t\t\t
\t\t\topts.position && node.data(position, opts.position);
\t\t\t
\t\t\topts.autoOpen !== false && \$(this).dialogelfinder('open');

\t\t});
\t} else {
\t\tif (opts === 'open') {
\t\t\tnode = \$(this);
\t\t\tpos = node.data(position) || {
\t\t\t\ttop  : parseInt(\$(document).scrollTop() + (\$(window).height() < node.height() ? 2 : (\$(window).height() - node.height())/2)),
\t\t\t\tleft : parseInt(\$(document).scrollLeft() + (\$(window).width() < node.width()  ? 2 : (\$(window).width()  - node.width())/2))
\t\t\t};

\t\t\tif (node.is(':hidden')) {
\t\t\t\tnode.addClass('ui-front').css(pos).show().trigger('resize');

\t\t\t\tsetTimeout(function() {
\t\t\t\t\t// fix resize icon position and make elfinder active
\t\t\t\t\tnode.trigger('resize').trigger('mousedown');
\t\t\t\t}, 200);
\t\t\t}
\t\t} else if (opts === 'close') {
\t\t\tnode = \$(this).removeClass('ui-front');
\t\t\t\t
\t\t\tif (node.is(':visible')) {
\t\t\t\t!!node.data(destroy)
\t\t\t\t\t? node.elfinder('destroy').remove()
\t\t\t\t\t: node.elfinder('close');
\t\t\t}
\t\t} else if (opts === 'instance') {
\t\t\treturn \$(this).getElFinder();
\t\t}
\t}

\treturn this;
};


/*
 * File: /js/i18n/elfinder.en.js
 */

/**
 * English translation
 * @author Troex Nevelin <troex@fury.scancode.ru>
 * @author Naoki Sawada <hypweb+elfinder@gmail.com>
 * @version 2020-01-16
 */
// elfinder.en.js is integrated into elfinder.(full|min).js by jake build
if (typeof elFinder === 'function' && elFinder.prototype.i18) {
\telFinder.prototype.i18.en = {
\t\ttranslator : 'Troex Nevelin &lt;troex@fury.scancode.ru&gt;, Naoki Sawada &lt;hypweb+elfinder@gmail.com&gt;',
\t\tlanguage   : 'English',
\t\tdirection  : 'ltr',
\t\tdateFormat : 'M d, Y h:i A', // will show like: Aug 24, 2018 04:39 PM
\t\tfancyDateFormat : '\$1 h:i A', // will show like: Today 04:39 PM
\t\tnonameDateFormat : 'ymd-His', // noname upload will show like: 180824-163916
\t\tmessages   : {

\t\t\t/********************************** errors **********************************/
\t\t\t'error'                : 'Error',
\t\t\t'errUnknown'           : 'Unknown error.',
\t\t\t'errUnknownCmd'        : 'Unknown command.',
\t\t\t'errJqui'              : 'Invalid jQuery UI configuration. Selectable, draggable and droppable components must be included.',
\t\t\t'errNode'              : 'elFinder requires DOM Element to be created.',
\t\t\t'errURL'               : 'Invalid elFinder configuration! URL option is not set.',
\t\t\t'errAccess'            : 'Access denied.',
\t\t\t'errConnect'           : 'Unable to connect to backend.',
\t\t\t'errAbort'             : 'Connection aborted.',
\t\t\t'errTimeout'           : 'Connection timeout.',
\t\t\t'errNotFound'          : 'Backend not found.',
\t\t\t'errResponse'          : 'Invalid backend response.',
\t\t\t'errConf'              : 'Invalid backend configuration.',
\t\t\t'errJSON'              : 'PHP JSON module not installed.',
\t\t\t'errNoVolumes'         : 'Readable volumes not available.',
\t\t\t'errCmdParams'         : 'Invalid parameters for command \"\$1\".',
\t\t\t'errDataNotJSON'       : 'Data is not JSON.',
\t\t\t'errDataEmpty'         : 'Data is empty.',
\t\t\t'errCmdReq'            : 'Backend request requires command name.',
\t\t\t'errOpen'              : 'Unable to open \"\$1\".',
\t\t\t'errNotFolder'         : 'Object is not a folder.',
\t\t\t'errNotFile'           : 'Object is not a file.',
\t\t\t'errRead'              : 'Unable to read \"\$1\".',
\t\t\t'errWrite'             : 'Unable to write into \"\$1\".',
\t\t\t'errPerm'              : 'Permission denied.',
\t\t\t'errLocked'            : '\"\$1\" is locked and can not be renamed, moved or removed.',
\t\t\t'errExists'            : 'Item named \"\$1\" already exists.',
\t\t\t'errInvName'           : 'Invalid file name.',
\t\t\t'errInvDirname'        : 'Invalid folder name.',  // from v2.1.24 added 12.4.2017
\t\t\t'errFolderNotFound'    : 'Folder not found.',
\t\t\t'errFileNotFound'      : 'File not found.',
\t\t\t'errTrgFolderNotFound' : 'Target folder \"\$1\" not found.',
\t\t\t'errPopup'             : 'Browser prevented opening popup window. To open file enable it in browser options.',
\t\t\t'errMkdir'             : 'Unable to create folder \"\$1\".',
\t\t\t'errMkfile'            : 'Unable to create file \"\$1\".',
\t\t\t'errRename'            : 'Unable to rename \"\$1\".',
\t\t\t'errCopyFrom'          : 'Copying files from volume \"\$1\" not allowed.',
\t\t\t'errCopyTo'            : 'Copying files to volume \"\$1\" not allowed.',
\t\t\t'errMkOutLink'         : 'Unable to create a link to outside the volume root.', // from v2.1 added 03.10.2015
\t\t\t'errUpload'            : 'Upload error.',  // old name - errUploadCommon
\t\t\t'errUploadFile'        : 'Unable to upload \"\$1\".', // old name - errUpload
\t\t\t'errUploadNoFiles'     : 'No files found for upload.',
\t\t\t'errUploadTotalSize'   : 'Data exceeds the maximum allowed size.', // old name - errMaxSize
\t\t\t'errUploadFileSize'    : 'File exceeds maximum allowed size.', //  old name - errFileMaxSize
\t\t\t'errUploadMime'        : 'File type not allowed.',
\t\t\t'errUploadTransfer'    : '\"\$1\" transfer error.',
\t\t\t'errUploadTemp'        : 'Unable to make temporary file for upload.', // from v2.1 added 26.09.2015
\t\t\t'errNotReplace'        : 'Object \"\$1\" already exists at this location and can not be replaced by object with another type.', // new
\t\t\t'errReplace'           : 'Unable to replace \"\$1\".',
\t\t\t'errSave'              : 'Unable to save \"\$1\".',
\t\t\t'errCopy'              : 'Unable to copy \"\$1\".',
\t\t\t'errMove'              : 'Unable to move \"\$1\".',
\t\t\t'errCopyInItself'      : 'Unable to copy \"\$1\" into itself.',
\t\t\t'errRm'                : 'Unable to remove \"\$1\".',
\t\t\t'errTrash'             : 'Unable into trash.', // from v2.1.24 added 30.4.2017
\t\t\t'errRmSrc'             : 'Unable remove source file(s).',
\t\t\t'errExtract'           : 'Unable to extract files from \"\$1\".',
\t\t\t'errArchive'           : 'Unable to create archive.',
\t\t\t'errArcType'           : 'Unsupported archive type.',
\t\t\t'errNoArchive'         : 'File is not archive or has unsupported archive type.',
\t\t\t'errCmdNoSupport'      : 'Backend does not support this command.',
\t\t\t'errReplByChild'       : 'The folder \"\$1\" can\\'t be replaced by an item it contains.',
\t\t\t'errArcSymlinks'       : 'For security reason denied to unpack archives contains symlinks or files with not allowed names.', // edited 24.06.2012
\t\t\t'errArcMaxSize'        : 'Archive files exceeds maximum allowed size.',
\t\t\t'errResize'            : 'Unable to resize \"\$1\".',
\t\t\t'errResizeDegree'      : 'Invalid rotate degree.',  // added 7.3.2013
\t\t\t'errResizeRotate'      : 'Unable to rotate image.',  // added 7.3.2013
\t\t\t'errResizeSize'        : 'Invalid image size.',  // added 7.3.2013
\t\t\t'errResizeNoChange'    : 'Image size not changed.',  // added 7.3.2013
\t\t\t'errUsupportType'      : 'Unsupported file type.',
\t\t\t'errNotUTF8Content'    : 'File \"\$1\" is not in UTF-8 and cannot be edited.',  // added 9.11.2011
\t\t\t'errNetMount'          : 'Unable to mount \"\$1\".', // added 17.04.2012
\t\t\t'errNetMountNoDriver'  : 'Unsupported protocol.',     // added 17.04.2012
\t\t\t'errNetMountFailed'    : 'Mount failed.',         // added 17.04.2012
\t\t\t'errNetMountHostReq'   : 'Host required.', // added 18.04.2012
\t\t\t'errSessionExpires'    : 'Your session has expired due to inactivity.',
\t\t\t'errCreatingTempDir'   : 'Unable to create temporary directory: \"\$1\"',
\t\t\t'errFtpDownloadFile'   : 'Unable to download file from FTP: \"\$1\"',
\t\t\t'errFtpUploadFile'     : 'Unable to upload file to FTP: \"\$1\"',
\t\t\t'errFtpMkdir'          : 'Unable to create remote directory on FTP: \"\$1\"',
\t\t\t'errArchiveExec'       : 'Error while archiving files: \"\$1\"',
\t\t\t'errExtractExec'       : 'Error while extracting files: \"\$1\"',
\t\t\t'errNetUnMount'        : 'Unable to unmount.', // from v2.1 added 30.04.2012
\t\t\t'errConvUTF8'          : 'Not convertible to UTF-8', // from v2.1 added 08.04.2014
\t\t\t'errFolderUpload'      : 'Try the modern browser, If you\\'d like to upload the folder.', // from v2.1 added 26.6.2015
\t\t\t'errSearchTimeout'     : 'Timed out while searching \"\$1\". Search result is partial.', // from v2.1 added 12.1.2016
\t\t\t'errReauthRequire'     : 'Re-authorization is required.', // from v2.1.10 added 24.3.2016
\t\t\t'errMaxTargets'        : 'Max number of selectable items is \$1.', // from v2.1.17 added 17.10.2016
\t\t\t'errRestore'           : 'Unable to restore from the trash. Can\\'t identify the restore destination.', // from v2.1.24 added 3.5.2017
\t\t\t'errEditorNotFound'    : 'Editor not found to this file type.', // from v2.1.25 added 23.5.2017
\t\t\t'errServerError'       : 'Error occurred on the server side.', // from v2.1.25 added 16.6.2017
\t\t\t'errEmpty'             : 'Unable to empty folder \"\$1\".', // from v2.1.25 added 22.6.2017
\t\t\t'moreErrors'           : 'There are \$1 more errors.', // from v2.1.44 added 9.12.2018

\t\t\t/******************************* commands names ********************************/
\t\t\t'cmdarchive'   : 'Create archive',
\t\t\t'cmdback'      : 'Back',
\t\t\t'cmdcopy'      : 'Copy',
\t\t\t'cmdcut'       : 'Cut',
\t\t\t'cmddownload'  : 'Download',
\t\t\t'cmdduplicate' : 'Duplicate',
\t\t\t'cmdedit'      : 'Edit file',
\t\t\t'cmdextract'   : 'Extract files from archive',
\t\t\t'cmdforward'   : 'Forward',
\t\t\t'cmdgetfile'   : 'Select files',
\t\t\t'cmdhelp'      : 'About this software',
\t\t\t'cmdhome'      : 'Root',
\t\t\t'cmdinfo'      : 'Get info',
\t\t\t'cmdmkdir'     : 'New folder',
\t\t\t'cmdmkdirin'   : 'Into New Folder', // from v2.1.7 added 19.2.2016
\t\t\t'cmdmkfile'    : 'New file',
\t\t\t'cmdopen'      : 'Open',
\t\t\t'cmdpaste'     : 'Paste',
\t\t\t'cmdquicklook' : 'Preview',
\t\t\t'cmdreload'    : 'Reload',
\t\t\t'cmdrename'    : 'Rename',
\t\t\t'cmdrm'        : 'Delete',
\t\t\t'cmdtrash'     : 'Into trash', //from v2.1.24 added 29.4.2017
\t\t\t'cmdrestore'   : 'Restore', //from v2.1.24 added 3.5.2017
\t\t\t'cmdsearch'    : 'Find files',
\t\t\t'cmdup'        : 'Go to parent folder',
\t\t\t'cmdupload'    : 'Upload files',
\t\t\t'cmdview'      : 'View',
\t\t\t'cmdresize'    : 'Resize & Rotate',
\t\t\t'cmdsort'      : 'Sort',
\t\t\t'cmdnetmount'  : 'Mount network volume', // added 18.04.2012
\t\t\t'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012
\t\t\t'cmdplaces'    : 'To Places', // added 28.12.2014
\t\t\t'cmdchmod'     : 'Change mode', // from v2.1 added 20.6.2015
\t\t\t'cmdopendir'   : 'Open a folder', // from v2.1 added 13.1.2016
\t\t\t'cmdcolwidth'  : 'Reset column width', // from v2.1.13 added 12.06.2016
\t\t\t'cmdfullscreen': 'Full Screen', // from v2.1.15 added 03.08.2016
\t\t\t'cmdmove'      : 'Move', // from v2.1.15 added 21.08.2016
\t\t\t'cmdempty'     : 'Empty the folder', // from v2.1.25 added 22.06.2017
\t\t\t'cmdundo'      : 'Undo', // from v2.1.27 added 31.07.2017
\t\t\t'cmdredo'      : 'Redo', // from v2.1.27 added 31.07.2017
\t\t\t'cmdpreference': 'Preferences', // from v2.1.27 added 03.08.2017
\t\t\t'cmdselectall' : 'Select all', // from v2.1.28 added 15.08.2017
\t\t\t'cmdselectnone': 'Select none', // from v2.1.28 added 15.08.2017
\t\t\t'cmdselectinvert': 'Invert selection', // from v2.1.28 added 15.08.2017
\t\t\t'cmdopennew'   : 'Open in new window', // from v2.1.38 added 3.4.2018
\t\t\t'cmdhide'      : 'Hide (Preference)', // from v2.1.41 added 24.7.2018

\t\t\t/*********************************** buttons ***********************************/
\t\t\t'btnClose'  : 'Close',
\t\t\t'btnSave'   : 'Save',
\t\t\t'btnRm'     : 'Remove',
\t\t\t'btnApply'  : 'Apply',
\t\t\t'btnCancel' : 'Cancel',
\t\t\t'btnNo'     : 'No',
\t\t\t'btnYes'    : 'Yes',
\t\t\t'btnMount'  : 'Mount',  // added 18.04.2012
\t\t\t'btnApprove': 'Goto \$1 & approve', // from v2.1 added 26.04.2012
\t\t\t'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012
\t\t\t'btnConv'   : 'Convert', // from v2.1 added 08.04.2014
\t\t\t'btnCwd'    : 'Here',      // from v2.1 added 22.5.2015
\t\t\t'btnVolume' : 'Volume',    // from v2.1 added 22.5.2015
\t\t\t'btnAll'    : 'All',       // from v2.1 added 22.5.2015
\t\t\t'btnMime'   : 'MIME Type', // from v2.1 added 22.5.2015
\t\t\t'btnFileName':'Filename',  // from v2.1 added 22.5.2015
\t\t\t'btnSaveClose': 'Save & Close', // from v2.1 added 12.6.2015
\t\t\t'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015
\t\t\t'btnRename'    : 'Rename',      // from v2.1.24 added 6.4.2017
\t\t\t'btnRenameAll' : 'Rename(All)', // from v2.1.24 added 6.4.2017
\t\t\t'btnPrevious' : 'Prev (\$1/\$2)', // from v2.1.24 added 11.5.2017
\t\t\t'btnNext'     : 'Next (\$1/\$2)', // from v2.1.24 added 11.5.2017
\t\t\t'btnSaveAs'   : 'Save As', // from v2.1.25 added 24.5.2017

\t\t\t/******************************** notifications ********************************/
\t\t\t'ntfopen'     : 'Open folder',
\t\t\t'ntffile'     : 'Open file',
\t\t\t'ntfreload'   : 'Reload folder content',
\t\t\t'ntfmkdir'    : 'Creating folder',
\t\t\t'ntfmkfile'   : 'Creating files',
\t\t\t'ntfrm'       : 'Delete items',
\t\t\t'ntfcopy'     : 'Copy items',
\t\t\t'ntfmove'     : 'Move items',
\t\t\t'ntfprepare'  : 'Checking existing items',
\t\t\t'ntfrename'   : 'Rename files',
\t\t\t'ntfupload'   : 'Uploading files',
\t\t\t'ntfdownload' : 'Downloading files',
\t\t\t'ntfsave'     : 'Save files',
\t\t\t'ntfarchive'  : 'Creating archive',
\t\t\t'ntfextract'  : 'Extracting files from archive',
\t\t\t'ntfsearch'   : 'Searching files',
\t\t\t'ntfresize'   : 'Resizing images',
\t\t\t'ntfsmth'     : 'Doing something',
\t\t\t'ntfloadimg'  : 'Loading image',
\t\t\t'ntfnetmount' : 'Mounting network volume', // added 18.04.2012
\t\t\t'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012
\t\t\t'ntfdim'      : 'Acquiring image dimension', // added 20.05.2013
\t\t\t'ntfreaddir'  : 'Reading folder infomation', // from v2.1 added 01.07.2013
\t\t\t'ntfurl'      : 'Getting URL of link', // from v2.1 added 11.03.2014
\t\t\t'ntfchmod'    : 'Changing file mode', // from v2.1 added 20.6.2015
\t\t\t'ntfpreupload': 'Verifying upload file name', // from v2.1 added 31.11.2015
\t\t\t'ntfzipdl'    : 'Creating a file for download', // from v2.1.7 added 23.1.2016
\t\t\t'ntfparents'  : 'Getting path infomation', // from v2.1.17 added 2.11.2016
\t\t\t'ntfchunkmerge': 'Processing the uploaded file', // from v2.1.17 added 2.11.2016
\t\t\t'ntftrash'    : 'Doing throw in the trash', // from v2.1.24 added 2.5.2017
\t\t\t'ntfrestore'  : 'Doing restore from the trash', // from v2.1.24 added 3.5.2017
\t\t\t'ntfchkdir'   : 'Checking destination folder', // from v2.1.24 added 3.5.2017
\t\t\t'ntfundo'     : 'Undoing previous operation', // from v2.1.27 added 31.07.2017
\t\t\t'ntfredo'     : 'Redoing previous undone', // from v2.1.27 added 31.07.2017
\t\t\t'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018

\t\t\t/*********************************** volumes *********************************/
\t\t\t'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017

\t\t\t/************************************ dates **********************************/
\t\t\t'dateUnknown' : 'unknown',
\t\t\t'Today'       : 'Today',
\t\t\t'Yesterday'   : 'Yesterday',
\t\t\t'msJan'       : 'Jan',
\t\t\t'msFeb'       : 'Feb',
\t\t\t'msMar'       : 'Mar',
\t\t\t'msApr'       : 'Apr',
\t\t\t'msMay'       : 'May',
\t\t\t'msJun'       : 'Jun',
\t\t\t'msJul'       : 'Jul',
\t\t\t'msAug'       : 'Aug',
\t\t\t'msSep'       : 'Sep',
\t\t\t'msOct'       : 'Oct',
\t\t\t'msNov'       : 'Nov',
\t\t\t'msDec'       : 'Dec',
\t\t\t'January'     : 'January',
\t\t\t'February'    : 'February',
\t\t\t'March'       : 'March',
\t\t\t'April'       : 'April',
\t\t\t'May'         : 'May',
\t\t\t'June'        : 'June',
\t\t\t'July'        : 'July',
\t\t\t'August'      : 'August',
\t\t\t'September'   : 'September',
\t\t\t'October'     : 'October',
\t\t\t'November'    : 'November',
\t\t\t'December'    : 'December',
\t\t\t'Sunday'      : 'Sunday',
\t\t\t'Monday'      : 'Monday',
\t\t\t'Tuesday'     : 'Tuesday',
\t\t\t'Wednesday'   : 'Wednesday',
\t\t\t'Thursday'    : 'Thursday',
\t\t\t'Friday'      : 'Friday',
\t\t\t'Saturday'    : 'Saturday',
\t\t\t'Sun'         : 'Sun',
\t\t\t'Mon'         : 'Mon',
\t\t\t'Tue'         : 'Tue',
\t\t\t'Wed'         : 'Wed',
\t\t\t'Thu'         : 'Thu',
\t\t\t'Fri'         : 'Fri',
\t\t\t'Sat'         : 'Sat',

\t\t\t/******************************** sort variants ********************************/
\t\t\t'sortname'          : 'by name',
\t\t\t'sortkind'          : 'by kind',
\t\t\t'sortsize'          : 'by size',
\t\t\t'sortdate'          : 'by date',
\t\t\t'sortFoldersFirst'  : 'Folders first',
\t\t\t'sortperm'          : 'by permission', // from v2.1.13 added 13.06.2016
\t\t\t'sortmode'          : 'by mode',       // from v2.1.13 added 13.06.2016
\t\t\t'sortowner'         : 'by owner',      // from v2.1.13 added 13.06.2016
\t\t\t'sortgroup'         : 'by group',      // from v2.1.13 added 13.06.2016
\t\t\t'sortAlsoTreeview'  : 'Also Treeview',  // from v2.1.15 added 01.08.2016

\t\t\t/********************************** new items **********************************/
\t\t\t'untitled file.txt' : 'NewFile.txt', // added 10.11.2015
\t\t\t'untitled folder'   : 'NewFolder',   // added 10.11.2015
\t\t\t'Archive'           : 'NewArchive',  // from v2.1 added 10.11.2015
\t\t\t'untitled file'     : 'NewFile.\$1',  // from v2.1.41 added 6.8.2018
\t\t\t'extentionfile'     : '\$1: File',    // from v2.1.41 added 6.8.2018
\t\t\t'extentiontype'     : '\$1: \$2',      // from v2.1.43 added 17.10.2018

\t\t\t/********************************** messages **********************************/
\t\t\t'confirmReq'      : 'Confirmation required',
\t\t\t'confirmRm'       : 'Are you sure you want to permanently remove items?<br/>This cannot be undone!',
\t\t\t'confirmRepl'     : 'Replace old file with new one? (If it contains folders, it will be merged. To backup and replace, select Backup.)',
\t\t\t'confirmRest'     : 'Replace existing item with the item in trash?', // fromv2.1.24 added 5.5.2017
\t\t\t'confirmConvUTF8' : 'Not in UTF-8<br/>Convert to UTF-8?<br/>Contents become UTF-8 by saving after conversion.', // from v2.1 added 08.04.2014
\t\t\t'confirmNonUTF8'  : 'Character encoding of this file couldn\\'t be detected. It need to temporarily convert to UTF-8 for editting.<br/>Please select character encoding of this file.', // from v2.1.19 added 28.11.2016
\t\t\t'confirmNotSave'  : 'It has been modified.<br/>Losing work if you do not save changes.', // from v2.1 added 15.7.2015
\t\t\t'confirmTrash'    : 'Are you sure you want to move items to trash bin?', //from v2.1.24 added 29.4.2017
\t\t\t'confirmMove'     : 'Are you sure you want to move items to \"\$1\"?', //from v2.1.50 added 27.7.2019
\t\t\t'apllyAll'        : 'Apply to all',
\t\t\t'name'            : 'Name',
\t\t\t'size'            : 'Size',
\t\t\t'perms'           : 'Permissions',
\t\t\t'modify'          : 'Modified',
\t\t\t'kind'            : 'Kind',
\t\t\t'read'            : 'read',
\t\t\t'write'           : 'write',
\t\t\t'noaccess'        : 'no access',
\t\t\t'and'             : 'and',
\t\t\t'unknown'         : 'unknown',
\t\t\t'selectall'       : 'Select all items',
\t\t\t'selectfiles'     : 'Select item(s)',
\t\t\t'selectffile'     : 'Select first item',
\t\t\t'selectlfile'     : 'Select last item',
\t\t\t'viewlist'        : 'List view',
\t\t\t'viewicons'       : 'Icons view',
\t\t\t'viewSmall'       : 'Small icons', // from v2.1.39 added 22.5.2018
\t\t\t'viewMedium'      : 'Medium icons', // from v2.1.39 added 22.5.2018
\t\t\t'viewLarge'       : 'Large icons', // from v2.1.39 added 22.5.2018
\t\t\t'viewExtraLarge'  : 'Extra large icons', // from v2.1.39 added 22.5.2018
\t\t\t'places'          : 'Places',
\t\t\t'calc'            : 'Calculate',
\t\t\t'path'            : 'Path',
\t\t\t'aliasfor'        : 'Alias for',
\t\t\t'locked'          : 'Locked',
\t\t\t'dim'             : 'Dimensions',
\t\t\t'files'           : 'Files',
\t\t\t'folders'         : 'Folders',
\t\t\t'items'           : 'Items',
\t\t\t'yes'             : 'yes',
\t\t\t'no'              : 'no',
\t\t\t'link'            : 'Link',
\t\t\t'searcresult'     : 'Search results',
\t\t\t'selected'        : 'selected items',
\t\t\t'about'           : 'About',
\t\t\t'shortcuts'       : 'Shortcuts',
\t\t\t'help'            : 'Help',
\t\t\t'webfm'           : 'Web file manager',
\t\t\t'ver'             : 'Version',
\t\t\t'protocolver'     : 'protocol version',
\t\t\t'homepage'        : 'Project home',
\t\t\t'docs'            : 'Documentation',
\t\t\t'github'          : 'Fork us on GitHub',
\t\t\t'twitter'         : 'Follow us on Twitter',
\t\t\t'facebook'        : 'Join us on Facebook',
\t\t\t'team'            : 'Team',
\t\t\t'chiefdev'        : 'chief developer',
\t\t\t'developer'       : 'developer',
\t\t\t'contributor'     : 'contributor',
\t\t\t'maintainer'      : 'maintainer',
\t\t\t'translator'      : 'translator',
\t\t\t'icons'           : 'Icons',
\t\t\t'dontforget'      : 'and don\\'t forget to take your towel',
\t\t\t'shortcutsof'     : 'Shortcuts disabled',
\t\t\t'dropFiles'       : 'Drop files here',
\t\t\t'or'              : 'or',
\t\t\t'selectForUpload' : 'Select files',
\t\t\t'moveFiles'       : 'Move items',
\t\t\t'copyFiles'       : 'Copy items',
\t\t\t'restoreFiles'    : 'Restore items', // from v2.1.24 added 5.5.2017
\t\t\t'rmFromPlaces'    : 'Remove from places',
\t\t\t'aspectRatio'     : 'Aspect ratio',
\t\t\t'scale'           : 'Scale',
\t\t\t'width'           : 'Width',
\t\t\t'height'          : 'Height',
\t\t\t'resize'          : 'Resize',
\t\t\t'crop'            : 'Crop',
\t\t\t'rotate'          : 'Rotate',
\t\t\t'rotate-cw'       : 'Rotate 90 degrees CW',
\t\t\t'rotate-ccw'      : 'Rotate 90 degrees CCW',
\t\t\t'degree'          : '°',
\t\t\t'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012
\t\t\t'protocol'            : 'Protocol', // added 18.04.2012
\t\t\t'host'                : 'Host', // added 18.04.2012
\t\t\t'port'                : 'Port', // added 18.04.2012
\t\t\t'user'                : 'User', // added 18.04.2012
\t\t\t'pass'                : 'Password', // added 18.04.2012
\t\t\t'confirmUnmount'      : 'Are you sure to unmount \$1?',  // from v2.1 added 30.04.2012
\t\t\t'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012
\t\t\t'dropPasteFiles'  : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014
\t\t\t'encoding'        : 'Encoding', // from v2.1 added 19.12.2014
\t\t\t'locale'          : 'Locale',   // from v2.1 added 19.12.2014
\t\t\t'searchTarget'    : 'Target: \$1',                // from v2.1 added 22.5.2015
\t\t\t'searchMime'      : 'Search by input MIME Type', // from v2.1 added 22.5.2015
\t\t\t'owner'           : 'Owner', // from v2.1 added 20.6.2015
\t\t\t'group'           : 'Group', // from v2.1 added 20.6.2015
\t\t\t'other'           : 'Other', // from v2.1 added 20.6.2015
\t\t\t'execute'         : 'Execute', // from v2.1 added 20.6.2015
\t\t\t'perm'            : 'Permission', // from v2.1 added 20.6.2015
\t\t\t'mode'            : 'Mode', // from v2.1 added 20.6.2015
\t\t\t'emptyFolder'     : 'Folder is empty', // from v2.1.6 added 30.12.2015
\t\t\t'emptyFolderDrop' : 'Folder is empty\\\\A Drop to add items', // from v2.1.6 added 30.12.2015
\t\t\t'emptyFolderLTap' : 'Folder is empty\\\\A Long tap to add items', // from v2.1.6 added 30.12.2015
\t\t\t'quality'         : 'Quality', // from v2.1.6 added 5.1.2016
\t\t\t'autoSync'        : 'Auto sync',  // from v2.1.6 added 10.1.2016
\t\t\t'moveUp'          : 'Move up',  // from v2.1.6 added 18.1.2016
\t\t\t'getLink'         : 'Get URL link', // from v2.1.7 added 9.2.2016
\t\t\t'selectedItems'   : 'Selected items (\$1)', // from v2.1.7 added 2.19.2016
\t\t\t'folderId'        : 'Folder ID', // from v2.1.10 added 3.25.2016
\t\t\t'offlineAccess'   : 'Allow offline access', // from v2.1.10 added 3.25.2016
\t\t\t'reAuth'          : 'To re-authenticate', // from v2.1.10 added 3.25.2016
\t\t\t'nowLoading'      : 'Now loading...', // from v2.1.12 added 4.26.2016
\t\t\t'openMulti'       : 'Open multiple files', // from v2.1.12 added 5.14.2016
\t\t\t'openMultiConfirm': 'You are trying to open the \$1 files. Are you sure you want to open in browser?', // from v2.1.12 added 5.14.2016
\t\t\t'emptySearch'     : 'Search results is empty in search target.', // from v2.1.12 added 5.16.2016
\t\t\t'editingFile'     : 'It is editing a file.', // from v2.1.13 added 6.3.2016
\t\t\t'hasSelected'     : 'You have selected \$1 items.', // from v2.1.13 added 6.3.2016
\t\t\t'hasClipboard'    : 'You have \$1 items in the clipboard.', // from v2.1.13 added 6.3.2016
\t\t\t'incSearchOnly'   : 'Incremental search is only from the current view.', // from v2.1.13 added 6.30.2016
\t\t\t'reinstate'       : 'Reinstate', // from v2.1.15 added 3.8.2016
\t\t\t'complete'        : '\$1 complete', // from v2.1.15 added 21.8.2016
\t\t\t'contextmenu'     : 'Context menu', // from v2.1.15 added 9.9.2016
\t\t\t'pageTurning'     : 'Page turning', // from v2.1.15 added 10.9.2016
\t\t\t'volumeRoots'     : 'Volume roots', // from v2.1.16 added 16.9.2016
\t\t\t'reset'           : 'Reset', // from v2.1.16 added 1.10.2016
\t\t\t'bgcolor'         : 'Background color', // from v2.1.16 added 1.10.2016
\t\t\t'colorPicker'     : 'Color picker', // from v2.1.16 added 1.10.2016
\t\t\t'8pxgrid'         : '8px Grid', // from v2.1.16 added 4.10.2016
\t\t\t'enabled'         : 'Enabled', // from v2.1.16 added 4.10.2016
\t\t\t'disabled'        : 'Disabled', // from v2.1.16 added 4.10.2016
\t\t\t'emptyIncSearch'  : 'Search results is empty in current view.\\\\A Press [Enter] to expand search target.', // from v2.1.16 added 5.10.2016
\t\t\t'emptyLetSearch'  : 'First letter search results is empty in current view.', // from v2.1.23 added 24.3.2017
\t\t\t'textLabel'       : 'Text label', // from v2.1.17 added 13.10.2016
\t\t\t'minsLeft'        : '\$1 mins left', // from v2.1.17 added 13.11.2016
\t\t\t'openAsEncoding'  : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016
\t\t\t'saveAsEncoding'  : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016
\t\t\t'selectFolder'    : 'Select folder', // from v2.1.20 added 13.12.2016
\t\t\t'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017
\t\t\t'presets'         : 'Presets', // from v2.1.25 added 26.5.2017
\t\t\t'tooManyToTrash'  : 'It\\'s too many items so it can\\'t into trash.', // from v2.1.25 added 9.6.2017
\t\t\t'TextArea'        : 'TextArea', // from v2.1.25 added 14.6.2017
\t\t\t'folderToEmpty'   : 'Empty the folder \"\$1\".', // from v2.1.25 added 22.6.2017
\t\t\t'filderIsEmpty'   : 'There are no items in a folder \"\$1\".', // from v2.1.25 added 22.6.2017
\t\t\t'preference'      : 'Preference', // from v2.1.26 added 28.6.2017
\t\t\t'language'        : 'Language', // from v2.1.26 added 28.6.2017
\t\t\t'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017
\t\t\t'toolbarPref'     : 'Toolbar settings', // from v2.1.27 added 2.8.2017
\t\t\t'charsLeft'       : '... \$1 chars left.',  // from v2.1.29 added 30.8.2017
\t\t\t'linesLeft'       : '... \$1 lines left.',  // from v2.1.52 added 16.1.2020
\t\t\t'sum'             : 'Sum', // from v2.1.29 added 28.9.2017
\t\t\t'roughFileSize'   : 'Rough file size', // from v2.1.30 added 2.11.2017
\t\t\t'autoFocusDialog' : 'Focus on the element of dialog with mouseover',  // from v2.1.30 added 2.11.2017
\t\t\t'select'          : 'Select', // from v2.1.30 added 23.11.2017
\t\t\t'selectAction'    : 'Action when select file', // from v2.1.30 added 23.11.2017
\t\t\t'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017
\t\t\t'selectinvert'    : 'Invert selection', // from v2.1.30 added 25.11.2017
\t\t\t'renameMultiple'  : 'Are you sure you want to rename \$1 selected items like \$2?<br/>This cannot be undone!', // from v2.1.31 added 4.12.2017
\t\t\t'batchRename'     : 'Batch rename', // from v2.1.31 added 8.12.2017
\t\t\t'plusNumber'      : '+ Number', // from v2.1.31 added 8.12.2017
\t\t\t'asPrefix'        : 'Add prefix', // from v2.1.31 added 8.12.2017
\t\t\t'asSuffix'        : 'Add suffix', // from v2.1.31 added 8.12.2017
\t\t\t'changeExtention' : 'Change extention', // from v2.1.31 added 8.12.2017
\t\t\t'columnPref'      : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018
\t\t\t'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018
\t\t\t'reflectOnUnmount'   : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018
\t\t\t'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018
\t\t\t'selectionInfo'   : 'Selection Info', // from v2.1.33 added 7.3.2018
\t\t\t'hashChecker'     : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018
\t\t\t'infoItems'       : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018
\t\t\t'pressAgainToExit': 'Press again to exit.', // from v2.1.38 added 1.4.2018
\t\t\t'toolbar'         : 'Toolbar', // from v2.1.38 added 4.4.2018
\t\t\t'workspace'       : 'Work Space', // from v2.1.38 added 4.4.2018
\t\t\t'dialog'          : 'Dialog', // from v2.1.38 added 4.4.2018
\t\t\t'all'             : 'All', // from v2.1.38 added 4.4.2018
\t\t\t'iconSize'        : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018
\t\t\t'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018
\t\t\t'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018
\t\t\t'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018
\t\t\t'convertOn'       : 'Convert on the site of \$1', // from v2.1.40 added 10.7.2018
\t\t\t'integrations'    : 'Integrations', // from v2.1.40 added 11.7.2018
\t\t\t'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018
\t\t\t'showHidden'      : 'Show hidden items', // from v2.1.41 added 24.7.2018
\t\t\t'hideHidden'      : 'Hide hidden items', // from v2.1.41 added 24.7.2018
\t\t\t'toggleHidden'    : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018
\t\t\t'makefileTypes'   : 'File types to enable with \"New file\"', // from v2.1.41 added 7.8.2018
\t\t\t'typeOfTextfile'  : 'Type of the Text file', // from v2.1.41 added 7.8.2018
\t\t\t'add'             : 'Add', // from v2.1.41 added 7.8.2018
\t\t\t'theme'           : 'Theme', // from v2.1.43 added 19.10.2018
\t\t\t'default'         : 'Default', // from v2.1.43 added 19.10.2018
\t\t\t'description'     : 'Description', // from v2.1.43 added 19.10.2018
\t\t\t'website'         : 'Website', // from v2.1.43 added 19.10.2018
\t\t\t'author'          : 'Author', // from v2.1.43 added 19.10.2018
\t\t\t'email'           : 'Email', // from v2.1.43 added 19.10.2018
\t\t\t'license'         : 'License', // from v2.1.43 added 19.10.2018
\t\t\t'exportToSave'    : 'This item can\\'t be saved. To avoid losing the edits you need to export to your PC.', // from v2.1.44 added 1.12.2018
\t\t\t'dblclickToSelect': 'Double click on the file to select it.', // from v2.1.47 added 22.1.2019
\t\t\t'useFullscreen'   : 'Use fullscreen mode', // from v2.1.47 added 19.2.2019

\t\t\t/********************************** mimetypes **********************************/
\t\t\t'kindUnknown'     : 'Unknown',
\t\t\t'kindRoot'        : 'Volume Root', // from v2.1.16 added 16.10.2016
\t\t\t'kindFolder'      : 'Folder',
\t\t\t'kindSelects'     : 'Selections', // from v2.1.29 added 29.8.2017
\t\t\t'kindAlias'       : 'Alias',
\t\t\t'kindAliasBroken' : 'Broken alias',
\t\t\t// applications
\t\t\t'kindApp'         : 'Application',
\t\t\t'kindPostscript'  : 'Postscript document',
\t\t\t'kindMsOffice'    : 'Microsoft Office document',
\t\t\t'kindMsWord'      : 'Microsoft Word document',
\t\t\t'kindMsExcel'     : 'Microsoft Excel document',
\t\t\t'kindMsPP'        : 'Microsoft Powerpoint presentation',
\t\t\t'kindOO'          : 'Open Office document',
\t\t\t'kindAppFlash'    : 'Flash application',
\t\t\t'kindPDF'         : 'Portable Document Format (PDF)',
\t\t\t'kindTorrent'     : 'Bittorrent file',
\t\t\t'kind7z'          : '7z archive',
\t\t\t'kindTAR'         : 'TAR archive',
\t\t\t'kindGZIP'        : 'GZIP archive',
\t\t\t'kindBZIP'        : 'BZIP archive',
\t\t\t'kindXZ'          : 'XZ archive',
\t\t\t'kindZIP'         : 'ZIP archive',
\t\t\t'kindRAR'         : 'RAR archive',
\t\t\t'kindJAR'         : 'Java JAR file',
\t\t\t'kindTTF'         : 'True Type font',
\t\t\t'kindOTF'         : 'Open Type font',
\t\t\t'kindRPM'         : 'RPM package',
\t\t\t// texts
\t\t\t'kindText'        : 'Text document',
\t\t\t'kindTextPlain'   : 'Plain text',
\t\t\t'kindPHP'         : 'PHP source',
\t\t\t'kindCSS'         : 'Cascading style sheet',
\t\t\t'kindHTML'        : 'HTML document',
\t\t\t'kindJS'          : 'Javascript source',
\t\t\t'kindRTF'         : 'Rich Text Format',
\t\t\t'kindC'           : 'C source',
\t\t\t'kindCHeader'     : 'C header source',
\t\t\t'kindCPP'         : 'C++ source',
\t\t\t'kindCPPHeader'   : 'C++ header source',
\t\t\t'kindShell'       : 'Unix shell script',
\t\t\t'kindPython'      : 'Python source',
\t\t\t'kindJava'        : 'Java source',
\t\t\t'kindRuby'        : 'Ruby source',
\t\t\t'kindPerl'        : 'Perl script',
\t\t\t'kindSQL'         : 'SQL source',
\t\t\t'kindXML'         : 'XML document',
\t\t\t'kindAWK'         : 'AWK source',
\t\t\t'kindCSV'         : 'Comma separated values',
\t\t\t'kindDOCBOOK'     : 'Docbook XML document',
\t\t\t'kindMarkdown'    : 'Markdown text', // added 20.7.2015
\t\t\t// images
\t\t\t'kindImage'       : 'Image',
\t\t\t'kindBMP'         : 'BMP image',
\t\t\t'kindJPEG'        : 'JPEG image',
\t\t\t'kindGIF'         : 'GIF Image',
\t\t\t'kindPNG'         : 'PNG Image',
\t\t\t'kindTIFF'        : 'TIFF image',
\t\t\t'kindTGA'         : 'TGA image',
\t\t\t'kindPSD'         : 'Adobe Photoshop image',
\t\t\t'kindXBITMAP'     : 'X bitmap image',
\t\t\t'kindPXM'         : 'Pixelmator image',
\t\t\t// media
\t\t\t'kindAudio'       : 'Audio media',
\t\t\t'kindAudioMPEG'   : 'MPEG audio',
\t\t\t'kindAudioMPEG4'  : 'MPEG-4 audio',
\t\t\t'kindAudioMIDI'   : 'MIDI audio',
\t\t\t'kindAudioOGG'    : 'Ogg Vorbis audio',
\t\t\t'kindAudioWAV'    : 'WAV audio',
\t\t\t'AudioPlaylist'   : 'MP3 playlist',
\t\t\t'kindVideo'       : 'Video media',
\t\t\t'kindVideoDV'     : 'DV movie',
\t\t\t'kindVideoMPEG'   : 'MPEG movie',
\t\t\t'kindVideoMPEG4'  : 'MPEG-4 movie',
\t\t\t'kindVideoAVI'    : 'AVI movie',
\t\t\t'kindVideoMOV'    : 'Quick Time movie',
\t\t\t'kindVideoWM'     : 'Windows Media movie',
\t\t\t'kindVideoFlash'  : 'Flash movie',
\t\t\t'kindVideoMKV'    : 'Matroska movie',
\t\t\t'kindVideoOGG'    : 'Ogg movie'
\t\t}
\t};
}



/*
 * File: /js/ui/button.js
 */

/**
 * @class  elFinder toolbar button widget.
 * If command has variants - create menu
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderbutton = function(cmd) {
\t\treturn this.each(function() {
\t\t
\t\tvar c        = 'class',
\t\t\tfm       = cmd.fm,
\t\t\tdisabled = fm.res(c, 'disabled'),
\t\t\tactive   = fm.res(c, 'active'),
\t\t\thover    = fm.res(c, 'hover'),
\t\t\titem     = 'elfinder-button-menu-item',
\t\t\tselected = 'elfinder-button-menu-item-selected',
\t\t\tmenu,
\t\t\ttext     = \$('<span class=\"elfinder-button-text\">'+cmd.title+'</span>'),
\t\t\tprvCname = cmd.className? cmd.className : cmd.name,
\t\t\tbutton   = \$(this).addClass('ui-state-default elfinder-button')
\t\t\t\t.attr('title', cmd.title)
\t\t\t\t.append('<span class=\"elfinder-button-icon elfinder-button-icon-' + prvCname + '\"></span>', text)
\t\t\t\t.on('mouseenter mouseleave', function(e) { !button.hasClass(disabled) && button[e.type == 'mouseleave' ? 'removeClass' : 'addClass'](hover);})
\t\t\t\t.on('click', function(e) { 
\t\t\t\t\tif (!button.hasClass(disabled)) {
\t\t\t\t\t\tif (menu && cmd.variants.length >= 1) {
\t\t\t\t\t\t\t// close other menus
\t\t\t\t\t\t\tmenu.is(':hidden') && fm.getUI().click();
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\tmenu.css(getMenuOffset()).slideToggle({
\t\t\t\t\t\t\t\tduration: 100,
\t\t\t\t\t\t\t\tdone: function(e) {
\t\t\t\t\t\t\t\t\tfm[menu.is(':visible')? 'toFront' : 'toHide'](menu);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.exec(cmd.name, getSelected(), {_userAction: true, _currentType: 'toolbar', _currentNode: button });
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t}
\t\t\t\t}),
\t\t\thideMenu = function() {
\t\t\t\tfm.toHide(menu);
\t\t\t},
\t\t\tgetMenuOffset = function() {
\t\t\t\tvar fmNode = fm.getUI(),
\t\t\t\t\tbaseOffset = fmNode.offset(),
\t\t\t\t\tbuttonOffset = button.offset();
\t\t\t\treturn {
\t\t\t\t\ttop : buttonOffset.top - baseOffset.top,
\t\t\t\t\tleft : buttonOffset.left - baseOffset.left,
\t\t\t\t\tmaxHeight : fmNode.height() - 40
\t\t\t\t};
\t\t\t},
\t\t\tgetSelected = function() {
\t\t\t\tvar sel = fm.selected(),
\t\t\t\t\tcwd;
\t\t\t\tif (!sel.length) {
\t\t\t\t\tif (cwd = fm.cwd()) {
\t\t\t\t\t\tsel = [ fm.cwd().hash ];
\t\t\t\t\t} else {
\t\t\t\t\t\tsel = void(0);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn sel;
\t\t\t},
\t\t\ttm;
\t\t\t
\t\ttext.hide();
\t\t
\t\t// set self button object to cmd object
\t\tcmd.button = button;
\t\t
\t\t// if command has variants create menu
\t\tif (Array.isArray(cmd.variants)) {
\t\t\tbutton.addClass('elfinder-menubutton');
\t\t\t
\t\t\tmenu = \$('<div class=\"ui-front ui-widget ui-widget-content elfinder-button-menu elfinder-button-' + prvCname + '-menu ui-corner-all\"></div>')
\t\t\t\t.hide()
\t\t\t\t.appendTo(fm.getUI())
\t\t\t\t.on('mouseenter mouseleave', '.'+item, function() { \$(this).toggleClass(hover); })
\t\t\t\t.on('click', '.'+item, function(e) {
\t\t\t\t\tvar opts = \$(this).data('value');
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tbutton.removeClass(hover);
\t\t\t\t\tfm.toHide(menu);
\t\t\t\t\tif (typeof opts === 'undefined') {
\t\t\t\t\t\topts = {};
\t\t\t\t\t}
\t\t\t\t\tif (typeof opts === 'object') {
\t\t\t\t\t\topts._userAction = true;
\t\t\t\t\t}
\t\t\t\t\tfm.exec(cmd.name, getSelected(), opts);
\t\t\t\t})
\t\t\t\t.on('close', hideMenu);

\t\t\tfm.bind('disable select', hideMenu).getUI().on('click', hideMenu);
\t\t\t
\t\t\tcmd.change(function() {
\t\t\t\tmenu.html('');
\t\t\t\t\$.each(cmd.variants, function(i, variant) {
\t\t\t\t\tmenu.append(\$('<div class=\"'+item+'\">'+variant[1]+'</div>').data('value', variant[0]).addClass(variant[0] == cmd.value ? selected : ''));
\t\t\t\t});
\t\t\t});
\t\t}\t
\t\t\t
\t\tcmd.change(function() {
\t\t\tvar cName;
\t\t\ttm && cancelAnimationFrame(tm);
\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\tif (cmd.disabled()) {
\t\t\t\t\tbutton.removeClass(active+' '+hover).addClass(disabled);
\t\t\t\t} else {
\t\t\t\t\tbutton.removeClass(disabled);
\t\t\t\t\tbutton[cmd.active() ? 'addClass' : 'removeClass'](active);
\t\t\t\t}
\t\t\t\tif (cmd.syncTitleOnChange) {
\t\t\t\t\tcName = cmd.className? cmd.className : cmd.name;
\t\t\t\t\tif (prvCname !== cName) {
\t\t\t\t\t\tbutton.children('.elfinder-button-icon').removeClass('elfinder-button-icon-' + prvCname).addClass('elfinder-button-icon-' + cName);
\t\t\t\t\t\tif (menu) {
\t\t\t\t\t\t\tmenu.removeClass('elfinder-button-' + prvCname + '-menu').addClass('elfinder-button-' + cName + '-menu');
\t\t\t\t\t\t}
\t\t\t\t\t\tprvCname = cName;
\t\t\t\t\t}
\t\t\t\t\ttext.html(cmd.title);
\t\t\t\t\tbutton.attr('title', cmd.title);
\t\t\t\t}
\t\t\t});
\t\t})
\t\t.change();
\t});
};


/*
 * File: /js/ui/contextmenu.js
 */

/**
 * @class  elFinder contextmenu
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindercontextmenu = function(fm) {
\t\treturn this.each(function() {
\t\tvar self   = \$(this),
\t\t\tcmItem = 'elfinder-contextmenu-item',
\t\t\tsmItem = 'elfinder-contextsubmenu-item',
\t\t\texIcon = 'elfinder-contextmenu-extra-icon',
\t\t\tcHover = fm.res('class', 'hover'),
\t\t\tdragOpt = {
\t\t\t\tdistance: 8,
\t\t\t\tstart: function() {
\t\t\t\t\tmenu.data('drag', true).data('touching') && menu.find('.'+cHover).removeClass(cHover);
\t\t\t\t},
\t\t\t\tstop: function() {
\t\t\t\t\tmenu.data('draged', true).removeData('drag');
\t\t\t\t}
\t\t\t},
\t\t\tmenu = \$(this).addClass('touch-punch ui-helper-reset ui-front ui-widget ui-state-default ui-corner-all elfinder-contextmenu elfinder-contextmenu-'+fm.direction)
\t\t\t\t.hide()
\t\t\t\t.on('touchstart', function(e) {
\t\t\t\t\tmenu.data('touching', true).children().removeClass(cHover);
\t\t\t\t})
\t\t\t\t.on('touchend', function(e) {
\t\t\t\t\tmenu.removeData('touching');
\t\t\t\t})
\t\t\t\t.on('mouseenter mouseleave', '.'+cmItem, function(e) {
\t\t\t\t\t\$(this).toggleClass(cHover, (e.type === 'mouseenter' || (! menu.data('draged') && menu.data('submenuKeep'))? true : false));
\t\t\t\t\tif (menu.data('draged') && menu.data('submenuKeep')) {
\t\t\t\t\t\tmenu.find('.elfinder-contextmenu-sub:visible').parent().addClass(cHover);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('mouseenter mouseleave', '.'+exIcon, function(e) {
\t\t\t\t\t\$(this).parent().toggleClass(cHover, e.type === 'mouseleave');
\t\t\t\t})
\t\t\t\t.on('mouseenter mouseleave', '.'+cmItem+',.'+smItem, function(e) {
\t\t\t\t\tvar setIndex = function(target, sub) {
\t\t\t\t\t\t\$.each(sub? subnodes : nodes, function(i, n) {
\t\t\t\t\t\t\tif (target[0] === n) {
\t\t\t\t\t\t\t\t(sub? subnodes : nodes)._cur = i;
\t\t\t\t\t\t\t\tif (sub) {
\t\t\t\t\t\t\t\t\tsubselected = target;
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tselected = target;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t};
\t\t\t\t\tif (e.originalEvent) {
\t\t\t\t\t\tvar target = \$(this),
\t\t\t\t\t\t\tunHover = function() {
\t\t\t\t\t\t\t\tif (selected && !selected.children('div.elfinder-contextmenu-sub:visible').length) {
\t\t\t\t\t\t\t\t\tselected.removeClass(cHover);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\tif (e.type === 'mouseenter') {
\t\t\t\t\t\t\t// mouseenter
\t\t\t\t\t\t\tif (target.hasClass(smItem)) {
\t\t\t\t\t\t\t\t// submenu
\t\t\t\t\t\t\t\tif (subselected) {
\t\t\t\t\t\t\t\t\tsubselected.removeClass(cHover);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (selected) {
\t\t\t\t\t\t\t\t\tsubnodes = selected.find('div.'+smItem);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tsetIndex(target, true);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t// menu
\t\t\t\t\t\t\t\tunHover();
\t\t\t\t\t\t\t\tsetIndex(target);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t// mouseleave
\t\t\t\t\t\t\tif (target.hasClass(smItem)) {
\t\t\t\t\t\t\t\t//submenu
\t\t\t\t\t\t\t\tsubselected = null;
\t\t\t\t\t\t\t\tsubnodes = null;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t// menu
\t\t\t\t\t\t\t\tunHover();
\t\t\t\t\t\t\t\t(function(sel) {
\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\tif (sel === selected) {
\t\t\t\t\t\t\t\t\t\t\tselected = null;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}, 250);
\t\t\t\t\t\t\t\t})(selected);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('contextmenu', function(){return false;})
\t\t\t\t.on('mouseup', function() {
\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\tmenu.removeData('draged');
\t\t\t\t\t}, 100);
\t\t\t\t})
\t\t\t\t.draggable(dragOpt),
\t\t\tltr = fm.direction === 'ltr',
\t\t\tsubpos = ltr? 'left' : 'right',
\t\t\ttypes = Object.assign({}, fm.options.contextmenu),
\t\t\ttpl     = '<div class=\"'+cmItem+'{className}\"><span class=\"elfinder-button-icon {icon} elfinder-contextmenu-icon\"{style}></span><span>{label}</span></div>',
\t\t\titem = function(label, icon, callback, opts) {
\t\t\t\tvar className = '',
\t\t\t\t\tstyle = '',
\t\t\t\t\ticonClass = '',
\t\t\t\t\tv, pos;
\t\t\t\tif (opts) {
\t\t\t\t\tif (opts.className) {
\t\t\t\t\t\tclassName = ' ' + opts.className;
\t\t\t\t\t}
\t\t\t\t\tif (opts.iconClass) {
\t\t\t\t\t\ticonClass = opts.iconClass;
\t\t\t\t\t\ticon = '';
\t\t\t\t\t}
\t\t\t\t\tif (opts.iconImg) {
\t\t\t\t\t\tv = opts.iconImg.split(/ +/);
\t\t\t\t\t\tpos = v[1] && v[2]? fm.escape(v[1] + 'px ' + v[2] + 'px') : '';
\t\t\t\t\t\tstyle = ' style=\"background:url(\\''+fm.escape(v[0])+'\\') '+(pos? pos : '0 0')+' no-repeat;'+(pos? '' : 'posbackground-size:contain;')+'\"';
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn \$(tpl.replace('{icon}', icon ? 'elfinder-button-icon-'+icon : (iconClass? iconClass : ''))
\t\t\t\t\t\t.replace('{label}', label)
\t\t\t\t\t\t.replace('{style}', style)
\t\t\t\t\t\t.replace('{className}', className))
\t\t\t\t\t.on('click', function(e) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tcallback();
\t\t\t\t\t});
\t\t\t},
\t\t\turlIcon = function(iconUrl) {
\t\t\t\tvar v = iconUrl.split(/ +/),
\t\t\t\t\tpos = v[1] && v[2]? (v[1] + 'px ' + v[2] + 'px') : '';
\t\t\t\treturn {
\t\t\t\t\tbackgroundImage: 'url(\"'+v[0]+'\")',
\t\t\t\t\tbackgroundRepeat: 'no-repeat',
\t\t\t\t\tbackgroundPosition: pos? pos : '',
\t\t\t\t\tbackgroundSize: pos? '' : 'contain'
\t\t\t\t};
\t\t\t},
\t\t\tbase, cwd,
\t\t\tnodes, selected, subnodes, subselected, autoSyncStop, subHoverTm,

\t\t\tautoToggle = function() {
\t\t\t\tvar evTouchStart = 'touchstart.contextmenuAutoToggle';
\t\t\t\tmenu.data('hideTm') && clearTimeout(menu.data('hideTm'));
\t\t\t\tif (menu.is(':visible')) {
\t\t\t\t\tmenu.on('touchstart', function(e) {
\t\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\tmenu.stop();
\t\t\t\t\t\tfm.toFront(menu);
\t\t\t\t\t\tmenu.data('hideTm') && clearTimeout(menu.data('hideTm'));
\t\t\t\t\t})
\t\t\t\t\t.data('hideTm', setTimeout(function() {
\t\t\t\t\t\tif (menu.is(':visible')) {
\t\t\t\t\t\t\tcwd.find('.elfinder-cwd-file').off(evTouchStart);
\t\t\t\t\t\t\tcwd.find('.elfinder-cwd-file.ui-selected')
\t\t\t\t\t\t\t.one(evTouchStart, function(e) {
\t\t\t\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tvar tgt = \$(e.target);
\t\t\t\t\t\t\t\tif (menu.first().length && !tgt.is('input:checkbox') && !tgt.hasClass('elfinder-cwd-select')) {
\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t//e.preventDefault();
\t\t\t\t\t\t\t\t\topen(e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY);
\t\t\t\t\t\t\t\t\tcwd.data('longtap', true)
\t\t\t\t\t\t\t\t\ttgt.one('touchend', function() {
\t\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\t\tcwd.removeData('longtap');
\t\t\t\t\t\t\t\t\t\t}, 80);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tcwd.find('.elfinder-cwd-file').off(evTouchStart);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.one('unselect.'+fm.namespace, function() {
\t\t\t\t\t\t\t\tcwd.find('.elfinder-cwd-file').off(evTouchStart);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tmenu.fadeOut({
\t\t\t\t\t\t\t\tduration: 300,
\t\t\t\t\t\t\t\tfail: function() {
\t\t\t\t\t\t\t\t\tmenu.css('opacity', '1').show();
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\tdone: function() {
\t\t\t\t\t\t\t\t\tfm.toHide(menu);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}, 4500));
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tkeyEvts = function(e) {
\t\t\t\tvar code = e.keyCode,
\t\t\t\t\tESC = \$.ui.keyCode.ESCAPE,
\t\t\t\t\tENT = \$.ui.keyCode.ENTER,
\t\t\t\t\tLEFT = \$.ui.keyCode.LEFT,
\t\t\t\t\tRIGHT = \$.ui.keyCode.RIGHT,
\t\t\t\t\tUP = \$.ui.keyCode.UP,
\t\t\t\t\tDOWN = \$.ui.keyCode.DOWN,
\t\t\t\t\tsubent = fm.direction === 'ltr'? RIGHT : LEFT,
\t\t\t\t\tsublev = subent === RIGHT? LEFT : RIGHT;
\t\t\t\t
\t\t\t\tif (\$.inArray(code, [ESC, ENT, LEFT, RIGHT, UP, DOWN]) !== -1) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\tif (code == ESC || code === sublev) {
\t\t\t\t\t\tif (selected && subnodes && subselected) {
\t\t\t\t\t\t\tsubselected.trigger('mouseleave').trigger('submenuclose');
\t\t\t\t\t\t\tselected.addClass(cHover);
\t\t\t\t\t\t\tsubnodes = null;
\t\t\t\t\t\t\tsubselected = null;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcode == ESC && close();
\t\t\t\t\t\t}
\t\t\t\t\t} else if (code == UP || code == DOWN) {
\t\t\t\t\t\tif (subnodes) {
\t\t\t\t\t\t\tif (subselected) {
\t\t\t\t\t\t\t\tsubselected.trigger('mouseleave');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (code == DOWN && (! subselected || subnodes.length <= ++subnodes._cur)) {
\t\t\t\t\t\t\t\tsubnodes._cur = 0;
\t\t\t\t\t\t\t} else if (code == UP && (! subselected || --subnodes._cur < 0)) {
\t\t\t\t\t\t\t\tsubnodes._cur = subnodes.length - 1;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tsubselected = subnodes.eq(subnodes._cur).trigger('mouseenter');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tsubnodes = null;
\t\t\t\t\t\t\tif (selected) {
\t\t\t\t\t\t\t\tselected.trigger('mouseleave');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (code == DOWN && (! selected || nodes.length <= ++nodes._cur)) {
\t\t\t\t\t\t\t\tnodes._cur = 0;
\t\t\t\t\t\t\t} else if (code == UP && (! selected || --nodes._cur < 0)) {
\t\t\t\t\t\t\t\tnodes._cur = nodes.length - 1;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tselected = nodes.eq(nodes._cur).addClass(cHover);
\t\t\t\t\t\t}
\t\t\t\t\t} else if (selected && (code == ENT || code === subent)) {
\t\t\t\t\t\tif (selected.hasClass('elfinder-contextmenu-group')) {
\t\t\t\t\t\t\tif (subselected) {
\t\t\t\t\t\t\t\tcode == ENT && subselected.click();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tselected.trigger('mouseenter');
\t\t\t\t\t\t\t\tsubnodes = selected.find('div.'+smItem);
\t\t\t\t\t\t\t\tsubnodes._cur = 0;
\t\t\t\t\t\t\t\tsubselected = subnodes.first().addClass(cHover);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcode == ENT && selected.click();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\topen = function(x, y, css) {
\t\t\t\tvar width      = menu.outerWidth(),
\t\t\t\t\theight     = menu.outerHeight(),
\t\t\t\t\tbstyle     = base.attr('style'),
\t\t\t\t\tbpos       = base.offset(),
\t\t\t\t\tbwidth     = base.width(),
\t\t\t\t\tbheight    = base.height(),
\t\t\t\t\tmw         = fm.UA.Mobile? 40 : 2,
\t\t\t\t\tmh         = fm.UA.Mobile? 20 : 2,
\t\t\t\t\tx          = x - (bpos? bpos.left : 0),
\t\t\t\t\ty          = y - (bpos? bpos.top : 0),
\t\t\t\t\tcss        = Object.assign(css || {}, {
\t\t\t\t\t\ttop  : Math.max(0, y + mh + height < bheight ? y + mh : y - (y + height - bheight)),
\t\t\t\t\t\tleft : Math.max(0, (x < width + mw || x + mw + width < bwidth)? x + mw : x - mw - width),
\t\t\t\t\t\topacity : '1'
\t\t\t\t\t}),
\t\t\t\t\tevts;

\t\t\t\tautoSyncStop = true;
\t\t\t\tfm.autoSync('stop');
\t\t\t\tbase.width(bwidth);
\t\t\t\tmenu.stop().removeAttr('style').css(css);
\t\t\t\tfm.toFront(menu);
\t\t\t\tmenu.show();
\t\t\t\tbase.attr('style', bstyle);
\t\t\t\t
\t\t\t\tcss[subpos] = parseInt(menu.width());
\t\t\t\tmenu.find('.elfinder-contextmenu-sub').css(css);
\t\t\t\tif (fm.UA.iOS) {
\t\t\t\t\t\$('div.elfinder div.overflow-scrolling-touch').css('-webkit-overflow-scrolling', 'auto');
\t\t\t\t}
\t\t\t\t
\t\t\t\tselected = null;
\t\t\t\tsubnodes = null;
\t\t\t\tsubselected = null;
\t\t\t\t\$(document).on('keydown.' + fm.namespace, keyEvts);
\t\t\t\tevts = \$._data(document).events;
\t\t\t\tif (evts && evts.keydown) {
\t\t\t\t\tevts.keydown.unshift(evts.keydown.pop());
\t\t\t\t}
\t\t\t\t
\t\t\t\tfm.UA.Mobile && autoToggle();
\t\t\t\t
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tfm.getUI().one('click.' + fm.namespace, close);
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\tclose = function() {
\t\t\t\tfm.getUI().off('click.' + fm.namespace, close);
\t\t\t\t\$(document).off('keydown.' + fm.namespace, keyEvts);

\t\t\t\tcurrentType = currentTargets = null;
\t\t\t\t
\t\t\t\tif (menu.is(':visible') || menu.children().length) {
\t\t\t\t\tfm.toHide(menu.removeAttr('style').empty().removeData('submenuKeep'));
\t\t\t\t\ttry {
\t\t\t\t\t\tif (! menu.draggable('instance')) {
\t\t\t\t\t\t\tmenu.draggable(dragOpt);
\t\t\t\t\t\t}
\t\t\t\t\t} catch(e) {
\t\t\t\t\t\tif (! menu.hasClass('ui-draggable')) {
\t\t\t\t\t\t\tmenu.draggable(dragOpt);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (menu.data('prevNode')) {
\t\t\t\t\t\tmenu.data('prevNode').after(menu);
\t\t\t\t\t\tmenu.removeData('prevNode');
\t\t\t\t\t}
\t\t\t\t\tfm.trigger('closecontextmenu');
\t\t\t\t\tif (fm.UA.iOS) {
\t\t\t\t\t\t\$('div.elfinder div.overflow-scrolling-touch').css('-webkit-overflow-scrolling', 'touch');
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tautoSyncStop && fm.searchStatus.state < 1 && ! fm.searchStatus.ininc && fm.autoSync();
\t\t\t\tautoSyncStop = false;
\t\t\t},
\t\t\t
\t\t\tcreate = function(type, targets) {
\t\t\t\tvar sep    = false,
\t\t\t\t\tinsSep = false,
\t\t\t\t\tdisabled = [],
\t\t\t\t\tisCwd = type === 'cwd',
\t\t\t\t\tselcnt = 0,
\t\t\t\t\tcmdMap;

\t\t\t\tcurrentType = type;
\t\t\t\tcurrentTargets = targets;
\t\t\t\t
\t\t\t\t// get current uiCmdMap option
\t\t\t\tif (!(cmdMap = fm.option('uiCmdMap', isCwd? void(0) : targets[0]))) {
\t\t\t\t\tcmdMap = {};
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (!isCwd) {
\t\t\t\t\tdisabled = fm.getDisabledCmds(targets);
\t\t\t\t}
\t\t\t\t
\t\t\t\tselcnt = fm.selected().length;
\t\t\t\tif (selcnt > 1) {
\t\t\t\t\tmenu.append('<div class=\"ui-corner-top ui-widget-header elfinder-contextmenu-header\"><span>'
\t\t\t\t\t + fm.i18n('selectedItems', ''+selcnt)
\t\t\t\t\t + '</span></div>');
\t\t\t\t}
\t\t\t\t
\t\t\t\tnodes = \$();
\t\t\t\t\$.each(types[type]||[], function(i, name) {
\t\t\t\t\tvar cmd, cmdName, useMap, node, submenu, hover;
\t\t\t\t\t
\t\t\t\t\tif (name === '|') {
\t\t\t\t\t\tif (sep) {
\t\t\t\t\t\t\tinsSep = true;
\t\t\t\t\t\t}
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (cmdMap[name]) {
\t\t\t\t\t\tcmdName = cmdMap[name];
\t\t\t\t\t\tuseMap = true;
\t\t\t\t\t} else {
\t\t\t\t\t\tcmdName = name;
\t\t\t\t\t}
\t\t\t\t\tcmd = fm.getCommand(cmdName);

\t\t\t\t\tif (cmd && !isCwd && (!fm.searchStatus.state || !cmd.disableOnSearch)) {
\t\t\t\t\t\tcmd.__disabled = cmd._disabled;
\t\t\t\t\t\tcmd._disabled = !(cmd.alwaysEnabled || (fm._commands[cmdName] ? \$.inArray(name, disabled) === -1 && (!useMap || !disabled[cmdName]) : false));
\t\t\t\t\t\t\$.each(cmd.linkedCmds, function(i, n) {
\t\t\t\t\t\t\tvar c;
\t\t\t\t\t\t\tif (c = fm.getCommand(n)) {
\t\t\t\t\t\t\t\tc.__disabled = c._disabled;
\t\t\t\t\t\t\t\tc._disabled = !(c.alwaysEnabled || (fm._commands[n] ? !disabled[n] : false));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}

\t\t\t\t\tif (cmd && !cmd._disabled && cmd.getstate(targets) != -1) {
\t\t\t\t\t\tif (cmd.variants) {
\t\t\t\t\t\t\tif (!cmd.variants.length) {
\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tnode = item(cmd.title, cmd.className? cmd.className : cmd.name, function(){}, cmd.contextmenuOpts);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tsubmenu = \$('<div class=\"ui-front ui-corner-all elfinder-contextmenu-sub\"></div>')
\t\t\t\t\t\t\t\t.hide()
\t\t\t\t\t\t\t\t.css('max-height', fm.getUI().height() - 30)
\t\t\t\t\t\t\t\t.appendTo(node.append('<span class=\"elfinder-contextmenu-arrow\"></span>'));
\t\t\t\t\t\t\t
\t\t\t\t\t\t\thover = function(show){
\t\t\t\t\t\t\t\tif (! show) {
\t\t\t\t\t\t\t\t\tsubmenu.hide();
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tvar bstyle = base.attr('style');
\t\t\t\t\t\t\t\t\tbase.width(base.width());
\t\t\t\t\t\t\t\t\t// top: '-1000px' to prevent visible scrollbar of window with the elFinder option `height: '100%'`
\t\t\t\t\t\t\t\t\tsubmenu.css({ top: '-1000px', left: 'auto', right: 'auto' });
\t\t\t\t\t\t\t\t\tvar nodeOffset = node.offset(),
\t\t\t\t\t\t\t\t\t\tnodeleft   = nodeOffset.left,
\t\t\t\t\t\t\t\t\t\tnodetop    = nodeOffset.top,
\t\t\t\t\t\t\t\t\t\tnodewidth  = node.outerWidth(),
\t\t\t\t\t\t\t\t\t\twidth      = submenu.outerWidth(true),
\t\t\t\t\t\t\t\t\t\theight     = submenu.outerHeight(true),
\t\t\t\t\t\t\t\t\t\tbaseOffset = base.offset(),
\t\t\t\t\t\t\t\t\t\twwidth     = baseOffset.left + base.width(),
\t\t\t\t\t\t\t\t\t\twheight    = baseOffset.top + base.height(),
\t\t\t\t\t\t\t\t\t\tcltr       = ltr, 
\t\t\t\t\t\t\t\t\t\tx          = nodewidth,
\t\t\t\t\t\t\t\t\t\ty, over;
\t
\t\t\t\t\t\t\t\t\tif (ltr) {
\t\t\t\t\t\t\t\t\t\tover = (nodeleft + nodewidth + width) - wwidth;
\t\t\t\t\t\t\t\t\t\tif (over > 10) {
\t\t\t\t\t\t\t\t\t\t\tif (nodeleft > width - 5) {
\t\t\t\t\t\t\t\t\t\t\t\tx = x - 5;
\t\t\t\t\t\t\t\t\t\t\t\tcltr = false;
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tif (!fm.UA.Mobile) {
\t\t\t\t\t\t\t\t\t\t\t\t\tx = nodewidth - over;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tover = width - nodeleft;
\t\t\t\t\t\t\t\t\t\tif (over > 0) {
\t\t\t\t\t\t\t\t\t\t\tif ((nodeleft + nodewidth + width - 15) < wwidth) {
\t\t\t\t\t\t\t\t\t\t\t\tx = x - 5;
\t\t\t\t\t\t\t\t\t\t\t\tcltr = true;
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tif (!fm.UA.Mobile) {
\t\t\t\t\t\t\t\t\t\t\t\t\tx = nodewidth - over;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tover = (nodetop + 5 + height) - wheight;
\t\t\t\t\t\t\t\t\ty = (over > 0 && nodetop < wheight)? 5 - over : (over > 0? 30 - height : 5);
\t
\t\t\t\t\t\t\t\t\tmenu.find('.elfinder-contextmenu-sub:visible').hide();
\t\t\t\t\t\t\t\t\tsubmenu.css({
\t\t\t\t\t\t\t\t\t\ttop : y,
\t\t\t\t\t\t\t\t\t\tleft : cltr? x : 'auto',
\t\t\t\t\t\t\t\t\t\tright: cltr? 'auto' : x,
\t\t\t\t\t\t\t\t\t\toverflowY: 'auto'
\t\t\t\t\t\t\t\t\t}).show();
\t\t\t\t\t\t\t\t\tbase.attr('style', bstyle);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tnode.addClass('elfinder-contextmenu-group')
\t\t\t\t\t\t\t\t.on('mouseleave', '.elfinder-contextmenu-sub', function(e) {
\t\t\t\t\t\t\t\t\tif (! menu.data('draged')) {
\t\t\t\t\t\t\t\t\t\tmenu.removeData('submenuKeep');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('submenuclose', '.elfinder-contextmenu-sub', function(e) {
\t\t\t\t\t\t\t\t\thover(false);
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('click', '.'+smItem, function(e){
\t\t\t\t\t\t\t\t\tvar opts, \$this;
\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\tif (! menu.data('draged')) {
\t\t\t\t\t\t\t\t\t\t\$this = \$(this);
\t\t\t\t\t\t\t\t\t\tif (!cmd.keepContextmenu) {
\t\t\t\t\t\t\t\t\t\t\tmenu.hide();
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\$this.removeClass(cHover);
\t\t\t\t\t\t\t\t\t\t\tnode.addClass(cHover);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\topts = \$this.data('exec');
\t\t\t\t\t\t\t\t\t\tif (typeof opts === 'undefined') {
\t\t\t\t\t\t\t\t\t\t\topts = {};
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tif (typeof opts === 'object') {
\t\t\t\t\t\t\t\t\t\t\topts._userAction = true;
\t\t\t\t\t\t\t\t\t\t\topts._currentType = type;
\t\t\t\t\t\t\t\t\t\t\topts._currentNode = \$this;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t!cmd.keepContextmenu && close();
\t\t\t\t\t\t\t\t\t\tfm.exec(cmd.name, targets, opts);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('touchend', function(e) {
\t\t\t\t\t\t\t\t\tif (! menu.data('drag')) {
\t\t\t\t\t\t\t\t\t\thover(true);
\t\t\t\t\t\t\t\t\t\tmenu.data('submenuKeep', true);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('mouseenter mouseleave', function(e){
\t\t\t\t\t\t\t\t\tif (! menu.data('touching')) {
\t\t\t\t\t\t\t\t\t\tif (node.data('timer')) {
\t\t\t\t\t\t\t\t\t\t\tclearTimeout(node.data('timer'));
\t\t\t\t\t\t\t\t\t\t\tnode.removeData('timer');
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tif (!\$(e.target).closest('.elfinder-contextmenu-sub', menu).length) {
\t\t\t\t\t\t\t\t\t\t\tif (e.type === 'mouseleave') {
\t\t\t\t\t\t\t\t\t\t\t\tif (! menu.data('submenuKeep')) {
\t\t\t\t\t\t\t\t\t\t\t\t\tnode.data('timer', setTimeout(function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tnode.removeData('timer');
\t\t\t\t\t\t\t\t\t\t\t\t\t\thover(false);
\t\t\t\t\t\t\t\t\t\t\t\t\t}, 250));
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tnode.data('timer', setTimeout(function() {
\t\t\t\t\t\t\t\t\t\t\t\t\tnode.removeData('timer');
\t\t\t\t\t\t\t\t\t\t\t\t\thover(true);
\t\t\t\t\t\t\t\t\t\t\t\t}, nodes.find('div.elfinder-contextmenu-sub:visible').length? 250 : 0));
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\$.each(cmd.variants, function(i, variant) {
\t\t\t\t\t\t\t\tvar item = variant === '|' ? '<div class=\"elfinder-contextmenu-separator\"></div>' :
\t\t\t\t\t\t\t\t\t\$('<div class=\"'+cmItem+' '+smItem+'\"><span>'+variant[1]+'</span></div>').data('exec', variant[0]),
\t\t\t\t\t\t\t\t\ticonClass, icon;
\t\t\t\t\t\t\t\tif (typeof variant[2] !== 'undefined') {
\t\t\t\t\t\t\t\t\ticon = \$('<span></span>').addClass('elfinder-button-icon elfinder-contextmenu-icon');
\t\t\t\t\t\t\t\t\tif (! /\\//.test(variant[2])) {
\t\t\t\t\t\t\t\t\t\ticon.addClass('elfinder-button-icon-'+variant[2]);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\ticon.css(urlIcon(variant[2]));
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\titem.prepend(icon).addClass(smItem+'-icon');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tsubmenu.append(item);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tnode = item(cmd.title, cmd.className? cmd.className : cmd.name, function() {
\t\t\t\t\t\t\t\tif (! menu.data('draged')) {
\t\t\t\t\t\t\t\t\t!cmd.keepContextmenu && close();
\t\t\t\t\t\t\t\t\tfm.exec(cmd.name, targets, {_userAction: true, _currentType: type, _currentNode: node});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}, cmd.contextmenuOpts);
\t\t\t\t\t\t\tif (cmd.extra && cmd.extra.node) {
\t\t\t\t\t\t\t\t\$('<span class=\"elfinder-button-icon elfinder-button-icon-'+(cmd.extra.icon || '')+' '+exIcon+'\"></span>')
\t\t\t\t\t\t\t\t\t.append(cmd.extra.node).appendTo(node);
\t\t\t\t\t\t\t\t\$(cmd.extra.node).trigger('ready', {targets: targets});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tnode.remove('.'+exIcon);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (cmd.extendsCmd) {
\t\t\t\t\t\t\tnode.children('span.elfinder-button-icon').addClass('elfinder-button-icon-' + cmd.extendsCmd);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (insSep) {
\t\t\t\t\t\t\tmenu.append('<div class=\"elfinder-contextmenu-separator\"></div>');
\t\t\t\t\t\t}
\t\t\t\t\t\tmenu.append(node);
\t\t\t\t\t\tsep = true;
\t\t\t\t\t\tinsSep = false;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (cmd && typeof cmd.__disabled !== 'undefined') {
\t\t\t\t\t\tcmd._disabled = cmd.__disabled;
\t\t\t\t\t\tdelete cmd.__disabled;
\t\t\t\t\t\t\$.each(cmd.linkedCmds, function(i, n) {
\t\t\t\t\t\t\tvar c;
\t\t\t\t\t\t\tif (c = fm.getCommand(n)) {
\t\t\t\t\t\t\t\tc._disabled = c.__disabled;
\t\t\t\t\t\t\t\tdelete c.__disabled;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tnodes = menu.children('div.'+cmItem);
\t\t\t},
\t\t\t
\t\t\tcreateFromRaw = function(raw) {
\t\t\t\tcurrentType = 'raw';
\t\t\t\t\$.each(raw, function(i, data) {
\t\t\t\t\tvar node;
\t\t\t\t\t
\t\t\t\t\tif (data === '|') {
\t\t\t\t\t\tmenu.append('<div class=\"elfinder-contextmenu-separator\"></div>');
\t\t\t\t\t} else if (data.label && typeof data.callback == 'function') {
\t\t\t\t\t\tnode = item(data.label, data.icon, function() {
\t\t\t\t\t\t\tif (! menu.data('draged')) {
\t\t\t\t\t\t\t\t!data.remain && close();
\t\t\t\t\t\t\t\tdata.callback();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}, data.options || null);
\t\t\t\t\t\tmenu.append(node);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tnodes = menu.children('div.'+cmItem);
\t\t\t},
\t\t\t
\t\t\tcurrentType = null,
\t\t\tcurrentTargets = null;
\t\t
\t\tfm.one('load', function() {
\t\t\tbase = fm.getUI();
\t\t\tcwd = fm.getUI('cwd');
\t\t\tfm.bind('contextmenu', function(e) {
\t\t\t\tvar data = e.data,
\t\t\t\t\tcss = {},
\t\t\t\t\tprevNode;

\t\t\t\tif (data.type && data.type !== 'files') {
\t\t\t\t\tcwd.trigger('unselectall');
\t\t\t\t}
\t\t\t\tclose();

\t\t\t\tif (data.type && data.targets) {
\t\t\t\t\tfm.trigger('contextmenucreate', data);
\t\t\t\t\tcreate(data.type, data.targets);
\t\t\t\t\tfm.trigger('contextmenucreatedone', data);
\t\t\t\t} else if (data.raw) {
\t\t\t\t\tcreateFromRaw(data.raw);
\t\t\t\t}

\t\t\t\tif (menu.children().length) {
\t\t\t\t\tprevNode = data.prevNode || null;
\t\t\t\t\tif (prevNode) {
\t\t\t\t\t\tmenu.data('prevNode', menu.prev());
\t\t\t\t\t\tprevNode.after(menu);
\t\t\t\t\t}
\t\t\t\t\tif (data.fitHeight) {
\t\t\t\t\t\tcss = {maxHeight: Math.min(fm.getUI().height(), \$(window).height()), overflowY: 'auto'};
\t\t\t\t\t\tmenu.draggable('destroy').removeClass('ui-draggable');
\t\t\t\t\t}
\t\t\t\t\topen(data.x, data.y, css);
\t\t\t\t\t// call opened callback function
\t\t\t\t\tif (data.opened && typeof data.opened === 'function') {
\t\t\t\t\t\tdata.opened.call(menu);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t})
\t\t\t.one('destroy', function() { menu.remove(); })
\t\t\t.bind('disable', close)
\t\t\t.bind('select', function(e){
\t\t\t\t(currentType === 'files' && (!e.data || e.data.selected.toString() !== currentTargets.toString())) && close();
\t\t\t});
\t\t})
\t\t.shortcut({
\t\t\tpattern     : fm.OS === 'mac' ? 'ctrl+m' : 'contextmenu shift+f10',
\t\t\tdescription : 'contextmenu',
\t\t\tcallback    : function(e) {
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\t\$(document).one('contextmenu.' + fm.namespace, function(e) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t});
\t\t\t\tvar sel = fm.selected(),
\t\t\t\t\ttype, targets, pos, elm;
\t\t\t\t
\t\t\t\tif (sel.length) {
\t\t\t\t\ttype = 'files';
\t\t\t\t\ttargets = sel;
\t\t\t\t\telm = fm.cwdHash2Elm(sel[0]);
\t\t\t\t} else {
\t\t\t\t\ttype = 'cwd';
\t\t\t\t\ttargets = [ fm.cwd().hash ];
\t\t\t\t\tpos = fm.getUI('workzone').offset();
\t\t\t\t}
\t\t\t\tif (! elm || ! elm.length) {
\t\t\t\t\telm = fm.getUI('workzone');
\t\t\t\t}
\t\t\t\tpos = elm.offset();
\t\t\t\tpos.top += (elm.height() / 2);
\t\t\t\tpos.left += (elm.width() / 2);
\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t'type'    : type,
\t\t\t\t\t'targets' : targets,
\t\t\t\t\t'x'       : pos.left,
\t\t\t\t\t'y'       : pos.top
\t\t\t\t});
\t\t\t}
\t\t});
\t\t
\t});
\t
};


/*
 * File: /js/ui/cwd.js
 */

/**
 * elFinder current working directory ui.
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindercwd = function(fm, options) {
\t\tthis.not('.elfinder-cwd').each(function() {
\t\t// fm.time('cwdLoad');
\t\t
\t\tvar mobile = fm.UA.Mobile,
\t\t\tlist = fm.viewType == 'list',

\t\t\tundef = 'undefined',
\t\t\t/**
\t\t\t * Select event full name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tevtSelect = 'select.'+fm.namespace,
\t\t\t
\t\t\t/**
\t\t\t * Unselect event full name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tevtUnselect = 'unselect.'+fm.namespace,
\t\t\t
\t\t\t/**
\t\t\t * Disable event full name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tevtDisable = 'disable.'+fm.namespace,
\t\t\t
\t\t\t/**
\t\t\t * Disable event full name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tevtEnable = 'enable.'+fm.namespace,
\t\t\t
\t\t\tc = 'class',
\t\t\t/**
\t\t\t * File css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclFile       = fm.res(c, 'cwdfile'),
\t\t\t
\t\t\t/**
\t\t\t * Selected css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tfileSelector = '.'+clFile,
\t\t\t
\t\t\t/**
\t\t\t * Selected css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclSelected = 'ui-selected',
\t\t\t
\t\t\t/**
\t\t\t * Disabled css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclDisabled = fm.res(c, 'disabled'),
\t\t\t
\t\t\t/**
\t\t\t * Draggable css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclDraggable = fm.res(c, 'draggable'),
\t\t\t
\t\t\t/**
\t\t\t * Droppable css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclDroppable = fm.res(c, 'droppable'),
\t\t\t
\t\t\t/**
\t\t\t * Hover css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclHover     = fm.res(c, 'hover'),

\t\t\t/**
\t\t\t * Active css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclActive     = fm.res(c, 'active'),

\t\t\t/**
\t\t\t * Hover css class
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclDropActive = fm.res(c, 'adroppable'),

\t\t\t/**
\t\t\t * Css class for temporary nodes (for mkdir/mkfile) commands
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tclTmp = clFile+'-tmp',

\t\t\t/**
\t\t\t * Select checkbox css class
\t\t\t * 
\t\t\t * @type String
\t\t\t */
\t\t\tclSelChk = 'elfinder-cwd-selectchk',

\t\t\t/**
\t\t\t * Number of thumbnails to load in one request (new api only)
\t\t\t *
\t\t\t * @type Number
\t\t\t **/
\t\t\ttmbNum = fm.options.loadTmbs > 0 ? fm.options.loadTmbs : 5,
\t\t\t
\t\t\t/**
\t\t\t * Current search query.
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tquery = '',

\t\t\t/**
\t\t\t * Currect clipboard(cut) hashes as object key
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\tclipCuts = {},

\t\t\t/**
\t\t\t * Parents hashes of cwd
\t\t\t *
\t\t\t * @type Array
\t\t\t */
\t\t\tcwdParents = [],
\t\t\t
\t\t\t/**
\t\t\t * cwd current hashes
\t\t\t * 
\t\t\t * @type Array
\t\t\t */
\t\t\tcwdHashes = [],

\t\t\t/**
\t\t\t * incsearch current hashes
\t\t\t * 
\t\t\t * @type Array
\t\t\t */
\t\t\tincHashes = void 0,

\t\t\t/**
\t\t\t * Custom columns name and order
\t\t\t *
\t\t\t * @type Array
\t\t\t */
\t\t\tcustomCols = [],

\t\t\t/**
\t\t\t * Current clicked element id of first time for dblclick
\t\t\t * 
\t\t\t * @type String
\t\t\t */
\t\t\tcurClickId = '',

\t\t\t/**
\t\t\t * Custom columns builder
\t\t\t *
\t\t\t * @type Function
\t\t\t */
\t\t\tcustomColsBuild = function() {
\t\t\t\tvar cols = '';
\t\t\t\tfor (var i = 0; i < customCols.length; i++) {
\t\t\t\t\tcols += '<td class=\"elfinder-col-'+customCols[i]+'\">{' + customCols[i] + '}</td>';
\t\t\t\t}
\t\t\t\treturn cols;
\t\t\t},

\t\t\t/**
\t\t\t * Make template.row from customCols
\t\t\t *
\t\t\t * @type Function
\t\t\t */
\t\t\tmakeTemplateRow = function() {
\t\t\t\treturn '<tr id=\"{id}\" class=\"'+clFile+' {permsclass} {dirclass}\" title=\"{tooltip}\"{css}><td class=\"elfinder-col-name\"><div class=\"elfinder-cwd-file-wrapper\"><span class=\"elfinder-cwd-icon {mime}\"{style}></span>{marker}<span class=\"elfinder-cwd-filename\">{name}</span></div>'+selectCheckbox+'</td>'+customColsBuild()+'</tr>';
\t\t\t},
\t\t\t
\t\t\tselectCheckbox = (\$.map(options.showSelectCheckboxUA, function(t) {return (fm.UA[t] || t.match(/^all\$/i))? true : null;}).length)? '<div class=\"elfinder-cwd-select\"><input type=\"checkbox\" class=\"'+clSelChk+'\"></div>' : '',

\t\t\tcolResizing = false,
\t\t\t
\t\t\tcolWidth = null,

\t\t\t/**
\t\t\t * Table header height
\t\t\t */
\t\t\tthHeight,

\t\t\t/**
\t\t\t * File templates
\t\t\t *
\t\t\t * @type Object
\t\t\t **/
\t\t\ttemplates = {
\t\t\t\ticon : '<div id=\"{id}\" class=\"'+clFile+' {permsclass} {dirclass} ui-corner-all\" title=\"{tooltip}\"><div class=\"elfinder-cwd-file-wrapper ui-corner-all\"><div class=\"elfinder-cwd-icon {mime} ui-corner-all\" unselectable=\"on\"{style}></div>{marker}</div><div class=\"elfinder-cwd-filename\" title=\"{nametitle}\">{name}</div>'+selectCheckbox+'</div>',
\t\t\t\trow  : ''
\t\t\t},
\t\t\t
\t\t\tpermsTpl = fm.res('tpl', 'perms'),
\t\t\t
\t\t\tlockTpl = fm.res('tpl', 'lock'),
\t\t\t
\t\t\tsymlinkTpl = fm.res('tpl', 'symlink'),
\t\t\t
\t\t\t/**
\t\t\t * Template placeholders replacement rules
\t\t\t *
\t\t\t * @type Object
\t\t\t **/
\t\t\treplacement = {
\t\t\t\tid : function(f) {
\t\t\t\t\treturn fm.cwdHash2Id(f.hash);
\t\t\t\t},
\t\t\t\tname : function(f) {
\t\t\t\t\tvar name = fm.escape(f.i18 || f.name);
\t\t\t\t\t!list && (name = name.replace(/([_.])/g, '&#8203;\$1'));
\t\t\t\t\treturn name;
\t\t\t\t},
\t\t\t\tnametitle : function(f) {
\t\t\t\t\treturn fm.escape(f.i18 || f.name);
\t\t\t\t},
\t\t\t\tpermsclass : function(f) {
\t\t\t\t\treturn fm.perms2class(f);
\t\t\t\t},
\t\t\t\tperm : function(f) {
\t\t\t\t\treturn fm.formatPermissions(f);
\t\t\t\t},
\t\t\t\tdirclass : function(f) {
\t\t\t\t\tvar cName = f.mime == 'directory' ? 'directory' : '';
\t\t\t\t\tf.isroot && (cName += ' isroot');
\t\t\t\t\tf.csscls && (cName += ' ' + fm.escape(f.csscls));
\t\t\t\t\toptions.getClass && (cName += ' ' + options.getClass(f));
\t\t\t\t\treturn cName;
\t\t\t\t},
\t\t\t\tstyle : function(f) {
\t\t\t\t\treturn f.icon? fm.getIconStyle(f) : '';
\t\t\t\t},
\t\t\t\tmime : function(f) {
\t\t\t\t\tvar cName = fm.mime2class(f.mime);
\t\t\t\t\tf.icon && (cName += ' elfinder-cwd-bgurl');
\t\t\t\t\treturn cName;
\t\t\t\t},
\t\t\t\tsize : function(f) {
\t\t\t\t\treturn (f.mime === 'directory' && !f.size)? '-' : fm.formatSize(f.size);
\t\t\t\t},
\t\t\t\tdate : function(f) {
\t\t\t\t\treturn fm.formatDate(f);
\t\t\t\t},
\t\t\t\tkind : function(f) {
\t\t\t\t\treturn fm.mime2kind(f);
\t\t\t\t},
\t\t\t\tmode : function(f) {
\t\t\t\t\treturn f.perm? fm.formatFileMode(f.perm) : '';
\t\t\t\t},
\t\t\t\tmodestr : function(f) {
\t\t\t\t\treturn f.perm? fm.formatFileMode(f.perm, 'string') : '';
\t\t\t\t},
\t\t\t\tmodeoct : function(f) {
\t\t\t\t\treturn f.perm? fm.formatFileMode(f.perm, 'octal') : '';
\t\t\t\t},
\t\t\t\tmodeboth : function(f) {
\t\t\t\t\treturn f.perm? fm.formatFileMode(f.perm, 'both') : '';
\t\t\t\t},
\t\t\t\tmarker : function(f) {
\t\t\t\t\treturn (f.alias || f.mime == 'symlink-broken' ? symlinkTpl : '')+(!f.read || !f.write ? permsTpl : '')+(f.locked ? lockTpl : '');
\t\t\t\t},
\t\t\t\ttooltip : function(f) {
\t\t\t\t\tvar title = fm.formatDate(f) + (f.size > 0 ? ' ('+fm.formatSize(f.size)+')' : ''),
\t\t\t\t\t\tinfo  = '';
\t\t\t\t\tif (query && f.path) {
\t\t\t\t\t\tinfo = fm.escape(f.path.replace(/\\/[^\\/]*\$/, ''));
\t\t\t\t\t} else {
\t\t\t\t\t\tinfo = f.tooltip? fm.escape(f.tooltip).replace(/\\r/g, '&#13;') : '';
\t\t\t\t\t}
\t\t\t\t\tif (list) {
\t\t\t\t\t\tinfo += (info? '&#13;' : '') + fm.escape(f.i18 || f.name);
\t\t\t\t\t}
\t\t\t\t\treturn info? info + '&#13;' + title : title;
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Type badge CSS added flag
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\taddedBadges = {},
\t\t\t
\t\t\t/**
\t\t\t * Type badge style sheet element
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\taddBadgeStyleSheet,
\t\t\t
\t\t\t/**
\t\t\t * Add type badge CSS into 'head'
\t\t\t * 
\t\t\t * @type Fundtion
\t\t\t */
\t\t\taddBadgeStyle = function(mime, name) {
\t\t\t\tvar sel, ext, type;
\t\t\t\tif (mime && ! addedBadges[mime]) {
\t\t\t\t\tif (typeof addBadgeStyleSheet === 'undefined') {
\t\t\t\t\t\tif (\$('#elfinderAddBadgeStyle'+fm.namespace).length) {
\t\t\t\t\t\t\t\$('#elfinderAddBadgeStyle'+fm.namespace).remove();
\t\t\t\t\t\t}
\t\t\t\t\t\taddBadgeStyleSheet = \$('<style id=\"addBadgeStyle'+fm.namespace+'\"></style>').insertBefore(\$('head').children(':first')).get(0).sheet || null;
\t\t\t\t\t}
\t\t\t\t\tif (addBadgeStyleSheet) {
\t\t\t\t\t\tmime = mime.toLowerCase();
\t\t\t\t\t\ttype = mime.split('/');
\t\t\t\t\t\text = fm.escape(fm.mimeTypes[mime] || (name.replace(/.bac?k\$/i, '').match(/\\.([^.]+)\$/) || ['',''])[1]);
\t\t\t\t\t\tif (ext) {
\t\t\t\t\t\t\tsel = '.elfinder-cwd-icon-' + type[0].replace(/(\\.|\\+)/g, '-');
\t\t\t\t\t\t\tif (typeof type[1] !== 'undefined') {
\t\t\t\t\t\t\t\tsel += '.elfinder-cwd-icon-' + type[1].replace(/(\\.|\\+)/g, '-');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\taddBadgeStyleSheet.insertRule(sel + ':before{content:\"' + ext.toLowerCase() + '\"}', 0);
\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t}
\t\t\t\t\t\taddedBadges[mime] = true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Return file html
\t\t\t *
\t\t\t * @param  Object  file info
\t\t\t * @return String
\t\t\t **/
\t\t\titemhtml = function(f) {
\t\t\t\tf.mime && f.mime !== 'directory' && !addedBadges[f.mime] && addBadgeStyle(f.mime, f.name);
\t\t\t\treturn templates[list ? 'row' : 'icon']
\t\t\t\t\t\t.replace(/\\{([a-z0-9_]+)\\}/g, function(s, e) { 
\t\t\t\t\t\t\treturn replacement[e] ? replacement[e](f, fm) : (f[e] ? f[e] : ''); 
\t\t\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * jQueery node that will be selected next
\t\t\t * 
\t\t\t * @type Object jQuery node
\t\t\t */
\t\t\tselectedNext = \$(),
\t\t\t
\t\t\t/**
\t\t\t * Flag. Required for msie to avoid unselect files on dragstart
\t\t\t *
\t\t\t * @type Boolean
\t\t\t **/
\t\t\tselectLock = false,
\t\t\t
\t\t\t/**
\t\t\t * Move selection to prev/next file
\t\t\t *
\t\t\t * @param String  move direction
\t\t\t * @param Boolean append to current selection
\t\t\t * @return void
\t\t\t * @rise select\t\t\t
\t\t\t */
\t\t\tselect = function(keyCode, append) {
\t\t\t\tvar code     = \$.ui.keyCode,
\t\t\t\t\tprev     = keyCode == code.LEFT || keyCode == code.UP,
\t\t\t\t\tsel      = cwd.find('[id].'+clSelected),
\t\t\t\t\tselector = prev ? 'first:' : 'last',
\t\t\t\t\ts, n, sib, top, left;

\t\t\t\tfunction sibling(n, direction) {
\t\t\t\t\treturn n[direction+'All']('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):first');
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (sel.length) {
\t\t\t\t\ts = sel.filter(prev ? ':first' : ':last');
\t\t\t\t\tsib = sibling(s, prev ? 'prev' : 'next');
\t\t\t\t\t
\t\t\t\t\tif (!sib.length) {
\t\t\t\t\t\t// there is no sibling on required side - do not move selection
\t\t\t\t\t\tn = s;
\t\t\t\t\t} else if (list || keyCode == code.LEFT || keyCode == code.RIGHT) {
\t\t\t\t\t\t// find real prevoius file
\t\t\t\t\t\tn = sib;
\t\t\t\t\t} else {
\t\t\t\t\t\t// find up/down side file in icons view
\t\t\t\t\t\ttop = s.position().top;
\t\t\t\t\t\tleft = s.position().left;

\t\t\t\t\t\tn = s;
\t\t\t\t\t\tif (prev) {
\t\t\t\t\t\t\tdo {
\t\t\t\t\t\t\t\tn = n.prev('[id]');
\t\t\t\t\t\t\t} while (n.length && !(n.position().top < top && n.position().left <= left));

\t\t\t\t\t\t\tif (n.hasClass(clDisabled)) {
\t\t\t\t\t\t\t\tn = sibling(n, 'next');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdo {
\t\t\t\t\t\t\t\tn = n.next('[id]');
\t\t\t\t\t\t\t} while (n.length && !(n.position().top > top && n.position().left >= left));
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (n.hasClass(clDisabled)) {
\t\t\t\t\t\t\t\tn = sibling(n, 'prev');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t// there is row before last one - select last file
\t\t\t\t\t\t\tif (!n.length) {
\t\t\t\t\t\t\t\tsib = cwd.find('[id]:not(.'+clDisabled+'):last');
\t\t\t\t\t\t\t\tif (sib.position().top > top) {
\t\t\t\t\t\t\t\t\tn = sib;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t// !append && unselectAll();
\t\t\t\t} else {
\t\t\t\t\tif (selectedNext.length) {
\t\t\t\t\t\tn = prev? selectedNext.prev() : selectedNext;
\t\t\t\t\t} else {
\t\t\t\t\t\t// there are no selected file - select first/last one
\t\t\t\t\t\tn = cwd.find('[id]:not(.'+clDisabled+'):not(.elfinder-cwd-parent):'+(prev ? 'last' : 'first'));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (n && n.length && !n.hasClass('elfinder-cwd-parent')) {
\t\t\t\t\tif (s && append) {
\t\t\t\t\t\t// append new files to selected
\t\t\t\t\t\tn = s.add(s[prev ? 'prevUntil' : 'nextUntil']('#'+n.attr('id'))).add(n);
\t\t\t\t\t} else {
\t\t\t\t\t\t// unselect selected files
\t\t\t\t\t\tsel.trigger(evtUnselect);
\t\t\t\t\t}
\t\t\t\t\t// select file(s)
\t\t\t\t\tn.trigger(evtSelect);
\t\t\t\t\t// set its visible
\t\t\t\t\tscrollToView(n.filter(prev ? ':first' : ':last'));
\t\t\t\t\t// update cache/view
\t\t\t\t\ttrigger();
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tselectedFiles = {},
\t\t\t
\t\t\tselectFile = function(hash) {
\t\t\t\tfm.cwdHash2Elm(hash).trigger(evtSelect);
\t\t\t},
\t\t\t
\t\t\tallSelected = false,
\t\t\t
\t\t\tselectAll = function() {
\t\t\t\tvar phash = fm.cwd().hash;

\t\t\t\tselectCheckbox && selectAllCheckbox.find('input').prop('checked', true);
\t\t\t\tfm.lazy(function() {
\t\t\t\t\tvar files;
\t\t\t\t\tif (fm.maxTargets && (incHashes || cwdHashes).length > fm.maxTargets) {
\t\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\t\tfiles = \$.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null; });
\t\t\t\t\t\tfiles = files.slice(0, fm.maxTargets);
\t\t\t\t\t\tselectedFiles = {};
\t\t\t\t\t\t\$.each(files, function(i, v) {
\t\t\t\t\t\t\tselectedFiles[v.hash] = true;
\t\t\t\t\t\t\tfm.cwdHash2Elm(v.hash).trigger(evtSelect);
\t\t\t\t\t\t});
\t\t\t\t\t\tfm.toast({mode: 'warning', msg: fm.i18n(['errMaxTargets', fm.maxTargets])});
\t\t\t\t\t} else {
\t\t\t\t\t\tcwd.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').trigger(evtSelect);
\t\t\t\t\t\tselectedFiles = fm.arrayFlip(incHashes || cwdHashes, true);
\t\t\t\t\t}
\t\t\t\t\ttrigger();
\t\t\t\t\tselectCheckbox && selectAllCheckbox.data('pending', false);
\t\t\t\t}, 0, {repaint: true});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Unselect all files
\t\t\t *
\t\t\t * @param  Object  options
\t\t\t * @return void
\t\t\t */
\t\t\tunselectAll = function(opts) {
\t\t\t\tvar o = opts || {};
\t\t\t\tselectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
\t\t\t\tif (Object.keys(selectedFiles).length) {
\t\t\t\t\tselectLock = false;
\t\t\t\t\tselectedFiles = {};
\t\t\t\t\tcwd.find('[id].'+clSelected).trigger(evtUnselect);
\t\t\t\t\tselectCheckbox && cwd.find('input:checkbox.'+clSelChk).prop('checked', false);
\t\t\t\t}
\t\t\t\t!o.notrigger && trigger();
\t\t\t\tselectCheckbox && selectAllCheckbox.data('pending', false);
\t\t\t\tcwd.removeClass('elfinder-cwd-allselected');
\t\t\t},
\t\t\t
\t\t\tselectInvert = function() {
\t\t\t\tvar invHashes = {};
\t\t\t\tif (allSelected) {
\t\t\t\t\tunselectAll();
\t\t\t\t} else if (! Object.keys(selectedFiles).length) {
\t\t\t\t\tselectAll();
\t\t\t\t} else {
\t\t\t\t\t\$.each((incHashes || cwdHashes), function(i, h) {
\t\t\t\t\t\tvar itemNode = fm.cwdHash2Elm(h);
\t\t\t\t\t\tif (! selectedFiles[h]) {
\t\t\t\t\t\t\tinvHashes[h] = true;
\t\t\t\t\t\t\titemNode.length && itemNode.trigger(evtSelect);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\titemNode.length && itemNode.trigger(evtUnselect);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tselectedFiles = invHashes;
\t\t\t\t\ttrigger();
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Return selected files hashes list
\t\t\t *
\t\t\t * @return Array
\t\t\t */
\t\t\tselected = function() {
\t\t\t\treturn Object.keys(selectedFiles);
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Last selected node id
\t\t\t * 
\t\t\t * @type String|Void
\t\t\t */
\t\t\tlastSelect = void 0,
\t\t\t
\t\t\t/**
\t\t\t * Fire elfinder \"select\" event and pass selected files to it
\t\t\t *
\t\t\t * @return void
\t\t\t */
\t\t\ttrigger = function() {
\t\t\t\tvar selected = Object.keys(selectedFiles),
\t\t\t\t\topts = {
\t\t\t\t\t\tselected : selected,
\t\t\t\t\t\torigin : 'cwd'
\t\t\t\t\t};
\t\t\t\t
\t\t\t\tif (oldSchoolItem && (selected.length > 1 || selected[0] !== fm.cwdId2Hash(
\t\t\t\t\toldSchoolItem.attr('id'))) && oldSchoolItem.hasClass(clSelected)) {
\t\t\t\t\toldSchoolItem.trigger(evtUnselect);
\t\t\t\t}
\t\t\t\tallSelected = selected.length && (selected.length === (incHashes || cwdHashes).length) && (!fm.maxTargets || selected.length <= fm.maxTargets);
\t\t\t\tif (selectCheckbox) {
\t\t\t\t\tselectAllCheckbox.find('input').prop('checked', allSelected);
\t\t\t\t\tcwd[allSelected? 'addClass' : 'removeClass']('elfinder-cwd-allselected');
\t\t\t\t}
\t\t\t\tif (allSelected) {
\t\t\t\t\topts.selectall = true;
\t\t\t\t} else if (! selected.length) {
\t\t\t\t\topts.unselectall = true;
\t\t\t\t}
\t\t\t\tfm.trigger('select', opts);
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Scroll file to set it visible
\t\t\t *
\t\t\t * @param DOMElement  file/dir node
\t\t\t * @return void
\t\t\t */
\t\t\tscrollToView = function(o, blink) {
\t\t\t\tif (! o.length) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar ftop    = o.position().top,
\t\t\t\t\tfheight = o.outerHeight(true),
\t\t\t\t\twtop    = wrapper.scrollTop(),
\t\t\t\t\twheight = wrapper.get(0).clientHeight,
\t\t\t\t\tthheight = tableHeader? tableHeader.outerHeight(true) : 0;

\t\t\t\tif (ftop + thheight + fheight > wtop + wheight) {
\t\t\t\t\twrapper.scrollTop(parseInt(ftop + thheight + fheight - wheight));
\t\t\t\t} else if (ftop < wtop) {
\t\t\t\t\twrapper.scrollTop(ftop);
\t\t\t\t}
\t\t\t\tlist && wrapper.scrollLeft(0);
\t\t\t\t!!blink && fm.resources.blink(o, 'lookme');
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Files we get from server but not show yet
\t\t\t *
\t\t\t * @type Array
\t\t\t **/
\t\t\tbuffer = [],
\t\t\t
\t\t\t/**
\t\t\t * Extra data of buffer
\t\t\t *
\t\t\t * @type Object
\t\t\t **/
\t\t\tbufferExt = {},
\t\t\t
\t\t\t/**
\t\t\t * Return index of elements with required hash in buffer 
\t\t\t *
\t\t\t * @param String  file hash
\t\t\t * @return Number
\t\t\t */
\t\t\tindex = function(hash) {
\t\t\t\tvar l = buffer.length;
\t\t\t\t
\t\t\t\twhile (l--) {
\t\t\t\t\tif (buffer[l].hash == hash) {
\t\t\t\t\t\treturn l;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn -1;
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Scroll start event name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tscrollStartEvent = 'elfscrstart',
\t\t\t
\t\t\t/**
\t\t\t * Scroll stop event name
\t\t\t *
\t\t\t * @type String
\t\t\t **/
\t\t\tscrollEvent = 'elfscrstop',
\t\t\t
\t\t\tscrolling = false,
\t\t\t
\t\t\t/**
\t\t\t * jQuery UI selectable option
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\tselectableOption = {
\t\t\t\tdisabled   : true,
\t\t\t\tfilter     : '[id]:first',
\t\t\t\tstop       : trigger,
\t\t\t\tdelay      : 250,
\t\t\t\tappendTo   : 'body',
\t\t\t\tautoRefresh: false,
\t\t\t\tselected   : function(e, ui) { \$(ui.selected).trigger(evtSelect); },
\t\t\t\tunselected : function(e, ui) { \$(ui.unselected).trigger(evtUnselect); }
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * hashes of items displayed in current view
\t\t\t * 
\t\t\t * @type Object  ItemHash => DomId
\t\t\t */
\t\t\tinViewHashes = {},
\t\t\t
\t\t\t/**
\t\t\t * Processing when the current view is changed (On open, search, scroll, resize etc.)
\t\t\t * 
\t\t\t * @return void
\t\t\t */
\t\t\twrapperRepaint = function(init, recnt) {
\t\t\t\tif (!bufferExt.renderd) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar firstNode = (list? cwd.find('tbody:first') : cwd).children('[id]'+(options.oldSchool? ':not(.elfinder-cwd-parent)' : '')+':first');
\t\t\t\tif (!firstNode.length) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar selectable = cwd.data('selectable'),
\t\t\t\t\trec = (function() {
\t\t\t\t\t\tvar wos = wrapper.offset(),
\t\t\t\t\t\t\tww = wrapper.width(),
\t\t\t\t\t\t\tw = \$(window),
\t\t\t\t\t\t\tx = firstNode.width() / 2,
\t\t\t\t\t\t\tl = Math.min(wos.left - w.scrollLeft() + (fm.direction === 'ltr'? x : ww - x), wos.left + ww - 10),
\t\t\t\t\t\t\tt = wos.top - w.scrollTop() + 10 + (list? thHeight : 0);
\t\t\t\t\t\treturn {left: Math.max(0, Math.round(l)), top: Math.max(0, Math.round(t))};
\t\t\t\t\t})(),
\t\t\t\t\ttgt = init? firstNode : \$(document.elementFromPoint(rec.left , rec.top)),
\t\t\t\t\tids = {},
\t\t\t\t\ttmbs = {},
\t\t\t\t\tmulti = 5,
\t\t\t\t\tcnt = Math.ceil((bufferExt.hpi? Math.ceil((wz.data('rectangle').height / bufferExt.hpi) * 1.5) : showFiles) / multi),
\t\t\t\t\tchk = function() {
\t\t\t\t\t\tvar id, hash, file, i;
\t\t\t\t\t\tfor (i = 0; i < multi; i++) {
\t\t\t\t\t\t\tid = tgt.attr('id');
\t\t\t\t\t\t\tif (id) {
\t\t\t\t\t\t\t\tbufferExt.getTmbs = [];
\t\t\t\t\t\t\t\thash = fm.cwdId2Hash(id);
\t\t\t\t\t\t\t\tinViewHashes[hash] = id;
\t\t\t\t\t\t\t\t// for tmbs
\t\t\t\t\t\t\t\tif (bufferExt.attachTmbs[hash]) {
\t\t\t\t\t\t\t\t\ttmbs[hash] = bufferExt.attachTmbs[hash];
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t// for selectable
\t\t\t\t\t\t\t\tselectable && (ids[id] = true);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t// next node
\t\t\t\t\t\t\ttgt = tgt.next();
\t\t\t\t\t\t\tif (!tgt.length) {
\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tdone = function() {
\t\t\t\t\t\tvar idsArr;
\t\t\t\t\t\tif (cwd.data('selectable')) {
\t\t\t\t\t\t\tObject.assign(ids, selectedFiles);
\t\t\t\t\t\t\tidsArr = Object.keys(ids);
\t\t\t\t\t\t\tif (idsArr.length) {
\t\t\t\t\t\t\t\tselectableOption.filter = '#'+idsArr.join(', #');
\t\t\t\t\t\t\t\tcwd.selectable('enable').selectable('option', {filter : selectableOption.filter}).selectable('refresh');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (Object.keys(tmbs).length) {
\t\t\t\t\t\t\tbufferExt.getTmbs = [];
\t\t\t\t\t\t\tattachThumbnails(tmbs);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetTarget = function() {
\t\t\t\t\t\tif (!tgt.hasClass(clFile)) {
\t\t\t\t\t\t\ttgt = tgt.closest(fileSelector);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tarr, widget;
\t\t\t\t
\t\t\t\tinViewHashes = {};
\t\t\t\tselectable && cwd.selectable('option', 'disabled');
\t\t\t\t
\t\t\t\tif (tgt.length) {
\t\t\t\t\tif (!tgt.hasClass(clFile) && !tgt.closest(fileSelector).length) {
\t\t\t\t\t\t// dialog, serach button etc.
\t\t\t\t\t\twidget = fm.getUI().find('.ui-dialog:visible,.ui-widget:visible');
\t\t\t\t\t\tif (widget.length) {
\t\t\t\t\t\t\twidget.hide();
\t\t\t\t\t\t\ttgt = \$(document.elementFromPoint(rec.left , rec.top));
\t\t\t\t\t\t\twidget.show();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\twidget = null;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tsetTarget();
\t\t\t\t\tif (!tgt.length) {
\t\t\t\t\t\t// try search 5px down
\t\t\t\t\t\twidget && widget.hide();
\t\t\t\t\t\ttgt = \$(document.elementFromPoint(rec.left , rec.top + 5));
\t\t\t\t\t\twidget && widget.show();
\t\t\t\t\t\tsetTarget();
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tif (tgt.length) {
\t\t\t\t\tif (tgt.attr('id')) {
\t\t\t\t\t\tif (init) {
\t\t\t\t\t\t\tfor (var i = 0; i < cnt; i++) {
\t\t\t\t\t\t\t\tchk();
\t\t\t\t\t\t\t\tif (! tgt.length) {
\t\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdone();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tbufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
\t\t\t\t\t\t\tarr = new Array(cnt);
\t\t\t\t\t\t\tbufferExt.repaintJob = fm.asyncJob(function() {
\t\t\t\t\t\t\t\tchk();
\t\t\t\t\t\t\t\tif (! tgt.length) {
\t\t\t\t\t\t\t\t\tdone();
\t\t\t\t\t\t\t\t\tbufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}, arr).done(done);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else if (init && bufferExt.renderd) {
\t\t\t\t\t// In initial request, cwd DOM not renderd so doing lazy check
\t\t\t\t\trecnt = recnt || 0;
\t\t\t\t\tif (recnt < 10) { // Prevent infinite loop
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\twrapperRepaint(init, ++recnt);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Item node of oldScholl \"..\"
\t\t\t */
\t\t\toldSchoolItem = null,

\t\t\t/**
\t\t\t * display parent folder with \"..\" name
\t\t\t * 
\t\t\t * @param  String  phash
\t\t\t * @return void
\t\t\t */
\t\t\toldSchool = function(p) {
\t\t\t\tvar phash = fm.cwd().phash,
\t\t\t\t\tpdir  = fm.file(phash) || null,
\t\t\t\t\tset   = function(pdir) {
\t\t\t\t\t\tif (pdir) {
\t\t\t\t\t\t\toldSchoolItem = \$(itemhtml(\$.extend(true, {}, pdir, {name : '..', i18 : '..', mime : 'directory'})))
\t\t\t\t\t\t\t\t.addClass('elfinder-cwd-parent')
\t\t\t\t\t\t\t\t.on('dblclick', function() {
\t\t\t\t\t\t\t\t\tfm.trigger('select', {selected : [phash]}).exec('open', phash);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t(list ? oldSchoolItem.children('td:first') : oldSchoolItem).children('.elfinder-cwd-select').remove();
\t\t\t\t\t\t\tif (fm.cwdHash2Elm(phash).length) {
\t\t\t\t\t\t\t\tfm.cwdHash2Elm(phash).replaceWith(oldSchoolItem);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t(list ? cwd.find('tbody') : cwd).prepend(oldSchoolItem);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tfm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
\t\t\t\t\t\t}
\t\t\t\t\t};
\t\t\t\tif (pdir) {
\t\t\t\t\tset(pdir);
\t\t\t\t} else {
\t\t\t\t\tset({hash: phash, read: true, write: true});
\t\t\t\t\tif (fm.getUI('tree').length) {
\t\t\t\t\t\tfm.one('parents', function() {
\t\t\t\t\t\t\tset(fm.file(phash) || null);
\t\t\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\tdata : {cmd : 'parents', target : fm.cwd().hash},
\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t})
\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\tset(fm.file(phash) || null);
\t\t\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tshowFiles = fm.options.showFiles,
\t\t\t
\t\t\t/**
\t\t\t * Cwd scroll event handler.
\t\t\t * Lazy load - append to cwd not shown files
\t\t\t *
\t\t\t * @return void
\t\t\t */
\t\t\trender = function() {
\t\t\t\tif (bufferExt.rendering || (bufferExt.renderd && ! buffer.length)) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar place = (list ? cwd.children('table').children('tbody') : cwd),
\t\t\t\t\tphash,
\t\t\t\t\tchk,
\t\t\t\t\t// created document fragment for jQuery >= 1.12, 2.2, 3.0
\t\t\t\t\t// see Studio-42/elFinder#1544 @ github
\t\t\t\t\tdocFlag = \$.htmlPrefilter? true : false,
\t\t\t\t\ttempDom = docFlag? \$(document.createDocumentFragment()) : \$('<div></div>'),
\t\t\t\t\tgo      = function(o){
\t\t\t\t\t\tvar over  = o || null,
\t\t\t\t\t\t\thtml  = [],
\t\t\t\t\t\t\tdirs  = false,
\t\t\t\t\t\t\tatmb  = {},
\t\t\t\t\t\t\tstmb  = (fm.option('tmbUrl') === 'self'),
\t\t\t\t\t\t\tinit  = bufferExt.renderd? false : true,
\t\t\t\t\t\t\tfiles, locks, selected;
\t\t\t\t\t\t
\t\t\t\t\t\tfiles = buffer.splice(0, showFiles + (over || 0) / (bufferExt.hpi || 1));
\t\t\t\t\t\tbufferExt.renderd += files.length;
\t\t\t\t\t\tif (! buffer.length) {
\t\t\t\t\t\t\tbottomMarker.hide();
\t\t\t\t\t\t\twrapper.off(scrollEvent, render);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tlocks = [];
\t\t\t\t\t\thtml = \$.map(files, function(f) {
\t\t\t\t\t\t\tif (f.hash && f.name) {
\t\t\t\t\t\t\t\tif (f.mime == 'directory') {
\t\t\t\t\t\t\t\t\tdirs = true;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif ((f.tmb && (f.tmb != 1 || f.size > 0)) || (stmb && f.mime.indexOf('image/') === 0)) {
\t\t\t\t\t\t\t\t\tatmb[f.hash] = f.tmb || 'self';
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tclipCuts[f.hash] && locks.push(f.hash);
\t\t\t\t\t\t\t\treturn itemhtml(f);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\treturn null;
\t\t\t\t\t\t});

\t\t\t\t\t\t// html into temp node
\t\t\t\t\t\ttempDom.empty().append(html.join(''));
\t\t\t\t\t\t
\t\t\t\t\t\t// make directory droppable
\t\t\t\t\t\tdirs && !mobile && makeDroppable(tempDom);
\t\t\t\t\t\t
\t\t\t\t\t\t// check selected items
\t\t\t\t\t\tselected = [];
\t\t\t\t\t\tif (Object.keys(selectedFiles).length) {
\t\t\t\t\t\t\ttempDom.find('[id]:not(.'+clSelected+'):not(.elfinder-cwd-parent)').each(function() {
\t\t\t\t\t\t\t\tselectedFiles[fm.cwdId2Hash(this.id)] && selected.push(\$(this));
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// append to cwd
\t\t\t\t\t\tplace.append(docFlag? tempDom : tempDom.children());
\t\t\t\t\t\t
\t\t\t\t\t\t// trigger select
\t\t\t\t\t\tif (selected.length) {
\t\t\t\t\t\t\t\$.each(selected, function(i, n) { n.trigger(evtSelect); });
\t\t\t\t\t\t\ttrigger();
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tlocks.length && fm.trigger('lockfiles', {files: locks});
\t\t\t\t\t\t!bufferExt.hpi && bottomMarkerShow(place, files.length);
\t\t\t\t\t\t
\t\t\t\t\t\tif (list) {
\t\t\t\t\t\t\t// show thead
\t\t\t\t\t\t\tcwd.find('thead').show();
\t\t\t\t\t\t\t// fixed table header
\t\t\t\t\t\t\tfixTableHeader({fitWidth: ! colWidth});
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (Object.keys(atmb).length) {
\t\t\t\t\t\t\tObject.assign(bufferExt.attachTmbs, atmb);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (init) {
\t\t\t\t\t\t\tif (! mobile && ! cwd.data('selectable')) {
\t\t\t\t\t\t\t\t// make files selectable
\t\t\t\t\t\t\t\tcwd.selectable(selectableOption).data('selectable', true);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}

\t\t\t\t\t\t! scrolling && wrapper.trigger(scrollEvent);
\t\t\t\t\t};
\t\t\t\t
\t\t\t\tif (! bufferExt.renderd) {
\t\t\t\t\t// first time to go()
\t\t\t\t\tbufferExt.rendering = true;
\t\t\t\t\t// scroll top on dir load to avoid scroll after page reload
\t\t\t\t\twrapper.scrollTop(0);
\t\t\t\t\tphash = fm.cwd().phash;
\t\t\t\t\tgo();
\t\t\t\t\tif (options.oldSchool) {
\t\t\t\t\t\tif (phash && !query) {
\t\t\t\t\t\t\toldSchool(phash);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\toldSchoolItem = \$();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (list) {
\t\t\t\t\t\tcolWidth && setColwidth();
\t\t\t\t\t\tfixTableHeader({fitWidth: true});
\t\t\t\t\t}
\t\t\t\t\tbufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
\t\t\t\t\tfm.trigger('cwdrender');
\t\t\t\t\tbufferExt.rendering = false;
\t\t\t\t\twrapperRepaint(true);
\t\t\t\t}
\t\t\t\tif (! bufferExt.rendering && buffer.length) {
\t\t\t\t\t// next go()
\t\t\t\t\tif ((chk = (wrapper.height() + wrapper.scrollTop() + fm.options.showThreshold + bufferExt.row) - (bufferExt.renderd * bufferExt.hpi)) > 0) {
\t\t\t\t\t\tbufferExt.rendering = true;
\t\t\t\t\t\tfm.lazy(function() {
\t\t\t\t\t\t\tgo(chk);
\t\t\t\t\t\t\tbufferExt.rendering = false;
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\t!fm.enabled() && resize();
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tresize();
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t// fixed table header jQuery object
\t\t\ttableHeader = null,

\t\t\t// Is UA support CSS sticky
\t\t\tcssSticky = fm.UA.CSS.positionSticky && fm.UA.CSS.widthMaxContent,
\t\t\t
\t\t\t// To fixed table header colmun
\t\t\tfixTableHeader = function(optsArg) {
\t\t\t\tthHeight = 0;
\t\t\t\tif (! options.listView.fixedHeader) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar setPos = function() {
\t\t\t\t\tvar val, pos;
\t\t\t\t\tpos = (fm.direction === 'ltr')? 'left' : 'right';
\t\t\t\t\tval = ((fm.direction === 'ltr')? wrapper.scrollLeft() : table.outerWidth(true) - wrapper.width() - wrapper.scrollLeft()) * -1;
\t\t\t\t\tif (base.css(pos) !== val) {
\t\t\t\t\t\tbase.css(pos, val);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\topts = optsArg || {},
\t\t\t\tcnt, base, table, htable, thead, tbody, hheight, htr, btr, htd, btd, htw, btw, init;
\t\t\t\t
\t\t\t\ttbody = cwd.find('tbody');
\t\t\t\tbtr = tbody.children('tr:first');
\t\t\t\tif (btr.length && btr.is(':visible')) {
\t\t\t\t\ttable = tbody.parent();
\t\t\t\t\tif (! tableHeader) {
\t\t\t\t\t\tinit = true;
\t\t\t\t\t\ttbody.addClass('elfinder-cwd-fixheader');
\t\t\t\t\t\tthead = cwd.find('thead').attr('id', fm.namespace+'-cwd-thead');
\t\t\t\t\t\thtr = thead.children('tr:first');
\t\t\t\t\t\thheight = htr.outerHeight(true);
\t\t\t\t\t\tcwd.css('margin-top', hheight - parseInt(table.css('padding-top')));
\t\t\t\t\t\tif (cssSticky) {
\t\t\t\t\t\t\ttableHeader = \$('<div class=\"elfinder-table-header-sticky\"></div>').addClass(cwd.attr('class')).append(\$('<table></table>').append(thead));
\t\t\t\t\t\t\tcwd.after(tableHeader);
\t\t\t\t\t\t\twrapper.on('resize.fixheader', function(e) {
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\tfixTableHeader({fitWidth: true});
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tbase = \$('<div></div>').addClass(cwd.attr('class')).append(\$('<table></table>').append(thead));
\t\t\t\t\t\t\ttableHeader = \$('<div></div>').addClass(wrapper.attr('class') + ' elfinder-cwd-fixheader')
\t\t\t\t\t\t\t\t.removeClass('ui-droppable native-droppable')
\t\t\t\t\t\t\t\t.css(wrapper.position())
\t\t\t\t\t\t\t\t.css({ height: hheight, width: cwd.outerWidth() })
\t\t\t\t\t\t\t\t.append(base);
\t\t\t\t\t\t\tif (fm.direction === 'rtl') {
\t\t\t\t\t\t\t\ttableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tsetPos();
\t\t\t\t\t\t\twrapper.after(tableHeader)
\t\t\t\t\t\t\t\t.on('scroll.fixheader resize.fixheader', function(e) {
\t\t\t\t\t\t\t\t\tsetPos();
\t\t\t\t\t\t\t\t\tif (e.type === 'resize') {
\t\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t\ttableHeader.css(wrapper.position());
\t\t\t\t\t\t\t\t\t\twrapper.data('width', wrapper.css('overflow', 'hidden').width());
\t\t\t\t\t\t\t\t\t\twrapper.css('overflow', 'auto');
\t\t\t\t\t\t\t\t\t\tfixTableHeader();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tthead = \$('#'+fm.namespace+'-cwd-thead');
\t\t\t\t\t\thtr = thead.children('tr:first');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (init || opts.fitWidth || Math.abs(btr.outerWidth() - htr.outerWidth()) > 2) {
\t\t\t\t\t\tcnt = customCols.length + 1;
\t\t\t\t\t\tfor (var i = 0; i < cnt; i++) {
\t\t\t\t\t\t\thtd = htr.children('td:eq('+i+')');
\t\t\t\t\t\t\tbtd = btr.children('td:eq('+i+')');
\t\t\t\t\t\t\thtw = htd.width();
\t\t\t\t\t\t\tbtw = btd.width();
\t\t\t\t\t\t\tif (typeof htd.data('delta') === 'undefined') {
\t\t\t\t\t\t\t\thtd.data('delta', (htd.outerWidth() - htw) - (btd.outerWidth() - btw));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tbtw -= htd.data('delta');
\t\t\t\t\t\t\tif (! init && ! opts.fitWidth && htw === btw) {
\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\thtd.css('width', btw + 'px');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!cssSticky) {
\t\t\t\t\t\ttableHeader.data('widthTimer') && cancelAnimationFrame(tableHeader.data('widthTimer'));
\t\t\t\t\t\ttableHeader.data('widthTimer', requestAnimationFrame(function() {
\t\t\t\t\t\t\tif (tableHeader) {
\t\t\t\t\t\t\t\ttableHeader.css('width', mBoard.width() + 'px');
\t\t\t\t\t\t\t\tif (fm.direction === 'rtl') {
\t\t\t\t\t\t\t\t\ttableHeader.css('left', (wrapper.data('width') - wrapper.width()) + 'px');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}));
\t\t\t\t\t}
\t\t\t\t\tthHeight = thead.height();
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t// Set colmun width
\t\t\tsetColwidth = function() {
\t\t\t\tif (list && colWidth) {
\t\t\t\t\tvar cl = 'elfinder-cwd-colwidth',
\t\t\t\t\tfirst = cwd.find('tr[id]:first'),
\t\t\t\t\tformer;
\t\t\t\t\tif (! first.hasClass(cl)) {
\t\t\t\t\t\tformer = cwd.find('tr.'+cl);
\t\t\t\t\t\tformer.removeClass(cl).find('td').css('width', '');
\t\t\t\t\t\tfirst.addClass(cl);
\t\t\t\t\t\tcwd.find('table:first').css('table-layout', 'fixed');
\t\t\t\t\t\t\$.each(\$.merge(['name'], customCols), function(i, k) {
\t\t\t\t\t\t\tvar w = colWidth[k] || first.find('td.elfinder-col-'+k).width();
\t\t\t\t\t\t\tfirst.find('td.elfinder-col-'+k).width(w);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Droppable options for cwd.
\t\t\t * Drop target is `wrapper`
\t\t\t * Do not add class on childs file over
\t\t\t *
\t\t\t * @type Object
\t\t\t */
\t\t\tdroppable = Object.assign({}, fm.droppable, {
\t\t\t\tover : function(e, ui) {
\t\t\t\t\tvar dst    = \$(this),
\t\t\t\t\t\thelper = ui.helper,
\t\t\t\t\t\tctr    = (e.shiftKey || e.ctrlKey || e.metaKey),
\t\t\t\t\t\thash, status, inParent;
\t\t\t\t\te.stopPropagation();
\t\t\t\t\thelper.data('dropover', helper.data('dropover') + 1);
\t\t\t\t\tdst.data('dropover', true);
\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\tif (helper.data('namespace') !== fm.namespace || ! fm.insideWorkzone(e.pageX, e.pageY)) {
\t\t\t\t\t\tdst.removeClass(clDropActive);
\t\t\t\t\t\t//helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tif (dst.hasClass(fm.res(c, 'cwdfile'))) {
\t\t\t\t\t\thash = fm.cwdId2Hash(dst.attr('id'));
\t\t\t\t\t\tdst.data('dropover', hash);
\t\t\t\t\t} else {
\t\t\t\t\t\thash = fm.cwd().hash;
\t\t\t\t\t\tfm.cwd().write && dst.data('dropover', hash);
\t\t\t\t\t}
\t\t\t\t\tinParent = (fm.file(helper.data('files')[0]).phash === hash);
\t\t\t\t\tif (dst.data('dropover') === hash) {
\t\t\t\t\t\t\$.each(helper.data('files'), function(i, h) {
\t\t\t\t\t\t\tif (h === hash || (inParent && !ctr && !helper.hasClass('elfinder-drag-helper-plus'))) {
\t\t\t\t\t\t\t\tdst.removeClass(clDropActive);
\t\t\t\t\t\t\t\treturn false; // break \$.each
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdst.removeClass(clDropActive);
\t\t\t\t\t}
\t\t\t\t\tif (helper.data('locked') || inParent) {
\t\t\t\t\t\tstatus = 'elfinder-drag-helper-plus';
\t\t\t\t\t} else {
\t\t\t\t\t\tstatus = 'elfinder-drag-helper-move';
\t\t\t\t\t\tif (ctr) {
\t\t\t\t\t\t\tstatus += ' elfinder-drag-helper-plus';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tdst.hasClass(clDropActive) && helper.addClass(status);
\t\t\t\t\trequestAnimationFrame(function(){ dst.hasClass(clDropActive) && helper.addClass(status); });
\t\t\t\t},
\t\t\t\tout : function(e, ui) {
\t\t\t\t\tvar helper = ui.helper;
\t\t\t\t\te.stopPropagation();
\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
\t\t\t\t\t\$(this).removeData('dropover')
\t\t\t\t\t       .removeClass(clDropActive);
\t\t\t\t},
\t\t\t\tdeactivate : function() {
\t\t\t\t\t\$(this).removeData('dropover')
\t\t\t\t\t       .removeClass(clDropActive);
\t\t\t\t},
\t\t\t\tdrop : function(e, ui) {
\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\tfm.droppable.drop.call(this, e, ui);
\t\t\t\t}
\t\t\t}),
\t\t\t
\t\t\t/**
\t\t\t * Make directory droppable
\t\t\t *
\t\t\t * @return void
\t\t\t */
\t\t\tmakeDroppable = function(place) {
\t\t\t\tplace = place? place : (list ? cwd.find('tbody') : cwd);
\t\t\t\tvar targets = place.children('.directory:not(.'+clDroppable+',.elfinder-na,.elfinder-ro)');

\t\t\t\tif (fm.isCommandEnabled('paste')) {
\t\t\t\t\ttargets.droppable(droppable);
\t\t\t\t}
\t\t\t\tif (fm.isCommandEnabled('upload')) {
\t\t\t\t\ttargets.addClass('native-droppable');
\t\t\t\t}
\t\t\t\t
\t\t\t\tplace.children('.isroot').each(function(i, n) {
\t\t\t\t\tvar \$n   = \$(n),
\t\t\t\t\t\thash = fm.cwdId2Hash(n.id);
\t\t\t\t\t
\t\t\t\t\tif (fm.isCommandEnabled('paste', hash)) {
\t\t\t\t\t\tif (! \$n.hasClass(clDroppable+',elfinder-na,elfinder-ro')) {
\t\t\t\t\t\t\t\$n.droppable(droppable);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (\$n.hasClass(clDroppable)) {
\t\t\t\t\t\t\t\$n.droppable('destroy');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (fm.isCommandEnabled('upload', hash)) {
\t\t\t\t\t\tif (! \$n.hasClass('native-droppable,elfinder-na,elfinder-ro')) {
\t\t\t\t\t\t\t\$n.addClass('native-droppable');
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (\$n.hasClass('native-droppable')) {
\t\t\t\t\t\t\t\$n.removeClass('native-droppable');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Preload required thumbnails and on load add css to files.
\t\t\t * Return false if required file is not visible yet (in buffer) -
\t\t\t * required for old api to stop loading thumbnails.
\t\t\t *
\t\t\t * @param  Object  file hash -> thumbnail map
\t\t\t * @param  Bool    reload
\t\t\t * @return void
\t\t\t */
\t\t\tattachThumbnails = function(tmbs, reload) {
\t\t\t\tvar attach = function(node, tmb) {
\t\t\t\t\t\t\$('<img/>')
\t\t\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\t\t\tnode.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\");
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.attr('src', tmb.url);
\t\t\t\t\t},
\t\t\t\t\tchk  = function(hash, tmb) {
\t\t\t\t\t\tvar node = fm.cwdHash2Elm(hash),
\t\t\t\t\t\t\tfile, tmbObj, reloads = [];
\t
\t\t\t\t\t\tif (node.length) {
\t\t\t\t\t\t\tif (tmb != '1') {
\t\t\t\t\t\t\t\tfile = fm.file(hash);
\t\t\t\t\t\t\t\tif (file.tmb !== tmb) {
\t\t\t\t\t\t\t\t\tfile.tmb = tmb;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\ttmbObj = fm.tmb(file);
\t\t\t\t\t\t\t\tif (reload) {
\t\t\t\t\t\t\t\t\tnode.find('.elfinder-cwd-icon').addClass(tmbObj.className).css('background-image', \"url('\"+tmbObj.url+\"')\");
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tattach(node, tmbObj);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdelete bufferExt.attachTmbs[hash];
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (reload) {
\t\t\t\t\t\t\t\t\tloadThumbnails([hash]);
\t\t\t\t\t\t\t\t} else if (! bufferExt.tmbLoading[hash]) {
\t\t\t\t\t\t\t\t\tbufferExt.getTmbs.push(hash);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t};

\t\t\t\tif (\$.isPlainObject(tmbs) && Object.keys(tmbs).length) {
\t\t\t\t\tObject.assign(bufferExt.attachTmbs, tmbs);
\t\t\t\t\t\$.each(tmbs, chk);
\t\t\t\t\tif (! reload && bufferExt.getTmbs.length && ! Object.keys(bufferExt.tmbLoading).length) {
\t\t\t\t\t\tloadThumbnails();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Load thumbnails from backend.
\t\t\t *
\t\t\t * @param  Array|void reloads  hashes list for reload thumbnail items
\t\t\t * @return void
\t\t\t */
\t\t\tloadThumbnails = function(reloads) {
\t\t\t\tvar tmbs = [],
\t\t\t\t\treload = false;
\t\t\t\t
\t\t\t\tif (fm.oldAPI) {
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'tmb', current : fm.cwd().hash},
\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tif (data.images && Object.keys(data.images).length) {
\t\t\t\t\t\t\tattachThumbnails(data.images);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (data.tmb) {
\t\t\t\t\t\t\tloadThumbnails();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\treturn;
\t\t\t\t} 

\t\t\t\tif (reloads) {
\t\t\t\t\treload = true;
\t\t\t\t\ttmbs = reloads.splice(0, tmbNum);
\t\t\t\t} else {
\t\t\t\t\ttmbs = bufferExt.getTmbs.splice(0, tmbNum);
\t\t\t\t}
\t\t\t\tif (tmbs.length) {
\t\t\t\t\tif (reload || inViewHashes[tmbs[0]] || inViewHashes[tmbs[tmbs.length-1]]) {
\t\t\t\t\t\t\$.each(tmbs, function(i, h) {
\t\t\t\t\t\t\tbufferExt.tmbLoading[h] = true;
\t\t\t\t\t\t});
\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\tdata : {cmd : 'tmb', targets : tmbs},
\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t})
\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\tvar errs = [],
\t\t\t\t\t\t\t\tresLen;
\t\t\t\t\t\t\tif (data.images) {
\t\t\t\t\t\t\t\tif (resLen = Object.keys(data.images).length) {
\t\t\t\t\t\t\t\t\tif (resLen < tmbs.length) {
\t\t\t\t\t\t\t\t\t\t\$.each(tmbs, function(i, h) {
\t\t\t\t\t\t\t\t\t\t\tif (! data.images[h]) {
\t\t\t\t\t\t\t\t\t\t\t\terrs.push(h);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tattachThumbnails(data.images, reload);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\terrs = tmbs;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t// unset error items from bufferExt.attachTmbs
\t\t\t\t\t\t\t\tif (errs.length) {
\t\t\t\t\t\t\t\t\t\$.each(errs, function(i, h) {
\t\t\t\t\t\t\t\t\t\tdelete bufferExt.attachTmbs[h];
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (reload) {
\t\t\t\t\t\t\t\tif (reloads.length) {
\t\t\t\t\t\t\t\t\tloadThumbnails(reloads);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\tbufferExt.tmbLoading = {};
\t\t\t\t\t\t\tif (! reload && bufferExt.getTmbs.length) {
\t\t\t\t\t\t\t\tloadThumbnails();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Add new files to cwd/buffer
\t\t\t *
\t\t\t * @param  Array  new files
\t\t\t * @return void
\t\t\t */
\t\t\tadd = function(files, mode) {
\t\t\t\tvar place    = list ? cwd.find('tbody') : cwd,
\t\t\t\t\tl        = files.length, 
\t\t\t\t\tatmb     = {},
\t\t\t\t\tfindNode = function(file) {
\t\t\t\t\t\tvar pointer = cwd.find('[id]:first'), file2;

\t\t\t\t\t\twhile (pointer.length) {
\t\t\t\t\t\t\tfile2 = fm.file(fm.cwdId2Hash(pointer.attr('id')));
\t\t\t\t\t\t\tif (!pointer.hasClass('elfinder-cwd-parent') && file2 && fm.compare(file, file2) < 0) {
\t\t\t\t\t\t\t\treturn pointer;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tpointer = pointer.next('[id]');
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tfindIndex = function(file) {
\t\t\t\t\t\tvar l = buffer.length, i;
\t\t\t\t\t\t
\t\t\t\t\t\tfor (i =0; i < l; i++) {
\t\t\t\t\t\t\tif (fm.compare(file, buffer[i]) < 0) {
\t\t\t\t\t\t\t\treturn i;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn l || -1;
\t\t\t\t\t},
\t\t\t\t\t// created document fragment for jQuery >= 1.12, 2.2, 3.0
\t\t\t\t\t// see Studio-42/elFinder#1544 @ github
\t\t\t\t\tdocFlag = \$.htmlPrefilter? true : false,
\t\t\t\t\ttempDom = docFlag? \$(document.createDocumentFragment()) : \$('<div></div>'),
\t\t\t\t\tfile, hash, node, nodes, ndx, stmb;

\t\t\t\tif (l > showFiles) {
\t\t\t\t\t// re-render for performance tune
\t\t\t\t\tcontent();
\t\t\t\t\tselectedFiles = fm.arrayFlip(\$.map(files, function(f) { return f.hash; }), true);
\t\t\t\t\ttrigger();
\t\t\t\t} else {
\t\t\t\t\t// add the item immediately
\t\t\t\t\tl && wz.removeClass('elfinder-cwd-wrapper-empty');
\t\t\t\t\t
\t\t\t\t\t// Self thumbnail
\t\t\t\t\tstmb = (fm.option('tmbUrl') === 'self');
\t\t\t\t\t
\t\t\t\t\twhile (l--) {
\t\t\t\t\t\tfile = files[l];
\t\t\t\t\t\thash = file.hash;
\t\t\t\t\t\t
\t\t\t\t\t\tif (fm.cwdHash2Elm(hash).length) {
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif ((node = findNode(file)) && ! node.length) {
\t\t\t\t\t\t\tnode = null;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (! node && (ndx = findIndex(file)) >= 0) {
\t\t\t\t\t\t\tbuffer.splice(ndx, 0, file);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\ttempDom.empty().append(itemhtml(file));
\t\t\t\t\t\t\t(file.mime === 'directory') && !mobile && makeDroppable(tempDom);
\t\t\t\t\t\t\tnodes = docFlag? tempDom : tempDom.children();
\t\t\t\t\t\t\tif (node) {
\t\t\t\t\t\t\t\tnode.before(nodes);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tplace.append(nodes);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t++bufferExt.renderd;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (fm.cwdHash2Elm(hash).length) {
\t\t\t\t\t\t\tif ((file.tmb && (file.tmb != 1 || file.size > 0)) || (stmb && file.mime.indexOf('image/') === 0)) {
\t\t\t\t\t\t\t\tatmb[hash] = file.tmb || 'self';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t
\t\t\t\t\tif (list) {
\t\t\t\t\t\tsetColwidth();
\t\t\t\t\t\tfixTableHeader({fitWidth: ! colWidth});
\t\t\t\t\t}
\t\t\t\t\tbottomMarkerShow(place);
\t\t\t\t\tif (Object.keys(atmb).length) {
\t\t\t\t\t\tObject.assign(bufferExt.attachTmbs, atmb);
\t\t\t\t\t\tif (buffer.length < 1) {
\t\t\t\t\t\t\tloadThumbnails();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Remove files from cwd/buffer
\t\t\t *
\t\t\t * @param  Array  files hashes
\t\t\t * @return void
\t\t\t */
\t\t\tremove = function(files) {
\t\t\t\tvar l = files.length,
\t\t\t\t\tinSearch = fm.searchStatus.state > 1,
\t\t\t\t\tcurCmd = fm.getCommand(fm.currentReqCmd) || {},
\t\t\t\t\thash, n, ndx, found;

\t\t\t\t// removed cwd
\t\t\t\tif (!fm.cwd().hash && !curCmd.noChangeDirOnRemovedCwd) {
\t\t\t\t\t\$.each(cwdParents.reverse(), function(i, h) {
\t\t\t\t\t\tif (fm.file(h)) {
\t\t\t\t\t\t\tfound = true;
\t\t\t\t\t\t\tfm.one(fm.currentReqCmd + 'done', function() {
\t\t\t\t\t\t\t\t!fm.cwd().hash && fm.exec('open', h);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t// fallback to fm.roots[0]
\t\t\t\t\t!found && !fm.cwd().hash && fm.exec('open', fm.roots[Object.keys(fm.roots)[0]]);
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\t
\t\t\t\twhile (l--) {
\t\t\t\t\thash = files[l];
\t\t\t\t\tif ((n = fm.cwdHash2Elm(hash)).length) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tn.remove();
\t\t\t\t\t\t\t--bufferExt.renderd;
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tfm.debug('error', e);
\t\t\t\t\t\t}
\t\t\t\t\t} else if ((ndx = index(hash)) !== -1) {
\t\t\t\t\t\tbuffer.splice(ndx, 1);
\t\t\t\t\t}
\t\t\t\t\tselectedFiles[hash] && delete selectedFiles[hash];
\t\t\t\t\tif (inSearch) {
\t\t\t\t\t\tif ((ndx = \$.inArray(hash, cwdHashes)) !== -1) {
\t\t\t\t\t\t\tcwdHashes.splice(ndx, 1);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tinSearch && fm.trigger('cwdhasheschange', cwdHashes);
\t\t\t\t
\t\t\t\tif (list) {
\t\t\t\t\tsetColwidth();
\t\t\t\t\tfixTableHeader({fitWidth: ! colWidth});
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tcustomColsNameBuild = function() {
\t\t\t\tvar name = '',
\t\t\t\tcustomColsName = '';
\t\t\t\tfor (var i = 0; i < customCols.length; i++) {
\t\t\t\t\tname = fm.getColumnName(customCols[i]);
\t\t\t\t\tcustomColsName +='<td class=\"elfinder-cwd-view-th-'+customCols[i]+' sortable-item\">'+name+'</td>';
\t\t\t\t}
\t\t\t\treturn customColsName;
\t\t\t},
\t\t\t
\t\t\tsetItemBoxSize = function(boxSize) {
\t\t\t\tvar place, elm;
\t\t\t\tif (!boxSize.height) {
\t\t\t\t\tplace = (list ? cwd.find('tbody') : cwd);
\t\t\t\t\telm = place.find(list? 'tr:first' : '[id]:first');
\t\t\t\t\tboxSize.height = elm.outerHeight(true);
\t\t\t\t\tif (!list) {
\t\t\t\t\t\tboxSize.width = elm.outerWidth(true);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},

\t\t\tbottomMarkerShow = function(cur, cnt) {
\t\t\t\tvar place = cur || (list ? cwd.find('tbody') : cwd),
\t\t\t\t\tboxSize = itemBoxSize[fm.viewType],
\t\t\t\t\tcol = 1,
\t\t\t\t\trow;

\t\t\t\tif (buffer.length > 0) {
\t\t\t\t\tif (!bufferExt.hpi) {
\t\t\t\t\t\tsetItemBoxSize(boxSize);
\t\t\t\t\t\tif (! list) {
\t\t\t\t\t\t\tcol = Math.floor(place.width() / boxSize.width);
\t\t\t\t\t\t\tbufferExt.row = boxSize.height;
\t\t\t\t\t\t\tbufferExt.hpi = bufferExt.row / col;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tbufferExt.row = bufferExt.hpi = boxSize.height;
\t\t\t\t\t\t}
\t\t\t\t\t} else if (!list) {
\t\t\t\t\t\tcol = Math.floor(place.width() / boxSize.width);
\t\t\t\t\t}
\t\t\t\t\trow = Math.ceil((buffer.length + (cnt || 0)) / col);
\t\t\t\t\tif (list && tableHeader) {
\t\t\t\t\t\t++row;
\t\t\t\t\t}
\t\t\t\t\tbottomMarker.css({top: (bufferExt.row * row) + 'px'}).show();
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\twrapperContextMenu = {
\t\t\t\tcontextmenu : function(e) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\tif (cwd.data('longtap') !== void(0)) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t'type'    : 'cwd',
\t\t\t\t\t\t'targets' : [fm.cwd().hash],
\t\t\t\t\t\t'x'       : e.pageX,
\t\t\t\t\t\t'y'       : e.pageY
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\ttouchstart : function(e) {
\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tif (cwd.data('longtap') !== false) {
\t\t\t\t\t\twrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
\t\t\t\t\t\tcwd.data('tmlongtap', setTimeout(function(){
\t\t\t\t\t\t\t// long tap
\t\t\t\t\t\t\tcwd.data('longtap', true);
\t\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t\t'type'    : 'cwd',
\t\t\t\t\t\t\t\t'targets' : [fm.cwd().hash],
\t\t\t\t\t\t\t\t'x'       : wrapper.data('touching').x,
\t\t\t\t\t\t\t\t'y'       : wrapper.data('touching').y
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, 500));
\t\t\t\t\t}
\t\t\t\t\tcwd.data('longtap', null);
\t\t\t\t},
\t\t\t\ttouchend : function(e) {
\t\t\t\t\tif (e.type === 'touchmove') {
\t\t\t\t\t\tif (! wrapper.data('touching') ||
\t\t\t\t\t\t\t\t( Math.abs(wrapper.data('touching').x - e.originalEvent.touches[0].pageX)
\t\t\t\t\t\t\t\t+ Math.abs(wrapper.data('touching').y - e.originalEvent.touches[0].pageY)) > 4) {
\t\t\t\t\t\t\twrapper.data('touching', null);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tcwd.removeData('longtap');
\t\t\t\t\t\t}, 80);
\t\t\t\t\t}
\t\t\t\t\tclearTimeout(cwd.data('tmlongtap'));
\t\t\t\t},
\t\t\t\tclick : function(e) {
\t\t\t\t\tif (cwd.data('longtap')) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Update directory content
\t\t\t *
\t\t\t * @return void
\t\t\t */
\t\t\tcontent = function() {
\t\t\t\tfm.lazy(function() {
\t\t\t\t\tvar phash, emptyMethod, thtr;

\t\t\t\t\twz.append(selectAllCheckbox).removeClass('elfinder-cwd-wrapper-empty elfinder-search-result elfinder-incsearch-result elfinder-letsearch-result');
\t\t\t\t\tif (fm.searchStatus.state > 1 || fm.searchStatus.ininc) {
\t\t\t\t\t\twz.addClass('elfinder-search-result' + (fm.searchStatus.ininc? ' elfinder-'+(query.substr(0,1) === '/' ? 'let':'inc')+'search-result' : ''));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// abort attachThumbJob
\t\t\t\t\tbufferExt.attachThumbJob && bufferExt.attachThumbJob._abort();
\t\t\t\t\t
\t\t\t\t\t// destroy selectable for GC
\t\t\t\t\tcwd.data('selectable') && cwd.selectable('disable').selectable('destroy').removeData('selectable');
\t\t\t\t\t
\t\t\t\t\t// notify cwd init
\t\t\t\t\tfm.trigger('cwdinit');
\t\t\t\t\t
\t\t\t\t\tselectedNext = \$();
\t\t\t\t\ttry {
\t\t\t\t\t\t// to avoid problem with draggable
\t\t\t\t\t\tcwd.empty();
\t\t\t\t\t} catch (e) {
\t\t\t\t\t\tcwd.html('');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (tableHeader) {
\t\t\t\t\t\twrapper.off('scroll.fixheader resize.fixheader');
\t\t\t\t\t\ttableHeader.remove();
\t\t\t\t\t\ttableHeader = null;
\t\t\t\t\t}

\t\t\t\t\tcwd.removeClass('elfinder-cwd-view-icons elfinder-cwd-view-list')
\t\t\t\t\t\t.addClass('elfinder-cwd-view-'+(list ? 'list' :'icons'))
\t\t\t\t\t\t.attr('style', '')
\t\t\t\t\t\t.css('height', 'auto');
\t\t\t\t\tbottomMarker.hide();

\t\t\t\t\twrapper[list ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-list')._padding = parseInt(wrapper.css('padding-top')) + parseInt(wrapper.css('padding-bottom'));
\t\t\t\t\tif (fm.UA.iOS) {
\t\t\t\t\t\twrapper.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
\t\t\t\t\t}

\t\t\t\t\tif (list) {
\t\t\t\t\t\tcwd.html('<table><thead></thead><tbody></tbody></table>');
\t\t\t\t\t\tthtr = \$('<tr class=\"ui-state-default\"><td class=\"elfinder-cwd-view-th-name\">'+fm.getColumnName('name')+'</td>'+customColsNameBuild()+'</tr>');
\t\t\t\t\t\tcwd.find('thead').hide().append(thtr).find('td:first').append(selectAllCheckbox);
\t\t\t\t\t\tif (\$.fn.sortable) {
\t\t\t\t\t\t\tthtr.addClass('touch-punch touch-punch-keep-default')
\t\t\t\t\t\t\t\t.sortable({
\t\t\t\t\t\t\t\taxis: 'x',
\t\t\t\t\t\t\t\tdistance: 8,
\t\t\t\t\t\t\t\titems: '> .sortable-item',
\t\t\t\t\t\t\t\tstart: function(e, ui) {
\t\t\t\t\t\t\t\t\t\$(ui.item[0]).data('dragging', true);
\t\t\t\t\t\t\t\t\tui.placeholder
\t\t\t\t\t\t\t\t\t\t.width(ui.helper.removeClass('ui-state-hover').width())
\t\t\t\t\t\t\t\t\t\t.removeClass('ui-state-active')
\t\t\t\t\t\t\t\t\t\t.addClass('ui-state-hover')
\t\t\t\t\t\t\t\t\t\t.css('visibility', 'visible');
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\tupdate: function(e, ui){
\t\t\t\t\t\t\t\t\tvar target = \$(ui.item[0]).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', ''),
\t\t\t\t\t\t\t\t\t\tprev, done;
\t\t\t\t\t\t\t\t\tcustomCols = \$.map(\$(this).children(), function(n) {
\t\t\t\t\t\t\t\t\t\tvar name = \$(n).attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '');
\t\t\t\t\t\t\t\t\t\tif (! done) {
\t\t\t\t\t\t\t\t\t\t\tif (target === name) {
\t\t\t\t\t\t\t\t\t\t\t\tdone = true;
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tprev = name;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\treturn (name === 'name')? null : name;
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\ttemplates.row = makeTemplateRow();
\t\t\t\t\t\t\t\t\tfm.storage('cwdCols', customCols);
\t\t\t\t\t\t\t\t\tprev = '.elfinder-col-'+prev+':first';
\t\t\t\t\t\t\t\t\ttarget = '.elfinder-col-'+target+':first';
\t\t\t\t\t\t\t\t\tfm.lazy(function() {
\t\t\t\t\t\t\t\t\t\tcwd.find('tbody tr').each(function() {
\t\t\t\t\t\t\t\t\t\t\tvar \$this = \$(this);
\t\t\t\t\t\t\t\t\t\t\t\$this.children(prev).after(\$this.children(target));
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\tstop: function(e, ui) {
\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\t\$(ui.item[0]).removeData('dragging');
\t\t\t\t\t\t\t\t\t}, 100);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}

\t\t\t\t\t\tthtr.find('td').addClass('touch-punch').resizable({
\t\t\t\t\t\t\thandles: fm.direction === 'ltr'? 'e' : 'w',
\t\t\t\t\t\t\tstart: function(e, ui) {
\t\t\t\t\t\t\t\tvar target = cwd.find('td.elfinder-col-'
\t\t\t\t\t\t\t\t\t+ ui.element.attr('class').split(' ')[0].replace('elfinder-cwd-view-th-', '')
\t\t\t\t\t\t\t\t\t+ ':first');
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tui.element
\t\t\t\t\t\t\t\t\t.data('dragging', true)
\t\t\t\t\t\t\t\t\t.data('resizeTarget', target)
\t\t\t\t\t\t\t\t\t.data('targetWidth', target.width());
\t\t\t\t\t\t\t\tcolResizing = true;
\t\t\t\t\t\t\t\tif (cwd.find('table').css('table-layout') !== 'fixed') {
\t\t\t\t\t\t\t\t\tcwd.find('tbody tr:first td').each(function() {
\t\t\t\t\t\t\t\t\t\t\$(this).width(\$(this).width());
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tcwd.find('table').css('table-layout', 'fixed');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tresize: function(e, ui) {
\t\t\t\t\t\t\t\tui.element.data('resizeTarget').width(ui.element.data('targetWidth') - (ui.originalSize.width - ui.size.width));
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tstop : function(e, ui) {
\t\t\t\t\t\t\t\tcolResizing = false;
\t\t\t\t\t\t\t\tfixTableHeader({fitWidth: true});
\t\t\t\t\t\t\t\tcolWidth = {};
\t\t\t\t\t\t\t\tcwd.find('tbody tr:first td').each(function() {
\t\t\t\t\t\t\t\t\tvar name = \$(this).attr('class').split(' ')[0].replace('elfinder-col-', '');
\t\t\t\t\t\t\t\t\tcolWidth[name] = \$(this).width();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tfm.storage('cwdColWidth', colWidth);
\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\tui.element.removeData('dragging');
\t\t\t\t\t\t\t\t}, 100);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.find('.ui-resizable-handle').addClass('ui-icon ui-icon-grip-dotted-vertical');
\t\t\t\t\t}

\t\t\t\t\tbuffer = \$.map(incHashes || cwdHashes, function(hash) { return fm.file(hash) || null; });
\t\t\t\t\t
\t\t\t\t\tbuffer = fm.sortFiles(buffer);
\t\t\t\t\t
\t\t\t\t\tif (incHashes) {
\t\t\t\t\t\tincHashes = \$.map(buffer, function(f) { return f.hash; });
\t\t\t\t\t} else {
\t\t\t\t\t\tcwdHashes = \$.map(buffer, function(f) { return f.hash; });
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tbufferExt = {
\t\t\t\t\t\trenderd: 0,
\t\t\t\t\t\tattachTmbs: {},
\t\t\t\t\t\tgetTmbs: [],
\t\t\t\t\t\ttmbLoading: {},
\t\t\t\t\t\tlazyOpts: { tm : 0 }
\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\twz[(buffer.length < 1) ? 'addClass' : 'removeClass']('elfinder-cwd-wrapper-empty');
\t\t\t\t\twrapper.off(scrollEvent, render).on(scrollEvent, render).trigger(scrollEvent);
\t\t\t\t\t
\t\t\t\t\t// set droppable
\t\t\t\t\tif (!fm.cwd().write) {
\t\t\t\t\t\twrapper.removeClass('native-droppable')
\t\t\t\t\t\t       .droppable('disable')
\t\t\t\t\t\t       .removeClass('ui-state-disabled'); // for old jQueryUI see https://bugs.jqueryui.com/ticket/5974
\t\t\t\t\t} else {
\t\t\t\t\t\twrapper[fm.isCommandEnabled('upload')? 'addClass' : 'removeClass']('native-droppable');
\t\t\t\t\t\twrapper.droppable(fm.isCommandEnabled('paste')? 'enable' : 'disable');
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * CWD node itself
\t\t\t *
\t\t\t * @type JQuery
\t\t\t **/
\t\t\tcwd = \$(this)
\t\t\t\t.addClass('ui-helper-clearfix elfinder-cwd')
\t\t\t\t.attr('unselectable', 'on')
\t\t\t\t// fix ui.selectable bugs and add shift+click support 
\t\t\t\t.on('click.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tvar p    = this.id ? \$(this) : \$(this).parents('[id]:first'),
\t\t\t\t\t\ttgt  = \$(e.target),
\t\t\t\t\t\tprev,
\t\t\t\t\t\tnext,
\t\t\t\t\t\tpl,
\t\t\t\t\t\tnl,
\t\t\t\t\t\tsib;

\t\t\t\t\tif (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tp.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
\t\t\t\t\t\ttrigger();
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\ttgt.prop('checked', p.hasClass(clSelected));
\t\t\t\t\t\t});
\t\t\t\t\t\treturn;
\t\t\t\t\t}

\t\t\t\t\tif (cwd.data('longtap') || tgt.hasClass('elfinder-cwd-nonselect')) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}

\t\t\t\t\tif (!curClickId) {
\t\t\t\t\t\tcurClickId = p.attr('id');
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tcurClickId = '';
\t\t\t\t\t\t}, 500);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (e.shiftKey) {
\t\t\t\t\t\tprev = p.prevAll(lastSelect || '.'+clSelected+':first');
\t\t\t\t\t\tnext = p.nextAll(lastSelect || '.'+clSelected+':first');
\t\t\t\t\t\tpl   = prev.length;
\t\t\t\t\t\tnl   = next.length;
\t\t\t\t\t}
\t\t\t\t\tif (e.shiftKey && (pl || nl)) {
\t\t\t\t\t\tsib = pl ? p.prevUntil('#'+prev.attr('id')) : p.nextUntil('#'+next.attr('id'));
\t\t\t\t\t\tsib = sib.add(p);
\t\t\t\t\t\tif (!pl) {
\t\t\t\t\t\t\tsib  = \$(sib.get().reverse());
\t\t\t\t\t\t}
\t\t\t\t\t\tsib.trigger(evtSelect);
\t\t\t\t\t} else if (e.ctrlKey || e.metaKey) {
\t\t\t\t\t\tp.trigger(p.hasClass(clSelected) ? evtUnselect : evtSelect);
\t\t\t\t\t} else {
\t\t\t\t\t\tif (wrapper.data('touching') && p.hasClass(clSelected)) {
\t\t\t\t\t\t\twrapper.data('touching', null);
\t\t\t\t\t\t\tfm.dblclick({file : fm.cwdId2Hash(this.id)});
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\t\t\tp.trigger(evtSelect);
\t\t\t\t\t\t}
\t\t\t\t\t}

\t\t\t\t\ttrigger();
\t\t\t\t})
\t\t\t\t// call fm.open()
\t\t\t\t.on('dblclick.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tif (curClickId) {
\t\t\t\t\t\tvar hash = fm.cwdId2Hash(curClickId);
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tif (this.id !== curClickId) {
\t\t\t\t\t\t\t\$(this).trigger(evtUnselect);
\t\t\t\t\t\t\t\$('#'+curClickId).trigger(evtSelect);
\t\t\t\t\t\t\ttrigger();
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.dblclick({file : hash});
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// for touch device
\t\t\t\t.on('touchstart.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tvar p   = this.id ? \$(this) : \$(this).parents('[id]:first'),
\t\t\t\t\t\ttgt = \$(e.target),
\t\t\t\t\t\tnodeName = e.target.nodeName,
\t\t\t\t\t\tsel;
\t\t\t\t\t
\t\t\t\t\tif ((nodeName === 'INPUT' && e.target.type === 'text') || nodeName === 'TEXTAREA' || tgt.hasClass('elfinder-cwd-nonselect')) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t// now name editing
\t\t\t\t\tif (p.find('input:text,textarea').length) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\twrapper.data('touching', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY});
\t\t\t\t\tif (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tsel = p.prevAll('.'+clSelected+':first').length +
\t\t\t\t\t      p.nextAll('.'+clSelected+':first').length;
\t\t\t\t\tcwd.data('longtap', null);
\t\t\t\t\tif (Object.keys(selectedFiles).length
\t\t\t\t\t\t||
\t\t\t\t\t\t(list && e.target.nodeName !== 'TD')
\t\t\t\t\t\t||
\t\t\t\t\t\t(!list && this !== e.target)
\t\t\t\t\t) {
\t\t\t\t\t\tcwd.data('longtap', false);
\t\t\t\t\t\tp.addClass(clHover);
\t\t\t\t\t\tp.data('tmlongtap', setTimeout(function(){
\t\t\t\t\t\t\t// long tap
\t\t\t\t\t\t\tcwd.data('longtap', true);
\t\t\t\t\t\t\tp.trigger(evtSelect);
\t\t\t\t\t\t\ttrigger();
\t\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t\t'type'    : 'files',
\t\t\t\t\t\t\t\t'targets' : fm.selected(),
\t\t\t\t\t\t\t\t'x'       : e.originalEvent.touches[0].pageX,
\t\t\t\t\t\t\t\t'y'       : e.originalEvent.touches[0].pageY
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, 500));
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tvar tgt = \$(e.target),
\t\t\t\t\t\tp;
\t\t\t\t\tif (selectCheckbox && (tgt.is('input:checkbox.'+clSelChk) || tgt.hasClass('elfinder-cwd-select'))) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tif (e.target.nodeName == 'INPUT' || e.target.nodeName == 'TEXTAREA') {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tp = this.id ? \$(this) : \$(this).parents('[id]:first');
\t\t\t\t\tclearTimeout(p.data('tmlongtap'));
\t\t\t\t\tif (e.type === 'touchmove') {
\t\t\t\t\t\twrapper.data('touching', null);
\t\t\t\t\t\tp.removeClass(clHover);
\t\t\t\t\t} else {
\t\t\t\t\t\tif (wrapper.data('touching') && !cwd.data('longtap') && p.hasClass(clSelected)) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\twrapper.data('touching', null);
\t\t\t\t\t\t\tfm.dblclick({file : fm.cwdId2Hash(this.id)});
\t\t\t\t\t\t}
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tcwd.removeData('longtap');
\t\t\t\t\t\t}, 80);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// attach draggable
\t\t\t\t.on('mouseenter.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tif (scrolling) { return; }
\t\t\t\t\tvar \$this = \$(this), helper = null;

\t\t\t\t\tif (!mobile && !\$this.data('dragRegisted') && !\$this.hasClass(clTmp) && !\$this.hasClass(clDraggable) && !\$this.hasClass(clDisabled)) {
\t\t\t\t\t\t\$this.data('dragRegisted', true);
\t\t\t\t\t\tif (!fm.isCommandEnabled('copy', fm.searchStatus.state > 1 || \$this.hasClass('isroot')? fm.cwdId2Hash(\$this.attr('id')) : void 0)) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\t\$this.on('mousedown', function(e) {
\t\t\t\t\t\t\t// shiftKey or altKey + drag start for HTML5 native drag function
\t\t\t\t\t\t\t// Note: can no use shiftKey with the Google Chrome 
\t\t\t\t\t\t\tvar metaKey = options.metakeyDragout && !fm.UA.IE && (e.shiftKey || e.altKey),
\t\t\t\t\t\t\t\tdisable = false;
\t\t\t\t\t\t\tif (metaKey && cwd.data('selectable')) {
\t\t\t\t\t\t\t\t// destroy jQuery-ui selectable while trigger native drag
\t\t\t\t\t\t\t\tcwd.selectable('disable').selectable('destroy').removeData('selectable');
\t\t\t\t\t\t\t\trequestAnimationFrame(function(){
\t\t\t\t\t\t\t\t\tcwd.selectable(selectableOption).selectable('option', {disabled: false}).selectable('refresh').data('selectable', true);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\$this.removeClass('ui-state-disabled');
\t\t\t\t\t\t\tif (metaKey) {
\t\t\t\t\t\t\t\t\$this.draggable('option', 'disabled', true).attr('draggable', 'true');
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (!\$this.hasClass(clSelected)) {
\t\t\t\t\t\t\t\t\tif (list) {
\t\t\t\t\t\t\t\t\t\tdisable = \$(e.target).closest('span,tr').is('tr');
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tdisable = \$(e.target).hasClass('elfinder-cwd-file');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (disable) {
\t\t\t\t\t\t\t\t\t// removeClass('ui-state-disabled') for old version of jQueryUI
\t\t\t\t\t\t\t\t\t\$this.draggable('option', 'disabled', true).removeClass('ui-state-disabled');
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\$this.draggable('option', 'disabled', false)
\t\t\t\t\t\t\t\t\t\t  .removeAttr('draggable')
\t\t\t\t\t\t\t\t\t      .draggable('option', 'cursorAt', {left: 50 - parseInt(\$(e.currentTarget).css('margin-left')), top: 47});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('dragstart', function(e) {
\t\t\t\t\t\t\tvar dt = e.dataTransfer || e.originalEvent.dataTransfer || null;
\t\t\t\t\t\t\thelper = null;
\t\t\t\t\t\t\tif (dt && !fm.UA.IE) {
\t\t\t\t\t\t\t\tvar p = this.id ? \$(this) : \$(this).parents('[id]:first'),
\t\t\t\t\t\t\t\t\telm   = \$('<span>'),
\t\t\t\t\t\t\t\t\turl   = '',
\t\t\t\t\t\t\t\t\tdurl  = null,
\t\t\t\t\t\t\t\t\tmurl  = null,
\t\t\t\t\t\t\t\t\tfiles = [],
\t\t\t\t\t\t\t\t\ticon  = function(f) {
\t\t\t\t\t\t\t\t\t\tvar mime = f.mime, i, tmb = fm.tmb(f);
\t\t\t\t\t\t\t\t\t\ti = '<div class=\"elfinder-cwd-icon elfinder-cwd-icon-drag '+fm.mime2class(mime)+' ui-corner-all\"></div>';
\t\t\t\t\t\t\t\t\t\tif (tmb) {
\t\t\t\t\t\t\t\t\t\t\ti = \$(i).addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\").get(0).outerHTML;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\treturn i;
\t\t\t\t\t\t\t\t\t}, l, geturl = [];
\t\t\t\t\t\t\t\tp.trigger(evtSelect);
\t\t\t\t\t\t\t\ttrigger();
\t\t\t\t\t\t\t\t\$.each(selectedFiles, function(v){
\t\t\t\t\t\t\t\t\tvar file = fm.file(v),
\t\t\t\t\t\t\t\t\t\tfurl = file.url;
\t\t\t\t\t\t\t\t\tif (file && file.mime !== 'directory') {
\t\t\t\t\t\t\t\t\t\tif (!furl) {
\t\t\t\t\t\t\t\t\t\t\tfurl = fm.url(file.hash);
\t\t\t\t\t\t\t\t\t\t} else if (furl == '1') {
\t\t\t\t\t\t\t\t\t\t\tgeturl.push(v);
\t\t\t\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tif (furl) {
\t\t\t\t\t\t\t\t\t\t\tfurl = fm.convAbsUrl(furl);
\t\t\t\t\t\t\t\t\t\t\tfiles.push(v);
\t\t\t\t\t\t\t\t\t\t\t\$('<a>').attr('href', furl).text(furl).appendTo(elm);
\t\t\t\t\t\t\t\t\t\t\turl += furl + \"\\n\";
\t\t\t\t\t\t\t\t\t\t\tif (!durl) {
\t\t\t\t\t\t\t\t\t\t\t\tdurl = file.mime + ':' + file.name + ':' + furl;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\tif (!murl) {
\t\t\t\t\t\t\t\t\t\t\t\tmurl = furl + \"\\n\" + file.name;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (geturl.length) {
\t\t\t\t\t\t\t\t\t\$.each(geturl, function(i, v){
\t\t\t\t\t\t\t\t\t\tvar rfile = fm.file(v);
\t\t\t\t\t\t\t\t\t\trfile.url = '';
\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\tdata : {cmd : 'url', target : v},
\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'url', cnt : 1},
\t\t\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\t\t\t\trfile.url = data.url? data.url : '1';
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t} else if (url) {
\t\t\t\t\t\t\t\t\tif (dt.setDragImage) {
\t\t\t\t\t\t\t\t\t\thelper = \$('<div class=\"elfinder-drag-helper html5-native\"></div>').append(icon(fm.file(files[0]))).appendTo(\$(document.body));
\t\t\t\t\t\t\t\t\t\tif ((l = files.length) > 1) {
\t\t\t\t\t\t\t\t\t\t\thelper.append(icon(fm.file(files[l-1])) + '<span class=\"elfinder-drag-num\">'+l+'</span>');
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tdt.setDragImage(helper.get(0), 50, 47);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tdt.effectAllowed = 'copyLink';
\t\t\t\t\t\t\t\t\tdt.setData('DownloadURL', durl);
\t\t\t\t\t\t\t\t\tdt.setData('text/x-moz-url', murl);
\t\t\t\t\t\t\t\t\tdt.setData('text/uri-list', url);
\t\t\t\t\t\t\t\t\tdt.setData('text/plain', url);
\t\t\t\t\t\t\t\t\tdt.setData('text/html', elm.html());
\t\t\t\t\t\t\t\t\tdt.setData('elfinderfrom', window.location.href + fm.cwd().hash);
\t\t\t\t\t\t\t\t\tdt.setData('elfinderfrom:' + dt.getData('elfinderfrom'), '');
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('dragend', function(e){
\t\t\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\t\t\thelper && helper.remove();
\t\t\t\t\t\t})
\t\t\t\t\t\t.draggable(fm.draggable);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// add hover class to selected file
\t\t\t\t.on(evtSelect, fileSelector, function(e) {
\t\t\t\t\tvar \$this = \$(this),
\t\t\t\t\t\tid    = fm.cwdId2Hash(\$this.attr('id'));
\t\t\t\t\t
\t\t\t\t\tif (!selectLock && !\$this.hasClass(clDisabled)) {
\t\t\t\t\t\tlastSelect = '#'+ this.id;
\t\t\t\t\t\t\$this.addClass(clSelected).children().addClass(clHover).find('input:checkbox.'+clSelChk).prop('checked', true);
\t\t\t\t\t\tif (! selectedFiles[id]) {
\t\t\t\t\t\t\tselectedFiles[id] = true;
\t\t\t\t\t\t}
\t\t\t\t\t\t// will be selected next
\t\t\t\t\t\tselectedNext = cwd.find('[id].'+clSelected+':last').next();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// remove hover class from unselected file
\t\t\t\t.on(evtUnselect, fileSelector, function(e) {
\t\t\t\t\tvar \$this = \$(this), 
\t\t\t\t\t\tid    = fm.cwdId2Hash(\$this.attr('id'));
\t\t\t\t\t
\t\t\t\t\tif (!selectLock) {
\t\t\t\t\t\t\$this.removeClass(clSelected).children().removeClass(clHover).find('input:checkbox.'+clSelChk).prop('checked', false);
\t\t\t\t\t\tif (cwd.hasClass('elfinder-cwd-allselected')) {
\t\t\t\t\t\t\tselectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
\t\t\t\t\t\t\tcwd.removeClass('elfinder-cwd-allselected');
\t\t\t\t\t\t}
\t\t\t\t\t\tselectedFiles[id] && delete selectedFiles[id];
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t})
\t\t\t\t// disable files wich removing or moving
\t\t\t\t.on(evtDisable, fileSelector, function() {
\t\t\t\t\tvar \$this  = \$(this).removeClass(clHover+' '+clSelected).addClass(clDisabled), 
\t\t\t\t\t\tchild  = \$this.children(),
\t\t\t\t\t\ttarget = (list ? \$this : child.find('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename'));
\t\t\t\t\t
\t\t\t\t\tchild.removeClass(clHover+' '+clSelected);
\t\t\t\t\t
\t\t\t\t\t\$this.hasClass(clDroppable) && \$this.droppable('disable');
\t\t\t\t\ttarget.hasClass(clDraggable) && target.draggable('disable');
\t\t\t\t})
\t\t\t\t// if any files was not removed/moved - unlock its
\t\t\t\t.on(evtEnable, fileSelector, function() {
\t\t\t\t\tvar \$this  = \$(this).removeClass(clDisabled), 
\t\t\t\t\t\ttarget = list ? \$this : \$this.children('div.elfinder-cwd-file-wrapper,div.elfinder-cwd-filename');
\t\t\t\t\t
\t\t\t\t\t\$this.hasClass(clDroppable) && \$this.droppable('enable');\t
\t\t\t\t\ttarget.hasClass(clDraggable) && target.draggable('enable');
\t\t\t\t})
\t\t\t\t.on('scrolltoview', fileSelector, function(e, data) {
\t\t\t\t\tscrollToView(\$(this), (data && typeof data.blink !== 'undefined')? data.blink : true);
\t\t\t\t})
\t\t\t\t.on('mouseenter.'+fm.namespace+' mouseleave.'+fm.namespace, fileSelector, function(e) {
\t\t\t\t\tvar enter = (e.type === 'mouseenter');
\t\t\t\t\tif (enter && (scrolling || fm.UA.Mobile)) { return; }
\t\t\t\t\tfm.trigger('hover', {hash : fm.cwdId2Hash(\$(this).attr('id')), type : e.type});
\t\t\t\t\t\$(this).toggleClass(clHover, (e.type == 'mouseenter'));
\t\t\t\t})
\t\t\t\t// for file contextmenu
\t\t\t\t.on('mouseenter.'+fm.namespace+' mouseleave.'+fm.namespace, '.elfinder-cwd-file-wrapper,.elfinder-cwd-filename', function(e) {
\t\t\t\t\tvar enter = (e.type === 'mouseenter');
\t\t\t\t\tif (enter && scrolling) { return; }
\t\t\t\t\t\$(this).closest(fileSelector).children('.elfinder-cwd-file-wrapper,.elfinder-cwd-filename').toggleClass(clActive, (e.type == 'mouseenter'));
\t\t\t\t})
\t\t\t\t.on('contextmenu.'+fm.namespace, function(e) {
\t\t\t\t\tvar file = \$(e.target).closest(fileSelector);
\t\t\t\t\t
\t\t\t\t\tif (file.get(0) === e.target && !selectedFiles[fm.cwdId2Hash(file.get(0).id)]) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}

\t\t\t\t\t// now filename editing
\t\t\t\t\tif (file.find('input:text,textarea').length) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (file.length && (e.target.nodeName != 'TD' || selectedFiles[fm.cwdId2Hash(file.get(0).id)])) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tif (!file.hasClass(clDisabled) && !wrapper.data('touching')) {
\t\t\t\t\t\t\tif (!file.hasClass(clSelected)) {
\t\t\t\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\t\t\t\tfile.trigger(evtSelect);
\t\t\t\t\t\t\t\ttrigger();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t\t'type'    : 'files',
\t\t\t\t\t\t\t\t'targets' : fm.selected(),
\t\t\t\t\t\t\t\t'x'       : e.pageX,
\t\t\t\t\t\t\t\t'y'       : e.pageY
\t\t\t\t\t\t\t});

\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// unselect all on cwd click
\t\t\t\t.on('click.'+fm.namespace, function(e) {
\t\t\t\t\tif (e.target === this && ! cwd.data('longtap')) {
\t\t\t\t\t\t!e.shiftKey && !e.ctrlKey && !e.metaKey && unselectAll();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// prepend fake file/dir
\t\t\t\t.on('create.'+fm.namespace, function(e, f) {
\t\t\t\t\tvar parent = list ? cwd.find('tbody') : cwd,
\t\t\t\t\t\tp = parent.find('.elfinder-cwd-parent'),
\t\t\t\t\t\tlock = f.move || false,
\t\t\t\t\t\tfile = \$(itemhtml(f)).addClass(clTmp),
\t\t\t\t\t\tselected = fm.selected();
\t\t\t\t\t\t
\t\t\t\t\tif (selected.length) {
\t\t\t\t\t\tlock && fm.trigger('lockfiles', {files: selected});
\t\t\t\t\t} else {
\t\t\t\t\t\tunselectAll();
\t\t\t\t\t}

\t\t\t\t\tif (p.length) {
\t\t\t\t\t\tp.after(file);
\t\t\t\t\t} else {
\t\t\t\t\t\tparent.prepend(file);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tsetColwidth();
\t\t\t\t\twrapper.scrollTop(0).scrollLeft(0);
\t\t\t\t})
\t\t\t\t// unselect all selected files
\t\t\t\t.on('unselectall', unselectAll)
\t\t\t\t.on('selectfile', function(e, id) {
\t\t\t\t\tfm.cwdHash2Elm(id).trigger(evtSelect);
\t\t\t\t\ttrigger();
\t\t\t\t})
\t\t\t\t.on('colwidth', function() {
\t\t\t\t\tif (list) {
\t\t\t\t\t\tcwd.find('table').css('table-layout', '')
\t\t\t\t\t\t\t.find('td').css('width', '');
\t\t\t\t\t\tfixTableHeader({fitWidth: true});
\t\t\t\t\t\tfm.storage('cwdColWidth', colWidth = null);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('iconpref', function(e, data) {
\t\t\t\t\tcwd.removeClass(function(i, cName) {
\t\t\t\t\t\treturn (cName.match(/\\belfinder-cwd-size\\S+/g) || []).join(' ');
\t\t\t\t\t});
\t\t\t\t\ticonSize = data? (parseInt(data.size) || 0) : 0;
\t\t\t\t\tif (!list) {
\t\t\t\t\t\tif (iconSize > 0) {
\t\t\t\t\t\t\tcwd.addClass('elfinder-cwd-size' + iconSize);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (bufferExt.renderd) {
\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\titemBoxSize.icons = {};
\t\t\t\t\t\t\t\tbufferExt.hpi = null;
\t\t\t\t\t\t\t\tbottomMarkerShow(cwd, bufferExt.renderd);
\t\t\t\t\t\t\t\twrapperRepaint();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// Change icon size with mouse wheel event
\t\t\t\t.on('onwheel' in document ? 'wheel' : 'mousewheel', function(e) {
\t\t\t\t\tvar tm, size, delta;
\t\t\t\t\tif (!list && ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey))) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\ttm = cwd.data('wheelTm');
\t\t\t\t\t\tif (typeof tm !== 'undefined') {
\t\t\t\t\t\t\tclearTimeout(tm);
\t\t\t\t\t\t\tcwd.data('wheelTm', setTimeout(function() {
\t\t\t\t\t\t\t\tcwd.removeData('wheelTm');
\t\t\t\t\t\t\t}, 200));
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tcwd.data('wheelTm', false);
\t\t\t\t\t\t\tsize = iconSize || 0;
\t\t\t\t\t\t\tdelta = e.originalEvent.deltaY ? e.originalEvent.deltaY : -(e.originalEvent.wheelDelta);
\t\t\t\t\t\t\tif (delta > 0) {
\t\t\t\t\t\t\t\tif (iconSize > 0) {
\t\t\t\t\t\t\t\t\tsize = iconSize - 1;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (iconSize < options.iconsView.sizeMax) {
\t\t\t\t\t\t\t\t\tsize = iconSize + 1;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (size !== iconSize) {
\t\t\t\t\t\t\t\tfm.storage('iconsize', size);
\t\t\t\t\t\t\t\tcwd.trigger('iconpref', {size: size});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}),
\t\t\twrapper = \$('<div class=\"elfinder-cwd-wrapper\"></div>')
\t\t\t\t// make cwd itself droppable for folders from nav panel
\t\t\t\t.droppable(Object.assign({}, droppable, {autoDisable: false}))
\t\t\t\t.on('contextmenu.'+fm.namespace, wrapperContextMenu.contextmenu)
\t\t\t\t.on('touchstart.'+fm.namespace, wrapperContextMenu.touchstart)
\t\t\t\t.on('touchmove.'+fm.namespace+' touchend.'+fm.namespace, wrapperContextMenu.touchend)
\t\t\t\t.on('click.'+fm.namespace, wrapperContextMenu.click)
\t\t\t\t.on('scroll.'+fm.namespace, function() {
\t\t\t\t\tif (! scrolling) {
\t\t\t\t\t\tcwd.data('selectable') && cwd.selectable('disable');
\t\t\t\t\t\twrapper.trigger(scrollStartEvent);
\t\t\t\t\t}
\t\t\t\t\tscrolling = true;
\t\t\t\t\tbufferExt.scrtm && cancelAnimationFrame(bufferExt.scrtm);
\t\t\t\t\tif (bufferExt.scrtm && Math.abs((bufferExt.scrolltop || 0) - (bufferExt.scrolltop = (this.scrollTop || \$(this).scrollTop()))) < 5) {
\t\t\t\t\t\tbufferExt.scrtm = 0;
\t\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t\t}
\t\t\t\t\tbufferExt.scrtm = requestAnimationFrame(function() {
\t\t\t\t\t\tbufferExt.scrtm = 0;
\t\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.on(scrollEvent, function() {
\t\t\t\t\tscrolling = false;
\t\t\t\t\twrapperRepaint();
\t\t\t\t}),
\t\t\t
\t\t\tbottomMarker = \$('<div>&nbsp;</div>')
\t\t\t\t.css({position: 'absolute', width: '1px', height: '1px'})
\t\t\t\t.hide(),
\t\t\t
\t\t\tselectAllCheckbox = selectCheckbox? \$('<div class=\"elfinder-cwd-selectall\"><input type=\"checkbox\"/></div>')
\t\t\t\t.attr('title', fm.i18n('selectall'))
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.preventDefault();
\t\t\t\t\tif (\$(this).data('pending')) {
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\tselectAllCheckbox.data('pending', true);
\t\t\t\t\tif (cwd.hasClass('elfinder-cwd-allselected')) {
\t\t\t\t\t\tselectAllCheckbox.find('input').prop('checked', false);
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\tunselectAll();
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tselectAll();
\t\t\t\t\t}
\t\t\t\t}) : \$(),
\t\t\t
\t\t\trestm = null,
\t\t\tresize = function(init) {
\t\t\t\tvar initHeight = function() {
\t\t\t\t\tif (typeof bufferExt.renderd !== 'undefined') {
\t\t\t\t\t\tvar h = 0;
\t\t\t\t\t\twrapper.siblings('div.elfinder-panel:visible').each(function() {
\t\t\t\t\t\t\th += \$(this).outerHeight(true);
\t\t\t\t\t\t});
\t\t\t\t\t\twrapper.height(wz.height() - h - wrapper._padding);
\t\t\t\t\t}
\t\t\t\t};
\t\t\t\t
\t\t\t\tinit && initHeight();
\t\t\t\t
\t\t\t\trestm && cancelAnimationFrame(restm);
\t\t\t\trestm = requestAnimationFrame(function(){
\t\t\t\t\t!init && initHeight();
\t\t\t\t\tvar wph, cwdoh;
\t\t\t\t\t// fix cwd height if it less then wrapper
\t\t\t\t\tcwd.css('height', 'auto');
\t\t\t\t\twph = wrapper[0].clientHeight - parseInt(wrapper.css('padding-top')) - parseInt(wrapper.css('padding-bottom')) - parseInt(cwd.css('margin-top')),
\t\t\t\t\tcwdoh = cwd.outerHeight(true);
\t\t\t\t\tif (cwdoh < wph) {
\t\t\t\t\t\tcwd.height(wph);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\tlist && ! colResizing && (init? wrapper.trigger('resize.fixheader') : fixTableHeader());
\t\t\t\t
\t\t\t\twrapperRepaint();
\t\t\t},
\t\t\t
\t\t\t// elfinder node
\t\t\tparent = \$(this).parent().on('resize', resize),
\t\t\t
\t\t\t// workzone node 
\t\t\twz = parent.children('.elfinder-workzone').append(wrapper.append(this).append(bottomMarker)),
\t\t\t
\t\t\t// message board
\t\t\tmBoard = \$('<div class=\"elfinder-cwd-message-board\"></div>').insertAfter(cwd),

\t\t\t// Volume expires
\t\t\tvExpires = \$('<div class=\"elfinder-cwd-expires\" ></div>'),

\t\t\tvExpiresTm,

\t\t\tshowVolumeExpires = function() {
\t\t\t\tvar remain, sec, int;
\t\t\t\tvExpiresTm && clearTimeout(vExpiresTm);
\t\t\t\tif (curVolId && fm.volumeExpires[curVolId]) {
\t\t\t\t\tsec = fm.volumeExpires[curVolId] - ((+new Date()) / 1000);
\t\t\t\t\tint = (sec % 60) + 0.1;
\t\t\t\t\tremain = Math.floor(sec / 60);
\t\t\t\t\tvExpires.html(fm.i18n(['minsLeft', remain])).show();
\t\t\t\t\tif (remain) {
\t\t\t\t\t\tvExpiresTm = setTimeout(showVolumeExpires, int * 1000);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},

\t\t\t// each item box size
\t\t\titemBoxSize = {
\t\t\t\ticons : {},
\t\t\t\tlist : {}
\t\t\t},

\t\t\t// has UI tree
\t\t\thasUiTree,

\t\t\t// Icon size of icons view
\t\t\ticonSize,

\t\t\t// Current volume id
\t\t\tcurVolId,
\t\t\t
\t\t\twinScrTm;

\t\t// IE < 11 not support CSS `pointer-events: none`
\t\tif (!fm.UA.ltIE10) {
\t\t\tmBoard.append(\$('<div class=\"elfinder-cwd-trash\" ></div>').html(fm.i18n('volume_Trash')))
\t\t\t      .append(vExpires);
\t\t}

\t\t// setup by options
\t\treplacement = Object.assign(replacement, options.replacement || {});
\t\t
\t\ttry {
\t\t\tcolWidth = fm.storage('cwdColWidth')? fm.storage('cwdColWidth') : null;
\t\t} catch(e) {
\t\t\tcolWidth = null;
\t\t}
\t\t
\t\t// setup costomCols
\t\tfm.bind('columnpref', function(e) {
\t\t\tvar opts = e.data || {};
\t\t\tif (customCols = fm.storage('cwdCols')) {
\t\t\t\tcustomCols = \$.grep(customCols, function(n) {
\t\t\t\t\treturn (options.listView.columns.indexOf(n) !== -1)? true : false;
\t\t\t\t});
\t\t\t\tif (options.listView.columns.length > customCols.length) {
\t\t\t\t\t\$.each(options.listView.columns, function(i, n) {
\t\t\t\t\t\tif (customCols.indexOf(n) === -1) {
\t\t\t\t\t\t\tcustomCols.push(n);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t} else {
\t\t\t\tcustomCols = options.listView.columns;
\t\t\t}
\t\t\t// column names array that hidden
\t\t\tvar columnhides = fm.storage('columnhides') || null;
\t\t\tif (columnhides && Object.keys(columnhides).length)
\t\t\tcustomCols = \$.grep(customCols, function(n) {
\t\t\t\treturn columnhides[n]? false : true;
\t\t\t});
\t\t\t// make template with customCols
\t\t\ttemplates.row = makeTemplateRow();
\t\t\t// repaint if need it
\t\t\tlist && opts.repaint && content();
\t\t}).trigger('columnpref');

\t\tif (mobile) {
\t\t\t// for iOS5 bug
\t\t\t\$('body').on('touchstart touchmove touchend', function(e){});
\t\t}
\t\t
\t\tselectCheckbox && cwd.addClass('elfinder-has-checkbox');
\t\t
\t\t\$(window).on('scroll.'+fm.namespace, function() {
\t\t\twinScrTm && cancelAnimationFrame(winScrTm);
\t\t\twinScrTm = requestAnimationFrame(function() {
\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t});
\t\t});
\t\t
\t\t\$(document).on('keydown.'+fm.namespace, function(e) {
\t\t\tif (e.keyCode == \$.ui.keyCode.ESCAPE) {
\t\t\t\tif (! fm.getUI().find('.ui-widget:visible').length) {
\t\t\t\t\tunselectAll();
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\tfm
\t\t\t.one('init', function(){
\t\t\t\tvar style = document.createElement('style'),
\t\t\t\tsheet, node, base, resizeTm, iconSize, i = 0;
\t\t\t\tif (document.head) {
\t\t\t\t\tdocument.head.appendChild(style);
\t\t\t\t\tsheet = style.sheet;
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptyFolder')+'\" }', i++);
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty .native-droppable .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptyFolder'+(mobile? 'LTap' : 'Drop'))+'\" }', i++);
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty .ui-droppable-disabled .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptyFolder')+'\" }', i++);
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptySearch')+'\" }', i++);
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-incsearch-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptyIncSearch')+'\" }', i++);
\t\t\t\t\tsheet.insertRule('.elfinder-cwd-wrapper-empty.elfinder-search-result.elfinder-letsearch-result .elfinder-cwd:not(.elfinder-table-header-sticky):after{ content:\"'+fm.i18n('emptyLetSearch')+'\" }', i++);
\t\t\t\t}
\t\t\t\tif (iconSize = (fm.storage('iconsize') || options.iconsView.size || 0)) {
\t\t\t\t\ticonSize = Math.min(iconSize, options.iconsView.sizeMax);
\t\t\t\t\tcwd.trigger('iconpref', {size: iconSize});
\t\t\t\t}
\t\t\t\tif (! mobile) {
\t\t\t\t\tfm.one('open', function() {
\t\t\t\t\t\tsheet && fm.zIndex && sheet.insertRule('.ui-selectable-helper{z-index:'+fm.zIndex+';}', i++);
\t\t\t\t\t});
\t\t\t\t\tbase = \$('<div style=\"position:absolute\"></div>');
\t\t\t\t\tnode = fm.getUI();
\t\t\t\t\tnode.on('resize', function(e, data) {
\t\t\t\t\t\tvar offset;
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tif (data && data.fullscreen) {
\t\t\t\t\t\t\toffset = node.offset();
\t\t\t\t\t\t\tif (data.fullscreen === 'on') {
\t\t\t\t\t\t\t\tbase.css({top:offset.top * -1 , left:offset.left * -1 }).appendTo(node);
\t\t\t\t\t\t\t\tselectableOption.appendTo = base;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tbase.detach();
\t\t\t\t\t\t\t\tselectableOption.appendTo = 'body';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tcwd.data('selectable') && cwd.selectable('option', {appendTo : selectableOption.appendTo});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\thasUiTree = fm.getUI('tree').length;
\t\t\t})
\t\t\t.bind('enable', function() {
\t\t\t\tresize();
\t\t\t})
\t\t\t.bind('request.open', function() {
\t\t\t\tbufferExt.getTmbs = [];
\t\t\t})
\t\t\t.one('open', function() {
\t\t\t\tif (fm.maxTargets) {
\t\t\t\t\ttmbNum = Math.min(fm.maxTargets, tmbNum);
\t\t\t\t}
\t\t\t})
\t\t\t.bind('open add remove searchend', function() {
\t\t\t\tvar phash = fm.cwd().hash,
\t\t\t\t\ttype = this.type;
\t\t\t\tif (type === 'open' || type === 'searchend' || fm.searchStatus.state < 2) {
\t\t\t\t\tcwdHashes = \$.map(fm.files(phash), function(f) { return f.hash; });
\t\t\t\t\tfm.trigger('cwdhasheschange', cwdHashes);
\t\t\t\t}
\t\t\t\tif (type === 'open') {
\t\t\t\t\tvar inTrash = function() {
\t\t\t\t\t\t\tvar isIn = false;
\t\t\t\t\t\t\t\$.each(cwdParents, function(i, h) {
\t\t\t\t\t\t\t\tif (fm.trashes[h]) {
\t\t\t\t\t\t\t\t\tisIn = true;
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\treturn isIn;
\t\t\t\t\t\t},
\t\t\t\t\t\treq = phash?
\t\t\t\t\t\t\t(! fm.file(phash) || hasUiTree?
\t\t\t\t\t\t\t\t(! hasUiTree?
\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\tdata: {
\t\t\t\t\t\t\t\t\t\t\tcmd    : 'parents',
\t\t\t\t\t\t\t\t\t\t\ttarget : fm.cwd().hash
\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t\t\t\t}) : (function() {
\t\t\t\t\t\t\t\t\t\tvar dfd = \$.Deferred();
\t\t\t\t\t\t\t\t\t\tfm.one('treesync', function(e) {
\t\t\t\t\t\t\t\t\t\t\te.data.always(function() {
\t\t\t\t\t\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\treturn dfd;
\t\t\t\t\t\t\t\t\t})()
\t\t\t\t\t\t\t\t) : null
\t\t\t\t\t\t\t) : null,
\t\t\t\t\t\tcwdObj = fm.cwd();
\t\t\t\t\t// add/remove volume id class
\t\t\t\t\tif (cwdObj.volumeid !== curVolId) {
\t\t\t\t\t\tvExpires.empty().hide();
\t\t\t\t\t\tif (curVolId) {
\t\t\t\t\t\t\twrapper.removeClass('elfinder-cwd-wrapper-' + curVolId);
\t\t\t\t\t\t}
\t\t\t\t\t\tcurVolId = cwdObj.volumeid;
\t\t\t\t\t\tshowVolumeExpires();
\t\t\t\t\t\twrapper.addClass('elfinder-cwd-wrapper-' + curVolId);
\t\t\t\t\t}
\t\t\t\t\t// add/remove trash class
\t\t\t\t\t\$.when(req).done(function() {
\t\t\t\t\t\tcwdParents = fm.parents(cwdObj.hash);
\t\t\t\t\t\twrapper[inTrash()? 'addClass':'removeClass']('elfinder-cwd-wrapper-trash');
\t\t\t\t\t});
\t\t\t\t\tincHashes = void 0;
\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\tcontent();
\t\t\t\t}
\t\t\t})
\t\t\t.bind('search', function(e) {
\t\t\t\tcwdHashes = \$.map(e.data.files, function(f) { return f.hash; });
\t\t\t\tfm.trigger('cwdhasheschange', cwdHashes);
\t\t\t\tincHashes = void 0;
\t\t\t\tfm.searchStatus.ininc = false;
\t\t\t\tcontent();
\t\t\t\tfm.autoSync('stop');
\t\t\t})
\t\t\t.bind('searchend', function(e) {
\t\t\t\tif (query || incHashes) {
\t\t\t\t\tquery = '';
\t\t\t\t\tif (incHashes) {
\t\t\t\t\t\tfm.trigger('incsearchend', e.data);
\t\t\t\t\t} else {
\t\t\t\t\t\tif (!e.data || !e.data.noupdate) {
\t\t\t\t\t\t\tcontent();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tfm.autoSync();
\t\t\t})
\t\t\t.bind('searchstart', function(e) {
\t\t\t\tunselectAll();
\t\t\t\tquery = e.data.query;
\t\t\t})
\t\t\t.bind('incsearchstart', function(e) {
\t\t\t\tvar q = e.data.query || '',
\t\t\t\t\ttype =  e.data.type || 'SearchName',
\t\t\t\t\tsearchTypes = fm.options.commandsOptions.search.searchTypes || {};

\t\t\t\tif ((searchTypes[type] && searchTypes[type].incsearch) || type === 'SearchName') {
\t\t\t\t\tselectedFiles = {};
\t\t\t\t\tfm.lazy(function() {
\t\t\t\t\t\t// incremental search
\t\t\t\t\t\tvar regex, incSearch, fst = '';
\t\t\t\t\t\tquery = q;
\t\t\t\t\t\tif (q) {
\t\t\t\t\t\t\tif (q.substr(0,1) === '/') {
\t\t\t\t\t\t\t\tq = q.substr(1);
\t\t\t\t\t\t\t\tfst = '^';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tregex = new RegExp(fst + q.replace(/([\\\\*\\;\\.\\?\\[\\]\\{\\}\\(\\)\\^\\\$\\-\\|])/g, '\\\\\$1'), 'i');
\t\t\t\t\t\t\tif (type === 'SearchName') {
\t\t\t\t\t\t\t\tincHashes = \$.grep(cwdHashes, function(hash) {
\t\t\t\t\t\t\t\t\tvar file = fm.file(hash);
\t\t\t\t\t\t\t\t\treturn (file && (file.name.match(regex) || (file.i18 && file.i18.match(regex))))? true : false;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tincSearch = searchTypes[type].incsearch;
\t\t\t\t\t\t\t\tif (typeof incSearch === 'string') {
\t\t\t\t\t\t\t\t\tincHashes = \$.grep(cwdHashes, function(hash) {
\t\t\t\t\t\t\t\t\t\tvar file = fm.file(hash);
\t\t\t\t\t\t\t\t\t\treturn (file && file[incSearch] && (file[incSearch] + '').match(regex))? true : false;
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else if (typeof incSearch === 'function') {
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tincHashes = \$.grep(incSearch({val: q, regex: regex}, cwdHashes, fm), function(hash) {
\t\t\t\t\t\t\t\t\t\t\treturn fm.file(hash)? true : false;
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\t\tincHashes = [];
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tfm.trigger('incsearch', { hashes: incHashes, query: q })
\t\t\t\t\t\t\t\t.searchStatus.ininc = true;
\t\t\t\t\t\t\tcontent();
\t\t\t\t\t\t\tfm.autoSync('stop');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.trigger('incsearchend');
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t})
\t\t\t.bind('incsearchend', function(e) {
\t\t\t\tquery = '';
\t\t\t\tfm.searchStatus.ininc = false;
\t\t\t\tincHashes = void 0;
\t\t\t\tif (!e.data || !e.data.noupdate) {
\t\t\t\t\tcontent();
\t\t\t\t}
\t\t\t\tfm.autoSync();
\t\t\t})
\t\t\t.bind('sortchange', function() {
\t\t\t\tvar lastScrollLeft = wrapper.scrollLeft(),
\t\t\t\t\tallsel = cwd.hasClass('elfinder-cwd-allselected');
\t\t\t\t
\t\t\t\tcontent();
\t\t\t\tfm.one('cwdrender', function() {
\t\t\t\t\twrapper.scrollLeft(lastScrollLeft);
\t\t\t\t\tif (allsel) {
\t\t\t\t\t\tselectedFiles = fm.arrayFlip(incHashes || cwdHashes, true);
\t\t\t\t\t}
\t\t\t\t\t(allsel || Object.keys(selectedFiles).length) && trigger();
\t\t\t\t});
\t\t\t})
\t\t\t.bind('viewchange', function() {
\t\t\t\tvar l      = fm.viewType != 'list',
\t\t\t\t\tallsel = cwd.hasClass('elfinder-cwd-allselected');
\t\t\t\t
\t\t\t\tif (l != list) {
\t\t\t\t\tlist = l;
\t\t\t\t\tfm.viewType = list? 'list' : 'icons';
\t\t\t\t\tif (iconSize) {
\t\t\t\t\t\tfm.one('cwdinit', function() {
\t\t\t\t\t\t\tcwd.trigger('iconpref', {size: iconSize});
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tcontent();
\t\t\t\t\tresize();

\t\t\t\t\tif (allsel) {
\t\t\t\t\t\tcwd.addClass('elfinder-cwd-allselected');
\t\t\t\t\t\tselectAllCheckbox.find('input').prop('checked', true);
\t\t\t\t\t}
\t\t\t\t\tObject.keys(selectedFiles).length && trigger();
\t\t\t\t}
\t\t\t})
\t\t\t.bind('wzresize', function() {
\t\t\t\tvar place = list ? cwd.find('tbody') : cwd,
\t\t\t\t\tcwdOffset;
\t\t\t\tresize(true);
\t\t\t\tif (bufferExt.hpi) {
\t\t\t\t\tbottomMarkerShow(place, place.find('[id]').length);
\t\t\t\t}
\t\t\t\t
\t\t\t\tcwdOffset = cwd.offset();
\t\t\t\twz.data('rectangle', Object.assign(
\t\t\t\t\t{
\t\t\t\t\t\twidth: wz.width(),
\t\t\t\t\t\theight: wz.height(),
\t\t\t\t\t\tcwdEdge: (fm.direction === 'ltr')? cwdOffset.left : cwdOffset.left + cwd.width()
\t\t\t\t\t},
\t\t\t\t\twz.offset())
\t\t\t\t);
\t\t\t\t
\t\t\t\tbufferExt.itemH = (list? place.find('tr:first') : place.find('[id]:first')).outerHeight(true);
\t\t\t})
\t\t\t.bind('changeclipboard', function(e) {
\t\t\t\tclipCuts = {};
\t\t\t\tif (e.data && e.data.clipboard && e.data.clipboard.length) {
\t\t\t\t\t\$.each(e.data.clipboard, function(i, f) {
\t\t\t\t\t\tif (f.cut) {
\t\t\t\t\t\t\tclipCuts[f.hash] = true;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t})
\t\t\t.bind('resMixinMake', function() {
\t\t\t\tsetColwidth();
\t\t\t})
\t\t\t.bind('tmbreload', function(e) {
\t\t\t\tvar imgs = {},
\t\t\t\t\tfiles = (e.data && e.data.files)? e.data.files : null;
\t\t\t\t
\t\t\t\t\$.each(files, function(i, f) {
\t\t\t\t\tif (f.tmb && f.tmb != '1') {
\t\t\t\t\t\timgs[f.hash] = f.tmb;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (Object.keys(imgs).length) {
\t\t\t\t\tattachThumbnails(imgs, true);
\t\t\t\t}
\t\t\t})
\t\t\t.add(function(e) {
\t\t\t\tvar regex = query? new RegExp(query.replace(/([\\\\*\\;\\.\\?\\[\\]\\{\\}\\(\\)\\^\\\$\\-\\|])/g, '\\\\\$1'), 'i') : null,
\t\t\t\t\tmime  = fm.searchStatus.mime,
\t\t\t\t\tinSearch = fm.searchStatus.state > 1,
\t\t\t\t\tphash = inSearch && fm.searchStatus.target? fm.searchStatus.target : fm.cwd().hash,
\t\t\t\t\tcurPath = fm.path(phash),
\t\t\t\t\tinTarget = function(f) {
\t\t\t\t\t\tvar res, parents, path;
\t\t\t\t\t\tres = (f.phash === phash);
\t\t\t\t\t\tif (!res && inSearch) {
\t\t\t\t\t\t\tpath = f.path || fm.path(f.hash);
\t\t\t\t\t\t\tres = (curPath && path.indexOf(curPath) === 0);
\t\t\t\t\t\t\tif (! res && fm.searchStatus.mixed) {
\t\t\t\t\t\t\t\tres = \$.grep(fm.searchStatus.mixed, function(vid) { return f.hash.indexOf(vid) === 0? true : false; }).length? true : false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (res && inSearch) {
\t\t\t\t\t\t\tif (mime) {
\t\t\t\t\t\t\t\tres = (f.mime.indexOf(mime) === 0);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tres = (f.name.match(regex) || (f.i18 && f.i18.match(regex)))? true : false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn res;
\t\t\t\t\t},
\t\t\t\t\tfiles = \$.grep(e.data.added || [], function(f) { return inTarget(f)? true : false ;});
\t\t\t\tadd(files);
\t\t\t\tif (fm.searchStatus.state === 2) {
\t\t\t\t\t\$.each(files, function(i, f) {
\t\t\t\t\t\tif (\$.inArray(f.hash, cwdHashes) === -1) {
\t\t\t\t\t\t\tcwdHashes.push(f.hash);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tfm.trigger('cwdhasheschange', cwdHashes);
\t\t\t\t}
\t\t\t\tlist && resize();
\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t})
\t\t\t.change(function(e) {
\t\t\t\tvar phash = fm.cwd().hash,
\t\t\t\t\tsel   = fm.selected(),
\t\t\t\t\tfiles, added;

\t\t\t\tif (query) {
\t\t\t\t\t\$.each(e.data.changed || [], function(i, file) {
\t\t\t\t\t\tif (fm.cwdHash2Elm(file.hash).length) {
\t\t\t\t\t\t\tremove([file.hash]);
\t\t\t\t\t\t\tadd([file], 'change');
\t\t\t\t\t\t\t\$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
\t\t\t\t\t\t\tadded = true;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\t\$.each(\$.grep(e.data.changed || [], function(f) { return f.phash == phash ? true : false; }), function(i, file) {
\t\t\t\t\t\tif (fm.cwdHash2Elm(file.hash).length) {
\t\t\t\t\t\t\tremove([file.hash]);
\t\t\t\t\t\t\tadd([file], 'change');
\t\t\t\t\t\t\t\$.inArray(file.hash, sel) !== -1 && selectFile(file.hash);
\t\t\t\t\t\t\tadded = true;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (added) {
\t\t\t\t\tfm.trigger('cwdhasheschange', cwdHashes);
\t\t\t\t\tlist && resize();
\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t}
\t\t\t\t
\t\t\t\ttrigger();
\t\t\t})
\t\t\t.remove(function(e) {
\t\t\t\tvar place = list ? cwd.find('tbody') : cwd;
\t\t\t\tremove(e.data.removed || []);
\t\t\t\ttrigger();
\t\t\t\tif (buffer.length < 1 && place.children(fileSelector + (options.oldSchool? ':not(.elfinder-cwd-parent)' : '')).length < 1) {
\t\t\t\t\twz.addClass('elfinder-cwd-wrapper-empty');
\t\t\t\t\tselectCheckbox && selectAllCheckbox.find('input').prop('checked', false);
\t\t\t\t\tbottomMarker.hide();
\t\t\t\t\twrapper.off(scrollEvent, render);
\t\t\t\t\tresize();
\t\t\t\t} else {
\t\t\t\t\tbottomMarkerShow(place);
\t\t\t\t\twrapper.trigger(scrollEvent);
\t\t\t\t}
\t\t\t})
\t\t\t// select dragged file if no selected, disable selectable
\t\t\t.dragstart(function(e) {
\t\t\t\tvar target = \$(e.data.target),
\t\t\t\t\toe     = e.data.originalEvent;

\t\t\t\tif (target.hasClass(clFile)) {
\t\t\t\t\t
\t\t\t\t\tif (!target.hasClass(clSelected)) {
\t\t\t\t\t\t!(oe.ctrlKey || oe.metaKey || oe.shiftKey) && unselectAll({ notrigger: true });
\t\t\t\t\t\ttarget.trigger(evtSelect);
\t\t\t\t\t\ttrigger();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tcwd.removeClass(clDisabled).data('selectable') && cwd.selectable('disable');
\t\t\t\tselectLock = true;
\t\t\t})
\t\t\t// enable selectable
\t\t\t.dragstop(function() {
\t\t\t\tcwd.data('selectable') && cwd.selectable('enable');
\t\t\t\tselectLock = false;
\t\t\t})
\t\t\t.bind('lockfiles unlockfiles selectfiles unselectfiles', function(e) {
\t\t\t\tvar events = {
\t\t\t\t\t\tlockfiles     : evtDisable ,
\t\t\t\t\t\tunlockfiles   : evtEnable ,
\t\t\t\t\t\tselectfiles   : evtSelect,
\t\t\t\t\t\tunselectfiles : evtUnselect },
\t\t\t\t\tevent  = events[e.type],
\t\t\t\t\tfiles  = e.data.files || [],
\t\t\t\t\tl      = files.length,
\t\t\t\t\thelper = e.data.helper || \$(),
\t\t\t\t\tparents, ctr, add;

\t\t\t\tif (l > 0) {
\t\t\t\t\tparents = fm.parents(files[0]);
\t\t\t\t}
\t\t\t\tif (event === evtSelect || event === evtUnselect) {
\t\t\t\t\tadd  = (event === evtSelect),
\t\t\t\t\t\$.each(files, function(i, hash) {
\t\t\t\t\t\tvar all = cwd.hasClass('elfinder-cwd-allselected');
\t\t\t\t\t\tif (! selectedFiles[hash]) {
\t\t\t\t\t\t\tadd && (selectedFiles[hash] = true);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (all) {
\t\t\t\t\t\t\t\tselectCheckbox && selectAllCheckbox.children('input').prop('checked', false);
\t\t\t\t\t\t\t\tcwd.removeClass('elfinder-cwd-allselected');
\t\t\t\t\t\t\t\tall = false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t! add && delete selectedFiles[hash];
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (!helper.data('locked')) {
\t\t\t\t\twhile (l--) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tfm.cwdHash2Elm(files[l]).trigger(event);
\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t}
\t\t\t\t\t! e.data.inselect && trigger();
\t\t\t\t}
\t\t\t\tif (wrapper.data('dropover') && parents.indexOf(wrapper.data('dropover')) !== -1) {
\t\t\t\t\tctr = e.type !== 'lockfiles';
\t\t\t\t\thelper.toggleClass('elfinder-drag-helper-plus', ctr);
\t\t\t\t\twrapper.toggleClass(clDropActive, ctr);
\t\t\t\t}
\t\t\t})
\t\t\t// select new files after some actions
\t\t\t.bind('mkdir mkfile duplicate upload rename archive extract paste multiupload', function(e) {
\t\t\t\tif (e.type == 'upload' && e.data._multiupload) return;
\t\t\t\tvar phash = fm.cwd().hash, files;
\t\t\t\t
\t\t\t\tunselectAll({ notrigger: true });

\t\t\t\t\$.each((e.data.added || []).concat(e.data.changed || []), function(i, file) { 
\t\t\t\t\tfile && file.phash == phash && selectFile(file.hash);
\t\t\t\t});
\t\t\t\ttrigger();
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     :'ctrl+a', 
\t\t\t\tdescription : 'selectall',
\t\t\t\tcallback    : selectAll
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     :'ctrl+shift+i', 
\t\t\t\tdescription : 'selectinvert',
\t\t\t\tcallback    : selectInvert
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : 'left right up down shift+left shift+right shift+up shift+down',
\t\t\t\tdescription : 'selectfiles',
\t\t\t\ttype        : 'keydown' , //fm.UA.Firefox || fm.UA.Opera ? 'keypress' : 'keydown',
\t\t\t\tcallback    : function(e) { select(e.keyCode, e.shiftKey); }
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : 'home',
\t\t\t\tdescription : 'selectffile',
\t\t\t\tcallback    : function(e) { 
\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\tscrollToView(cwd.find('[id]:first').trigger(evtSelect));
\t\t\t\t\ttrigger();
\t\t\t\t}
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : 'end',
\t\t\t\tdescription : 'selectlfile',
\t\t\t\tcallback    : function(e) { 
\t\t\t\t\tunselectAll({ notrigger: true });
\t\t\t\t\tscrollToView(cwd.find('[id]:last').trigger(evtSelect)) ;
\t\t\t\t\ttrigger();
\t\t\t\t}
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : 'page_up',
\t\t\t\tdescription : 'pageTurning',
\t\t\t\tcallback    : function(e) {
\t\t\t\t\tif (bufferExt.itemH) {
\t\t\t\t\t\twrapper.scrollTop(
\t\t\t\t\t\t\tMath.round(
\t\t\t\t\t\t\t\twrapper.scrollTop()
\t\t\t\t\t\t\t\t- (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
\t\t\t\t\t\t\t)
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}).shortcut({
\t\t\t\tpattern     : 'page_down',
\t\t\t\tdescription : 'pageTurning',
\t\t\t\tcallback    : function(e) { 
\t\t\t\t\tif (bufferExt.itemH) {
\t\t\t\t\t\twrapper.scrollTop(
\t\t\t\t\t\t\tMath.round(
\t\t\t\t\t\t\t\twrapper.scrollTop()
\t\t\t\t\t\t\t\t+ (Math.floor((wrapper.height() + (list? bufferExt.itemH * -1 : 16)) / bufferExt.itemH)) * bufferExt.itemH
\t\t\t\t\t\t\t)
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t
\t});
\t
\t// fm.timeEnd('cwdLoad')
\t
\treturn this;
};


/*
 * File: /js/ui/dialog.js
 */

/**
 * @class  elFinder dialog
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderdialog = function(opts, fm) {
\t\tvar platformWin = (window.navigator.platform.indexOf('Win') != -1),
\t\tdelta       = {},
\t\tsyncSize    = { enabled: false, width: false, height: false, defaultSize: null },
\t\tfitSize     = function(dialog) {
\t\t\tvar opts, node;
\t\t\tif (syncSize.enabled) {
\t\t\t\tnode = fm.options.dialogContained? elfNode : \$(window);
\t\t\t\topts = {
\t\t\t\t\tmaxWidth : syncSize.width?  node.width() - delta.width  : null,
\t\t\t\t\tmaxHeight: syncSize.height? node.height() - delta.height : null
\t\t\t\t};
\t\t\t\tObject.assign(restoreStyle, opts);
\t\t\t\tdialog.css(opts).trigger('resize');
\t\t\t\tif (dialog.data('hasResizable') && (dialog.resizable('option', 'maxWidth') < opts.maxWidth || dialog.resizable('option', 'maxHeight') < opts.maxHeight)) {
\t\t\t\t\tdialog.resizable('option', opts);
\t\t\t\t}
\t\t\t}
\t\t},
\t\tsyncFunc    = function(e) {
\t\t\tvar dialog = e.data;
\t\t\tsyncTm && cancelAnimationFrame(syncTm);
\t\t\tsyncTm = requestAnimationFrame(function() {
\t\t\t\tvar opts, offset;
\t\t\t\tif (syncSize.enabled) {
\t\t\t\t\tfitSize(dialog);
\t\t\t\t}
\t\t\t});
\t\t},
\t\tcheckEditing = function() {
\t\t\tvar cldialog = 'elfinder-dialog',
\t\t\t\tdialogs = elfNode.children('.' + cldialog + '.' + fm.res('class', 'editing') + ':visible');
\t\t\tfm[dialogs.length? 'disable' : 'enable']();
\t\t},
\t\tpropagationEvents = {},
\t\tsyncTm, dialog, elfNode, restoreStyle;
\t
\tif (fm && fm.ui) {
\t\telfNode = fm.getUI();
\t} else {
\t\telfNode = this.closest('.elfinder');
\t\tif (! fm) {
\t\t\tfm = elfNode.elfinder('instance');
\t\t}
\t}
\t
\tif (typeof opts  === 'string') {
\t\tif ((dialog = this.closest('.ui-dialog')).length) {
\t\t\tif (opts === 'open') {
\t\t\t\tif (dialog.css('display') === 'none') {
\t\t\t\t\t// Need dialog.show() and hide() to detect elements size in open() callbacks
\t\t\t\t\tdialog.trigger('posinit').show().trigger('open').hide();
\t\t\t\t\tdialog.fadeIn(120, function() {
\t\t\t\t\t\tfm.trigger('dialogopened', {dialog: dialog});
\t\t\t\t\t});
\t\t\t\t}
\t\t\t} else if (opts === 'close' || opts === 'destroy') {
\t\t\t\tdialog.stop(true);
\t\t\t\tif (dialog.is(':visible') || elfNode.is(':hidden')) {
\t\t\t\t\tdialog.trigger('close');
\t\t\t\t\tfm.trigger('dialogclosed', {dialog: dialog});
\t\t\t\t}
\t\t\t\tif (opts === 'destroy') {
\t\t\t\t\tdialog.remove();
\t\t\t\t\tfm.trigger('dialogremoved', {dialog: dialog});
\t\t\t\t} else if (dialog.data('minimized')) {
\t\t\t\t\tdialog.data('minimized').close();
\t\t\t\t}
\t\t\t} else if (opts === 'toTop') {
\t\t\t\tdialog.trigger('totop');
\t\t\t\tfm.trigger('dialogtotoped', {dialog: dialog});
\t\t\t} else if (opts === 'posInit') {
\t\t\t\tdialog.trigger('posinit');
\t\t\t\tfm.trigger('dialogposinited', {dialog: dialog});
\t\t\t} else if (opts === 'tabstopsInit') {
\t\t\t\tdialog.trigger('tabstopsInit');
\t\t\t\tfm.trigger('dialogtabstopsinited', {dialog: dialog});
\t\t\t} else if (opts === 'checkEditing') {
\t\t\t\tcheckEditing();
\t\t\t}
\t\t}
\t\treturn this;
\t}
\t
\topts = Object.assign({}, \$.fn.elfinderdialog.defaults, opts);
\t
\tif (opts.allowMinimize && opts.allowMinimize === 'auto') {
\t\topts.allowMinimize = this.find('textarea,input').length? true : false; 
\t}
\topts.openMaximized = opts.allowMinimize && opts.openMaximized;
\tif (opts.headerBtnPos && opts.headerBtnPos === 'auto') {
\t\topts.headerBtnPos = platformWin? 'right' : 'left';
\t}
\tif (opts.headerBtnOrder && opts.headerBtnOrder === 'auto') {
\t\topts.headerBtnOrder = platformWin? 'close:maximize:minimize' : 'close:minimize:maximize';
\t}
\t
\tif (opts.modal && opts.allowMinimize) {
\t\topts.allowMinimize = false;
\t}
\t
\tif (fm.options.dialogContained) {
\t\tsyncSize.width = syncSize.height = syncSize.enabled = true;
\t} else {
\t\tsyncSize.width = (opts.maxWidth === 'window');
\t\tsyncSize.height = (opts.maxHeight === 'window');
\t\tif (syncSize.width || syncSize.height) {
\t\t\tsyncSize.enabled = true;
\t\t}
\t}

\tpropagationEvents = fm.arrayFlip(opts.propagationEvents, true);
\t
\tthis.filter(':not(.ui-dialog-content)').each(function() {
\t\tvar self       = \$(this).addClass('ui-dialog-content ui-widget-content'),
\t\t\tclactive   = 'elfinder-dialog-active',
\t\t\tcldialog   = 'elfinder-dialog',
\t\t\tclnotify   = 'elfinder-dialog-notify',
\t\t\tclhover    = 'ui-state-hover',
\t\t\tcltabstop  = 'elfinder-tabstop',
\t\t\tcl1stfocus = 'elfinder-focus',
\t\t\tclmodal    = 'elfinder-dialog-modal',
\t\t\tid         = parseInt(Math.random()*1000000),
\t\t\ttitlebar   = \$('<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-top ui-helper-clearfix\"><span class=\"elfinder-dialog-title\">'+opts.title+'</span></div>'),
\t\t\tbuttonset  = \$('<div class=\"ui-dialog-buttonset\"></div>'),
\t\t\tbuttonpane = \$('<div class=\" ui-helper-clearfix ui-dialog-buttonpane ui-widget-content\"></div>')
\t\t\t\t.append(buttonset),
\t\t\tbtnWidth   = 0,
\t\t\tbtnCnt     = 0,
\t\t\ttabstops   = \$(),
\t\t\tevCover    = \$('<div style=\"width:100%;height:100%;position:absolute;top:0px;left:0px;\"></div>').hide(),
\t\t\tnumberToTel = function() {
\t\t\t\tif (opts.optimizeNumber) {
\t\t\t\t\tdialog.find('input[type=number]').each(function() {
\t\t\t\t\t\t\$(this).attr('inputmode', 'numeric');
\t\t\t\t\t\t\$(this).attr('pattern', '[0-9]*');
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\ttabstopsInit = function() {
\t\t\t\ttabstops = dialog.find('.'+cltabstop);
\t\t\t\tif (tabstops.length) {
\t\t\t\t\ttabstops.attr('tabindex', '-1');
\t\t\t\t\tif (! tabstops.filter('.'+cl1stfocus).length) {
\t\t\t\t\t\tbuttonset.children('.'+cltabstop+':'+(platformWin? 'first' : 'last')).addClass(cl1stfocus);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\ttabstopNext = function(cur) {
\t\t\t\tvar elms = tabstops.filter(':visible:enabled'),
\t\t\t\t\tnode = cur? null : elms.filter('.'+cl1stfocus+':first');
\t\t\t\t\t
\t\t\t\tif (! node || ! node.length) {
\t\t\t\t\tnode = elms.first();
\t\t\t\t}
\t\t\t\tif (cur) {
\t\t\t\t\t\$.each(elms, function(i, elm) {
\t\t\t\t\t\tif (elm === cur && elms[i+1]) {
\t\t\t\t\t\t\tnode = elms.eq(i+1);
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\treturn node;
\t\t\t},
\t\t\ttabstopPrev = function(cur) {
\t\t\t\tvar elms = tabstops.filter(':visible:enabled'),
\t\t\t\t\tnode = elms.last();
\t\t\t\t\$.each(elms, function(i, elm) {
\t\t\t\t\tif (elm === cur && elms[i-1]) {
\t\t\t\t\t\tnode = elms.eq(i-1);
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\treturn node;
\t\t\t},
\t\t\tmakeHeaderBtn = function() {
\t\t\t\t\$.each(opts.headerBtnOrder.split(':').reverse(), function(i, v) {
\t\t\t\t\theaderBtns[v] && headerBtns[v]();
\t\t\t\t});
\t\t\t\tif (platformWin) {
\t\t\t\t\ttitlebar.children('.elfinder-titlebar-button').addClass('elfinder-titlebar-button-right');
\t\t\t\t}
\t\t\t},
\t\t\theaderBtns = {
\t\t\t\tclose: function() {
\t\t\t\t\ttitlebar.prepend(\$('<span class=\"ui-widget-header ui-dialog-titlebar-close ui-corner-all elfinder-titlebar-button\"><span class=\"ui-icon ui-icon-closethick\"></span></span>')
\t\t\t\t\t\t.on('mousedown touchstart', function(e) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\tself.elfinderdialog('close');
\t\t\t\t\t\t})
\t\t\t\t\t);
\t\t\t\t},
\t\t\t\tmaximize: function() {
\t\t\t\t\tif (opts.allowMaximize) {
\t\t\t\t\t\tdialog.on('resize', function(e, data) {
\t\t\t\t\t\t\tvar full, elm;
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\tif (data && data.maximize) {
\t\t\t\t\t\t\t\telm = titlebar.find('.elfinder-titlebar-full');
\t\t\t\t\t\t\t\tfull = (data.maximize === 'on');
\t\t\t\t\t\t\t\telm.children('span.ui-icon')
\t\t\t\t\t\t\t\t\t.toggleClass('ui-icon-plusthick', ! full)
\t\t\t\t\t\t\t\t\t.toggleClass('ui-icon-arrowreturnthick-1-s', full);
\t\t\t\t\t\t\t\tif (full) {
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tdialog.hasClass('ui-draggable') && dialog.draggable('disable');
\t\t\t\t\t\t\t\t\t\tdialog.hasClass('ui-resizable') && dialog.resizable('disable');
\t\t\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t\t\t\tself.css('width', '100%').css('height', dialog.height() - dialog.children('.ui-dialog-titlebar').outerHeight(true) - buttonpane.outerHeight(true));
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tself.attr('style', elm.data('style'));
\t\t\t\t\t\t\t\t\telm.removeData('style');
\t\t\t\t\t\t\t\t\tposCheck();
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tdialog.hasClass('ui-draggable') && dialog.draggable('enable');
\t\t\t\t\t\t\t\t\t\tdialog.hasClass('ui-resizable') && dialog.resizable('enable');
\t\t\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdialog.trigger('resize', {init: true});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\ttitlebar.prepend(\$('<span class=\"ui-widget-header ui-corner-all elfinder-titlebar-button elfinder-titlebar-full\"><span class=\"ui-icon ui-icon-plusthick\"></span></span>')
\t\t\t\t\t\t\t.on('mousedown touchstart', function(e) {
\t\t\t\t\t\t\t\tvar elm = \$(this);
\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\tif (!dialog.hasClass('elfinder-maximized') && typeof elm.data('style') === 'undefined') {
\t\t\t\t\t\t\t\t\tself.height(self.height());
\t\t\t\t\t\t\t\t\telm.data('style', self.attr('style') || '');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.toggleMaximize(dialog);
\t\t\t\t\t\t\t\ttypeof(opts.maximize) === 'function' && opts.maximize.call(self[0]);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t},
\t\t\t\tminimize: function() {
\t\t\t\t\tvar btn, mnode, doffset;
\t\t\t\t\tif (opts.allowMinimize) {
\t\t\t\t\t\tbtn = \$('<span class=\"ui-widget-header ui-corner-all elfinder-titlebar-button elfinder-titlebar-minimize\"><span class=\"ui-icon ui-icon-minusthick\"></span></span>')
\t\t\t\t\t\t\t.on('mousedown touchstart', function(e) {
\t\t\t\t\t\t\t\tvar \$this = \$(this),
\t\t\t\t\t\t\t\t\ttray = fm.getUI('bottomtray'),
\t\t\t\t\t\t\t\t\tdumStyle = { width: 70, height: 24 },
\t\t\t\t\t\t\t\t\tdum = \$('<div></div>').css(dumStyle).addClass(dialog.get(0).className + ' elfinder-dialog-minimized'),
\t\t\t\t\t\t\t\t\tclose = function() {
\t\t\t\t\t\t\t\t\t\tmnode.remove();
\t\t\t\t\t\t\t\t\t\tdialog.removeData('minimized').show();
\t\t\t\t\t\t\t\t\t\tself.elfinderdialog('close');
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tpos = {};
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\tif (!dialog.data('minimized')) {
\t\t\t\t\t\t\t\t\t// minimize
\t\t\t\t\t\t\t\t\tdoffset = dialog.data('minimized', {
\t\t\t\t\t\t\t\t\t\tdialog : function() { return mnode; },
\t\t\t\t\t\t\t\t\t\tshow : function() { mnode.show(); },
\t\t\t\t\t\t\t\t\t\thide : function() { mnode.hide(); },
\t\t\t\t\t\t\t\t\t\tclose : close,
\t\t\t\t\t\t\t\t\t\ttitle : function(v) { mnode.children('.ui-dialog-titlebar').children('.elfinder-dialog-title').text(v); }
\t\t\t\t\t\t\t\t\t}).position();
\t\t\t\t\t\t\t\t\tmnode = dialog.clone().on('mousedown', function() {
\t\t\t\t\t\t\t\t\t\t\$this.trigger('mousedown');
\t\t\t\t\t\t\t\t\t}).removeClass('ui-draggable ui-resizable elfinder-frontmost');
\t\t\t\t\t\t\t\t\ttray.append(dum);
\t\t\t\t\t\t\t\t\tObject.assign(pos, dum.offset(), dumStyle);
\t\t\t\t\t\t\t\t\tdum.remove();
\t\t\t\t\t\t\t\t\tmnode.height(dialog.height()).children('.ui-dialog-content:first').empty();
\t\t\t\t\t\t\t\t\tfm.toHide(dialog.before(mnode));
\t\t\t\t\t\t\t\t\tmnode.children('.ui-dialog-content:first,.ui-dialog-buttonpane,.ui-resizable-handle').remove();
\t\t\t\t\t\t\t\t\tmnode.find('.elfinder-titlebar-minimize,.elfinder-titlebar-full').remove();
\t\t\t\t\t\t\t\t\tmnode.find('.ui-dialog-titlebar-close').on('mousedown', function(e) {
\t\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\t\tclose();
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tmnode.animate(pos, function() {
\t\t\t\t\t\t\t\t\t\tmnode.attr('style', '')
\t\t\t\t\t\t\t\t\t\t.css({ maxWidth: dialog.width() })
\t\t\t\t\t\t\t\t\t\t.addClass('elfinder-dialog-minimized')
\t\t\t\t\t\t\t\t\t\t.appendTo(tray);
\t\t\t\t\t\t\t\t\t\tcheckEditing();
\t\t\t\t\t\t\t\t\t\ttypeof(opts.minimize) === 'function' && opts.minimize.call(self[0]);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t//restore
\t\t\t\t\t\t\t\t\tdialog.removeData('minimized').before(mnode.css(Object.assign({'position': 'absolute'}, mnode.offset())));
\t\t\t\t\t\t\t\t\tfm.toFront(mnode);
\t\t\t\t\t\t\t\t\tmnode.animate(Object.assign({ width: dialog.width(), height: dialog.height() }, doffset), function() {
\t\t\t\t\t\t\t\t\t\tdialog.show();
\t\t\t\t\t\t\t\t\t\tfm.toFront(dialog);
\t\t\t\t\t\t\t\t\t\tmnode.remove();
\t\t\t\t\t\t\t\t\t\tposCheck();
\t\t\t\t\t\t\t\t\t\tcheckEditing();
\t\t\t\t\t\t\t\t\t\tdialog.trigger('resize', {init: true});
\t\t\t\t\t\t\t\t\t\ttypeof(opts.minimize) === 'function' && opts.minimize.call(self[0]);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\ttitlebar.on('dblclick', function(e) {
\t\t\t\t\t\t\t\$(this).children('.elfinder-titlebar-minimize').trigger('mousedown');
\t\t\t\t\t\t}).prepend(btn);
\t\t\t\t\t\tdialog.on('togleminimize', function() {
\t\t\t\t\t\t\tbtn.trigger('mousedown');
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tdialog = \$('<div class=\"ui-front ui-dialog ui-widget ui-widget-content ui-corner-all ui-draggable std42-dialog touch-punch '+cldialog+' '+opts.cssClass+'\"></div>')
\t\t\t\t.hide()
\t\t\t\t.append(self)
\t\t\t\t.appendTo(elfNode)
\t\t\t\t.draggable({
\t\t\t\t\tcontainment : fm.options.dialogContained? elfNode : null,
\t\t\t\t\thandle : '.ui-dialog-titlebar',
\t\t\t\t\tstart : function() {
\t\t\t\t\t\tevCover.show();
\t\t\t\t\t},
\t\t\t\t\tdrag : function(e, ui) {
\t\t\t\t\t\tvar top = ui.offset.top,
\t\t\t\t\t\t\tleft = ui.offset.left;
\t\t\t\t\t\tif (top < 0) {
\t\t\t\t\t\t\tui.position.top = ui.position.top - top;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (left < 0) {
\t\t\t\t\t\t\tui.position.left = ui.position.left - left;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (fm.options.dialogContained) {
\t\t\t\t\t\t\tui.position.top < 0 && (ui.position.top = 0);
\t\t\t\t\t\t\tui.position.left < 0 && (ui.position.left = 0);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tstop : function(e, ui) {
\t\t\t\t\t\tevCover.hide();
\t\t\t\t\t\tdialog.css({height : opts.height});
\t\t\t\t\t\tself.data('draged', true);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.css({
\t\t\t\t\twidth     : opts.width,
\t\t\t\t\theight    : opts.height,
\t\t\t\t\tminWidth  : opts.minWidth,
\t\t\t\t\tminHeight : opts.minHeight,
\t\t\t\t\tmaxWidth  : opts.maxWidth,
\t\t\t\t\tmaxHeight : opts.maxHeight
\t\t\t\t})
\t\t\t\t.on('touchstart touchmove touchend click dblclick mouseup mouseenter mouseleave mouseout mouseover mousemove', function(e) {
\t\t\t\t\t// stopPropagation of user action events
\t\t\t\t\t!propagationEvents[e.type] && e.stopPropagation();
\t\t\t\t})
\t\t\t\t.on('mousedown', function(e) {
\t\t\t\t\t!propagationEvents[e.type] && e.stopPropagation();
\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\tif (dialog.is(':visible') && !dialog.hasClass('elfinder-frontmost')) {
\t\t\t\t\t\t\ttoFocusNode = \$(':focus');
\t\t\t\t\t\t\tif (!toFocusNode.length) {
\t\t\t\t\t\t\t\ttoFocusNode = void(0);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdialog.trigger('totop');
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.on('open', function() {
\t\t\t\t\tdialog.data('margin-y', self.outerHeight(true) - self.height());
\t\t\t\t\tif (syncSize.enabled) {
\t\t\t\t\t\tif (opts.height && opts.height !== 'auto') {
\t\t\t\t\t\t\tdialog.trigger('resize', {init: true});
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!syncSize.defaultSize) {
\t\t\t\t\t\t\tsyncSize.defaultSize = { width: self.width(), height: self.height() };
\t\t\t\t\t\t}
\t\t\t\t\t\tfitSize(dialog);
\t\t\t\t\t\tdialog.trigger('resize').trigger('posinit');
\t\t\t\t\t\telfNode.on('resize.'+fm.namespace, dialog, syncFunc);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!dialog.hasClass(clnotify)) {
\t\t\t\t\t\telfNode.children('.'+cldialog+':visible:not(.'+clnotify+')').each(function() {
\t\t\t\t\t\t\tvar d     = \$(this),
\t\t\t\t\t\t\t\ttop   = parseInt(d.css('top')),
\t\t\t\t\t\t\t\tleft  = parseInt(d.css('left')),
\t\t\t\t\t\t\t\t_top  = parseInt(dialog.css('top')),
\t\t\t\t\t\t\t\t_left = parseInt(dialog.css('left')),
\t\t\t\t\t\t\t\tct    = Math.abs(top - _top) < 10,
\t\t\t\t\t\t\t\tcl    = Math.abs(left - _left) < 10;

\t\t\t\t\t\t\tif (d[0] != dialog[0] && (ct || cl)) {
\t\t\t\t\t\t\t\tdialog.css({
\t\t\t\t\t\t\t\t\ttop  : ct ? (top + 10) : _top,
\t\t\t\t\t\t\t\t\tleft : cl ? (left + 10) : _left
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t} 
\t\t\t\t\t
\t\t\t\t\tif (dialog.data('modal')) {
\t\t\t\t\t\tdialog.addClass(clmodal);
\t\t\t\t\t\tfm.getUI('overlay').elfinderoverlay('show');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tdialog.trigger('totop');
\t\t\t\t\t
\t\t\t\t\topts.openMaximized && fm.toggleMaximize(dialog);

\t\t\t\t\tfm.trigger('dialogopen', {dialog: dialog});

\t\t\t\t\ttypeof(opts.open) == 'function' && \$.proxy(opts.open, self[0])();
\t\t\t\t\t
\t\t\t\t\tif (opts.closeOnEscape) {
\t\t\t\t\t\t\$(document).on('keydown.'+id, function(e) {
\t\t\t\t\t\t\tif (e.keyCode == \$.ui.keyCode.ESCAPE && dialog.hasClass('elfinder-frontmost')) {
\t\t\t\t\t\t\t\tself.elfinderdialog('close');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tdialog.hasClass(fm.res('class', 'editing')) && checkEditing();
\t\t\t\t})
\t\t\t\t.on('close', function(e) {
\t\t\t\t\tvar dialogs, dfd;
\t\t\t\t\t
\t\t\t\t\tif (opts.beforeclose && typeof opts.beforeclose === 'function') {
\t\t\t\t\t\tdfd = opts.beforeclose();
\t\t\t\t\t\tif (!dfd || !dfd.promise) {
\t\t\t\t\t\t\tdfd = !dfd? \$.Deferred().reject() : \$.Deferred().resolve();
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tdfd = \$.Deferred().resolve();
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tdfd.done(function() {
\t\t\t\t\t\tsyncSize.enabled && elfNode.off('resize.'+fm.namespace, syncFunc);
\t\t\t\t\t\t
\t\t\t\t\t\tif (opts.closeOnEscape) {
\t\t\t\t\t\t\t\$(document).off('keyup.'+id);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (opts.allowMaximize) {
\t\t\t\t\t\t\tfm.toggleMaximize(dialog, false);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tfm.toHide(dialog);
\t\t\t\t\t\tdialog.data('modal') && fm.getUI('overlay').elfinderoverlay('hide');
\t\t\t\t\t\t
\t\t\t\t\t\tif (typeof(opts.close) == 'function') {
\t\t\t\t\t\t\t\$.proxy(opts.close, self[0])();
\t\t\t\t\t\t}
\t\t\t\t\t\tif (opts.destroyOnClose && dialog.parent().length) {
\t\t\t\t\t\t\tdialog.hide().remove();
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// get focus to next dialog
\t\t\t\t\t\tdialogs = elfNode.children('.'+cldialog+':visible');
\t\t\t\t\t\t
\t\t\t\t\t\tdialog.hasClass(fm.res('class', 'editing')) && checkEditing();
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.on('totop frontmost', function() {
\t\t\t\t\tvar s = fm.storage('autoFocusDialog');
\t\t\t\t\t
\t\t\t\t\tdialog.data('focusOnMouseOver', s? (s > 0) : fm.options.uiOptions.dialog.focusOnMouseOver);
\t\t\t\t\t
\t\t\t\t\tif (dialog.data('minimized')) {
\t\t\t\t\t\ttitlebar.children('.elfinder-titlebar-minimize').trigger('mousedown');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!dialog.data('modal') && fm.getUI('overlay').is(':visible')) {
\t\t\t\t\t\tfm.getUI('overlay').before(dialog);
\t\t\t\t\t} else {
\t\t\t\t\t\tfm.toFront(dialog);
\t\t\t\t\t}
\t\t\t\t\telfNode.children('.'+cldialog+':not(.'+clmodal+')').removeClass(clactive);
\t\t\t\t\tdialog.addClass(clactive);

\t\t\t\t\t! fm.UA.Mobile && (toFocusNode || tabstopNext()).trigger('focus');

\t\t\t\t\ttoFocusNode = void(0);
\t\t\t\t})
\t\t\t\t.on('posinit', function() {
\t\t\t\t\tvar css = opts.position,
\t\t\t\t\t\tnodeOffset, minTop, minLeft, outerSize, win, winSize, nodeFull;
\t\t\t\t\tif (dialog.hasClass('elfinder-maximized')) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tif (! css && ! dialog.data('resizing')) {
\t\t\t\t\t\tnodeFull = elfNode.hasClass('elfinder-fullscreen') || fm.options.enableAlways;
\t\t\t\t\t\tdialog.css(nodeFull? {
\t\t\t\t\t\t\tmaxWidth  : '100%',
\t\t\t\t\t\t\tmaxHeight : '100%',
\t\t\t\t\t\t\toverflow   : 'auto'
\t\t\t\t\t\t} : restoreStyle);
\t\t\t\t\t\tif (fm.UA.Mobile && !nodeFull && dialog.data('rotated') === fm.UA.Rotated) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\tdialog.data('rotated', fm.UA.Rotated);
\t\t\t\t\t\twin = \$(window);
\t\t\t\t\t\tnodeOffset = elfNode.offset();
\t\t\t\t\t\touterSize = {
\t\t\t\t\t\t\twidth : dialog.outerWidth(true),
\t\t\t\t\t\t\theight: dialog.outerHeight(true)
\t\t\t\t\t\t};
\t\t\t\t\t\touterSize.right = nodeOffset.left + outerSize.width;
\t\t\t\t\t\touterSize.bottom = nodeOffset.top + outerSize.height;
\t\t\t\t\t\twinSize = {
\t\t\t\t\t\t\tscrLeft: win.scrollLeft(),
\t\t\t\t\t\t\tscrTop : win.scrollTop(),
\t\t\t\t\t\t\twidth  : win.width(),
\t\t\t\t\t\t\theight : win.height()
\t\t\t\t\t\t};
\t\t\t\t\t\twinSize.right = winSize.scrLeft + winSize.width;
\t\t\t\t\t\twinSize.bottom = winSize.scrTop + winSize.height;
\t\t\t\t\t\t
\t\t\t\t\t\tif (fm.options.dialogContained || nodeFull) {
\t\t\t\t\t\t\tminTop = 0;
\t\t\t\t\t\t\tminLeft = 0;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tminTop = nodeOffset.top * -1 + winSize.scrTop;
\t\t\t\t\t\t\tminLeft = nodeOffset.left * -1 + winSize.scrLeft;
\t\t\t\t\t\t}
\t\t\t\t\t\tcss = {
\t\t\t\t\t\t\ttop  : outerSize.height >= winSize.height? minTop  : Math.max(minTop, parseInt((elfNode.height() - outerSize.height)/2 - 42)),
\t\t\t\t\t\t\tleft : outerSize.width  >= winSize.width ? minLeft : Math.max(minLeft, parseInt((elfNode.width() - outerSize.width)/2))
\t\t\t\t\t\t};
\t\t\t\t\t\tif (outerSize.right + css.left > winSize.right) {
\t\t\t\t\t\t\tcss.left = Math.max(minLeft, winSize.right - outerSize.right);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (outerSize.bottom + css.top > winSize.bottom) {
\t\t\t\t\t\t\tcss.top = Math.max(minTop, winSize.bottom - outerSize.bottom);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (opts.absolute) {
\t\t\t\t\t\tcss.position = 'absolute';
\t\t\t\t\t}
\t\t\t\t\tcss && dialog.css(css);
\t\t\t\t})
\t\t\t\t.on('resize', function(e, data) {
\t\t\t\t\tvar oh = 0, init = data && data.init, h, minH, maxH, autoH;
\t\t\t\t\tif ((data && (data.minimize || data.maxmize)) || dialog.data('minimized')) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.preventDefault();
\t\t\t\t\tdialog.children('.ui-widget-header,.ui-dialog-buttonpane').each(function() {
\t\t\t\t\t\toh += \$(this).outerHeight(true);
\t\t\t\t\t});
\t\t\t\t\tautoH = (opts.height === 'auto')? true : false;
\t\t\t\t\tif (autoH) {
\t\t\t\t\t\tself.css({'max-height': '', 'height': 'auto'});
\t\t\t\t\t}
\t\t\t\t\tif (!init && syncSize.enabled && !e.originalEvent && !dialog.hasClass('elfinder-maximized')) {
\t\t\t\t\t\th = dialog.height();
\t\t\t\t\t\tminH = dialog.css('min-height') || h;
\t\t\t\t\t\tmaxH = dialog.css('max-height') || h;
\t\t\t\t\t\tif (minH.match(/%/)) {
\t\t\t\t\t\t\tminH = Math.floor((parseInt(minH) / 100) * dialog.parent().height());
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tminH = parseInt(minH);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (maxH.match(/%/)) {
\t\t\t\t\t\t\tmaxH = Math.floor((parseInt(maxH) / 100) * dialog.parent().height());
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tmaxH = parseInt(maxH);
\t\t\t\t\t\t}
\t\t\t\t\t\th = Math.min((autoH? dialog.height() : syncSize.defaultSize.height), Math.max(maxH, minH) - oh - dialog.data('margin-y'));
\t\t\t\t\t} else {
\t\t\t\t\t\th = dialog.height() - oh - dialog.data('margin-y');
\t\t\t\t\t}
\t\t\t\t\tself.css(autoH? 'max-height' : 'height', h);
\t\t\t\t\tif (init) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tposCheck();
\t\t\t\t\tminH = self.height();
\t\t\t\t\tminH = (h < minH)? (minH + oh + dialog.data('margin-y')) : opts.minHeight;
\t\t\t\t\tdialog.css('min-height', minH);
\t\t\t\t\tdialog.data('hasResizable') && dialog.resizable('option', { minHeight: minH });
\t\t\t\t\tif (typeof(opts.resize) === 'function') {
\t\t\t\t\t\t\$.proxy(opts.resize, self[0])(e, data);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('tabstopsInit', tabstopsInit)
\t\t\t\t.on('focus', '.'+cltabstop, function() {
\t\t\t\t\t\$(this).addClass(clhover).parent('label').addClass(clhover);
\t\t\t\t\tthis.id && \$(this).parent().find('label[for='+this.id+']').addClass(clhover);
\t\t\t\t})
\t\t\t\t.on('click', 'select.'+cltabstop, function() {
\t\t\t\t\tvar node = \$(this);
\t\t\t\t\tnode.data('keepFocus')? node.removeData('keepFocus') : node.data('keepFocus', true);
\t\t\t\t})
\t\t\t\t.on('blur', '.'+cltabstop, function() {
\t\t\t\t\t\$(this).removeClass(clhover).removeData('keepFocus').parent('label').removeClass(clhover);
\t\t\t\t\tthis.id && \$(this).parent().find('label[for='+this.id+']').removeClass(clhover);
\t\t\t\t})
\t\t\t\t.on('mouseenter mouseleave', '.'+cltabstop+',label', function(e) {
\t\t\t\t\tvar \$this = \$(this), labelfor;
\t\t\t\t\tif (this.nodeName === 'LABEL') {
\t\t\t\t\t\tif (!\$this.children('.'+cltabstop).length && (!(labelfor = \$this.attr('for')) || !\$('#'+labelfor).hasClass(cltabstop))) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (opts.btnHoverFocus && dialog.data('focusOnMouseOver')) {
\t\t\t\t\t\tif (e.type === 'mouseenter' && ! \$(':focus').data('keepFocus')) {
\t\t\t\t\t\t\t\$this.trigger('focus');
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\t\$this.toggleClass(clhover, e.type == 'mouseenter');
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('keydown', '.'+cltabstop, function(e) {
\t\t\t\t\tvar \$this = \$(this),
\t\t\t\t\t\tesc, move, moveTo;
\t\t\t\t\tif (\$this.is(':focus')) {
\t\t\t\t\t\tesc = e.keyCode === \$.ui.keyCode.ESCAPE;
\t\t\t\t\t\tif (e.keyCode === \$.ui.keyCode.ENTER) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\$this.trigger('click');
\t\t\t\t\t\t}  else if (((e.keyCode === \$.ui.keyCode.TAB) && e.shiftKey) || e.keyCode === \$.ui.keyCode.LEFT || e.keyCode == \$.ui.keyCode.UP) {
\t\t\t\t\t\t\tmove = 'prev';
\t\t\t\t\t\t}  else if (e.keyCode === \$.ui.keyCode.TAB || e.keyCode == \$.ui.keyCode.RIGHT || e.keyCode == \$.ui.keyCode.DOWN) {
\t\t\t\t\t\t\tmove = 'next';
\t\t\t\t\t\t}
\t\t\t\t\t\tif (move
\t\t\t\t\t\t\t\t&&
\t\t\t\t\t\t\t(
\t\t\t\t\t\t\t\t(\$this.is('textarea') && !(e.ctrlKey || e.metaKey))
\t\t\t\t\t\t\t\t\t||
\t\t\t\t\t\t\t\t(\$this.is('select,span.ui-slider-handle') && e.keyCode !== \$.ui.keyCode.TAB)
\t\t\t\t\t\t\t\t\t||
\t\t\t\t\t\t\t\t(\$this.is('input:not(:checkbox,:radio)') && (!(e.ctrlKey || e.metaKey) && e.keyCode === \$.ui.keyCode[move === 'prev'? 'LEFT':'RIGHT']))
\t\t\t\t\t\t\t)
\t\t\t\t\t\t) {
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!esc) {
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t} else if (\$this.is('input:not(:checkbox,:radio),textarea')) {
\t\t\t\t\t\t\tif (\$this.val() !== '') {
\t\t\t\t\t\t\t\t\$this.val('');
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (move) {
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t(move === 'prev'? tabstopPrev : tabstopNext)(this).trigger('focus');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.data({modal: opts.modal}),
\t\t\tposCheck = function() {
\t\t\t\tvar node = fm.getUI(),
\t\t\t\t\tpos;
\t\t\t\tif (node.hasClass('elfinder-fullscreen')) {
\t\t\t\t\tpos = dialog.position();
\t\t\t\t\tdialog.css('top', Math.max(Math.min(Math.max(pos.top, 0), node.height() - 100), 0));
\t\t\t\t\tdialog.css('left', Math.max(Math.min(Math.max(pos.left, 0), node.width() - 200), 0));
\t\t\t\t}
\t\t\t},
\t\t\tmaxSize, toFocusNode;
\t\t
\t\tdialog.prepend(titlebar);

\t\tmakeHeaderBtn();

\t\t\$.each(opts.buttons, function(name, cb) {
\t\t\tvar button = \$('<button type=\"button\" class=\"ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only '
\t\t\t\t\t+'elfinder-btncnt-'+(btnCnt++)+' '
\t\t\t\t\t+cltabstop
\t\t\t\t\t+'\"><span class=\"ui-button-text\">'+name+'</span></button>')
\t\t\t\t.on('click', \$.proxy(cb, self[0]));
\t\t\tif (cb._cssClass) {
\t\t\t\tbutton.addClass(cb._cssClass);
\t\t\t}
\t\t\tif (platformWin) {
\t\t\t\tbuttonset.append(button);
\t\t\t} else {
\t\t\t\tbuttonset.prepend(button);
\t\t\t}
\t\t});
\t\t
\t\tif (buttonset.children().length) {
\t\t\tdialog.append(buttonpane);
\t\t\t
\t\t\tdialog.show();
\t\t\tbuttonpane.find('button').each(function(i, btn) {
\t\t\t\tbtnWidth += \$(btn).outerWidth(true);
\t\t\t});
\t\t\tdialog.hide();
\t\t\tbtnWidth += 20;
\t\t\t
\t\t\tif (dialog.width() < btnWidth) {
\t\t\t\tdialog.width(btnWidth);
\t\t\t}
\t\t}
\t\t
\t\tdialog.append(evCover);
\t\t
\t\tif (syncSize.enabled) {
\t\t\tdelta.width = dialog.outerWidth(true) - dialog.width() + ((dialog.outerWidth() - dialog.width()) / 2);
\t\t\tdelta.height = dialog.outerHeight(true) - dialog.height() + ((dialog.outerHeight() - dialog.height()) / 2);
\t\t}
\t\t
\t\tif (fm.options.dialogContained) {
\t\t\tmaxSize = {
\t\t\t\tmaxWidth: elfNode.width() - delta.width,
\t\t\t\tmaxHeight: elfNode.height() - delta.height
\t\t\t};
\t\t\topts.maxWidth = opts.maxWidth? Math.min(maxSize.maxWidth, opts.maxWidth) : maxSize.maxWidth;
\t\t\topts.maxHeight = opts.maxHeight? Math.min(maxSize.maxHeight, opts.maxHeight) : maxSize.maxHeight;
\t\t\tdialog.css(maxSize);
\t\t}
\t\t
\t\trestoreStyle = {
\t\t\tmaxWidth  : dialog.css('max-width'),
\t\t\tmaxHeight : dialog.css('max-height'),
\t\t\toverflow   : dialog.css('overflow')
\t\t};
\t\t
\t\tif (opts.resizable) {
\t\t\tdialog.resizable({
\t\t\t\tminWidth   : opts.minWidth,
\t\t\t\tminHeight  : opts.minHeight,
\t\t\t\tmaxWidth   : opts.maxWidth,
\t\t\t\tmaxHeight  : opts.maxHeight,
\t\t\t\tstart      : function() {
\t\t\t\t\tevCover.show();
\t\t\t\t\tif (dialog.data('resizing') !== true && dialog.data('resizing')) {
\t\t\t\t\t\tclearTimeout(dialog.data('resizing'));
\t\t\t\t\t}
\t\t\t\t\tdialog.data('resizing', true);
\t\t\t\t},
\t\t\t\tstop       : function(e, ui) {
\t\t\t\t\tevCover.hide();
\t\t\t\t\tdialog.data('resizing', setTimeout(function() {
\t\t\t\t\t\tdialog.data('resizing', false);
\t\t\t\t\t}, 200));
\t\t\t\t\tif (syncSize.enabled) {
\t\t\t\t\t\tsyncSize.defaultSize = { width: self.width(), height: self.height() };
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}).data('hasResizable', true);
\t\t} 
\t\t
\t\tnumberToTel();
\t\t
\t\ttabstopsInit();
\t\t
\t\ttypeof(opts.create) == 'function' && \$.proxy(opts.create, this)();
\t\t
\t\tif (opts.autoOpen) {
\t\t\tif (opts.open) {
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tself.elfinderdialog('open');
\t\t\t\t});
\t\t\t} else {
\t\t\t\tself.elfinderdialog('open');
\t\t\t}
\t\t}

\t\tif (opts.resize) {
\t\t\tfm.bind('themechange', function() {
\t\t\t\tsetTimeout(function() {
\t\t\t\t\tdialog.data('margin-y', self.outerHeight(true) - self.height());
\t\t\t\t\tdialog.trigger('resize', {init: true});
\t\t\t\t}, 300);
\t\t\t});
\t\t}
\t});
\t
\treturn this;
};

\$.fn.elfinderdialog.defaults = {
\tcssClass  : '',
\ttitle     : '',
\tmodal     : false,
\tresizable : true,
\tautoOpen  : true,
\tcloseOnEscape : true,
\tdestroyOnClose : false,
\tbuttons   : {},
\tbtnHoverFocus : true,
\tposition  : null,
\tabsolute  : false,
\twidth     : 320,
\theight    : 'auto',
\tminWidth  : 200,
\tminHeight : 70,
\tmaxWidth  : null,
\tmaxHeight : null,
\tallowMinimize : 'auto',
\tallowMaximize : false,
\topenMaximized : false,
\theaderBtnPos : 'auto',
\theaderBtnOrder : 'auto',
\toptimizeNumber : true,
\tpropagationEvents : ['mousemove', 'mouseup']
};


/*
 * File: /js/ui/fullscreenbutton.js
 */

/**
 * @class  elFinder toolbar button to switch full scrren mode.
 *
 * @author Naoki Sawada
 **/

\$.fn.elfinderfullscreenbutton = function(cmd) {
\t\treturn this.each(function() {
\t\tvar button = \$(this).elfinderbutton(cmd),
\t\t\ticon   = button.children('.elfinder-button-icon'),
\t\t\ttm;
\t\tcmd.change(function() {
\t\t\ttm && cancelAnimationFrame(tm);
\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\tvar fullscreen = cmd.value;
\t\t\t\ticon.addClass('elfinder-button-icon-fullscreen').toggleClass('elfinder-button-icon-unfullscreen', fullscreen);
\t\t\t\tcmd.className = fullscreen? 'unfullscreen' : '';
\t\t\t});
\t\t});
\t});
};


/*
 * File: /js/ui/navbar.js
 */

/**
 * @class elfindernav - elFinder container for diretories tree and places
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindernavbar = function(fm, opts) {
\t\tthis.not('.elfinder-navbar').each(function() {
\t\tvar nav    = \$(this).hide().addClass('ui-state-default elfinder-navbar'),
\t\t\tparent = nav.css('overflow', 'hidden').parent(),
\t\t\twz     = parent.children('.elfinder-workzone').append(nav),
\t\t\tltr    = fm.direction == 'ltr',
\t\t\tdelta, deltaW, handle, swipeHandle, autoHide, setWidth, navdock,
\t\t\tsetWzRect = function() {
\t\t\t\tvar cwd = fm.getUI('cwd'),
\t\t\t\t\twz  = fm.getUI('workzone'),
\t\t\t\t\twzRect = wz.data('rectangle'),
\t\t\t\t\tcwdOffset = cwd.offset();
\t\t\t\twz.data('rectangle', Object.assign(wzRect, { cwdEdge: (fm.direction === 'ltr')? cwdOffset.left : cwdOffset.left + cwd.width() }));
\t\t\t},
\t\t\tsetDelta = function() {
\t\t\t\tnav.css('overflow', 'hidden');
\t\t\t\tdelta  = Math.round(nav.outerHeight() - nav.height());
\t\t\t\tdeltaW = Math.round(navdock.outerWidth() - navdock.innerWidth());
\t\t\t\tnav.css('overflow', 'auto');
\t\t\t};

\t\tfm.one('init', function() {
\t\t\tnavdock = fm.getUI('navdock');
\t\t\tvar set = function() {
\t\t\t\t\tsetDelta();
\t\t\t\t\tfm.bind('wzresize', function() {
\t\t\t\t\t\tvar navdockH = 0;
\t\t\t\t\t\tnavdock.width(nav.outerWidth() - deltaW);
\t\t\t\t\t\tif (navdock.children().length > 1) {
\t\t\t\t\t\t\tnavdockH = navdock.outerHeight(true);
\t\t\t\t\t\t}
\t\t\t\t\t\tnav.height(wz.height() - navdockH - delta);
\t\t\t\t\t}).trigger('wzresize');
\t\t\t\t};
\t\t\tif (fm.cssloaded) {
\t\t\t\tset();
\t\t\t} else {
\t\t\t\tfm.one('cssloaded', set);
\t\t\t}
\t\t})
\t\t.one('opendone',function() {
\t\t\thandle && handle.trigger('resize');
\t\t\tnav.css('overflow', 'auto');
\t\t}).bind('themechange', setDelta);
\t\t
\t\tif (fm.UA.Touch) {
\t\t\tautoHide = fm.storage('autoHide') || {};
\t\t\tif (typeof autoHide.navbar === 'undefined') {
\t\t\t\tautoHide.navbar = (opts.autoHideUA && opts.autoHideUA.length > 0 && \$.grep(opts.autoHideUA, function(v){ return fm.UA[v]? true : false; }).length);
\t\t\t\tfm.storage('autoHide', autoHide);
\t\t\t}
\t\t\t
\t\t\tif (autoHide.navbar) {
\t\t\t\tfm.one('init', function() {
\t\t\t\t\tif (nav.children().length) {
\t\t\t\t\t\tfm.uiAutoHide.push(function(){ nav.stop(true, true).trigger('navhide', { duration: 'slow', init: true }); });
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t\tfm.bind('load', function() {
\t\t\t\tif (nav.children().length) {
\t\t\t\t\tswipeHandle = \$('<div class=\"elfinder-navbar-swipe-handle\"></div>').hide().appendTo(wz);
\t\t\t\t\tif (swipeHandle.css('pointer-events') !== 'none') {
\t\t\t\t\t\tswipeHandle.remove();
\t\t\t\t\t\tswipeHandle = null;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tnav.on('navshow navhide', function(e, data) {
\t\t\t\tvar mode     = (e.type === 'navshow')? 'show' : 'hide',
\t\t\t\t\tduration = (data && data.duration)? data.duration : 'fast',
\t\t\t\t\thandleW = (data && data.handleW)? data.handleW : Math.max(50, fm.getUI().width() / 10);
\t\t\t\tnav.stop(true, true)[mode]({
\t\t\t\t\tduration: duration,
\t\t\t\t\tstep    : function() {
\t\t\t\t\t\tfm.trigger('wzresize');
\t\t\t\t\t},
\t\t\t\t\tcomplete: function() {
\t\t\t\t\t\tif (swipeHandle) {
\t\t\t\t\t\t\tif (mode === 'show') {
\t\t\t\t\t\t\t\tswipeHandle.stop(true, true).hide();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tswipeHandle.width(handleW? handleW : '');
\t\t\t\t\t\t\t\tfm.resources.blink(swipeHandle, 'slowonce');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.trigger('navbar'+ mode);
\t\t\t\t\t\tdata.init && fm.trigger('uiautohide');
\t\t\t\t\t\tsetWzRect();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tautoHide.navbar = (mode !== 'show');
\t\t\t\tfm.storage('autoHide', Object.assign(fm.storage('autoHide'), {navbar: autoHide.navbar}));
\t\t\t}).on('touchstart', function(e) {
\t\t\t\tif (\$(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
\t\t\t\t\te.originalEvent._preventSwipeX = true;
\t\t\t\t}
\t\t\t});
\t\t}
\t\t
\t\tif (! fm.UA.Mobile) {
\t\t\thandle = nav.resizable({
\t\t\t\t\thandles : ltr ? 'e' : 'w',
\t\t\t\t\tminWidth : opts.minWidth || 150,
\t\t\t\t\tmaxWidth : opts.maxWidth || 500,
\t\t\t\t\tresize : function() {
\t\t\t\t\t\tfm.trigger('wzresize');
\t\t\t\t\t},
\t\t\t\t\tstop : function(e, ui) {
\t\t\t\t\t\tfm.storage('navbarWidth', ui.size.width);
\t\t\t\t\t\tsetWzRect();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('resize scroll', function(e) {
\t\t\t\t\tvar \$this = \$(this),
\t\t\t\t\t\ttm = \$this.data('posinit');
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tif (! ltr && e.type === 'resize') {
\t\t\t\t\t\tnav.css('left', 0);
\t\t\t\t\t}
\t\t\t\t\ttm && cancelAnimationFrame(tm);
\t\t\t\t\t\$this.data('posinit', requestAnimationFrame(function() {
\t\t\t\t\t\tvar offset = (fm.UA.Opera && nav.scrollLeft())? 20 : 2;
\t\t\t\t\t\thandle.css('top', 0).css({
\t\t\t\t\t\t\ttop  : parseInt(nav.scrollTop())+'px',
\t\t\t\t\t\t\tleft : ltr ? 'auto' : parseInt(nav.scrollRight() -  offset) * -1,
\t\t\t\t\t\t\tright: ltr ? parseInt(nav.scrollLeft() - offset) * -1 : 'auto'
\t\t\t\t\t\t});
\t\t\t\t\t\tif (e.type === 'resize') {
\t\t\t\t\t\t\tfm.getUI('cwd').trigger('resize');
\t\t\t\t\t\t}
\t\t\t\t\t}));
\t\t\t\t})
\t\t\t\t.children('.ui-resizable-handle').addClass('ui-front');
\t\t}

\t\tif (setWidth = fm.storage('navbarWidth')) {
\t\t\tnav.width(setWidth);
\t\t} else {
\t\t\tif (fm.UA.Mobile) {
\t\t\t\tfm.one(fm.cssloaded? 'init' : 'cssloaded', function() {
\t\t\t\t\tvar set = function() {
\t\t\t\t\t\tsetWidth = nav.parent().width() / 2;
\t\t\t\t\t\tif (nav.data('defWidth') > setWidth) {
\t\t\t\t\t\t\tnav.width(setWidth);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tnav.width(nav.data('defWidth'));
\t\t\t\t\t\t}
\t\t\t\t\t\tnav.data('width', nav.width());
\t\t\t\t\t\tfm.trigger('wzresize');
\t\t\t\t\t};
\t\t\t\t\tnav.data('defWidth', nav.width());
\t\t\t\t\t\$(window).on('resize.' + fm.namespace, set);
\t\t\t\t\tset();
\t\t\t\t});
\t\t\t}
\t\t}

\t});
\t
\treturn this;
};


/*
 * File: /js/ui/navdock.js
 */

/**
 * @class elfindernavdock - elFinder container for preview etc at below the navbar
 *
 * @author Naoki Sawada
 **/
\$.fn.elfindernavdock = function(fm, opts) {
\t\tthis.not('.elfinder-navdock').each(function() {
\t\tvar self = \$(this).hide().addClass('ui-state-default elfinder-navdock touch-punch'),
\t\t\tnode = self.parent(),
\t\t\twz   = node.children('.elfinder-workzone').append(self),
\t\t\tresize = function(to, h) {
\t\t\t\tvar curH = h || self.height(),
\t\t\t\t\tdiff = to - curH,
\t\t\t\t\tlen  = Object.keys(sizeSyncs).length,
\t\t\t\t\tcalc = len? diff / len : 0,
\t\t\t\t\tovf;
\t\t\t\tif (diff) {
\t\t\t\t\tovf = self.css('overflow');
\t\t\t\t\tself.css('overflow', 'hidden');
\t\t\t\t\tself.height(to);
\t\t\t\t\t\$.each(sizeSyncs, function(id, n) {
\t\t\t\t\t\tn.height(n.height() + calc).trigger('resize.' + fm.namespace);
\t\t\t\t\t});
\t\t\t\t\tfm.trigger('wzresize');
\t\t\t\t\tself.css('overflow', ovf);
\t\t\t\t}
\t\t\t},
\t\t\thandle = \$('<div class=\"ui-front ui-resizable-handle ui-resizable-n\"></div>').appendTo(self),
\t\t\tsizeSyncs = {},
\t\t\tresizeFn = [],
\t\t\tinitMaxHeight = (parseInt(opts.initMaxHeight) || 50) / 100,
\t\t\tmaxHeight = (parseInt(opts.maxHeight) || 90) / 100,
\t\t\tbasicHeight, hasNode;
\t\t
\t\t
\t\tself.data('addNode', function(cNode, opts) {
\t\t\tvar wzH = fm.getUI('workzone').height(),
\t\t\t\timaxH = wzH * initMaxHeight,
\t\t\t\tcurH, tH, mH;
\t\t\topts = Object.assign({
\t\t\t\tfirst: false,
\t\t\t\tsizeSync: true,
\t\t\t\tinit: false
\t\t\t}, opts);
\t\t\tif (!cNode.attr('id')) {
\t\t\t\tcNode.attr('id', fm.namespace+'-navdock-' + (+new Date()));
\t\t\t}
\t\t\topts.sizeSync && (sizeSyncs[cNode.attr('id')] = cNode);
\t\t\tcurH = self.height();
\t\t\ttH = curH + cNode.outerHeight(true);
\t\t\t
\t\t\tif (opts.first) {
\t\t\t\thandle.after(cNode);
\t\t\t} else {
\t\t\t\tself.append(cNode);
\t\t\t}
\t\t\thasNode = true;
\t\t\tself.resizable('enable').height(tH).show();
\t\t\t
\t\t\tfm.trigger('wzresize');
\t\t\t
\t\t\tif (opts.init) {
\t\t\t\tmH = fm.storage('navdockHeight');
\t\t\t\tif (mH) {
\t\t\t\t\ttH = mH;
\t\t\t\t} else {
\t\t\t\t\ttH = tH > imaxH? imaxH : tH;
\t\t\t\t}
\t\t\t\tbasicHeight = tH;
\t\t\t}
\t\t\tresize(Math.min(tH, wzH * maxHeight));
\t\t\t
\t\t\treturn self;
\t\t}).data('removeNode', function(nodeId, appendTo) {
\t\t\tvar cNode = \$('#'+nodeId);
\t\t\tdelete sizeSyncs[nodeId];
\t\t\tself.height(self.height() - \$('#'+nodeId).outerHeight(true));
\t\t\tif (appendTo) {
\t\t\t\tif (appendTo === 'detach') {
\t\t\t\t\tcNode = cNode.detach();
\t\t\t\t} else {
\t\t\t\t\tappendTo.append(cNode);
\t\t\t\t}
\t\t\t} else {
\t\t\t\tcNode.remove();
\t\t\t}
\t\t\tif (self.children().length <= 1) {
\t\t\t\thasNode = false;
\t\t\t\tself.resizable('disable').height(0).hide();
\t\t\t}
\t\t\tfm.trigger('wzresize');
\t\t\treturn cNode;
\t\t});
\t\t
\t\tif (! opts.disabled) {
\t\t\tfm.one('init', function() {
\t\t\t\tvar ovf;
\t\t\t\tif (fm.getUI('navbar').children().not('.ui-resizable-handle').length) {
\t\t\t\t\tself.data('dockEnabled', true);
\t\t\t\t\tself.resizable({
\t\t\t\t\t\tmaxHeight: fm.getUI('workzone').height() * maxHeight,
\t\t\t\t\t\thandles: { n: handle },
\t\t\t\t\t\tstart: function(e, ui) {
\t\t\t\t\t\t\tovf = self.css('overflow');
\t\t\t\t\t\t\tself.css('overflow', 'hidden');
\t\t\t\t\t\t\tfm.trigger('navdockresizestart', {event: e, ui: ui}, true);
\t\t\t\t\t\t},
\t\t\t\t\t\tresize: function(e, ui) {
\t\t\t\t\t\t\tself.css('top', '');
\t\t\t\t\t\t\tfm.trigger('wzresize', { inNavdockResize : true });
\t\t\t\t\t\t},
\t\t\t\t\t\tstop: function(e, ui) {
\t\t\t\t\t\t\tfm.trigger('navdockresizestop', {event: e, ui: ui}, true);
\t\t\t\t\t\t\tself.css('top', '');
\t\t\t\t\t\t\tbasicHeight = ui.size.height;
\t\t\t\t\t\t\tfm.storage('navdockHeight', basicHeight);
\t\t\t\t\t\t\tresize(basicHeight, ui.originalSize.height);
\t\t\t\t\t\t\tself.css('overflow', ovf);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tfm.bind('wzresize', function(e) {
\t\t\t\t\t\tvar minH, maxH, h;
\t\t\t\t\t\tif (self.is(':visible')) {
\t\t\t\t\t\t\tmaxH = fm.getUI('workzone').height() * maxHeight;
\t\t\t\t\t\t\tif (! e.data || ! e.data.inNavdockResize) {
\t\t\t\t\t\t\t\th = self.height();
\t\t\t\t\t\t\t\tif (maxH < basicHeight) {
\t\t\t\t\t\t\t\t\tif (Math.abs(h - maxH) > 1) {
\t\t\t\t\t\t\t\t\t\tresize(maxH);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tif (Math.abs(h - basicHeight) > 1) {
\t\t\t\t\t\t\t\t\t\tresize(basicHeight);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tself.resizable('option', 'maxHeight', maxH);
\t\t\t\t\t\t}
\t\t\t\t\t}).bind('themechange', function() {
\t\t\t\t\t\tvar oldH = Math.round(self.height());
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\tvar curH = Math.round(self.height()),
\t\t\t\t\t\t\t\tdiff = oldH - curH;
\t\t\t\t\t\t\tif (diff !== 0) {
\t\t\t\t\t\t\t\tresize(self.height(),  curH - diff);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tfm.bind('navbarshow navbarhide', function(e) {
\t\t\t\t\tself[hasNode && e.type === 'navbarshow'? 'show' : 'hide']();
\t\t\t\t});
\t\t\t});
\t\t}
\t});
\treturn this;
};

/*
 * File: /js/ui/overlay.js
 */


\$.fn.elfinderoverlay = function(opts) {
\t\tvar fm = this.parent().elfinder('instance'),
\t\to, cnt, show, hide;
\t
\tthis.filter(':not(.elfinder-overlay)').each(function() {
\t\topts = Object.assign({}, opts);
\t\t\$(this).addClass('ui-front ui-widget-overlay elfinder-overlay')
\t\t\t.hide()
\t\t\t.on('mousedown', function(e) {
\t\t\t\te.preventDefault();
\t\t\t\te.stopPropagation();
\t\t\t})
\t\t\t.data({
\t\t\t\tcnt  : 0,
\t\t\t\tshow : typeof(opts.show) == 'function' ? opts.show : function() { },
\t\t\t\thide : typeof(opts.hide) == 'function' ? opts.hide : function() { }
\t\t\t});
\t});
\t
\tif (opts == 'show') {
\t\to    = this.eq(0);
\t\tcnt  = o.data('cnt') + 1;
\t\tshow = o.data('show');

\t\tfm.toFront(o);
\t\to.data('cnt', cnt);

\t\tif (o.is(':hidden')) {
\t\t\to.show();
\t\t\tshow();
\t\t}
\t} 
\t
\tif (opts == 'hide') {
\t\to    = this.eq(0);
\t\tcnt  = o.data('cnt') - 1;
\t\thide = o.data('hide');
\t\t
\t\to.data('cnt', cnt);
\t\t\t
\t\tif (cnt <= 0) {
\t\t\to.hide();
\t\t\thide();
\t\t}
\t}
\t
\treturn this;
};


/*
 * File: /js/ui/panel.js
 */

\$.fn.elfinderpanel = function(fm) {
\t\treturn this.each(function() {
\t\tvar panel = \$(this).addClass('elfinder-panel ui-state-default ui-corner-all'),
\t\t\tmargin = 'margin-'+(fm.direction == 'ltr' ? 'left' : 'right');
\t\t
\t\tfm.one('load', function(e) {
\t\t\tvar navbar = fm.getUI('navbar');
\t\t\t
\t\t\tpanel.css(margin, parseInt(navbar.outerWidth(true)));
\t\t\tnavbar.on('resize', function(e) {
\t\t\t\te.preventDefault();
\t\t\t\te.stopPropagation();
\t\t\t\tpanel.is(':visible') && panel.css(margin, parseInt(navbar.outerWidth(true)));
\t\t\t});
\t\t});
\t});
};


/*
 * File: /js/ui/path.js
 */

/**
 * @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) {
\t\treturn this.each(function() {
\t\tvar query  = '',
\t\t\ttarget = '',
\t\t\tmimes  = [],
\t\t\tplace  = 'statusbar',
\t\t\tclHover= fm.res('class', 'hover'),
\t\t\tprefix = 'path' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-',
\t\t\twzbase = \$('<div class=\"ui-widget-header ui-helper-clearfix elfinder-workzone-path\"></div>'),
\t\t\tpath   = \$(this).addClass('elfinder-path').html('&nbsp;')
\t\t\t\t.on('mousedown', 'span.elfinder-path-dir', function(e) {
\t\t\t\t\tvar hash = \$(this).attr('id').substr(prefix.length);
\t\t\t\t\te.preventDefault();
\t\t\t\t\tif (hash != fm.cwd().hash) {
\t\t\t\t\t\t\$(this).addClass(clHover);
\t\t\t\t\t\tif (query) {
\t\t\t\t\t\t\tfm.exec('search', query, { target: hash, mime: mimes.join(' ') });
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.trigger('select', {selected : [hash]}).exec('open', hash);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.prependTo(fm.getUI('statusbar').show()),
\t\t\troots = \$('<div class=\"elfinder-path-roots\"></div>').on('click', function(e) {
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\t
\t\t\t\tvar roots = \$.map(fm.roots, function(h) { return fm.file(h); }),
\t\t\t\traw = [];

\t\t\t\t\$.each(roots, function(i, f) {
\t\t\t\t\tif (! f.phash && fm.root(fm.cwd().hash, true) !== f.hash) {
\t\t\t\t\t\traw.push({
\t\t\t\t\t\t\tlabel    : fm.escape(f.i18 || f.name),
\t\t\t\t\t\t\ticon     : 'home',
\t\t\t\t\t\t\tcallback : function() { fm.exec('open', f.hash); },
\t\t\t\t\t\t\toptions  : {
\t\t\t\t\t\t\t\ticonClass : f.csscls || '',
\t\t\t\t\t\t\t\ticonImg   : f.icon   || ''
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\traw: raw,
\t\t\t\t\tx: e.pageX,
\t\t\t\t\ty: e.pageY
\t\t\t\t});
\t\t\t}).append('<span class=\"elfinder-button-icon elfinder-button-icon-menu\" ></span>').appendTo(wzbase),
\t\t\trender = function(cwd) {
\t\t\t\tvar dirs = [],
\t\t\t\t\tnames = [];
\t\t\t\t\$.each(fm.parents(cwd), function(i, hash) {
\t\t\t\t\tvar c = (cwd === hash)? 'elfinder-path-dir elfinder-path-cwd' : 'elfinder-path-dir',
\t\t\t\t\t\tf = fm.file(hash),
\t\t\t\t\t\tname = fm.escape(f.i18 || f.name);
\t\t\t\t\tnames.push(name);
\t\t\t\t\tdirs.push('<span id=\"'+prefix+hash+'\" class=\"'+c+'\" title=\"'+names.join(fm.option('separator'))+'\">'+name+'</span>');
\t\t\t\t});
\t\t\t\treturn dirs.join('<span class=\"elfinder-path-other\">'+fm.option('separator')+'</span>');
\t\t\t},
\t\t\ttoWorkzone = function() {
\t\t\t\tvar prev;
\t\t\t\tpath.children('span.elfinder-path-dir').attr('style', '');
\t\t\t\tprev = fm.direction === 'ltr'? \$('#'+prefix + fm.cwd().hash).prevAll('span.elfinder-path-dir:first') : \$();
\t\t\t\tpath.scrollLeft(prev.length? prev.position().left : 0);
\t\t\t},
\t\t\tfit = function() {
\t\t\t\tif (fm.UA.CSS.flex) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar dirs = path.children('span.elfinder-path-dir'),
\t\t\t\t\tcnt  = dirs.length,
\t\t\t\t\tm, bg = 0, ids;
\t\t\t\t
\t\t\t\tif (place === 'workzone' || cnt < 2) {
\t\t\t\t\tdirs.attr('style', '');
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tpath.width(path.css('max-width'));
\t\t\t\tdirs.css({maxWidth: (100/cnt)+'%', display: 'inline-block'});
\t\t\t\tm = path.width() - 9;
\t\t\t\tpath.children('span.elfinder-path-other').each(function() {
\t\t\t\t\tm -= \$(this).width();
\t\t\t\t});
\t\t\t\tids = [];
\t\t\t\tdirs.each(function(i) {
\t\t\t\t\tvar dir = \$(this),
\t\t\t\t\t\tw   = dir.width();
\t\t\t\t\tm -= w;
\t\t\t\t\tif (w < this.scrollWidth) {
\t\t\t\t\t\tids.push(i);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tpath.width('');
\t\t\t\tif (ids.length) {
\t\t\t\t\tif (m > 0) {
\t\t\t\t\t\tm = m / ids.length;
\t\t\t\t\t\t\$.each(ids, function(i, k) {
\t\t\t\t\t\t\tvar d = \$(dirs[k]);
\t\t\t\t\t\t\td.css('max-width', d.width() + m);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tdirs.last().attr('style', '');
\t\t\t\t} else {
\t\t\t\t\tdirs.attr('style', '');
\t\t\t\t}
\t\t\t},
\t\t\thasUiTree, hasUiStat;

\t\tfm.one('init', function() {
\t\t\thasUiTree = fm.getUI('tree').length;
\t\t\thasUiStat = fm.getUI('stat').length;
\t\t\tif (! hasUiTree && options.toWorkzoneWithoutNavbar) {
\t\t\t\twzbase.append(path).insertBefore(fm.getUI('workzone'));
\t\t\t\tplace = 'workzone';
\t\t\t\tfm.bind('open', toWorkzone)
\t\t\t\t.one('opendone', function() {
\t\t\t\t\tfm.getUI().trigger('resize');
\t\t\t\t});
\t\t\t}
\t\t})
\t\t.bind('open searchend parents', function() {
\t\t\tvar dirs = [];

\t\t\tquery  = '';
\t\t\ttarget = '';
\t\t\tmimes  = [];
\t\t\t
\t\t\tpath.html(render(fm.cwd().hash));
\t\t\tif (Object.keys(fm.roots).length > 1) {
\t\t\t\tpath.css('margin', '');
\t\t\t\troots.show();
\t\t\t} else {
\t\t\t\tpath.css('margin', 0);
\t\t\t\troots.hide();
\t\t\t}
\t\t\t!hasUiStat && fit();
\t\t})
\t\t.bind('searchstart', function(e) {
\t\t\tif (e.data) {
\t\t\t\tquery  = e.data.query || '';
\t\t\t\ttarget = e.data.target || '';
\t\t\t\tmimes  = e.data.mimes || [];
\t\t\t}
\t\t})
\t\t.bind('search', function(e) {
\t\t\tvar dirs = [],
\t\t\t\thtml = '';
\t\t\tif (target) {
\t\t\t\thtml = render(target);
\t\t\t} else {
\t\t\t\thtml = fm.i18n('btnAll');
\t\t\t}
\t\t\tpath.html('<span class=\"elfinder-path-other\">'+fm.i18n('searcresult') + ': </span>' + html);
\t\t\tfit();
\t\t})
\t\t// on swipe to navbar show/hide
\t\t.bind('navbarshow navbarhide', function() {
\t\t\tvar wz = fm.getUI('workzone');
\t\t\tif (this.type === 'navbarshow') {
\t\t\t\tfm.unbind('open', toWorkzone);
\t\t\t\tpath.prependTo(fm.getUI('statusbar'));
\t\t\t\twzbase.detach();
\t\t\t\tplace = 'statusbar';
\t\t\t} else {
\t\t\t\twzbase.append(path).insertBefore(wz);
\t\t\t\tplace = 'workzone';
\t\t\t\ttoWorkzone();
\t\t\t\tfm.bind('open', toWorkzone);
\t\t\t}
\t\t\tfm.trigger('uiresize');
\t\t})
\t\t.bind('resize uistatchange', fit);
\t});
};


/*
 * File: /js/ui/places.js
 */

/**
 * @class elFinder places/favorites ui
 *
 * @author Dmitry (dio) Levashov
 * @author Naoki Sawada
 **/
\$.fn.elfinderplaces = function(fm, opts) {
\t\treturn this.each(function() {
\t\tvar dirs      = {},
\t\t\tc         = 'class',
\t\t\tnavdir    = fm.res(c, 'navdir'),
\t\t\tcollapsed = fm.res(c, 'navcollapse'),
\t\t\texpanded  = fm.res(c, 'navexpand'),
\t\t\thover     = fm.res(c, 'hover'),
\t\t\tclroot    = fm.res(c, 'treeroot'),
\t\t\tdropover  = fm.res(c, 'adroppable'),
\t\t\ttpl       = fm.res('tpl', 'placedir'),
\t\t\tptpl      = fm.res('tpl', 'perms'),
\t\t\tspinner   = \$(fm.res('tpl', 'navspinner')),
\t\t\tsuffix    = opts.suffix? opts.suffix : '',
\t\t\tkey       = 'places' + suffix,
\t\t\tmenuTimer = null,
\t\t\t/**
\t\t\t * Convert places dir node into dir hash
\t\t\t *
\t\t\t * @param  String  directory id
\t\t\t * @return String
\t\t\t **/
\t\t\tid2hash   = function(id) { return id.substr(6);\t},
\t\t\t/**
\t\t\t * Convert places dir hash into dir node id
\t\t\t *
\t\t\t * @param  String  directory id
\t\t\t * @return String
\t\t\t **/
\t\t\thash2id   = function(hash) { return 'place-'+hash; },

\t\t\t/**
\t\t\t * Convert places dir hash into dir node elment (jQuery object)
\t\t\t *
\t\t\t * @param  String  directory id
\t\t\t * @return Object
\t\t\t **/
\t\t\thash2elm  = function(hash) { return \$(document.getElementById(hash2id(hash))); },
\t\t\t
\t\t\t/**
\t\t\t * Save current places state
\t\t\t *
\t\t\t * @return void
\t\t\t **/
\t\t\tsave      = function() {
\t\t\t\tvar hashes = [], data = {};
\t\t\t\t
\t\t\t\thashes = \$.map(subtree.children().find('[id]'), function(n) {
\t\t\t\t\treturn id2hash(n.id);
\t\t\t\t});
\t\t\t\tif (hashes.length) {
\t\t\t\t\t\$.each(hashes.reverse(), function(i, h) {
\t\t\t\t\t\tdata[h] = dirs[h];
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdata = null;
\t\t\t\t}
\t\t\t\t
\t\t\t\tfm.storage(key, data);
\t\t\t},
\t\t\t/**
\t\t\t * Init dir at places
\t\t\t *
\t\t\t * @return void
\t\t\t **/
\t\t\tinit = function() {
\t\t\t\tvar dat, hashes;
\t\t\t\tkey = 'places'+(opts.suffix? opts.suffix : ''),
\t\t\t\tdirs = {};
\t\t\t\tdat = fm.storage(key);
\t\t\t\tif (typeof dat === 'string') {
\t\t\t\t\t// old data type elFinder <= 2.1.12
\t\t\t\t\tdat = \$.grep(dat.split(','), function(hash) { return hash? true : false;});
\t\t\t\t\t\$.each(dat, function(i, d) {
\t\t\t\t\t\tvar dir = d.split('#');
\t\t\t\t\t\tdirs[dir[0]] = dir[1]? dir[1] : dir[0];
\t\t\t\t\t});
\t\t\t\t} else if (\$.isPlainObject(dat)) {
\t\t\t\t\tdirs = dat;
\t\t\t\t}
\t\t\t\t// allow modify `dirs`
\t\t\t\t/**
\t\t\t\t * example for preset places
\t\t\t\t * 
\t\t\t\t * elfinderInstance.bind('placesload', function(e, fm) {
\t\t\t\t * \t//if (fm.storage(e.data.storageKey) === null) { // for first time only
\t\t\t\t * \tif (!fm.storage(e.data.storageKey)) {           // for empty places
\t\t\t\t * \t\te.data.dirs[targetHash] = fallbackName;     // preset folder
\t\t\t\t * \t}
\t\t\t\t * }
\t\t\t\t **/
\t\t\t\tfm.trigger('placesload', {dirs: dirs, storageKey: key}, true);
\t\t\t\t
\t\t\t\thashes = Object.keys(dirs);
\t\t\t\tif (hashes.length) {
\t\t\t\t\troot.prepend(spinner);
\t\t\t\t\t
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'info', targets : hashes},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tvar exists = {};
\t\t\t\t\t\t
\t\t\t\t\t\tdata.files && data.files.length && fm.cache(data.files);
\t\t\t\t\t\t
\t\t\t\t\t\t\$.each(data.files, function(i, f) {
\t\t\t\t\t\t\tvar hash = f.hash;
\t\t\t\t\t\t\texists[hash] = f;
\t\t\t\t\t\t});
\t\t\t\t\t\t\$.each(dirs, function(h, f) {
\t\t\t\t\t\t\tadd(exists[h] || Object.assign({notfound: true}, f));
\t\t\t\t\t\t});
\t\t\t\t\t\tif (fm.storage('placesState') > 0) {
\t\t\t\t\t\t\troot.trigger('click');
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.always(function() {
\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\t/**
\t\t\t * Return node for given dir object
\t\t\t *
\t\t\t * @param  Object  directory object
\t\t\t * @return jQuery
\t\t\t **/
\t\t\tcreate    = function(dir, hash) {
\t\t\t\treturn \$(tpl.replace(/\\{id\\}/, hash2id(dir? dir.hash : hash))
\t\t\t\t\t\t.replace(/\\{name\\}/, fm.escape(dir? dir.i18 || dir.name : hash))
\t\t\t\t\t\t.replace(/\\{cssclass\\}/, dir? (fm.perms2class(dir) + (dir.notfound? ' elfinder-na' : '') + (dir.csscls? ' '+dir.csscls : '')) : '')
\t\t\t\t\t\t.replace(/\\{permissions\\}/, (dir && (!dir.read || !dir.write || dir.notfound))? ptpl : '')
\t\t\t\t\t\t.replace(/\\{title\\}/, dir? (' title=\"' + fm.escape(fm.path(dir.hash, true) || dir.i18 || dir.name) + '\"') : '')
\t\t\t\t\t\t.replace(/\\{symlink\\}/, '')
\t\t\t\t\t\t.replace(/\\{style\\}/, (dir && dir.icon)? fm.getIconStyle(dir) : ''));
\t\t\t},
\t\t\t/**
\t\t\t * Add new node into places
\t\t\t *
\t\t\t * @param  Object  directory object
\t\t\t * @return void
\t\t\t **/
\t\t\tadd = function(dir) {
\t\t\t\tvar node, hash;

\t\t\t\tif (dir.mime !== 'directory') {
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t\thash = dir.hash;
\t\t\t\tif (!fm.files().hasOwnProperty(hash)) {
\t\t\t\t\t// update cache
\t\t\t\t\tfm.trigger('tree', {tree: [dir]});
\t\t\t\t}
\t\t\t\t
\t\t\t\tnode = create(dir, hash);
\t\t\t\t
\t\t\t\tdirs[hash] = dir;
\t\t\t\tsubtree.prepend(node);
\t\t\t\troot.addClass(collapsed);
\t\t\t\tsortBtn.toggle(subtree.children().length > 1);
\t\t\t\t
\t\t\t\treturn true;
\t\t\t},
\t\t\t/**
\t\t\t * Remove dir from places
\t\t\t *
\t\t\t * @param  String  directory hash
\t\t\t * @return String  removed name
\t\t\t **/
\t\t\tremove = function(hash) {
\t\t\t\tvar name = null, tgt, cnt;

\t\t\t\tif (dirs[hash]) {
\t\t\t\t\tdelete dirs[hash];
\t\t\t\t\ttgt = hash2elm(hash);
\t\t\t\t\tif (tgt.length) {
\t\t\t\t\t\tname = tgt.text();
\t\t\t\t\t\ttgt.parent().remove();
\t\t\t\t\t\tcnt = subtree.children().length;
\t\t\t\t\t\tsortBtn.toggle(cnt > 1);
\t\t\t\t\t\tif (! cnt) {
\t\t\t\t\t\t\troot.removeClass(collapsed);
\t\t\t\t\t\t\tplaces.removeClass(expanded);
\t\t\t\t\t\t\tsubtree.slideToggle(false);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn name;
\t\t\t},
\t\t\t/**
\t\t\t * Move up dir on places
\t\t\t *
\t\t\t * @param  String  directory hash
\t\t\t * @return void
\t\t\t **/
\t\t\tmoveup = function(hash) {
\t\t\t\tvar self = hash2elm(hash),
\t\t\t\t\ttgt  = self.parent(),
\t\t\t\t\tprev = tgt.prev('div'),
\t\t\t\t\tcls  = 'ui-state-hover',
\t\t\t\t\tctm  = fm.getUI('contextmenu');
\t\t\t\t
\t\t\t\tmenuTimer && clearTimeout(menuTimer);
\t\t\t\t
\t\t\t\tif (prev.length) {
\t\t\t\t\tctm.find(':first').data('placesHash', hash);
\t\t\t\t\tself.addClass(cls);
\t\t\t\t\ttgt.insertBefore(prev);
\t\t\t\t\tprev = tgt.prev('div');
\t\t\t\t\tmenuTimer = setTimeout(function() {
\t\t\t\t\t\tself.removeClass(cls);
\t\t\t\t\t\tif (ctm.find(':first').data('placesHash') === hash) {
\t\t\t\t\t\t\tctm.hide().empty();
\t\t\t\t\t\t}
\t\t\t\t\t}, 1500);
\t\t\t\t}
\t\t\t\t
\t\t\t\tif(!prev.length) {
\t\t\t\t\tself.removeClass(cls);
\t\t\t\t\tctm.hide().empty();
\t\t\t\t}
\t\t\t},
\t\t\t/**
\t\t\t * Update dir at places
\t\t\t *
\t\t\t * @param  Object   directory
\t\t\t * @param  String   previous hash
\t\t\t * @return Boolean
\t\t\t **/
\t\t\tupdate = function(dir, preHash) {
\t\t\t\tvar hash = dir.hash,
\t\t\t\t\ttgt  = hash2elm(preHash || hash),
\t\t\t\t\tnode = create(dir, hash);

\t\t\t\tif (tgt.length > 0) {
\t\t\t\t\ttgt.parent().replaceWith(node);
\t\t\t\t\tdirs[hash] = dir;
\t\t\t\t\treturn true;
\t\t\t\t} else {
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t},
\t\t\t/**
\t\t\t * Remove all dir from places
\t\t\t *
\t\t\t * @return void
\t\t\t **/
\t\t\tclear = function() {
\t\t\t\tsubtree.empty();
\t\t\t\troot.removeClass(collapsed);
\t\t\t\tplaces.removeClass(expanded);
\t\t\t\tsubtree.slideToggle(false);
\t\t\t},
\t\t\t/**
\t\t\t * Sort places dirs A-Z
\t\t\t *
\t\t\t * @return void
\t\t\t **/
\t\t\tsort = function() {
\t\t\t\t\$.each(dirs, function(h, f) {
\t\t\t\t\tvar dir = fm.file(h) || f,
\t\t\t\t\t\tnode = create(dir, h),
\t\t\t\t\t\tret = null;
\t\t\t\t\tif (!dir) {
\t\t\t\t\t\tnode.hide();
\t\t\t\t\t}
\t\t\t\t\tif (subtree.children().length) {
\t\t\t\t\t\t\$.each(subtree.children(), function() {
\t\t\t\t\t\t\tvar current =  \$(this);
\t\t\t\t\t\t\tif ((dir.i18 || dir.name).localeCompare(current.children('.'+navdir).text()) < 0) {
\t\t\t\t\t\t\t\tret = !node.insertBefore(current);
\t\t\t\t\t\t\t\treturn ret;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tif (ret !== null) {
\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t!hash2elm(h).length && subtree.append(node);
\t\t\t\t});
\t\t\t\tsave();
\t\t\t},
\t\t\t// sort button
\t\t\tsortBtn = \$('<span class=\"elfinder-button-icon elfinder-button-icon-sort elfinder-places-root-icon\" title=\"'+fm.i18n('cmdsort')+'\"></span>')
\t\t\t\t.hide()
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tsubtree.empty();
\t\t\t\t\tsort();
\t\t\t\t}
\t\t\t),
\t\t\t/**
\t\t\t * Node - wrapper for places root
\t\t\t *
\t\t\t * @type jQuery
\t\t\t **/
\t\t\twrapper = create({
\t\t\t\t\thash  : 'root-'+fm.namespace, 
\t\t\t\t\tname  : fm.i18n(opts.name, 'places'),
\t\t\t\t\tread  : true,
\t\t\t\t\twrite : true
\t\t\t\t}),
\t\t\t/**
\t\t\t * Places root node
\t\t\t *
\t\t\t * @type jQuery
\t\t\t **/
\t\t\troot = wrapper.children('.'+navdir)
\t\t\t\t.addClass(clroot)
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tif (root.hasClass(collapsed)) {
\t\t\t\t\t\tplaces.toggleClass(expanded);
\t\t\t\t\t\tsubtree.slideToggle();
\t\t\t\t\t\tfm.storage('placesState', places.hasClass(expanded)? 1 : 0);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.append(sortBtn),
\t\t\t/**
\t\t\t * Container for dirs
\t\t\t *
\t\t\t * @type jQuery
\t\t\t **/
\t\t\tsubtree = wrapper.children('.'+fm.res(c, 'navsubtree')),
\t\t\t
\t\t\t/**
\t\t\t * Main places container
\t\t\t *
\t\t\t * @type jQuery
\t\t\t **/
\t\t\tplaces = \$(this).addClass(fm.res(c, 'tree')+' elfinder-places ui-corner-all')
\t\t\t\t.hide()
\t\t\t\t.append(wrapper)
\t\t\t\t.appendTo(fm.getUI('navbar'))
\t\t\t\t.on('mouseenter mouseleave', '.'+navdir, function(e) {
\t\t\t\t\t\$(this).toggleClass('ui-state-hover', (e.type == 'mouseenter'));
\t\t\t\t})
\t\t\t\t.on('click', '.'+navdir, function(e) {
\t\t\t\t\tvar p = \$(this);
\t\t\t\t\tif (p.data('longtap')) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t! p.hasClass('elfinder-na') && fm.exec('open', p.attr('id').substr(6));
\t\t\t\t})
\t\t\t\t.on('contextmenu', '.'+navdir+':not(.'+clroot+')', function(e) {
\t\t\t\t\tvar self = \$(this),
\t\t\t\t\t\thash = self.attr('id').substr(6);
\t\t\t\t\t
\t\t\t\t\te.preventDefault();

\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\traw : [{
\t\t\t\t\t\t\tlabel    : fm.i18n('moveUp'),
\t\t\t\t\t\t\ticon     : 'up',
\t\t\t\t\t\t\tremain   : true,
\t\t\t\t\t\t\tcallback : function() { moveup(hash); save(); }
\t\t\t\t\t\t},'|',{
\t\t\t\t\t\t\tlabel    : fm.i18n('rmFromPlaces'),
\t\t\t\t\t\t\ticon     : 'rm',
\t\t\t\t\t\t\tcallback : function() { remove(hash); save(); }
\t\t\t\t\t\t}],
\t\t\t\t\t\t'x'       : e.pageX,
\t\t\t\t\t\t'y'       : e.pageY
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tself.addClass('ui-state-hover');
\t\t\t\t\t
\t\t\t\t\tfm.getUI('contextmenu').children().on('mouseenter', function() {
\t\t\t\t\t\tself.addClass('ui-state-hover');
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tfm.bind('closecontextmenu', function() {
\t\t\t\t\t\tself.removeClass('ui-state-hover');
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.droppable({
\t\t\t\t\ttolerance  : 'pointer',
\t\t\t\t\taccept     : '.elfinder-cwd-file-wrapper,.elfinder-tree-dir,.elfinder-cwd-file',
\t\t\t\t\thoverClass : fm.res('class', 'adroppable'),
\t\t\t\t\tclasses    : { // Deprecated hoverClass jQueryUI>=1.12.0
\t\t\t\t\t\t'ui-droppable-hover': fm.res('class', 'adroppable')
\t\t\t\t\t},
\t\t\t\t\tover       : function(e, ui) {
\t\t\t\t\t\tvar helper = ui.helper,
\t\t\t\t\t\t\tdir    = \$.grep(helper.data('files'), function(h) { return (fm.file(h).mime === 'directory' && !dirs[h])? true : false; });
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\thelper.data('dropover', helper.data('dropover') + 1);
\t\t\t\t\t\tif (fm.insideWorkzone(e.pageX, e.pageY)) {
\t\t\t\t\t\t\tif (dir.length > 0) {
\t\t\t\t\t\t\t\thelper.addClass('elfinder-drag-helper-plus');
\t\t\t\t\t\t\t\tfm.trigger('unlockfiles', {files : helper.data('files'), helper: helper});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\$(this).removeClass(dropover);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tout : function(e, ui) {
\t\t\t\t\t\tvar helper = ui.helper;
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus').data('dropover', Math.max(helper.data('dropover') - 1, 0));
\t\t\t\t\t\t\$(this).removeData('dropover')
\t\t\t\t\t\t       .removeClass(dropover);
\t\t\t\t\t},
\t\t\t\t\tdrop       : function(e, ui) {
\t\t\t\t\t\tvar helper  = ui.helper,
\t\t\t\t\t\t\tresolve = true;
\t\t\t\t\t\t
\t\t\t\t\t\t\$.each(helper.data('files'), function(i, hash) {
\t\t\t\t\t\t\tvar dir = fm.file(hash);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (dir && dir.mime == 'directory' && !dirs[dir.hash]) {
\t\t\t\t\t\t\t\tadd(dir);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tresolve = false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tsave();
\t\t\t\t\t\tresolve && helper.hide();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// for touch device
\t\t\t\t.on('touchstart', '.'+navdir+':not(.'+clroot+')', function(e) {
\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tvar hash = \$(this).attr('id').substr(6),
\t\t\t\t\tp = \$(this)
\t\t\t\t\t.addClass(hover)
\t\t\t\t\t.data('longtap', null)
\t\t\t\t\t.data('tmlongtap', setTimeout(function(){
\t\t\t\t\t\t// long tap
\t\t\t\t\t\tp.data('longtap', true);
\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\traw : [{
\t\t\t\t\t\t\t\tlabel    : fm.i18n('rmFromPlaces'),
\t\t\t\t\t\t\t\ticon     : 'rm',
\t\t\t\t\t\t\t\tcallback : function() { remove(hash); save(); }
\t\t\t\t\t\t\t}],
\t\t\t\t\t\t\t'x'       : e.originalEvent.touches[0].pageX,
\t\t\t\t\t\t\t'y'       : e.originalEvent.touches[0].pageY
\t\t\t\t\t\t});
\t\t\t\t\t}, 500));
\t\t\t\t})
\t\t\t\t.on('touchmove touchend', '.'+navdir+':not(.'+clroot+')', function(e) {
\t\t\t\t\tclearTimeout(\$(this).data('tmlongtap'));
\t\t\t\t\tif (e.type == 'touchmove') {
\t\t\t\t\t\t\$(this).removeClass(hover);
\t\t\t\t\t}
\t\t\t\t});

\t\tif (\$.fn.sortable) {
\t\t\tsubtree.addClass('touch-punch')
\t\t\t.sortable({
\t\t\t\tappendTo : fm.getUI(),
\t\t\t\trevert   : false,
\t\t\t\thelper   : function(e) {
\t\t\t\t\tvar dir = \$(e.target).parent();
\t\t\t\t\t\t
\t\t\t\t\tdir.children().removeClass('ui-state-hover');
\t\t\t\t\t
\t\t\t\t\treturn \$('<div class=\"ui-widget elfinder-place-drag elfinder-'+fm.direction+'\"></div>')
\t\t\t\t\t\t\t.append(\$('<div class=\"elfinder-navbar\"></div>').show().append(dir.clone()));

\t\t\t\t},
\t\t\t\tstop     : function(e, ui) {
\t\t\t\t\tvar target = \$(ui.item[0]),
\t\t\t\t\t\ttop    = places.offset().top,
\t\t\t\t\t\tleft   = places.offset().left,
\t\t\t\t\t\twidth  = places.width(),
\t\t\t\t\t\theight = places.height(),
\t\t\t\t\t\tx      = e.pageX,
\t\t\t\t\t\ty      = e.pageY;
\t\t\t\t\t
\t\t\t\t\tif (!(x > left && x < left+width && y > top && y < y+height)) {
\t\t\t\t\t\tremove(id2hash(target.children(':first').attr('id')));
\t\t\t\t\t\tsave();
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tupdate   : function(e, ui) {
\t\t\t\t\tsave();
\t\t\t\t}
\t\t\t});
\t\t}

\t\t// \"on regist\" for command exec
\t\t\$(this).on('regist', function(e, files){
\t\t\tvar added = false;
\t\t\t\$.each(files, function(i, dir) {
\t\t\t\tif (dir && dir.mime == 'directory' && !dirs[dir.hash]) {
\t\t\t\t\tif (add(dir)) {
\t\t\t\t\t\tadded = true;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\tadded && save();
\t\t});
\t

\t\t// on fm load - show places and load files from backend
\t\tfm.one('load', function() {
\t\t\tvar dat, hashes;
\t\t\t
\t\t\tif (fm.oldAPI) {
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\tplaces.show().parent().show();

\t\t\tinit();

\t\t\tfm.change(function(e) {
\t\t\t\tvar changed = false;
\t\t\t\t\$.each(e.data.changed, function(i, file) {
\t\t\t\t\tif (dirs[file.hash]) {
\t\t\t\t\t\tif (file.mime !== 'directory') {
\t\t\t\t\t\t\tif (remove(file.hash)) {
\t\t\t\t\t\t\t\tchanged = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (update(file)) {
\t\t\t\t\t\t\t\tchanged = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tchanged && save();
\t\t\t})
\t\t\t.bind('rename', function(e) {
\t\t\t\tvar changed = false;
\t\t\t\tif (e.data.removed) {
\t\t\t\t\t\$.each(e.data.removed, function(i, hash) {
\t\t\t\t\t\tif (e.data.added[i]) {
\t\t\t\t\t\t\tif (update(e.data.added[i], hash)) {
\t\t\t\t\t\t\t\tchanged = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tchanged && save();
\t\t\t})
\t\t\t.bind('rm paste', function(e) {
\t\t\t\tvar names = [],
\t\t\t\t\tchanged = false;
\t\t\t\tif (e.data.removed) {
\t\t\t\t\t\$.each(e.data.removed, function(i, hash) {
\t\t\t\t\t\tvar name = remove(hash);
\t\t\t\t\t\tname && names.push(name);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (names.length) {
\t\t\t\t\tchanged = true;
\t\t\t\t}
\t\t\t\tif (e.data.added && names.length) {
\t\t\t\t\t\$.each(e.data.added, function(i, file) {
\t\t\t\t\t\tif (\$.inArray(file.name, names) !== 1) {
\t\t\t\t\t\t\tfile.mime == 'directory' && add(file);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tchanged && save();
\t\t\t})
\t\t\t.bind('sync netmount', function() {
\t\t\t\tvar ev = this,
\t\t\t\t\topSuffix = opts.suffix? opts.suffix : '',
\t\t\t\t\thashes;
\t\t\t\t
\t\t\t\tif (ev.type === 'sync') {
\t\t\t\t\t// check is change of opts.suffix
\t\t\t\t\tif (suffix !== opSuffix) {
\t\t\t\t\t\tsuffix = opSuffix;
\t\t\t\t\t\tclear();
\t\t\t\t\t\tinit();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\thashes = Object.keys(dirs);
\t\t\t\tif (hashes.length) {
\t\t\t\t\troot.prepend(spinner);

\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'info', targets : hashes},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tvar exists  = {},
\t\t\t\t\t\t\tupdated = false,
\t\t\t\t\t\t\tcwd     = fm.cwd().hash;
\t\t\t\t\t\t\$.each(data.files || [], function(i, file) {
\t\t\t\t\t\t\tvar hash = file.hash;
\t\t\t\t\t\t\texists[hash] = file;
\t\t\t\t\t\t\tif (!fm.files().hasOwnProperty(file.hash)) {
\t\t\t\t\t\t\t\t// update cache
\t\t\t\t\t\t\t\tfm.updateCache({tree: [file]});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\t\$.each(dirs, function(h, f) {
\t\t\t\t\t\t\tif (Boolean(f.notfound) === Boolean(exists[h])) {
\t\t\t\t\t\t\t\tif ((f.phash === cwd && ev.type !== 'netmount') || (exists[h] && exists[h].mime !== 'directory')) {
\t\t\t\t\t\t\t\t\tif (remove(h)) {
\t\t\t\t\t\t\t\t\t\tupdated = true;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tif (update(exists[h] || Object.assign({notfound: true}, f))) {
\t\t\t\t\t\t\t\t\t\tupdated = true;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else if (exists[h] && exists[h].phash != cwd) {
\t\t\t\t\t\t\t\t// update permission of except cwd
\t\t\t\t\t\t\t\tupdate(exists[h]);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tupdated && save();
\t\t\t\t\t})
\t\t\t\t\t.always(function() {
\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t});
\t\t
\t});
};


/*
 * File: /js/ui/searchbutton.js
 */

/**
 * @class  elFinder toolbar search button widget.
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindersearchbutton = function(cmd) {
\t\treturn this.each(function() {
\t\tvar result = false,
\t\t\tfm     = cmd.fm,
\t\t\tdisabled = fm.res('class', 'disabled'),
\t\t\tisopts = cmd.options.incsearch || { enable: false },
\t\t\tsTypes = cmd.options.searchTypes,
\t\t\tid     = function(name){return fm.namespace + fm.escape(name);},
\t\t\ttoolbar= fm.getUI('toolbar'),
\t\t\tbtnCls = fm.res('class', 'searchbtn'),
\t\t\tbutton = \$(this)
\t\t\t\t.hide()
\t\t\t\t.addClass('ui-widget-content elfinder-button '+btnCls)
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t}),
\t\t\tgetMenuOffset = function() {
\t\t\t\tvar fmNode = fm.getUI(),
\t\t\t\t\tbaseOffset = fmNode.offset(),
\t\t\t\t\tbuttonOffset = button.offset();
\t\t\t\treturn {
\t\t\t\t\ttop : buttonOffset.top - baseOffset.top,
\t\t\t\t\tmaxHeight : fmNode.height() - 40
\t\t\t\t};
\t\t\t},
\t\t\tsearch = function() {
\t\t\t\tinput.data('inctm') && clearTimeout(input.data('inctm'));
\t\t\t\tvar val = \$.trim(input.val()),
\t\t\t\t\tfrom = !\$('#' + id('SearchFromAll')).prop('checked'),
\t\t\t\t\tmime = \$('#' + id('SearchMime')).prop('checked'),
\t\t\t\t\ttype = '';
\t\t\t\tif (from) {
\t\t\t\t\tif (\$('#' + id('SearchFromVol')).prop('checked')) {
\t\t\t\t\t\tfrom = fm.root(fm.cwd().hash);
\t\t\t\t\t} else {
\t\t\t\t\t\tfrom = fm.cwd().hash;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tif (mime) {
\t\t\t\t\tmime = val;
\t\t\t\t\tval = '.';
\t\t\t\t}
\t\t\t\tif (typeSet) {
\t\t\t\t\ttype = typeSet.children('input:checked').val();
\t\t\t\t}
\t\t\t\tif (val) {
\t\t\t\t\tinput.trigger('focus');
\t\t\t\t\tcmd.exec(val, from, mime, type).done(function() {
\t\t\t\t\t\tresult = true;
\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\tabort();
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t} else {
\t\t\t\t\tfm.trigger('searchend');
\t\t\t\t}
\t\t\t},
\t\t\tabort = function() {
\t\t\t\tinput.data('inctm') && clearTimeout(input.data('inctm'));
\t\t\t\tinput.val('').trigger('blur');
\t\t\t\tif (result || incVal) {
\t\t\t\t\tresult = false;
\t\t\t\t\tincVal = '';
\t\t\t\t\tfm.lazy(function() {
\t\t\t\t\t\tfm.trigger('searchend');
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\tincVal = '',
\t\t\tinput  = \$('<input type=\"text\" size=\"42\"/>')
\t\t\t\t.on('focus', function() {
\t\t\t\t\t// close other menus
\t\t\t\t\t!button.hasClass('ui-state-active') && fm.getUI().click();
\t\t\t\t\tinFocus = true;
\t\t\t\t\tincVal = '';
\t\t\t\t\tbutton.addClass('ui-state-active');
\t\t\t\t\tfm.trigger('uiresize');
\t\t\t\t\topts && opts.css(getMenuOffset()).slideDown(function() {
\t\t\t\t\t\t// Care for on browser window re-active
\t\t\t\t\t\tbutton.addClass('ui-state-active');
\t\t\t\t\t\tfm.toFront(opts);
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.on('blur', function() {
\t\t\t\t\tinFocus = false;
\t\t\t\t\tif (opts) {
\t\t\t\t\t\tif (!opts.data('infocus')) {
\t\t\t\t\t\t\topts.slideUp(function() {
\t\t\t\t\t\t\t\tbutton.removeClass('ui-state-active');
\t\t\t\t\t\t\t\tfm.trigger('uiresize');
\t\t\t\t\t\t\t\tfm.toHide(opts);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\topts.data('infocus', false);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tbutton.removeClass('ui-state-active');
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.appendTo(button)
\t\t\t\t// to avoid fm shortcuts on arrows
\t\t\t\t.on('keypress', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t})
\t\t\t\t.on('keydown', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tif (e.keyCode === \$.ui.keyCode.ENTER) {
\t\t\t\t\t\tsearch();
\t\t\t\t\t} else if (e.keyCode === \$.ui.keyCode.ESCAPE) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tabort();
\t\t\t\t\t}
\t\t\t\t}),
\t\t\topts, typeSet, cwdReady, inFocus;
\t\t
\t\tif (isopts.enable) {
\t\t\tisopts.minlen = isopts.minlen || 2;
\t\t\tisopts.wait = isopts.wait || 500;
\t\t\tinput
\t\t\t\t.attr('title', fm.i18n('incSearchOnly'))
\t\t\t\t.on('compositionstart', function() {
\t\t\t\t\tinput.data('composing', true);
\t\t\t\t})
\t\t\t\t.on('compositionend', function() {
\t\t\t\t\tinput.removeData('composing');
\t\t\t\t\tinput.trigger('input'); // for IE, edge
\t\t\t\t})
\t\t\t\t.on('input', function() {
\t\t\t\t\tif (! input.data('composing')) {
\t\t\t\t\t\tinput.data('inctm') && clearTimeout(input.data('inctm'));
\t\t\t\t\t\tinput.data('inctm', setTimeout(function() {
\t\t\t\t\t\t\tvar val = input.val();
\t\t\t\t\t\t\tif (val.length === 0 || val.length >= isopts.minlen) {
\t\t\t\t\t\t\t\t(incVal !== val) && fm.trigger('incsearchstart', {
\t\t\t\t\t\t\t\t\tquery: val,
\t\t\t\t\t\t\t\t\ttype: typeSet? typeSet.children('input:checked').val() : 'searchName'
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tincVal = val;
\t\t\t\t\t\t\t\tif (val === '' && fm.searchStatus.state > 1 && fm.searchStatus.query) {
\t\t\t\t\t\t\t\t\tinput.val(fm.searchStatus.query).trigger('select');
\t\t\t\t\t\t\t\t} 
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}, isopts.wait));
\t\t\t\t\t}
\t\t\t\t});
\t\t\t
\t\t\tif (fm.UA.ltIE8) {
\t\t\t\tinput.on('keydown', function(e) {
\t\t\t\t\t\tif (e.keyCode === 229) {
\t\t\t\t\t\t\tinput.data('imetm') && clearTimeout(input.data('imetm'));
\t\t\t\t\t\t\tinput.data('composing', true);
\t\t\t\t\t\t\tinput.data('imetm', setTimeout(function() {
\t\t\t\t\t\t\t\tinput.removeData('composing');
\t\t\t\t\t\t\t}, 100));
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('keyup', function(e) {
\t\t\t\t\t\tinput.data('imetm') && clearTimeout(input.data('imetm'));
\t\t\t\t\t\tif (input.data('composing')) {
\t\t\t\t\t\t\te.keyCode === \$.ui.keyCode.ENTER && input.trigger('compositionend');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tinput.trigger('input');
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t}
\t\t}
\t\t
\t\t\$('<span class=\"ui-icon ui-icon-search\" title=\"'+cmd.title+'\"></span>')
\t\t\t.appendTo(button)
\t\t\t.on('mousedown', function(e) {
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\tif (button.hasClass('ui-state-active')) {
\t\t\t\t\tsearch();
\t\t\t\t} else {
\t\t\t\t\tinput.trigger('focus');
\t\t\t\t}
\t\t\t});
\t\t
\t\t\$('<span class=\"ui-icon ui-icon-close\"></span>')
\t\t\t.appendTo(button)
\t\t\t.on('mousedown', function(e) {
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\tif (input.val() === '' && !button.hasClass('ui-state-active')) {
\t\t\t\t\tinput.trigger('focus');
\t\t\t\t} else {
\t\t\t\t\tabort();
\t\t\t\t}
\t\t\t});
\t\t
\t\t// wait when button will be added to DOM
\t\tfm.bind('toolbarload', function(){
\t\t\tvar parent = button.parent();
\t\t\tif (parent.length) {
\t\t\t\ttoolbar.prepend(button.show());
\t\t\t\tparent.remove();
\t\t\t\t// position icons for ie7
\t\t\t\tif (fm.UA.ltIE7) {
\t\t\t\t\tvar icon = button.children(fm.direction == 'ltr' ? '.ui-icon-close' : '.ui-icon-search');
\t\t\t\t\ticon.css({
\t\t\t\t\t\tright : '',
\t\t\t\t\t\tleft  : parseInt(button.width())-icon.outerWidth(true)
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\tfm
\t\t\t.one('init', function() {
\t\t\t\tfm.getUI('cwd').on('touchstart click', function() {
\t\t\t\t\tinFocus && input.trigger('blur');
\t\t\t\t});
\t\t\t})
\t\t\t.one('open', function() {
\t\t\t\topts = (fm.api < 2.1)? null : \$('<div class=\"ui-front ui-widget ui-widget-content elfinder-button-menu elfinder-button-search-menu ui-corner-all\"></div>')
\t\t\t\t\t.append(
\t\t\t\t\t\t\$('<div class=\"buttonset\"></div>')
\t\t\t\t\t\t\t.append(
\t\t\t\t\t\t\t\t\$('<input id=\"'+id('SearchFromCwd')+'\" name=\"serchfrom\" type=\"radio\" checked=\"checked\"/><label for=\"'+id('SearchFromCwd')+'\">'+fm.i18n('btnCwd')+'</label>'),
\t\t\t\t\t\t\t\t\$('<input id=\"'+id('SearchFromVol')+'\" name=\"serchfrom\" type=\"radio\"/><label for=\"'+id('SearchFromVol')+'\">'+fm.i18n('btnVolume')+'</label>'),
\t\t\t\t\t\t\t\t\$('<input id=\"'+id('SearchFromAll')+'\" name=\"serchfrom\" type=\"radio\"/><label for=\"'+id('SearchFromAll')+'\">'+fm.i18n('btnAll')+'</label>')
\t\t\t\t\t\t\t),
\t\t\t\t\t\t\$('<div class=\"buttonset elfinder-search-type\"></div>')
\t\t\t\t\t\t\t.append(
\t\t\t\t\t\t\t\t\$('<input id=\"'+id('SearchName')+'\" name=\"serchcol\" type=\"radio\" checked=\"checked\" value=\"SearchName\"/><label for=\"'+id('SearchName')+'\">'+fm.i18n('btnFileName')+'</label>')
\t\t\t\t\t\t\t)
\t\t\t\t\t)
\t\t\t\t\t.hide()
\t\t\t\t\t.appendTo(fm.getUI());
\t\t\t\tif (opts) {
\t\t\t\t\tif (sTypes) {
\t\t\t\t\t\ttypeSet = opts.find('.elfinder-search-type');
\t\t\t\t\t\t\$.each(cmd.options.searchTypes, function(i, v) {
\t\t\t\t\t\t\ttypeSet.append(\$('<input id=\"'+id(i)+'\" name=\"serchcol\" type=\"radio\" value=\"'+fm.escape(i)+'\"/><label for=\"'+id(i)+'\">'+fm.i18n(v.name)+'</label>'));
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\topts.find('div.buttonset').buttonset();
\t\t\t\t\t\$('#'+id('SearchFromAll')).next('label').attr('title', fm.i18n('searchTarget', fm.i18n('btnAll')));
\t\t\t\t\tif (sTypes) {
\t\t\t\t\t\t\$.each(sTypes, function(i, v) {
\t\t\t\t\t\t\tif (v.title) {
\t\t\t\t\t\t\t\t\$('#'+id(i)).next('label').attr('title', fm.i18n(v.title));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\topts.on('mousedown', 'div.buttonset', function(e){
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\topts.data('infocus', true);
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('click', 'input', function(e) {
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\$.trim(input.val())? search() : input.trigger('focus');
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('close', function() {
\t\t\t\t\t\t\tinput.trigger('blur');
\t\t\t\t\t\t});
\t\t\t\t}
\t\t\t})
\t\t\t.bind('searchend', function() {
\t\t\t\tinput.val('');
\t\t\t})
\t\t\t.bind('open parents', function() {
\t\t\t\tvar dirs    = [],
\t\t\t\t\tvolroot = fm.file(fm.root(fm.cwd().hash));
\t\t\t\t
\t\t\t\tif (volroot) {
\t\t\t\t\t\$.each(fm.parents(fm.cwd().hash), function(i, hash) {
\t\t\t\t\t\tdirs.push(fm.file(hash).name);
\t\t\t\t\t});
\t\t
\t\t\t\t\t\$('#'+id('SearchFromCwd')).next('label').attr('title', fm.i18n('searchTarget', dirs.join(fm.option('separator'))));
\t\t\t\t\t\$('#'+id('SearchFromVol')).next('label').attr('title', fm.i18n('searchTarget', volroot.name));
\t\t\t\t}
\t\t\t})
\t\t\t.bind('open', function() {
\t\t\t\tincVal && abort();
\t\t\t})
\t\t\t.bind('cwdinit', function() {
\t\t\t\tcwdReady = false;
\t\t\t})
\t\t\t.bind('cwdrender',function() {
\t\t\t\tcwdReady = true;
\t\t\t})
\t\t\t.bind('keydownEsc', function() {
\t\t\t\tif (incVal && incVal.substr(0, 1) === '/') {
\t\t\t\t\tincVal = '';
\t\t\t\t\tinput.val('');
\t\t\t\t\tfm.trigger('searchend');
\t\t\t\t}
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : 'ctrl+f f3',
\t\t\t\tdescription : cmd.title,
\t\t\t\tcallback    : function() { 
\t\t\t\t\tinput.trigger('select').trigger('focus');
\t\t\t\t}
\t\t\t})
\t\t\t.shortcut({
\t\t\t\tpattern     : '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',
\t\t\t\tdescription : fm.i18n('firstLetterSearch'),
\t\t\t\tcallback    : function(e) { 
\t\t\t\t\tif (! cwdReady) { return; }
\t\t\t\t\t
\t\t\t\t\tvar code = e.originalEvent.keyCode,
\t\t\t\t\t\tnext = function() {
\t\t\t\t\t\t\tvar sel = fm.selected(),
\t\t\t\t\t\t\t\tkey = \$.ui.keyCode[(!sel.length || fm.cwdHash2Elm(sel[0]).next('[id]').length)? 'RIGHT' : 'HOME'];
\t\t\t\t\t\t\t\$(document).trigger(\$.Event('keydown', { keyCode: key, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
\t\t\t\t\t\t},
\t\t\t\t\t\tval;
\t\t\t\t\tif (code >= 96 && code <= 105) {
\t\t\t\t\t\tcode -= 48;
\t\t\t\t\t}
\t\t\t\t\tval = '/' + String.fromCharCode(code);
\t\t\t\t\tif (incVal !== val) {
\t\t\t\t\t\tinput.val(val);
\t\t\t\t\t\tincVal = val;
\t\t\t\t\t\tfm
\t\t\t\t\t\t\t.trigger('incsearchstart', { query: val })
\t\t\t\t\t\t\t.one('cwdrender', next);
\t\t\t\t\t} else{
\t\t\t\t\t\tnext();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});

\t});
};


/*
 * File: /js/ui/sortbutton.js
 */

/**
 * @class  elFinder toolbar button menu with sort variants.
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindersortbutton = function(cmd) {
\t\treturn this.each(function() {
\t\tvar fm       = cmd.fm,
\t\t\tname     = cmd.name,
\t\t\tc        = 'class',
\t\t\tdisabled = fm.res(c, 'disabled'),
\t\t\thover    = fm.res(c, 'hover'),
\t\t\titem     = 'elfinder-button-menu-item',
\t\t\tselected = item+'-selected',
\t\t\tasc      = selected+'-asc',
\t\t\tdesc     = selected+'-desc',
\t\t\ttext     = \$('<span class=\"elfinder-button-text\">'+cmd.title+'</span>'),
\t\t\tbutton   = \$(this).addClass('ui-state-default elfinder-button elfinder-menubutton elfiner-button-'+name)
\t\t\t\t.attr('title', cmd.title)
\t\t\t\t.append('<span class=\"elfinder-button-icon elfinder-button-icon-'+name+'\"></span>', text)
\t\t\t\t.on('mouseenter mouseleave', function(e) { !button.hasClass(disabled) && button.toggleClass(hover, e.type === 'mouseenter'); })
\t\t\t\t.on('click', function(e) {
\t\t\t\t\tif (!button.hasClass(disabled)) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\tmenu.is(':hidden') && fm.getUI().click();
\t\t\t\t\t\tmenu.css(getMenuOffset()).slideToggle({
\t\t\t\t\t\t\tduration: 100,
\t\t\t\t\t\t\tdone: function(e) {
\t\t\t\t\t\t\t\tfm[menu.is(':visible')? 'toFront' : 'toHide'](menu);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}),
\t\t\thide = function() { fm.toHide(menu); },
\t\t\tmenu = \$('<div class=\"ui-front ui-widget ui-widget-content elfinder-button-menu elfinder-button-sort-menu ui-corner-all\"></div>')
\t\t\t\t.hide()
\t\t\t\t.appendTo(fm.getUI())
\t\t\t\t.on('mouseenter mouseleave', '.'+item, function(e) { \$(this).toggleClass(hover, e.type === 'mouseenter'); })
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t})
\t\t\t\t.on('close', hide),
\t\t\tupdate = function() {
\t\t\t\tmenu.children('[rel]').removeClass(selected+' '+asc+' '+desc)
\t\t\t\t\t.filter('[rel=\"'+fm.sortType+'\"]')
\t\t\t\t\t.addClass(selected+' '+(fm.sortOrder == 'asc' ? asc : desc));

\t\t\t\tmenu.children('.elfinder-sort-stick').toggleClass(selected, fm.sortStickFolders);
\t\t\t\tmenu.children('.elfinder-sort-tree').toggleClass(selected, fm.sortAlsoTreeview);
\t\t\t},
\t\t\tgetMenuOffset = function() {
\t\t\t\tvar baseOffset = fm.getUI().offset(),
\t\t\t\t\tbuttonOffset = button.offset();
\t\t\t\treturn {
\t\t\t\t\ttop : buttonOffset.top - baseOffset.top,
\t\t\t\t\tleft : buttonOffset.left - baseOffset.left
\t\t\t\t};
\t\t\t},
\t\t\ttm;
\t\t\t
\t\ttext.hide();
\t\t
\t\t\$.each(fm.sortRules, function(name, value) {
\t\t\tmenu.append(\$('<div class=\"'+item+'\" rel=\"'+name+'\"><span class=\"ui-icon ui-icon-arrowthick-1-n\"></span><span class=\"ui-icon ui-icon-arrowthick-1-s\"></span>'+fm.i18n('sort'+name)+'</div>').data('type', name));
\t\t});
\t\t
\t\tmenu.children().on('click', function(e) {
\t\t\tcmd.exec([], \$(this).removeClass(hover).attr('rel'));
\t\t});
\t\t
\t\t\$('<div class=\"'+item+' '+item+'-separated elfinder-sort-ext elfinder-sort-stick\"><span class=\"ui-icon ui-icon-check\"></span>'+fm.i18n('sortFoldersFirst')+'</div>')
\t\t\t.appendTo(menu)
\t\t\t.on('click', function() {
\t\t\t\tcmd.exec([], 'stick');
\t\t\t});

\t\tfm.one('init', function() {
\t\t\tif (fm.ui.tree && fm.options.sortAlsoTreeview !== null) {
\t\t\t\t\$('<div class=\"'+item+' '+item+'-separated elfinder-sort-ext elfinder-sort-tree\"><span class=\"ui-icon ui-icon-check\"></span>'+fm.i18n('sortAlsoTreeview')+'</div>')
\t\t\t\t.appendTo(menu)
\t\t\t\t.on('click', function() {
\t\t\t\t\tcmd.exec([], 'tree');
\t\t\t\t});
\t\t\t}
\t\t})
\t\t.bind('disable select', hide)
\t\t.bind('sortchange', update).getUI().on('click', hide);
\t\t
\t\tif (menu.children().length > 1) {
\t\t\tcmd.change(function() {
\t\t\t\t\ttm && cancelAnimationFrame(tm);
\t\t\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\t\t\tbutton.toggleClass(disabled, cmd.disabled());
\t\t\t\t\t\tupdate();
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.change();
\t\t} else {
\t\t\tbutton.addClass(disabled);
\t\t}

\t});
\t
};


/*
 * File: /js/ui/stat.js
 */

/**
 * @class elFinder ui
 * Display number of files/selected files and its size in statusbar
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderstat = function(fm) {
\t\treturn this.each(function() {
\t\tvar size       = \$(this).addClass('elfinder-stat-size'),
\t\t\tsel        = \$('<div class=\"elfinder-stat-selected\"></div>')
\t\t\t\t.on('click', 'a', function(e) {
\t\t\t\t\tvar hash = \$(this).data('hash');
\t\t\t\t\te.preventDefault();
\t\t\t\t\tfm.exec('opendir', [ hash ]);
\t\t\t\t}),
\t\t\ttitleitems = fm.i18n('items'),
\t\t\ttitlesel   = fm.i18n('selected'),
\t\t\ttitlesize  = fm.i18n('size'),
\t\t\tsetstat    = function(files) {
\t\t\t\tvar c = 0, 
\t\t\t\t\ts = 0,
\t\t\t\t\tcwd = fm.cwd(),
\t\t\t\t\tcalc = true,
\t\t\t\t\thasSize = true;

\t\t\t\tif (cwd.sizeInfo || cwd.size) {
\t\t\t\t\ts = cwd.size;
\t\t\t\t\tcalc = false;
\t\t\t\t}
\t\t\t\t\$.each(files, function(i, file) {
\t\t\t\t\tc++;
\t\t\t\t\tif (calc) {
\t\t\t\t\t\ts += parseInt(file.size) || 0;
\t\t\t\t\t\tif (hasSize === true && file.mime === 'directory' && !file.sizeInfo) {
\t\t\t\t\t\t\thasSize = false;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tsize.html(titleitems+': <span class=\"elfinder-stat-incsearch\"></span>'+c+',&nbsp;<span class=\"elfinder-stat-size'+(hasSize? ' elfinder-stat-size-recursive' : '')+'\">'+fm.i18n(hasSize? 'sum' : 'size')+': '+fm.formatSize(s)+'</span>')
\t\t\t\t\t.attr('title', size.text());
\t\t\t\tfm.trigger('uistatchange');
\t\t\t},
\t\t\tsetIncsearchStat = function(data) {
\t\t\t\tsize.find('span.elfinder-stat-incsearch').html(data? data.hashes.length + ' / ' : '');
\t\t\t\tsize.attr('title', size.text());
\t\t\t\tfm.trigger('uistatchange');
\t\t\t},
\t\t\tsetSelect = function(files) {
\t\t\t\tvar s = 0,
\t\t\t\t\tc = 0,
\t\t\t\t\tdirs = [],
\t\t\t\t\tpath, file;

\t\t\t\tif (files.length === 1) {
\t\t\t\t\tfile = files[0];
\t\t\t\t\ts = file.size;
\t\t\t\t\tif (fm.searchStatus.state === 2) {
\t\t\t\t\t\tpath = fm.escape(file.path? file.path.replace(/\\/[^\\/]*\$/, '') : '..');
\t\t\t\t\t\tdirs.push('<a href=\"#elf_'+file.phash+'\" data-hash=\"'+file.hash+'\" title=\"'+path+'\">'+path+'</a>');
\t\t\t\t\t}
\t\t\t\t\tdirs.push(fm.escape(file.i18 || file.name));
\t\t\t\t\tsel.html(dirs.join('/') + (s > 0 ? ', '+fm.formatSize(s) : ''));
\t\t\t\t} else if (files.length) {
\t\t\t\t\t\$.each(files, function(i, file) {
\t\t\t\t\t\tc++;
\t\t\t\t\t\ts += parseInt(file.size)||0;
\t\t\t\t\t});
\t\t\t\t\tsel.html(c ? titlesel+': '+c+', '+titlesize+': '+fm.formatSize(s) : '&nbsp;');
\t\t\t\t} else {
\t\t\t\t\tsel.html('');
\t\t\t\t}
\t\t\t\tsel.attr('title', sel.text());
\t\t\t\tfm.trigger('uistatchange');
\t\t\t};

\t\tfm.getUI('statusbar').prepend(size).append(sel).show();
\t\tif (fm.UA.Mobile && \$.fn.tooltip) {
\t\t\tfm.getUI('statusbar').tooltip({
\t\t\t\tclasses: {
\t\t\t\t\t'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
\t\t\t\t},
\t\t\t\ttooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
\t\t\t\ttrack: true
\t\t\t});
\t\t}
\t\t
\t\tfm
\t\t.bind('cwdhasheschange', function(e) {
\t\t\tsetstat(\$.map(e.data, function(h) { return fm.file(h); }));
\t\t})
\t\t.change(function(e) {
\t\t\tvar files = e.data.changed || [],
\t\t\t\tcwdHash = fm.cwd().hash;
\t\t\t\$.each(files, function() {
\t\t\t\tif (this.hash === cwdHash) {
\t\t\t\t\tif (this.size) {
\t\t\t\t\t\tsize.children('.elfinder-stat-size').addClass('elfinder-stat-size-recursive').html(fm.i18n('sum')+': '+fm.formatSize(this.size));
\t\t\t\t\t\tsize.attr('title', size.text());
\t\t\t\t\t}
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t});
\t\t})
\t\t.select(function() {
\t\t\tsetSelect(fm.selectedFiles());
\t\t})
\t\t.bind('open', function() {
\t\t\tsetSelect([]);
\t\t})
\t\t.bind('incsearch', function(e) {
\t\t\tsetIncsearchStat(e.data);
\t\t})
\t\t.bind('incsearchend', function() {
\t\t\tsetIncsearchStat();
\t\t})
\t\t;
\t});
};


/*
 * File: /js/ui/toast.js
 */

/**
 * @class  elFinder toast
 * 
 * This was created inspired by the toastr. Thanks to developers of toastr.
 * CodeSeven/toastr: http://johnpapa.net <https://github.com/CodeSeven/toastr>
 *
 * @author Naoki Sawada
 **/
\$.fn.elfindertoast = function(opts, fm) {
\t\tvar defOpts = Object.assign({
\t\tmode: 'success', // or 'info', 'warning' and 'error'
\t\tmsg: '',
\t\tshowMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
\t\tshowDuration: 300,
\t\tshowEasing: 'swing', //swing and linear are built into jQuery
\t\tonShown: undefined,
\t\thideMethod: 'fadeOut',
\t\thideDuration: 1500,
\t\thideEasing: 'swing',
\t\tonHidden: undefined,
\t\ttimeOut: 3000,
\t\textNode: undefined,
\t\tbutton: undefined,
\t\twidth: undefined
\t}, \$.isPlainObject(fm.options.uiOptions.toast.defaults)? fm.options.uiOptions.toast.defaults : {});
\treturn this.each(function() {
\t\topts = Object.assign({}, defOpts, opts || {});
\t\t
\t\tvar self = \$(this),
\t\t\tshow = function(notm) {
\t\t\t\tself.stop();
\t\t\t\tfm.toFront(self);
\t\t\t\tself[opts.showMethod]({
\t\t\t\t\tduration: opts.showDuration,
\t\t\t\t\teasing: opts.showEasing,
\t\t\t\t\tcomplete: function() {
\t\t\t\t\t\topts.onShown && opts.onShown();
\t\t\t\t\t\tif (!notm && opts.timeOut) {
\t\t\t\t\t\t\trmTm = setTimeout(rm, opts.timeOut);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\trm = function() {
\t\t\t\tself[opts.hideMethod]({
\t\t\t\t\tduration: opts.hideDuration,
\t\t\t\t\teasing: opts.hideEasing,
\t\t\t\t\tcomplete: function() {
\t\t\t\t\t\topts.onHidden && opts.onHidden();
\t\t\t\t\t\tself.remove();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t},
\t\t\trmTm;
\t\t
\t\tself.on('click', function(e) {
\t\t\te.stopPropagation();
\t\t\te.preventDefault();
\t\t\trmTm && clearTimeout(rmTm);
\t\t\topts.onHidden && opts.onHidden();
\t\t\tself.stop().remove();
\t\t}).on('mouseenter mouseleave', function(e) {
\t\t\tif (opts.timeOut) {
\t\t\t\trmTm && clearTimeout(rmTm);
\t\t\t\trmTm = null;
\t\t\t\tif (e.type === 'mouseenter') {
\t\t\t\t\tshow(true);
\t\t\t\t} else {
\t\t\t\t\trmTm = setTimeout(rm, opts.timeOut);
\t\t\t\t}
\t\t\t}
\t\t}).hide().addClass('toast-' + opts.mode).append(\$('<div class=\"elfinder-toast-msg\"></div>').html(opts.msg.replace(/%([a-zA-Z0-9]+)%/g, function(m, m1) {
\t\t\treturn fm.i18n(m1);
\t\t})));
\t\t
\t\tif (opts.extNode) {
\t\t\tself.append(opts.extNode);
\t\t}

\t\tif (opts.button) {
\t\t\tself.append(
\t\t\t\t\$('<button class=\"ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop\"></button>')
\t\t\t\t.append(\$('<span class=\"ui-button-text\"></span>').text(fm.i18n(opts.button.text)))
\t\t\t\t.on('mouseenter mouseleave', function(e) { 
\t\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
\t\t\t\t})
\t\t\t\t.on('click', opts.button.click || function(){})
\t\t\t);
\t\t}

\t\tif (opts.width) {
\t\t\tself.css('max-width', opts.width);
\t\t}
\t\t
\t\tshow();
\t});
};

/*
 * File: /js/ui/toolbar.js
 */

/**
 * @class  elFinder toolbar
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindertoolbar = function(fm, opts) {
\t\tthis.not('.elfinder-toolbar').each(function() {
\t\tvar commands = fm._commands,
\t\t\tself     = \$(this).addClass('ui-helper-clearfix ui-widget-header elfinder-toolbar'),
\t\t\toptions  = {
\t\t\t\t// default options
\t\t\t\tdisplayTextLabel: false,
\t\t\t\tlabelExcludeUA: ['Mobile'],
\t\t\t\tautoHideUA: ['Mobile'],
\t\t\t\tshowPreferenceButton: 'none'
\t\t\t},
\t\t\tfilter   = function(opts) {
\t\t\t\treturn \$.grep(opts, function(v) {
\t\t\t\t\tif (\$.isPlainObject(v)) {
\t\t\t\t\t\toptions = Object.assign(options, v);
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\treturn true;
\t\t\t\t});
\t\t\t},
\t\t\trender = function(disabled){
\t\t\t\tvar name,cmdPref;
\t\t\t\t
\t\t\t\t\$.each(buttons, function(i, b) { b.detach(); });
\t\t\t\tself.empty();
\t\t\t\tl = panels.length;
\t\t\t\twhile (l--) {
\t\t\t\t\tif (panels[l]) {
\t\t\t\t\t\tpanel = \$('<div class=\"ui-widget-content ui-corner-all elfinder-buttonset\"></div>');
\t\t\t\t\t\ti = panels[l].length;
\t\t\t\t\t\twhile (i--) {
\t\t\t\t\t\t\tname = panels[l][i];
\t\t\t\t\t\t\tif ((!disabled || !disabled[name]) && (cmd = commands[name])) {
\t\t\t\t\t\t\t\tbutton = 'elfinder'+cmd.options.ui;
\t\t\t\t\t\t\t\tif (! buttons[name] && \$.fn[button]) {
\t\t\t\t\t\t\t\t\tbuttons[name] = \$('<div></div>')[button](cmd);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (buttons[name]) {
\t\t\t\t\t\t\t\t\tbuttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
\t\t\t\t\t\t\t\t\tpanel.prepend(buttons[name]);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tpanel.children().length && self.prepend(panel);
\t\t\t\t\t\tpanel.children(':gt(0)').before('<span class=\"ui-widget-content elfinder-toolbar-button-separator\"></span>');

\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (cmdPref = commands['preference']) {
\t\t\t\t\t//cmdPref.state = !self.children().length? 0 : -1;
\t\t\t\t\tif (options.showPreferenceButton === 'always' || (!self.children().length && options.showPreferenceButton === 'auto')) {
\t\t\t\t\t\t//cmdPref.state = 0;
\t\t\t\t\t\tpanel = \$('<div class=\"ui-widget-content ui-corner-all elfinder-buttonset\"></div>');
\t\t\t\t\t\tname = 'preference';
\t\t\t\t\t\tbutton = 'elfinder'+cmd.options.ui;
\t\t\t\t\t\tbuttons[name] = \$('<div></div>')[button](cmdPref);
\t\t\t\t\t\tbuttons[name].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
\t\t\t\t\t\tpanel.prepend(buttons[name]);
\t\t\t\t\t\tself.append(panel);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t(! self.data('swipeClose') && self.children().length)? self.show() : self.hide();
\t\t\t\tprevHeight = self[0].clientHeight;
\t\t\t\tfm.trigger('toolbarload').trigger('uiresize');
\t\t\t},
\t\t\tbuttons = {},
\t\t\tpanels   = filter(opts || []),
\t\t\tdispre   = null,
\t\t\tuiCmdMapPrev = '',
\t\t\tprevHeight = 0,
\t\t\tcontextRaw = [],
\t\t\tl, i, cmd, panel, button, swipeHandle, autoHide, textLabel, resizeTm;
\t\t
\t\t// normalize options
\t\toptions.showPreferenceButton = options.showPreferenceButton.toLowerCase();
\t\t
\t\tif (options.displayTextLabel !== 'none') {
\t\t\t// correction of options.displayTextLabel
\t\t\ttextLabel = fm.storage('toolbarTextLabel');
\t\t\tif (textLabel === null) {
\t\t\t\ttextLabel = (options.displayTextLabel && (! options.labelExcludeUA || ! options.labelExcludeUA.length || ! \$.grep(options.labelExcludeUA, function(v){ return fm.UA[v]? true : false; }).length));
\t\t\t} else {
\t\t\t\ttextLabel = (textLabel == 1);
\t\t\t}
\t\t\tcontextRaw.push({
\t\t\t\tlabel    : fm.i18n('textLabel'),
\t\t\t\ticon     : 'text',
\t\t\t\tcallback : function() {
\t\t\t\t\ttextLabel = ! textLabel;
\t\t\t\t\tself.css('height', '').find('.elfinder-button-text')[textLabel? 'show':'hide']();
\t\t\t\t\tfm.trigger('uiresize').storage('toolbarTextLabel', textLabel? '1' : '0');
\t\t\t\t},
\t\t\t});
\t\t}

\t\tif (options.preferenceInContextmenu && commands['preference']) {
\t\t\tcontextRaw.push({
\t\t\t\tlabel    : fm.i18n('toolbarPref'),
\t\t\t\ticon     : 'preference',
\t\t\t\tcallback : function() {
\t\t\t\t\tfm.exec('preference', void(0), {tab: 'toolbar'});
\t\t\t\t}
\t\t\t});
\t\t}

\t\t// add contextmenu
\t\tif (contextRaw.length) {
\t\t\tself.on('contextmenu', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.preventDefault();
\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\traw: contextRaw,
\t\t\t\t\t\tx: e.pageX,
\t\t\t\t\t\ty: e.pageY
\t\t\t\t\t});
\t\t\t\t}).on('touchstart', function(e) {
\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tself.data('tmlongtap') && clearTimeout(self.data('tmlongtap'));
\t\t\t\t\tself.removeData('longtap')
\t\t\t\t\t\t.data('longtap', {x: e.originalEvent.touches[0].pageX, y: e.originalEvent.touches[0].pageY})
\t\t\t\t\t\t.data('tmlongtap', setTimeout(function() {
\t\t\t\t\t\t\tself.removeData('longtapTm')
\t\t\t\t\t\t\t\t.trigger({
\t\t\t\t\t\t\t\t\ttype: 'contextmenu',
\t\t\t\t\t\t\t\t\tpageX: self.data('longtap').x,
\t\t\t\t\t\t\t\t\tpageY: self.data('longtap').y
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.data('longtap', {longtap: true});
\t\t\t\t\t\t}, 500));
\t\t\t\t}).on('touchmove touchend', function(e) {
\t\t\t\t\tif (self.data('tmlongtap')) {
\t\t\t\t\t\tif (e.type === 'touchend' ||
\t\t\t\t\t\t\t\t( Math.abs(self.data('longtap').x - e.originalEvent.touches[0].pageX)
\t\t\t\t\t\t\t\t+ Math.abs(self.data('longtap').y - e.originalEvent.touches[0].pageY)) > 4)
\t\t\t\t\t\tclearTimeout(self.data('tmlongtap'));
\t\t\t\t\t\tself.removeData('longtapTm');
\t\t\t\t\t}
\t\t\t\t}).on('click', function(e) {
\t\t\t\t\tif (self.data('longtap') && self.data('longtap').longtap) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t}
\t\t\t\t}).on('touchend click', '.elfinder-button', function(e) {
\t\t\t\t\tif (self.data('longtap') && self.data('longtap').longtap) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t);
\t\t}

\t\tself.prev().length && self.parent().prepend(this);
\t\t
\t\trender();
\t\t
\t\tfm.bind('open sync select toolbarpref', function() {
\t\t\tvar disabled = Object.assign({}, fm.option('disabledFlip')),
\t\t\t\tuserHides = fm.storage('toolbarhides'),
\t\t\t\tdoRender, sel, disabledKeys;
\t\t\t
\t\t\tif (! userHides && Array.isArray(options.defaultHides)) {
\t\t\t\tuserHides = {};
\t\t\t\t\$.each(options.defaultHides, function() {
\t\t\t\t\tuserHides[this] = true;
\t\t\t\t});
\t\t\t\tfm.storage('toolbarhides', userHides);
\t\t\t}
\t\t\tif (this.type === 'select') {
\t\t\t\tif (fm.searchStatus.state < 2) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tsel = fm.selected();
\t\t\t\tif (sel.length) {
\t\t\t\t\tdisabled = fm.getDisabledCmds(sel, true);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t\$.each(userHides, function(n) {
\t\t\t\tif (!disabled[n]) {
\t\t\t\t\tdisabled[n] = true;
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tif (Object.keys(fm.commandMap).length) {
\t\t\t\t\$.each(fm.commandMap, function(from, to){
\t\t\t\t\tif (to === 'hidden') {
\t\t\t\t\t\tdisabled[from] = true;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t\tdisabledKeys = Object.keys(disabled);
\t\t\tif (!dispre || dispre.toString() !== disabledKeys.sort().toString()) {
\t\t\t\trender(disabledKeys.length? disabled : null);
\t\t\t\tdoRender = true;
\t\t\t}
\t\t\tdispre = disabledKeys.sort();

\t\t\tif (doRender || uiCmdMapPrev !== JSON.stringify(fm.commandMap)) {
\t\t\t\tuiCmdMapPrev = JSON.stringify(fm.commandMap);
\t\t\t\tif (! doRender) {
\t\t\t\t\t// reset toolbar
\t\t\t\t\t\$.each(\$('div.elfinder-button'), function(){
\t\t\t\t\t\tvar origin = \$(this).data('origin');
\t\t\t\t\t\tif (origin) {
\t\t\t\t\t\t\t\$(this).after(origin).detach();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (Object.keys(fm.commandMap).length) {
\t\t\t\t\t\$.each(fm.commandMap, function(from, to){
\t\t\t\t\t\tvar cmd = fm._commands[to],
\t\t\t\t\t\t\tbutton = cmd? 'elfinder'+cmd.options.ui : null,
\t\t\t\t\t\t\tbtn;
\t\t\t\t\t\tif (button && \$.fn[button]) {
\t\t\t\t\t\t\tbtn = buttons[from];
\t\t\t\t\t\t\tif (btn) {
\t\t\t\t\t\t\t\tif (! buttons[to] && \$.fn[button]) {
\t\t\t\t\t\t\t\t\tbuttons[to] = \$('<div></div>')[button](cmd);
\t\t\t\t\t\t\t\t\tif (buttons[to]) {
\t\t\t\t\t\t\t\t\t\tbuttons[to].children('.elfinder-button-text')[textLabel? 'show' : 'hide']();
\t\t\t\t\t\t\t\t\t\tif (cmd.extendsCmd) {
\t\t\t\t\t\t\t\t\t\t\tbuttons[to].children('span.elfinder-button-icon').addClass('elfinder-button-icon-' + cmd.extendsCmd);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (buttons[to]) {
\t\t\t\t\t\t\t\t\tbtn.after(buttons[to]);
\t\t\t\t\t\t\t\t\tbuttons[to].data('origin', btn.detach());
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t}).bind('resize', function(e) {
\t\t\tresizeTm && cancelAnimationFrame(resizeTm);
\t\t\tresizeTm = requestAnimationFrame(function() {
\t\t\t\tvar h = self[0].clientHeight;
\t\t\t\tif (prevHeight !== h) {
\t\t\t\t\tprevHeight = h;
\t\t\t\t\tfm.trigger('uiresize');
\t\t\t\t}
\t\t\t});
\t\t});
\t\t
\t\tif (fm.UA.Touch) {
\t\t\tautoHide = fm.storage('autoHide') || {};
\t\t\tif (typeof autoHide.toolbar === 'undefined') {
\t\t\t\tautoHide.toolbar = (options.autoHideUA && options.autoHideUA.length > 0 && \$.grep(options.autoHideUA, function(v){ return fm.UA[v]? true : false; }).length);
\t\t\t\tfm.storage('autoHide', autoHide);
\t\t\t}
\t\t\t
\t\t\tif (autoHide.toolbar) {
\t\t\t\tfm.one('init', function() {
\t\t\t\t\tfm.uiAutoHide.push(function(){ self.stop(true, true).trigger('toggle', { duration: 500, init: true }); });
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t\tfm.bind('load', function() {
\t\t\t\tswipeHandle = \$('<div class=\"elfinder-toolbar-swipe-handle\"></div>').hide().appendTo(fm.getUI());
\t\t\t\tif (swipeHandle.css('pointer-events') !== 'none') {
\t\t\t\t\tswipeHandle.remove();
\t\t\t\t\tswipeHandle = null;
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tself.on('toggle', function(e, data) {
\t\t\t\tvar wz    = fm.getUI('workzone'),
\t\t\t\t\ttoshow= self.is(':hidden'),
\t\t\t\t\twzh   = wz.height(),
\t\t\t\t\th     = self.height(),
\t\t\t\t\ttbh   = self.outerHeight(true),
\t\t\t\t\tdelta = tbh - h,
\t\t\t\t\topt   = Object.assign({
\t\t\t\t\t\tstep: function(now) {
\t\t\t\t\t\t\twz.height(wzh + (toshow? (now + delta) * -1 : h - now));
\t\t\t\t\t\t\tfm.trigger('resize');
\t\t\t\t\t\t},
\t\t\t\t\t\talways: function() {
\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\tself.css('height', '');
\t\t\t\t\t\t\t\tfm.trigger('uiresize');
\t\t\t\t\t\t\t\tif (swipeHandle) {
\t\t\t\t\t\t\t\t\tif (toshow) {
\t\t\t\t\t\t\t\t\t\tswipeHandle.stop(true, true).hide();
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tswipeHandle.height(data.handleH? data.handleH : '');
\t\t\t\t\t\t\t\t\t\tfm.resources.blink(swipeHandle, 'slowonce');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\ttoshow && self.scrollTop('0px');
\t\t\t\t\t\t\t\tdata.init && fm.trigger('uiautohide');
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}, data);
\t\t\t\tself.data('swipeClose', ! toshow).stop(true, true).animate({height : 'toggle'}, opt);
\t\t\t\tautoHide.toolbar = !toshow;
\t\t\t\tfm.storage('autoHide', Object.assign(fm.storage('autoHide'), {toolbar: autoHide.toolbar}));
\t\t\t}).on('touchstart', function(e) {
\t\t\t\tif (self.scrollBottom() > 5) {
\t\t\t\t\te.originalEvent._preventSwipeY = true;
\t\t\t\t}
\t\t\t});
\t\t}
\t});
\t
\treturn this;
};


/*
 * File: /js/ui/tree.js
 */

/**
 * @class  elFinder folders tree
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfindertree = function(fm, opts) {
\t\tvar treeclass = fm.res('class', 'tree');
\t
\tthis.not('.'+treeclass).each(function() {

\t\tvar c = 'class', mobile = fm.UA.Mobile,
\t\t\t
\t\t\t/**
\t\t\t * Root directory class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\troot      = fm.res(c, 'treeroot'),

\t\t\t/**
\t\t\t * Open root dir if not opened yet
\t\t\t *
\t\t\t * @type Boolean
\t\t\t */
\t\t\topenRoot  = opts.openRootOnLoad,

\t\t\t/**
\t\t\t * Open current work dir if not opened yet
\t\t\t *
\t\t\t * @type Boolean
\t\t\t */
\t\t\topenCwd   = opts.openCwdOnOpen,

\t\t\t
\t\t\t/**
\t\t\t * Auto loading current directory parents and do expand their node
\t\t\t *
\t\t\t * @type Boolean
\t\t\t */
\t\t\tsyncTree  = openCwd || opts.syncTree,
\t\t\t
\t\t\t/**
\t\t\t * Subtree class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tsubtree   = fm.res(c, 'navsubtree'),
\t\t\t
\t\t\t/**
\t\t\t * Directory class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tnavdir    = fm.res(c, 'treedir'),
\t\t\t
\t\t\t/**
\t\t\t * Directory CSS selector
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tselNavdir = 'span.' + navdir,
\t\t\t
\t\t\t/**
\t\t\t * Collapsed arrow class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tcollapsed = fm.res(c, 'navcollapse'),
\t\t\t
\t\t\t/**
\t\t\t * Expanded arrow class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\texpanded  = fm.res(c, 'navexpand'),
\t\t\t
\t\t\t/**
\t\t\t * Class name to mark arrow for directory with already loaded children
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tloaded    = 'elfinder-subtree-loaded',
\t\t\t
\t\t\t/**
\t\t\t * Class name to mark need subdirs request
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tchksubdir = 'elfinder-subtree-chksubdir',
\t\t\t
\t\t\t/**
\t\t\t * Arraw class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tarrow = fm.res(c, 'navarrow'),
\t\t\t
\t\t\t/**
\t\t\t * Current directory class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tactive    = fm.res(c, 'active'),
\t\t\t
\t\t\t/**
\t\t\t * Droppable dirs dropover class
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tdropover = fm.res(c, 'adroppable'),
\t\t\t
\t\t\t/**
\t\t\t * Hover class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\thover    = fm.res(c, 'hover'),
\t\t\t
\t\t\t/**
\t\t\t * Disabled dir class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tdisabled = fm.res(c, 'disabled'),
\t\t\t
\t\t\t/**
\t\t\t * Draggable dir class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tdraggable = fm.res(c, 'draggable'),
\t\t\t
\t\t\t/**
\t\t\t * Droppable dir  class name
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tdroppable = fm.res(c, 'droppable'),
\t\t\t
\t\t\t/**
\t\t\t * root wrapper class
\t\t\t * 
\t\t\t * @type String
\t\t\t */
\t\t\twrapperRoot = 'elfinder-navbar-wrapper-root',

\t\t\t/**
\t\t\t * Un-disabled cmd `paste` volume's root wrapper class
\t\t\t * 
\t\t\t * @type String
\t\t\t */
\t\t\tpastable = 'elfinder-navbar-wrapper-pastable',
\t\t\t
\t\t\t/**
\t\t\t * Un-disabled cmd `upload` volume's root wrapper class
\t\t\t * 
\t\t\t * @type String
\t\t\t */
\t\t\tuploadable = 'elfinder-navbar-wrapper-uploadable',
\t\t\t
\t\t\t/**
\t\t\t * Is position x inside Navbar
\t\t\t * 
\t\t\t * @param x Numbar
\t\t\t * 
\t\t\t * @return
\t\t\t */
\t\t\tinsideNavbar = function(x) {
\t\t\t\tvar left = navbar.offset().left;
\t\t\t\t\t
\t\t\t\treturn left <= x && x <= left + navbar.width();
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * To call subdirs elements queue
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\tsubdirsQue = {},
\t\t\t
\t\t\t/**
\t\t\t * To exec subdirs elements ids
\t\t\t * 
\t\t\t */
\t\t\tsubdirsExecQue = [],
\t\t\t
\t\t\t/**
\t\t\t * Request subdirs to backend
\t\t\t * 
\t\t\t * @param id String
\t\t\t * 
\t\t\t * @return Deferred
\t\t\t */
\t\t\tsubdirs = function(ids) {
\t\t\t\tvar targets = [];
\t\t\t\t\$.each(ids, function(i, id) {
\t\t\t\t\tsubdirsQue[id] && targets.push(fm.navId2Hash(id));
\t\t\t\t\tdelete subdirsQue[id];
\t\t\t\t});
\t\t\t\tif (targets.length) {
\t\t\t\t\treturn fm.request({
\t\t\t\t\t\tdata: {
\t\t\t\t\t\t\tcmd: 'subdirs',
\t\t\t\t\t\t\ttargets: targets,
\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t}
\t\t\t\t\t}).done(function(res) {
\t\t\t\t\t\tif (res && res.subdirs) {
\t\t\t\t\t\t\t\$.each(res.subdirs, function(hash, subdirs) {
\t\t\t\t\t\t\t\tvar elm = fm.navHash2Elm(hash);
\t\t\t\t\t\t\t\telm.removeClass(chksubdir);
\t\t\t\t\t\t\t\telm[subdirs? 'addClass' : 'removeClass'](collapsed);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tsubdirsJobRes = null,
\t\t\t
\t\t\t/**
\t\t\t * To check target element is in window of subdirs
\t\t\t * 
\t\t\t * @return void
\t\t\t */
\t\t\tcheckSubdirs = function() {
\t\t\t\tvar ids = Object.keys(subdirsQue);
\t\t\t\tif (ids.length) {
\t\t\t\t\tsubdirsJobRes && subdirsJobRes._abort();
\t\t\t\t\texecSubdirsTm && clearTimeout(execSubdirsTm);
\t\t\t\t\tsubdirsExecQue = [];
\t\t\t\t\tsubdirsJobRes = fm.asyncJob(function(id) {
\t\t\t\t\t\treturn fm.isInWindow(\$('#'+id))? id : null;
\t\t\t\t\t}, ids, { numPerOnce: 200 })
\t\t\t\t\t.done(function(arr) {
\t\t\t\t\t\tif (arr.length) {
\t\t\t\t\t\t\tsubdirsExecQue = arr;
\t\t\t\t\t\t\texecSubdirs();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tsubdirsPending = 0,
\t\t\texecSubdirsTm,
\t\t\t
\t\t\t/**
\t\t\t * Exec subdirs as batch request
\t\t\t * 
\t\t\t * @return void
\t\t\t */
\t\t\texecSubdirs = function() {
\t\t\t\tvar cnt = opts.subdirsMaxConn - subdirsPending,
\t\t\t\t\tatOnce = fm.maxTargets? Math.min(fm.maxTargets, opts.subdirsAtOnce) : opts.subdirsAtOnce,
\t\t\t\t\ti, ids;
\t\t\t\texecSubdirsTm && cancelAnimationFrame(execSubdirsTm);
\t\t\t\tif (subdirsExecQue.length) {
\t\t\t\t\tif (cnt > 0) {
\t\t\t\t\t\tfor (i = 0; i < cnt; i++) {
\t\t\t\t\t\t\tif (subdirsExecQue.length) {
\t\t\t\t\t\t\t\tsubdirsPending++;
\t\t\t\t\t\t\t\tsubdirs(subdirsExecQue.splice(0, atOnce)).always(function() {
\t\t\t\t\t\t\t\t\tsubdirsPending--;
\t\t\t\t\t\t\t\t\texecSubdirs();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\texecSubdirsTm = requestAnimationFrame(function() {
\t\t\t\t\t\t\tsubdirsExecQue.length && execSubdirs();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\tdrop = fm.droppable.drop,
\t\t\t
\t\t\t/**
\t\t\t * Droppable options
\t\t\t *
\t\t\t * @type Object
\t\t\t */
\t\t\tdroppableopts = \$.extend(true, {}, fm.droppable, {
\t\t\t\t// show subfolders on dropover
\t\t\t\tover : function(e, ui) {
\t\t\t\t\tvar dst    = \$(this),
\t\t\t\t\t\thelper = ui.helper,
\t\t\t\t\t\tcl     = hover+' '+dropover,
\t\t\t\t\t\thash, status;
\t\t\t\t\te.stopPropagation();
\t\t\t\t\thelper.data('dropover', helper.data('dropover') + 1);
\t\t\t\t\tdst.data('dropover', true);
\t\t\t\t\tif (ui.helper.data('namespace') !== fm.namespace || ! fm.insideWorkzone(e.pageX, e.pageY)) {
\t\t\t\t\t\tdst.removeClass(cl);
\t\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tif (! insideNavbar(e.clientX)) {
\t\t\t\t\t\tdst.removeClass(cl);
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\tdst.addClass(hover);
\t\t\t\t\tif (dst.is('.'+collapsed+':not(.'+expanded+')')) {
\t\t\t\t\t\tdst.data('expandTimer', setTimeout(function() {
\t\t\t\t\t\t\tdst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).trigger('click');
\t\t\t\t\t\t}, 500));
\t\t\t\t\t}
\t\t\t\t\tif (dst.is('.elfinder-ro,.elfinder-na')) {
\t\t\t\t\t\tdst.removeClass(dropover);
\t\t\t\t\t\t//helper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\thash = fm.navId2Hash(dst.attr('id'));
\t\t\t\t\tdst.data('dropover', hash);
\t\t\t\t\t\$.each(ui.helper.data('files'), function(i, h) {
\t\t\t\t\t\tif (h === hash || (fm.file(h).phash === hash && !ui.helper.hasClass('elfinder-drag-helper-plus'))) {
\t\t\t\t\t\t\tdst.removeClass(cl);
\t\t\t\t\t\t\treturn false; // break \$.each
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tif (helper.data('locked')) {
\t\t\t\t\t\tstatus = 'elfinder-drag-helper-plus';
\t\t\t\t\t} else {
\t\t\t\t\t\tstatus = 'elfinder-drag-helper-move';
\t\t\t\t\t\tif (e.shiftKey || e.ctrlKey || e.metaKey) {
\t\t\t\t\t\t\tstatus += ' elfinder-drag-helper-plus';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tdst.hasClass(dropover) && helper.addClass(status);
\t\t\t\t\trequestAnimationFrame(function(){ dst.hasClass(dropover) && helper.addClass(status); });
\t\t\t\t},
\t\t\t\tout : function(e, ui) {
\t\t\t\t\tvar dst    = \$(this),
\t\t\t\t\t\thelper = ui.helper;
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tif (insideNavbar(e.clientX)) {
\t\t\t\t\t\thelper.removeClass('elfinder-drag-helper-move elfinder-drag-helper-plus');
\t\t\t\t\t}
\t\t\t\t\thelper.data('dropover', Math.max(helper.data('dropover') - 1, 0));
\t\t\t\t\tdst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
\t\t\t\t\tdst.removeData('dropover')
\t\t\t\t\t   .removeClass(hover+' '+dropover);
\t\t\t\t},
\t\t\t\tdeactivate : function() {
\t\t\t\t\t\$(this).removeData('dropover')
\t\t\t\t\t       .removeClass(hover+' '+dropover);
\t\t\t\t},
\t\t\t\tdrop : function(e, ui) {
\t\t\t\t\tinsideNavbar(e.clientX) && drop.call(this, e, ui);
\t\t\t\t}
\t\t\t}),
\t\t\t
\t\t\tspinner = \$(fm.res('tpl', 'navspinner')),
\t\t\t
\t\t\t/**
\t\t\t * Directory html template
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\ttpl = fm.res('tpl', 'navdir'),
\t\t\t
\t\t\t/**
\t\t\t * Permissions marker html template
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tptpl = fm.res('tpl', 'perms'),
\t\t\t
\t\t\t/**
\t\t\t * Lock marker html template
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tltpl = fm.res('tpl', 'lock'),
\t\t\t
\t\t\t/**
\t\t\t * Symlink marker html template
\t\t\t *
\t\t\t * @type String
\t\t\t */
\t\t\tstpl = fm.res('tpl', 'symlink'),
\t\t\t
\t\t\t/**
\t\t\t * Directory hashes that has more pages
\t\t\t * 
\t\t\t * @type Object
\t\t\t */
\t\t\thasMoreDirs = {},
\t\t\t
\t\t\t/**
\t\t\t * Html template replacement methods
\t\t\t *
\t\t\t * @type Object
\t\t\t */
\t\t\treplace = {
\t\t\t\tid          : function(dir) { return fm.navHash2Id(dir.hash); },
\t\t\t\tname        : function(dir) { return fm.escape(dir.i18 || dir.name); },
\t\t\t\tcssclass    : function(dir) {
\t\t\t\t\tvar cname = (dir.phash && ! dir.isroot ? '' : root)+' '+navdir+' '+fm.perms2class(dir);
\t\t\t\t\tdir.dirs && !dir.link && (cname += ' ' + collapsed) && dir.dirs == -1 && (cname += ' ' + chksubdir);
\t\t\t\t\topts.getClass && (cname += ' ' + opts.getClass(dir));
\t\t\t\t\tdir.csscls && (cname += ' ' + fm.escape(dir.csscls));
\t\t\t\t\treturn cname;
\t\t\t\t},
\t\t\t\ttitle       : function(dir) { return opts.attrTitle? (' title=\"' + fm.escape(fm.path(dir.hash, true) || dir.i18 || dir.name) + '\"') : ''; },
\t\t\t\troot        : function(dir) {
\t\t\t\t\tvar cls = '';
\t\t\t\t\tif (!dir.phash || dir.isroot) {
\t\t\t\t\t\tcls += ' '+wrapperRoot;
\t\t\t\t\t\tif (!dir.disabled || dir.disabled.length < 1) {
\t\t\t\t\t\t\tcls += ' '+pastable+' '+uploadable;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (\$.inArray('paste', dir.disabled) === -1) {
\t\t\t\t\t\t\t\tcls += ' '+pastable;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (\$.inArray('upload', dir.disabled) === -1) {
\t\t\t\t\t\t\t\tcls += ' '+uploadable;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn cls;
\t\t\t\t\t} else {
\t\t\t\t\t\treturn '';
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tpermissions : function(dir) { return !dir.read || !dir.write ? ptpl : ''; },
\t\t\t\tsymlink     : function(dir) { return dir.alias ? stpl : ''; },
\t\t\t\tstyle       : function(dir) { return dir.icon ? fm.getIconStyle(dir) : ''; }
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Return html for given dir
\t\t\t *
\t\t\t * @param  Object  directory
\t\t\t * @return String
\t\t\t */
\t\t\titemhtml = function(dir) {
\t\t\t\treturn tpl.replace(/(?:\\{([a-z]+)\\})/ig, function(m, key) {
\t\t\t\t\tvar res = replace[key] ? replace[key](dir) : (dir[key] || '');
\t\t\t\t\tif (key === 'id' && dir.dirs == -1) {
\t\t\t\t\t\tsubdirsQue[res] = res;
\t\t\t\t\t}
\t\t\t\t\treturn res;
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Return only dirs from files list
\t\t\t *
\t\t\t * @param  Array   files list
\t\t\t * @param  Boolean do check exists
\t\t\t * @return Array
\t\t\t */
\t\t\tfilter = function(files, checkExists) {
\t\t\t\treturn \$.map(files || [], function(f) {
\t\t\t\t\treturn (f.mime === 'directory' && (!checkExists || fm.navHash2Elm(f.hash).length)) ? f : null;
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Find parent subtree for required directory
\t\t\t *
\t\t\t * @param  String  dir hash
\t\t\t * @return jQuery
\t\t\t */
\t\t\tfindSubtree = function(hash) {
\t\t\t\treturn hash ? fm.navHash2Elm(hash).next('.'+subtree) : tree;
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Find directory (wrapper) in required node
\t\t\t * before which we can insert new directory
\t\t\t *
\t\t\t * @param  jQuery  parent directory
\t\t\t * @param  Object  new directory
\t\t\t * @return jQuery
\t\t\t */
\t\t\tfindSibling = function(subtree, dir) {
\t\t\t\tvar node = subtree.children(':first'),
\t\t\t\t\tinfo;

\t\t\t\twhile (node.length) {
\t\t\t\t\tinfo = fm.file(fm.navId2Hash(node.children('[id]').attr('id')));
\t\t\t\t\t
\t\t\t\t\tif ((info = fm.file(fm.navId2Hash(node.children('[id]').attr('id')))) 
\t\t\t\t\t&& compare(dir, info) < 0) {
\t\t\t\t\t\treturn node;
\t\t\t\t\t}
\t\t\t\t\tnode = node.next();
\t\t\t\t}
\t\t\t\treturn subtree.children('button.elfinder-navbar-pager-next');
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Add new dirs in tree
\t\t\t *
\t\t\t * @param  Array  dirs list
\t\t\t * @return void
\t\t\t */
\t\t\tupdateTree = function(dirs) {
\t\t\t\tvar length  = dirs.length,
\t\t\t\t\torphans = [],
\t\t\t\t\ti = length,
\t\t\t\t\ttgts = \$(),
\t\t\t\t\tdone = {},
\t\t\t\t\tcwd = fm.cwd(),
\t\t\t\t\tappend = function(parent, dirs, start, direction) {
\t\t\t\t\t\tvar hashes = {},
\t\t\t\t\t\t\tcurStart = 0,
\t\t\t\t\t\t\tmax = fm.newAPI? Math.min(10000, Math.max(10, opts.subTreeMax)) : 10000,
\t\t\t\t\t\t\tsetHashes = function() {
\t\t\t\t\t\t\t\thashes = {};
\t\t\t\t\t\t\t\t\$.each(dirs, function(i, d) {
\t\t\t\t\t\t\t\t\thashes[d.hash] = i;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tchange = function(mode) {
\t\t\t\t\t\t\t\tif (mode === 'prepare') {
\t\t\t\t\t\t\t\t\t\$.each(dirs, function(i, d) {
\t\t\t\t\t\t\t\t\t\td.node && parent.append(d.node.hide());
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else if (mode === 'done') {
\t\t\t\t\t\t\t\t\t\$.each(dirs, function(i, d) {
\t\t\t\t\t\t\t\t\t\td.node && d.node.detach().show();
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tupdate = function(e, data) {
\t\t\t\t\t\t\t\tvar i, changed;
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (data.select) {
\t\t\t\t\t\t\t\t\trender(getStart(data.select));
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (data.change) {
\t\t\t\t\t\t\t\t\tchange(data.change);
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (data.removed && data.removed.length) {
\t\t\t\t\t\t\t\t\tdirs = \$.grep(dirs, function(d) {
\t\t\t\t\t\t\t\t\t\tif (data.removed.indexOf(d.hash) === -1) {
\t\t\t\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t!changed && (changed = true);
\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (data.added && data.added.length) {
\t\t\t\t\t\t\t\t\tdirs = dirs.concat(\$.grep(data.added, function(d) {
\t\t\t\t\t\t\t\t\t\tif (hashes[d.hash] === void(0)) {
\t\t\t\t\t\t\t\t\t\t\t!changed && (changed = true);
\t\t\t\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (changed) {
\t\t\t\t\t\t\t\t\tdirs.sort(compare);
\t\t\t\t\t\t\t\t\tsetHashes();
\t\t\t\t\t\t\t\t\trender(curStart);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tgetStart = function(target) {
\t\t\t\t\t\t\t\tif (hashes[target] !== void(0)) {
\t\t\t\t\t\t\t\t\treturn Math.floor(hashes[target] / max) * max;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn void(0);
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttarget = fm.navId2Hash(parent.prev('[id]').attr('id')),
\t\t\t\t\t\t\trender = function(start, direction) {
\t\t\t\t\t\t\t\tvar html = [],
\t\t\t\t\t\t\t\t\tnodes = {},
\t\t\t\t\t\t\t\t\ttotal, page, s, parts, prev, next, prevBtn, nextBtn;
\t\t\t\t\t\t\t\tdelete hasMoreDirs[target];
\t\t\t\t\t\t\t\tcurStart = start;
\t\t\t\t\t\t\t\tparent.off('update.'+fm.namespace, update);
\t\t\t\t\t\t\t\tif (dirs.length > max) {
\t\t\t\t\t\t\t\t\tparent.on('update.'+fm.namespace, update);
\t\t\t\t\t\t\t\t\tif (start === void(0)) {
\t\t\t\t\t\t\t\t\t\ts = 0;
\t\t\t\t\t\t\t\t\t\tsetHashes();
\t\t\t\t\t\t\t\t\t\tstart = getStart(cwd.hash);
\t\t\t\t\t\t\t\t\t\tif (start === void(0)) {
\t\t\t\t\t\t\t\t\t\t\tstart = 0;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tparts = dirs.slice(start, start + max);
\t\t\t\t\t\t\t\t\thasMoreDirs[target] = parent;
\t\t\t\t\t\t\t\t\tprev = start? Math.max(-1, start - max) : -1;
\t\t\t\t\t\t\t\t\tnext = (start + max >= dirs.length)? 0 : start + max;
\t\t\t\t\t\t\t\t\ttotal = Math.ceil(dirs.length/max);
\t\t\t\t\t\t\t\t\tpage = Math.ceil(start/max);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\$.each(parts || dirs, function(i, d) {
\t\t\t\t\t\t\t\t\thtml.push(itemhtml(d));
\t\t\t\t\t\t\t\t\tif (d.node) {
\t\t\t\t\t\t\t\t\t\tnodes[d.hash] = d.node;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (prev > -1) {
\t\t\t\t\t\t\t\t\tprevBtn = \$('<button class=\"elfinder-navbar-pager elfinder-navbar-pager-prev\"></button>')
\t\t\t\t\t\t\t\t\t\t.text(fm.i18n('btnPrevious', page, total))
\t\t\t\t\t\t\t\t\t\t.button({
\t\t\t\t\t\t\t\t\t\t\ticons: {
\t\t\t\t\t\t\t\t\t\t\t\tprimary: \"ui-icon-caret-1-n\"
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t.on('click', function(e) {
\t\t\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t\t\trender(prev, 'up');
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tprevBtn = \$();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (next) {
\t\t\t\t\t\t\t\t\tnextBtn = \$('<button class=\"elfinder-navbar-pager elfinder-navbar-pager-next\"></button>')
\t\t\t\t\t\t\t\t\t\t.text(fm.i18n('btnNext', page + 2, total))
\t\t\t\t\t\t\t\t\t\t.button({
\t\t\t\t\t\t\t\t\t\t\ticons: {
\t\t\t\t\t\t\t\t\t\t\t\tprimary: \"ui-icon-caret-1-s\"
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t.on('click', function(e) {
\t\t\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t\t\trender(next, 'down');
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tnextBtn = \$();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdetach();
\t\t\t\t\t\t\t\tparent.empty()[parts? 'addClass' : 'removeClass']('elfinder-navbar-hasmore').append(prevBtn, html.join(''), nextBtn);
\t\t\t\t\t\t\t\t\$.each(nodes, function(h, n) {
\t\t\t\t\t\t\t\t\tfm.navHash2Elm(h).parent().replaceWith(n);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (direction) {
\t\t\t\t\t\t\t\t\tautoScroll(fm.navHash2Id(parts[direction === 'up'? parts.length - 1 : 0].hash));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t! mobile && fm.lazy(function() { updateDroppable(null, parent); });
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tdetach = function() {
\t\t\t\t\t\t\t\t\$.each(parent.children('.elfinder-navbar-wrapper'), function(i, elm) {
\t\t\t\t\t\t\t\t\tvar n = \$(elm),
\t\t\t\t\t\t\t\t\t\tch = n.children('[id]:first'),
\t\t\t\t\t\t\t\t\t\th, c;
\t\t\t\t\t\t\t\t\tif (ch.hasClass(loaded)) {
\t\t\t\t\t\t\t\t\t\th = fm.navId2Hash(ch.attr('id'));
\t\t\t\t\t\t\t\t\t\tif (h && (c = hashes[h]) !== void(0)) {
\t\t\t\t\t\t\t\t\t\t\tdirs[c].node = n.detach();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t};
\t\t\t\t\t\t
\t\t\t\t\t\trender();
\t\t\t\t\t},
\t\t\t\t\tdir, html, parent, sibling, init, atonce = {}, updates = [], base, node,
\t\t\t\t\tlastKey, lastNodes = {};
\t\t\t\t
\t\t\t\twhile (i--) {
\t\t\t\t\tdir = dirs[i];

\t\t\t\t\tif (done[dir.hash] || fm.navHash2Elm(dir.hash).length) {
\t\t\t\t\t\tcontinue;
\t\t\t\t\t}
\t\t\t\t\tdone[dir.hash] = true;
\t\t\t\t\t
\t\t\t\t\tif ((parent = findSubtree(dir.phash)).length) {
\t\t\t\t\t\tlastKey = dir.phash || 'treeroot';
\t\t\t\t\t\tif (typeof lastNodes[lastKey] === 'undefined') {
\t\t\t\t\t\t\tlastNodes[lastKey] = parent.children(':last');
\t\t\t\t\t\t}
\t\t\t\t\t\tinit = !lastNodes[lastKey].length;
\t\t\t\t\t\tif (dir.phash && (init || parent.hasClass('elfinder-navbar-hasmore') || (sibling = findSibling(parent, dir)).length)) {
\t\t\t\t\t\t\tif (init) {
\t\t\t\t\t\t\t\tif (!atonce[dir.phash]) {
\t\t\t\t\t\t\t\t\tatonce[dir.phash] = [];
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tatonce[dir.phash].push(dir);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (sibling) {
\t\t\t\t\t\t\t\t\tnode = itemhtml(dir);
\t\t\t\t\t\t\t\t\tsibling.before(node);
\t\t\t\t\t\t\t\t\t! mobile && (tgts = tgts.add(node));
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tupdates.push(dir);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tnode = itemhtml(dir);
\t\t\t\t\t\t\tif (init) {
\t\t\t\t\t\t\t\tparent.prepend(node);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tlastNodes[lastKey].after(node);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (!dir.phash || dir.isroot) {
\t\t\t\t\t\t\t\tbase = fm.navHash2Elm(dir.hash).parent();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t! mobile && updateDroppable(null, base);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\torphans.push(dir);
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\t// When init, html append at once
\t\t\t\tif (Object.keys(atonce).length){
\t\t\t\t\t\$.each(atonce, function(p, dirs){
\t\t\t\t\t\tvar parent = findSubtree(p),
\t\t\t\t\t\t    html   = [];
\t\t\t\t\t\tdirs.sort(compare);
\t\t\t\t\t\tappend(parent, dirs);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (updates.length) {
\t\t\t\t\tparent.trigger('update.' + fm.namespace, { added : updates });
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (orphans.length && orphans.length < length) {
\t\t\t\t\tupdateTree(orphans);
\t\t\t\t\treturn;
\t\t\t\t} 
\t\t\t\t
\t\t\t\t! mobile && tgts.length && fm.lazy(function() { updateDroppable(tgts); });
\t\t\t\t
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * sort function by dir.name
\t\t\t * 
\t\t\t */
\t\t\tcompare = function(dir1, dir2) {
\t\t\t\tif (! fm.sortAlsoTreeview) {
\t\t\t\t\treturn fm.sortRules.name(dir1, dir2);
\t\t\t\t} else {
\t\t\t\t\tvar asc   = fm.sortOrder == 'asc',
\t\t\t\t\t\ttype  = fm.sortType,
\t\t\t\t\t\trules = fm.sortRules,
\t\t\t\t\t\tres;
\t\t\t\t\t
\t\t\t\t\tres = asc? rules[fm.sortType](dir1, dir2) : rules[fm.sortType](dir2, dir1);
\t\t\t\t\t
\t\t\t\t\treturn type !== 'name' && res === 0
\t\t\t\t\t\t? res = asc ? rules.name(dir1, dir2) : rules.name(dir2, dir1)
\t\t\t\t\t\t: res;
\t\t\t\t}
\t\t\t},

\t\t\t/**
\t\t\t * Timer ID of autoScroll
\t\t\t * 
\t\t\t * @type  Integer
\t\t\t */
\t\t\tautoScrTm,

\t\t\t/**
\t\t\t * Auto scroll to cwd
\t\t\t *
\t\t\t * @return Object  jQuery Deferred
\t\t\t */
\t\t\tautoScroll = function(target) {
\t\t\t\tvar dfrd = \$.Deferred(),
\t\t\t\t\tcurrent, parent, top, treeH, bottom, tgtTop;
\t\t\t\tautoScrTm && clearTimeout(autoScrTm);
\t\t\t\tautoScrTm = setTimeout(function() {
\t\t\t\t\tcurrent = \$(document.getElementById((target || fm.navHash2Id(fm.cwd().hash))));
\t\t\t\t\tif (current.length) {
\t\t\t\t\t\t// expand parents directory
\t\t\t\t\t\t(openCwd? current : current.parent()).parents('.elfinder-navbar-wrapper').children('.'+loaded).addClass(expanded).next('.'+subtree).show();
\t\t\t\t\t\t
\t\t\t\t\t\tparent = tree.parent().stop(false, true);
\t\t\t\t\t\ttop = parent.offset().top;
\t\t\t\t\t\ttreeH = parent.height();
\t\t\t\t\t\tbottom = top + treeH - current.outerHeight();
\t\t\t\t\t\ttgtTop = current.offset().top;
\t\t\t\t\t\t
\t\t\t\t\t\tif (tgtTop < top || tgtTop > bottom) {
\t\t\t\t\t\t\tparent.animate({
\t\t\t\t\t\t\t\tscrollTop : parent.scrollTop() + tgtTop - top - treeH / 3
\t\t\t\t\t\t\t}, {
\t\t\t\t\t\t\t\tduration : opts.durations.autoScroll,
\t\t\t\t\t\t\t\tcomplete : function() {\tdfrd.resolve(); }
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t}
\t\t\t\t}, 100);
\t\t\t\treturn dfrd;
\t\t\t},
\t\t\t/**
\t\t\t * Get hashes array of items of the bottom of the leaf root back from the target
\t\t\t * 
\t\t\t * @param Object elFinder item(directory) object
\t\t\t * @return Array hashes
\t\t\t */
\t\t\tgetEnds = function(d) {
\t\t\t\tvar cur = d || fm.cwd(),
\t\t\t\t\tres = cur.hash? [ cur.hash ] : [],
\t\t\t\t\tphash, root, dir;
\t\t\t\t
\t\t\t\troot = fm.root(cur.hash);
\t\t\t\tdir = fm.file(root);
\t\t\t\twhile (dir && (phash = dir.phash)) {
\t\t\t\t\tres.unshift(phash);
\t\t\t\t\troot = fm.root(phash);
\t\t\t\t\tdir = fm.file(root);
\t\t\t\t\tif (fm.navHash2Elm(dir.hash).hasClass(loaded)) {
\t\t\t\t\t\tbreak;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn res;
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Select pages back in order to display the target
\t\t\t * 
\t\t\t * @param Object elFinder item(directory) object
\t\t\t * @return Object jQuery node object of target node
\t\t\t */
\t\t\tselectPages = function(current) {
\t\t\t\tvar cur = current || fm.cwd(),
\t\t\t\t\tcurHash = cur.hash,
\t\t\t\t\tnode = fm.navHash2Elm(curHash);
\t\t\t
\t\t\t\tif (!node.length) {
\t\t\t\t\twhile(cur && cur.phash) {
\t\t\t\t\t\tif (hasMoreDirs[cur.phash] && !fm.navHash2Elm(cur.hash).length) {
\t\t\t\t\t\t\thasMoreDirs[cur.phash].trigger('update.'+fm.namespace, { select : cur.hash });
\t\t\t\t\t\t}
\t\t\t\t\t\tcur = fm.file(cur.phash);
\t\t\t\t\t}
\t\t\t\t\tnode = fm.navHash2Elm(curHash);
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn node;
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Flag indicating that synchronization is currently in progress
\t\t\t * 
\t\t\t * @type Boolean
\t\t\t */
\t\t\tsyncing,

\t\t\t/**
\t\t\t * Mark current directory as active
\t\t\t * If current directory is not in tree - load it and its parents
\t\t\t *
\t\t\t * @param Array directory objects of cwd
\t\t\t * @param Boolean do auto scroll
\t\t\t * @return Object jQuery Deferred
\t\t\t */
\t\t\tsync = function(cwdDirs, aScr) {
\t\t\t\tvar cwd     = fm.cwd(),
\t\t\t\t\tcwdhash = cwd.hash,
\t\t\t\t\tautoScr = aScr === void(0)? syncTree : aScr,
\t\t\t\t\tloadParents = function(dir) {
\t\t\t\t\t\tvar dfd  = \$.Deferred(),
\t\t\t\t\t\t\treqs = [],
\t\t\t\t\t\t\tends = getEnds(dir),
\t\t\t\t\t\t\tmakeReq = function(cmd, h, until) {
\t\t\t\t\t\t\t\tvar data = {
\t\t\t\t\t\t\t\t\t\tcmd    : cmd,
\t\t\t\t\t\t\t\t\t\ttarget : h
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\tif (until) {
\t\t\t\t\t\t\t\t\tdata.until = until;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\t\tdata : data,
\t\t\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tbaseHash, baseId;
\t\t\t\t\t\t
\t\t\t\t\t\treqs = \$.map(ends, function(h) {
\t\t\t\t\t\t\tvar d = fm.file(h),
\t\t\t\t\t\t\t\tisRoot = d? fm.isRoot(d) : false,
\t\t\t\t\t\t\t\tnode = fm.navHash2Elm(h),
\t\t\t\t\t\t\t\tgetPhash = function(h, dep) {
\t\t\t\t\t\t\t\t\tvar d, ph,
\t\t\t\t\t\t\t\t\t\tdepth = dep || 1;
\t\t\t\t\t\t\t\t\tph = (d = fm.file(h))? d.phash : false;
\t\t\t\t\t\t\t\t\tif (ph && depth > 1) {
\t\t\t\t\t\t\t\t\t\treturn getPhash(ph, --depth);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\treturn ph;
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\tuntil,
\t\t\t\t\t\t\t\tclosest = (function() {
\t\t\t\t\t\t\t\t\tvar phash = getPhash(h);
\t\t\t\t\t\t\t\t\tuntil = phash;
\t\t\t\t\t\t\t\t\twhile (phash) {
\t\t\t\t\t\t\t\t\t\tif (fm.navHash2Elm(phash).hasClass(loaded)) {
\t\t\t\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tuntil = phash;
\t\t\t\t\t\t\t\t\t\tphash = getPhash(phash);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (!phash) {
\t\t\t\t\t\t\t\t\t\tuntil = void(0);
\t\t\t\t\t\t\t\t\t\tphash = fm.root(h);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\treturn phash;
\t\t\t\t\t\t\t\t})(),
\t\t\t\t\t\t\t\tcmd;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (!node.hasClass(loaded) && (isRoot || !d || !fm.navHash2Elm(d.phash).hasClass(loaded))) {
\t\t\t\t\t\t\t\tif (isRoot || closest === getPhash(h) || closest === getPhash(h, 2)) {
\t\t\t\t\t\t\t\t\tuntil = void(0);
\t\t\t\t\t\t\t\t\tcmd = 'tree';
\t\t\t\t\t\t\t\t\tif (!isRoot) {
\t\t\t\t\t\t\t\t\t\th = getPhash(h);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tcmd = 'parents';
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (!baseHash) {
\t\t\t\t\t\t\t\t\tbaseHash = (cmd === 'tree')? h : closest;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn makeReq(cmd, h, until);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\treturn null;
\t\t\t\t\t\t});
\t\t\t\t\t\t
\t\t\t\t\t\tif (reqs.length) {
\t\t\t\t\t\t\tselectPages(fm.file(baseHash));
\t\t\t\t\t\t\tbaseId = fm.navHash2Id(baseHash);
\t\t\t\t\t\t\tautoScr && autoScroll(baseId);
\t\t\t\t\t\t\tbaseNode = \$('#'+baseId);
\t\t\t\t\t\t\tspinner = \$(fm.res('tpl', 'navspinner')).insertBefore(baseNode.children('.'+arrow));
\t\t\t\t\t\t\tbaseNode.removeClass(collapsed);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\$.when.apply(\$, reqs)
\t\t\t\t\t\t\t.done(function() {
\t\t\t\t\t\t\t\tvar res = {},data, treeDirs, dirs, argLen, i;
\t\t\t\t\t\t\t\targLen = arguments.length;
\t\t\t\t\t\t\t\tif (argLen > 0) {
\t\t\t\t\t\t\t\t\tfor (i = 0; i < argLen; i++) {
\t\t\t\t\t\t\t\t\t\tdata = arguments[i].tree || [];
\t\t\t\t\t\t\t\t\t\tres[ends[i]] = Object.assign([], filter(data));
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdfd.resolve(res);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t
\t\t\t\t\t\t\treturn dfd;
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\treturn dfd.resolve();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tdone= function(res, dfrd) {
\t\t\t\t\t\tvar open = function() {
\t\t\t\t\t\t\t\tif (openRoot && baseNode) {
\t\t\t\t\t\t\t\t\tfindSubtree(baseNode.hash).show().prev(selNavdir).addClass(expanded);
\t\t\t\t\t\t\t\t\topenRoot = false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (autoScr) {
\t\t\t\t\t\t\t\t\tautoScroll().done(checkSubdirs);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tcheckSubdirs();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tcurrent;
\t\t\t\t\t\t
\t\t\t\t\t\tif (res) {
\t\t\t\t\t\t\t\$.each(res, function(endHash, dirs) {
\t\t\t\t\t\t\t\tdirs && updateTree(dirs);
\t\t\t\t\t\t\t\tselectPages(fm.file(endHash));
\t\t\t\t\t\t\t\tdirs && updateArrows(dirs, loaded);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (cwdDirs) {
\t\t\t\t\t\t\t(fm.api < 2.1) && cwdDirs.push(cwd);
\t\t\t\t\t\t\tupdateTree(cwdDirs);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// set current node
\t\t\t\t\t\tcurrent = selectPages();
\t\t\t\t\t\t
\t\t\t\t\t\tif (!current.hasClass(active)) {
\t\t\t\t\t\t\ttree.find(selNavdir+'.'+active).removeClass(active);
\t\t\t\t\t\t\tcurrent.addClass(active);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\t// mark as loaded to cwd parents
\t\t\t\t\t\tcurrent.parents('.elfinder-navbar-wrapper').children('.'+navdir).addClass(loaded);
\t\t\t\t\t\t
\t\t\t\t\t\tif (res) {
\t\t\t\t\t\t\tfm.lazy(open).done(function() {
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\topen();
\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\trmSpinner = function(fail) {
\t\t\t\t\t\tif (baseNode) {
\t\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t\t\tbaseNode.addClass(collapsed + (fail? '' : (' ' + loaded)));
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tdfrd = \$.Deferred(),
\t\t\t\t\tbaseNode, spinner;
\t\t\t\t
\t\t\t\tif (!fm.navHash2Elm(cwdhash).length) {
\t\t\t\t\tsyncing = true;
\t\t\t\t\tloadParents()
\t\t\t\t\t.done(function(res) {
\t\t\t\t\t\tdone(res, dfrd);
\t\t\t\t\t\trmSpinner();
\t\t\t\t\t})
\t\t\t\t\t.fail(function() { 
\t\t\t\t\t\trmSpinner(true);
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t})
\t\t\t\t\t.always(function() {
\t\t\t\t\t\tsyncing = false;
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdone(void(0), dfrd);
\t\t\t\t}
\t\t\t\t
\t\t\t\t// trigger 'treesync' with my \$.Deferred
\t\t\t\tfm.trigger('treesync', dfrd);

\t\t\t\treturn dfrd;
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Make writable and not root dirs droppable
\t\t\t *
\t\t\t * @return void
\t\t\t */
\t\t\tupdateDroppable = function(target, node) {
\t\t\t\tvar limit = 100,
\t\t\t\t\tnext;
\t\t\t\t
\t\t\t\tif (!target) {
\t\t\t\t\tif (!node || node.closest('div.'+wrapperRoot).hasClass(uploadable)) {
\t\t\t\t\t\t(node || tree.find('div.'+uploadable)).find(selNavdir+':not(.elfinder-ro,.elfinder-na)').addClass('native-droppable');
\t\t\t\t\t}
\t\t\t\t\tif (!node || node.closest('div.'+wrapperRoot).hasClass(pastable)) {
\t\t\t\t\t\ttarget = (node || tree.find('div.'+pastable)).find(selNavdir+':not(.'+droppable+')');
\t\t\t\t\t} else {
\t\t\t\t\t\ttarget = \$();
\t\t\t\t\t}
\t\t\t\t\tif (node) {
\t\t\t\t\t\t// check leaf roots
\t\t\t\t\t\tnode.children('div.'+wrapperRoot).each(function() {
\t\t\t\t\t\t\tupdateDroppable(null, \$(this));
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// make droppable on async
\t\t\t\tif (target.length) {
\t\t\t\t\tfm.asyncJob(function(elm) {
\t\t\t\t\t\t\$(elm).droppable(droppableopts);
\t\t\t\t\t}, \$.makeArray(target), {
\t\t\t\t\t\tinterval : 20,
\t\t\t\t\t\tnumPerOnce : 100
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\t
\t\t\t/**
\t\t\t * Check required folders for subfolders and update arrow classes
\t\t\t *
\t\t\t * @param  Array  folders to check
\t\t\t * @param  String css class 
\t\t\t * @return void
\t\t\t */
\t\t\tupdateArrows = function(dirs, cls) {
\t\t\t\tvar sel = cls == loaded
\t\t\t\t\t\t? '.'+collapsed+':not(.'+loaded+')'
\t\t\t\t\t\t: ':not(.'+collapsed+')';
\t\t\t\t
\t\t\t\t\$.each(dirs, function(i, dir) {
\t\t\t\t\tfm.navHash2Elm(dir.phash).filter(sel)
\t\t\t\t\t\t.filter(function() { return \$.grep(\$(this).next('.'+subtree).children(), function(n) {
\t\t\t\t\t\t\treturn (\$(n).children().hasClass(root))? false : true;
\t\t\t\t\t\t}).length > 0; })
\t\t\t\t\t\t.addClass(cls);
\t\t\t\t});
\t\t\t},
\t\t\t
\t\t\t
\t\t\t
\t\t\t/**
\t\t\t * Navigation tree
\t\t\t *
\t\t\t * @type JQuery
\t\t\t */
\t\t\ttree = \$(this).addClass(treeclass)
\t\t\t\t// make dirs draggable and toggle hover class
\t\t\t\t.on('mouseenter mouseleave', selNavdir, function(e) {
\t\t\t\t\tvar enter = (e.type === 'mouseenter');
\t\t\t\t\tif (enter && scrolling) { return; }
\t\t\t\t\tvar link  = \$(this),
\t\t\t\t\t\thash, dir; 
\t\t\t\t\t
\t\t\t\t\tif (!link.hasClass(dropover+' '+disabled)) {
\t\t\t\t\t\tif (!mobile && enter && !link.data('dragRegisted') && !link.hasClass(root+' '+draggable+' elfinder-na elfinder-wo')) {
\t\t\t\t\t\t\tlink.data('dragRegisted', true);
\t\t\t\t\t\t\tif (fm.isCommandEnabled('copy', (hash = fm.navId2Hash(link.attr('id'))))) {
\t\t\t\t\t\t\t\tlink.draggable(fm.draggable);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tlink.toggleClass(hover, enter);
\t\t\t\t\t}
\t\t\t\t\t// update title attr if necessary
\t\t\t\t\tif (enter && opts.attrTitle) {
\t\t\t\t\t\tdir = fm.file(hash || fm.navId2Hash(link.attr('id')));
\t\t\t\t\t\tif (!dir.isroot && link.attr('title') === (dir.i18 || dir.name)) {
\t\t\t\t\t\t\tlink.attr('title', fm.path(hash, true));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// native drag enter
\t\t\t\t.on('dragenter', selNavdir, function(e) {
\t\t\t\t\tif (e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar dst = \$(this);
\t\t\t\t\t\tdst.addClass(hover);
\t\t\t\t\t\tif (dst.is('.'+collapsed+':not(.'+expanded+')')) {
\t\t\t\t\t\t\tdst.data('expandTimer', setTimeout(function() {
\t\t\t\t\t\t\t\tdst.is('.'+collapsed+'.'+hover) && dst.children('.'+arrow).trigger('click');
\t\t\t\t\t\t\t}, 500));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// native drag leave
\t\t\t\t.on('dragleave', selNavdir, function(e) {
\t\t\t\t\tif (e.originalEvent.dataTransfer) {
\t\t\t\t\t\tvar dst = \$(this);
\t\t\t\t\t\tdst.data('expandTimer') && clearTimeout(dst.data('expandTimer'));
\t\t\t\t\t\tdst.removeClass(hover);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// open dir or open subfolders in tree
\t\t\t\t.on('click', selNavdir, function(e) {
\t\t\t\t\tvar link = \$(this),
\t\t\t\t\t\thash = fm.navId2Hash(link.attr('id')),
\t\t\t\t\t\tfile = fm.file(hash);
\t\t\t\t\t
\t\t\t\t\tif (link.data('longtap')) {
\t\t\t\t\t\tlink.removeData('longtap');
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (!link.hasClass(active)) {
\t\t\t\t\t\ttree.find(selNavdir+'.'+active).removeClass(active);
\t\t\t\t\t\tlink.addClass(active);
\t\t\t\t\t}
\t\t\t\t\tif (hash != fm.cwd().hash && !link.hasClass(disabled)) {
\t\t\t\t\t\tfm.exec('open', hash).done(function() {
\t\t\t\t\t\t\tfm.one('opendone', function() {
\t\t\t\t\t\t\t\tfm.select({selected: [hash], origin: 'navbar'});
\t\t\t\t\t\t\t});
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tif (link.hasClass(collapsed)) {
\t\t\t\t\t\t\tlink.children('.'+arrow).trigger('click');
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.select({selected: [hash], origin: 'navbar'});
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// for touch device
\t\t\t\t.on('touchstart', selNavdir, function(e) {
\t\t\t\t\tif (e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tvar evt = e.originalEvent,
\t\t\t\t\t\tp;
\t\t\t\t\t
\t\t\t\t\tif (e.target.nodeName === 'INPUT') {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tp = \$(this).addClass(hover)
\t\t\t\t\t.removeData('longtap')
\t\t\t\t\t.data('tmlongtap', setTimeout(function(e){
\t\t\t\t\t\t// long tap
\t\t\t\t\t\tp.data('longtap', true);
\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t'type'    : 'navbar',
\t\t\t\t\t\t\t'targets' : [fm.navId2Hash(p.attr('id'))],
\t\t\t\t\t\t\t'x'       : evt.touches[0].pageX,
\t\t\t\t\t\t\t'y'       : evt.touches[0].pageY
\t\t\t\t\t\t});
\t\t\t\t\t}, 500));
\t\t\t\t})
\t\t\t\t.on('touchmove touchend', selNavdir, function(e) {
\t\t\t\t\tif (e.target.nodeName === 'INPUT') {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tclearTimeout(\$(this).data('tmlongtap'));
\t\t\t\t\t\$(this).removeData('tmlongtap');
\t\t\t\t\tif (e.type == 'touchmove') {
\t\t\t\t\t\t\$(this).removeClass(hover);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t// toggle subfolders in tree
\t\t\t\t.on('click', selNavdir+'.'+collapsed+' .'+arrow, function(e) {
\t\t\t\t\tvar arrow = \$(this),
\t\t\t\t\t\tlink  = arrow.parent(selNavdir),
\t\t\t\t\t\tstree = link.next('.'+subtree),
\t\t\t\t\t\tdfrd  = \$.Deferred(),
\t\t\t\t\t\tslideTH = 30, cnt;

\t\t\t\t\te.stopPropagation();

\t\t\t\t\tif (link.hasClass(loaded)) {
\t\t\t\t\t\tlink.toggleClass(expanded);
\t\t\t\t\t\tfm.lazy(function() {
\t\t\t\t\t\t\tcnt = link.hasClass(expanded)? stree.children().length + stree.find('div.elfinder-navbar-subtree[style*=block]').children().length : stree.find('div:visible').length;
\t\t\t\t\t\t\tif (cnt > slideTH) {
\t\t\t\t\t\t\t\tstree.toggle();
\t\t\t\t\t\t\t\tfm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
\t\t\t\t\t\t\t\tcheckSubdirs();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tstree.stop(true, true)[link.hasClass(expanded)? 'slideDown' : 'slideUp'](opts.durations.slideUpDown, function(){
\t\t\t\t\t\t\t\t\tfm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
\t\t\t\t\t\t\t\t\tcheckSubdirs();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tspinner.insertBefore(arrow);
\t\t\t\t\t\tlink.removeClass(collapsed);

\t\t\t\t\t\tfm.request({cmd : 'tree', target : fm.navId2Hash(link.attr('id'))})
\t\t\t\t\t\t\t.done(function(data) { 
\t\t\t\t\t\t\t\tupdateTree(Object.assign([], filter(data.tree))); 
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (stree.children().length) {
\t\t\t\t\t\t\t\t\tlink.addClass(collapsed+' '+expanded);
\t\t\t\t\t\t\t\t\tif (stree.children().length > slideTH) {
\t\t\t\t\t\t\t\t\t\tstree.show();
\t\t\t\t\t\t\t\t\t\tfm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
\t\t\t\t\t\t\t\t\t\tcheckSubdirs();
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tstree.stop(true, true).slideDown(opts.durations.slideUpDown, function(){
\t\t\t\t\t\t\t\t\t\t\tfm.draggingUiHelper && fm.draggingUiHelper.data('refreshPositions', 1);
\t\t\t\t\t\t\t\t\t\t\tcheckSubdirs();
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} 
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t\t\t\tlink.addClass(loaded);
\t\t\t\t\t\t\t\tfm.one('treedone', function() {
\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tarrow.data('dfrd', dfrd);
\t\t\t\t})
\t\t\t\t.on('contextmenu', selNavdir, function(e) {
\t\t\t\t\tvar self = \$(this);
\t\t\t\t\t
\t\t\t\t\t// now dirname editing
\t\t\t\t\tif (self.find('input:text').length) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\te.preventDefault();

\t\t\t\t\tif (!self.data('tmlongtap')) {
\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t'type'    : 'navbar',
\t\t\t\t\t\t\t'targets' : [fm.navId2Hash(\$(this).attr('id'))],
\t\t\t\t\t\t\t'x'       : e.pageX,
\t\t\t\t\t\t\t'y'       : e.pageY
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tself.addClass('ui-state-hover');
\t\t\t\t\t
\t\t\t\t\tfm.getUI('contextmenu').children().on('mouseenter', function() {
\t\t\t\t\t\tself.addClass('ui-state-hover');
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tfm.bind('closecontextmenu', function() {
\t\t\t\t\t\tself.removeClass('ui-state-hover');
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t.on('scrolltoview', selNavdir, function(e, data) {
\t\t\t\t\tvar self = \$(this);
\t\t\t\t\tautoScroll(self.attr('id')).done(function() {
\t\t\t\t\t\tif (!data || data.blink === 'undefined' || data.blink) {
\t\t\t\t\t\t\tfm.resources.blink(self, 'lookme');
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t})
\t\t\t\t// prepend fake dir
\t\t\t\t.on('create.'+fm.namespace, function(e, item) {
\t\t\t\t\tvar pdir = findSubtree(item.phash),
\t\t\t\t\t\tlock = item.move || false,
\t\t\t\t\t\tdir  = \$(itemhtml(item)).addClass('elfinder-navbar-wrapper-tmp'),
\t\t\t\t\t\tselected = fm.selected();
\t\t\t\t\t\t
\t\t\t\t\tlock && selected.length && fm.trigger('lockfiles', {files: selected});
\t\t\t\t\tpdir.prepend(dir);
\t\t\t\t}),
\t\t\tscrolling = false,
\t\t\tnavbarScrTm,
\t\t\t// move tree into navbar
\t\t\tnavbar = fm.getUI('navbar').append(tree).show().on('scroll', function() {
\t\t\t\tscrolling = true;
\t\t\t\tnavbarScrTm && cancelAnimationFrame(navbarScrTm);
\t\t\t\tnavbarScrTm = requestAnimationFrame(function() {
\t\t\t\t\tscrolling = false;
\t\t\t\t\tcheckSubdirs();
\t\t\t\t});
\t\t\t}),
\t\t\t
\t\t\tprevSortTreeview = fm.sortAlsoTreeview;
\t\t\t
\t\tfm.open(function(e) {
\t\t\tvar data = e.data,
\t\t\t\tdirs = filter(data.files),
\t\t\t\tcontextmenu = fm.getUI('contextmenu');

\t\t\tdata.init && tree.empty();

\t\t\tif (fm.UA.iOS) {
\t\t\t\tnavbar.removeClass('overflow-scrolling-touch').addClass('overflow-scrolling-touch');
\t\t\t}

\t\t\tif (dirs.length) {
\t\t\t\tfm.lazy(function() {
\t\t\t\t\tif (!contextmenu.data('cmdMaps')) {
\t\t\t\t\t\tcontextmenu.data('cmdMaps', {});
\t\t\t\t\t}
\t\t\t\t\tupdateTree(dirs);
\t\t\t\t\tupdateArrows(dirs, loaded);
\t\t\t\t\tsync(dirs);
\t\t\t\t});
\t\t\t} else {
\t\t\t\tsync();
\t\t\t}
\t\t})
\t\t// add new dirs
\t\t.add(function(e) {
\t\t\tvar dirs = filter(e.data.added);

\t\t\tif (dirs.length) {
\t\t\t\tupdateTree(dirs);
\t\t\t\tupdateArrows(dirs, collapsed);
\t\t\t}
\t\t})
\t\t// update changed dirs
\t\t.change(function(e) {
\t\t\t// do ot perfome while syncing
\t\t\tif (syncing) {
\t\t\t\treturn;
\t\t\t}

\t\t\tvar dirs = filter(e.data.changed, true),
\t\t\t\tlength = dirs.length,
\t\t\t\tl    = length,
\t\t\t\ttgts = \$(),
\t\t\t\tchanged = {},
\t\t\t\tdir, phash, node, tmp, realParent, reqParent, realSibling, reqSibling, isExpanded, isLoaded, parent, subdirs;
\t\t\t
\t\t\t\$.each(hasMoreDirs, function(h, node) {
\t\t\t\tnode.trigger('update.'+fm.namespace, { change: 'prepare' });
\t\t\t});
\t\t\t
\t\t\twhile (l--) {
\t\t\t\tdir = dirs[l];
\t\t\t\tphash = dir.phash;
\t\t\t\tif ((node = fm.navHash2Elm(dir.hash)).length) {
\t\t\t\t\tparent = node.parent();
\t\t\t\t\tif (phash) {
\t\t\t\t\t\trealParent  = node.closest('.'+subtree);
\t\t\t\t\t\treqParent   = findSubtree(phash);
\t\t\t\t\t\trealSibling = node.parent().next();
\t\t\t\t\t\treqSibling  = findSibling(reqParent, dir);
\t\t\t\t\t\t
\t\t\t\t\t\tif (!reqParent.length) {
\t\t\t\t\t\t\tcontinue;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (reqParent[0] !== realParent[0] || realSibling.get(0) !== reqSibling.get(0)) {
\t\t\t\t\t\t\treqSibling.length ? reqSibling.before(parent) : reqParent.append(parent);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tisExpanded = node.hasClass(expanded);
\t\t\t\t\tisLoaded   = node.hasClass(loaded);
\t\t\t\t\ttmp        = \$(itemhtml(dir));
\t\t\t\t\tnode.replaceWith(tmp.children(selNavdir));
\t\t\t\t\t! mobile && updateDroppable(null, parent);
\t\t\t\t\t
\t\t\t\t\tif (dir.dirs
\t\t\t\t\t&& (isExpanded || isLoaded) 
\t\t\t\t\t&& (node = fm.navHash2Elm(dir.hash))
\t\t\t\t\t&& node.next('.'+subtree).children().length) {
\t\t\t\t\t\tisExpanded && node.addClass(expanded);
\t\t\t\t\t\tisLoaded && node.addClass(loaded);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tsubdirs |= dir.dirs == -1;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// to check subdirs
\t\t\tif (subdirs) {
\t\t\t\tcheckSubdirs();
\t\t\t}
\t\t\t
\t\t\t\$.each(hasMoreDirs, function(h, node) {
\t\t\t\tnode.trigger('update.'+fm.namespace, { change: 'done' });
\t\t\t});
\t\t\t
\t\t\tlength && sync(void(0), false);
\t\t})
\t\t// remove dirs
\t\t.remove(function(e) {
\t\t\tvar dirs = e.data.removed,
\t\t\t\tl    = dirs.length,
\t\t\t\tnode, stree, removed;
\t\t\t
\t\t\t\$.each(hasMoreDirs, function(h, node) {
\t\t\t\tnode.trigger('update.'+fm.namespace, { removed : dirs });
\t\t\t\tnode.trigger('update.'+fm.namespace, { change: 'prepare' });
\t\t\t});

\t\t\twhile (l--) {
\t\t\t\tif ((node = fm.navHash2Elm(dirs[l])).length) {
\t\t\t\t\tremoved = true;
\t\t\t\t\tstree = node.closest('.'+subtree);
\t\t\t\t\tnode.parent().detach();
\t\t\t\t\tif (!stree.children().length) {
\t\t\t\t\t\tstree.hide().prev(selNavdir).removeClass(collapsed+' '+expanded+' '+loaded);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tremoved && fm.getUI('navbar').children('.ui-resizable-handle').trigger('resize');
\t\t\t
\t\t\t\$.each(hasMoreDirs, function(h, node) {
\t\t\t\tnode.trigger('update.'+fm.namespace, { change: 'done' });
\t\t\t});
\t\t})
\t\t// lock/unlock dirs while moving
\t\t.bind('lockfiles unlockfiles', function(e) {
\t\t\tvar lock = e.type == 'lockfiles',
\t\t\t\thelperLocked = e.data.helper? e.data.helper.data('locked') : false,
\t\t\t\tact  = (lock && !helperLocked) ? 'disable' : 'enable',
\t\t\t\tdirs = \$.grep(e.data.files||[], function(h) {  
\t\t\t\t\tvar dir = fm.file(h);
\t\t\t\t\treturn dir && dir.mime == 'directory' ? true : false;
\t\t\t\t});
\t\t\t\t
\t\t\t\$.each(dirs, function(i, hash) {
\t\t\t\tvar dir = fm.navHash2Elm(hash);
\t\t\t\t
\t\t\t\tif (dir.length && !helperLocked) {
\t\t\t\t\tdir.hasClass(draggable) && dir.draggable(act);
\t\t\t\t\tdir.hasClass(droppable) && dir.droppable(act);
\t\t\t\t\tdir[lock ? 'addClass' : 'removeClass'](disabled);
\t\t\t\t}
\t\t\t});
\t\t})
\t\t.bind('sortchange', function() {
\t\t\tif (fm.sortAlsoTreeview || prevSortTreeview !== fm.sortAlsoTreeview) {
\t\t\t\tvar dirs,
\t\t\t\t\tends = [],
\t\t\t\t\tendsMap = {},
\t\t\t\t\tendsVid = {},
\t\t\t\t\ttopVid = '',
\t\t\t\t\tsingle = false,
\t\t\t\t\tcurrent;
\t\t\t\t
\t\t\t\tfm.lazy(function() {
\t\t\t\t\tdirs = filter(fm.files());
\t\t\t\t\tprevSortTreeview = fm.sortAlsoTreeview;
\t\t\t\t\t
\t\t\t\t\ttree.empty();
\t\t\t\t\t
\t\t\t\t\t// append volume roots at first
\t\t\t\t\tupdateTree(\$.map(fm.roots, function(h) {
\t\t\t\t\t\tvar dir = fm.file(h);
\t\t\t\t\t\treturn dir && !dir.phash? dir : null;
\t\t\t\t\t}));
\t\t\t\t\t
\t\t\t\t\tif (!Object.keys(hasMoreDirs).length) {
\t\t\t\t\t\tupdateTree(dirs);
\t\t\t\t\t\tcurrent = selectPages();
\t\t\t\t\t\tupdateArrows(dirs, loaded);
\t\t\t\t\t} else {
\t\t\t\t\t\tends = getEnds();
\t\t\t\t\t\tif (ends.length > 1) {
\t\t\t\t\t\t\t\$.each(ends, function(i, end) {
\t\t\t\t\t\t\t\tvar vid = fm.file(fm.root(end)).volumeid; 
\t\t\t\t\t\t\t\tif (i === 0) {
\t\t\t\t\t\t\t\t\ttopVid = vid;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tendsVid[vid] = end;
\t\t\t\t\t\t\t\tendsMap[end] = [];
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\$.each(dirs, function(i, d) {
\t\t\t\t\t\t\t\tif (!d.volumeid) {
\t\t\t\t\t\t\t\t\tsingle = true;
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tendsMap[endsVid[d.volumeid] || endsVid[topVid]].push(d);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tsingle = true;
\t\t\t\t\t\t}
\t\t\t\t\t\tif (single) {
\t\t\t\t\t\t\t\$.each(ends, function(i, endHash) {
\t\t\t\t\t\t\t\tupdateTree(dirs);
\t\t\t\t\t\t\t\tcurrent = selectPages(fm.file(endHash));
\t\t\t\t\t\t\t\tupdateArrows(dirs, loaded);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\$.each(endsMap, function(endHash, dirs) {
\t\t\t\t\t\t\t\tupdateTree(dirs);
\t\t\t\t\t\t\t\tcurrent = selectPages(fm.file(endHash));
\t\t\t\t\t\t\t\tupdateArrows(dirs, loaded);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tsync();
\t\t\t\t}, 100);
\t\t\t}
\t\t});

\t});
\t
\treturn this;
};


/*
 * File: /js/ui/uploadButton.js
 */

/**
 * @class  elFinder toolbar's button tor upload file
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderuploadbutton = function(cmd) {
\t\treturn this.each(function() {
\t\tvar fm = cmd.fm,
\t\t\tbutton = \$(this).elfinderbutton(cmd)
\t\t\t\t.off('click'), 
\t\t\tform = \$('<form></form>').appendTo(button),
\t\t\tinput = \$('<input type=\"file\" multiple=\"true\" title=\"'+cmd.fm.i18n('selectForUpload')+'\"/>')
\t\t\t\t.on('change', function() {
\t\t\t\t\tvar _input = \$(this);
\t\t\t\t\tif (_input.val()) {
\t\t\t\t\t\tfm.exec('upload', {input : _input.remove()[0]}, void(0), fm.cwd().hash);
\t\t\t\t\t\tinput.clone(true).appendTo(form);
\t\t\t\t\t} 
\t\t\t\t})
\t\t\t\t.on('dragover', function(e) {
\t\t\t\t\te.originalEvent.dataTransfer.dropEffect = 'copy';
\t\t\t\t}),
\t\t\ttm;

\t\tform.append(input.clone(true));
\t\t\t\t
\t\tcmd.change(function() {
\t\t\ttm && cancelAnimationFrame(tm);
\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\tvar toShow = cmd.disabled();
\t\t\t\tif (form.is('visible')) {
\t\t\t\t\t!toShow && form.hide();
\t\t\t\t} else {
\t\t\t\t\ttoShow && form.show();
\t\t\t\t}
\t\t\t});
\t\t})
\t\t.change();
\t});
};


/*
 * File: /js/ui/viewbutton.js
 */

/**
 * @class  elFinder toolbar button to switch current directory view.
 *
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderviewbutton = function(cmd) {
\t\treturn this.each(function() {
\t\tvar button = \$(this).elfinderbutton(cmd),
\t\t\ticon   = button.children('.elfinder-button-icon'),
\t\t\ttext   = button.children('.elfinder-button-text'),
\t\t\ttm;

\t\tcmd.change(function() {
\t\t\ttm && cancelAnimationFrame(tm);
\t\t\ttm = requestAnimationFrame(function() {
\t\t\t\tvar icons = cmd.value == 'icons';

\t\t\t\ticon.toggleClass('elfinder-button-icon-view-list', icons);
\t\t\t\tcmd.className = icons? 'view-list' : '';
\t\t\t\tcmd.title = cmd.fm.i18n(icons ? 'viewlist' : 'viewicons');
\t\t\t\tbutton.attr('title', cmd.title);
\t\t\t\ttext.html(cmd.title);
\t\t\t});
\t\t});
\t});
};


/*
 * File: /js/ui/workzone.js
 */

/**
 * @class elfinderworkzone - elFinder container for nav and current directory
 * @author Dmitry (dio) Levashov
 **/
\$.fn.elfinderworkzone = function(fm) {
\t\tvar cl = 'elfinder-workzone';
\t
\tthis.not('.'+cl).each(function() {
\t\tvar wz     = \$(this).addClass(cl),
\t\t\tprevH  = Math.round(wz.height()),
\t\t\tparent = wz.parent(),
\t\t\tsetDelta = function() {
\t\t\t\twdelta = wz.outerHeight(true) - wz.height();
\t\t\t},
\t\t\tfitsize = function(e) {
\t\t\t\tvar height = parent.height() - wdelta,
\t\t\t\t\tstyle  = parent.attr('style'),
\t\t\t\t\tcurH   = Math.round(wz.height());
\t
\t\t\t\tif (e) {
\t\t\t\t\te.preventDefault();
\t\t\t\t\te.stopPropagation();
\t\t\t\t}
\t\t\t\t
\t\t\t\tparent.css('overflow', 'hidden')
\t\t\t\t\t.children(':visible:not(.'+cl+')').each(function() {
\t\t\t\t\t\tvar ch = \$(this);
\t\t
\t\t\t\t\t\tif (ch.css('position') != 'absolute' && ch.css('position') != 'fixed') {
\t\t\t\t\t\t\theight -= ch.outerHeight(true);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\tparent.attr('style', style || '');
\t\t\t\t
\t\t\t\theight = Math.max(0, Math.round(height));
\t\t\t\tif (prevH !== height || curH !== height) {
\t\t\t\t\tprevH  = Math.round(wz.height());
\t\t\t\t\twz.height(height);
\t\t\t\t\tfm.trigger('wzresize');
\t\t\t\t}
\t\t\t},
\t\t\tcssloaded = function() {
\t\t\t\twdelta = wz.outerHeight(true) - wz.height();
\t\t\t\tfitsize();
\t\t\t},
\t\t\twdelta;
\t\t
\t\tsetDelta();
\t\tparent.on('resize.' + fm.namespace, fitsize);
\t\tfm.one('cssloaded', cssloaded)
\t\t  .bind('uiresize', fitsize)
\t\t  .bind('themechange', setDelta);
\t});
\treturn this;
};


/*
 * File: /js/commands/archive.js
 */

/**
 * @class  elFinder command \"archive\"
 * Archive selected files
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.archive = function() {
\t\tvar self  = this,
\t\tfm    = self.fm,
\t\tmimes = [],
\t\tdfrd;
\t\t
\tthis.variants = [];
\t
\tthis.disableOnSearch = false;
\t
\tthis.nextAction = {};
\t
\t/**
\t * Update mimes on open/reload
\t *
\t * @return void
\t **/
\tfm.bind('open reload', function() {
\t\tself.variants = [];
\t\t\$.each((mimes = fm.option('archivers')['create'] || []), function(i, mime) {
\t\t\tself.variants.push([mime, fm.mime2kind(mime)]);
\t\t});
\t\tself.change();
\t});
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length,
\t\t\tchk = (cnt && ! fm.isRoot(sel[0]) && (fm.file(sel[0].phash) || {}).write && ! \$.grep(sel, function(f){ return f.read ? false : true; }).length),
\t\t\tcwdId;
\t\t
\t\tif (chk && fm.searchStatus.state > 1) {
\t\t\tcwdId = fm.cwd().volumeid;
\t\t\tchk = (cnt === \$.grep(sel, function(f) { return f.read && f.hash.indexOf(cwdId) === 0 ? true : false; }).length);
\t\t}
\t\t
\t\treturn chk && !this._disabled && mimes.length && (cnt || (dfrd && dfrd.state() == 'pending')) ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes, type) {
\t\tvar files = this.files(hashes),
\t\t\tcnt   = files.length,
\t\t\tmime  = type || mimes[0],
\t\t\tcwd   = fm.file(files[0].phash) || null,
\t\t\terror = ['errArchive', 'errPerm', 'errCreatingTempDir', 'errFtpDownloadFile', 'errFtpUploadFile', 'errFtpMkdir', 'errArchiveExec', 'errExtractExec', 'errRm'],
\t\t\ti, open;

\t\tdfrd = \$.Deferred().fail(function(error) {
\t\t\terror && fm.error(error);
\t\t});

\t\tif (! (cnt && mimes.length && \$.inArray(mime, mimes) !== -1)) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tif (!cwd.write) {
\t\t\treturn dfrd.reject(error);
\t\t}
\t\t
\t\tfor (i = 0; i < cnt; i++) {
\t\t\tif (!files[i].read) {
\t\t\t\treturn dfrd.reject(error);
\t\t\t}
\t\t}

\t\tself.mime   = mime;
\t\tself.prefix = ((cnt > 1)? 'Archive' : files[0].name) + (fm.option('archivers')['createext']? '.' + fm.option('archivers')['createext'][mime] : '');
\t\tself.data   = {targets : self.hashes(hashes), type : mime};
\t\t
\t\tif (fm.cwd().hash !== cwd.hash) {
\t\t\topen = fm.exec('open', cwd.hash).done(function() {
\t\t\t\tfm.one('cwdrender', function() {
\t\t\t\t\tfm.selectfiles({files : hashes});
\t\t\t\t\tdfrd = \$.proxy(fm.res('mixin', 'make'), self)();
\t\t\t\t});
\t\t\t});
\t\t} else {
\t\t\tfm.selectfiles({files : hashes});
\t\t\tdfrd = \$.proxy(fm.res('mixin', 'make'), self)();
\t\t}
\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/back.js
 */

/**
 * @class  elFinder command \"back\"
 * Open last visited folder
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.back = function() {
\t\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts      = [{
\t\tpattern     : 'ctrl+left backspace'
\t}];
\t
\tthis.getstate = function() {
\t\treturn this.fm.history.canBack() ? 0 : -1;
\t};
\t
\tthis.exec = function() {
\t\treturn this.fm.history.back();
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/chmod.js
 */

/**
 * @class elFinder command \"chmod\".
 * Chmod files.
 *
 * @type  elFinder.command
 * @author Naoki Sawada
 */
elFinder.prototype.commands.chmod = function() {
\t\tthis.updateOnSelect = false;
\tvar fm  = this.fm,
\t\tlevel = {
\t\t\t0 : 'owner',
\t\t\t1 : 'group',
\t\t\t2 : 'other'
\t\t},
\t\tmsg = {
\t\t\tread     : fm.i18n('read'),
\t\t\twrite    : fm.i18n('write'),
\t\t\texecute  : fm.i18n('execute'),
\t\t\tperm     : fm.i18n('perm'),
\t\t\tkind     : fm.i18n('kind'),
\t\t\tfiles    : fm.i18n('files')
\t\t},
\t\tisPerm = function(perm){
\t\t\treturn (!isNaN(parseInt(perm, 8) && parseInt(perm, 8) <= 511) || perm.match(/^([r-][w-][x-]){3}\$/i));
\t\t};

\tthis.tpl = {
\t\tmain       : '<div class=\"ui-helper-clearfix elfinder-info-title\"><span class=\"elfinder-cwd-icon {class} ui-corner-all\"></span>{title}</div>'
\t\t\t\t\t+'{dataTable}',
\t\titemTitle  : '<strong>{name}</strong><span id=\"elfinder-info-kind\">{kind}</span>',
\t\tgroupTitle : '<strong>{items}: {num}</strong>',
\t\tdataTable  : '<table id=\"{id}-table-perm\"><tr><td>{0}</td><td>{1}</td><td>{2}</td></tr></table>'
\t\t\t\t\t+'<div class=\"\">'+msg.perm+': <input class=\"elfinder-tabstop elfinder-focus\" id=\"{id}-perm\" type=\"text\" size=\"4\" maxlength=\"3\" value=\"{value}\"></div>',
\t\tfieldset   : '<fieldset id=\"{id}-fieldset-{level}\"><legend>{f_title}{name}</legend>'
\t\t\t\t\t+'<input type=\"checkbox\" value=\"4\" class=\"elfinder-tabstop\" id=\"{id}-read-{level}-perm\"{checked-r}> <label for=\"{id}-read-{level}-perm\">'+msg.read+'</label><br>'
\t\t\t\t\t+'<input type=\"checkbox\" value=\"6\" class=\"elfinder-tabstop\" id=\"{id}-write-{level}-perm\"{checked-w}> <label for=\"{id}-write-{level}-perm\">'+msg.write+'</label><br>'
\t\t\t\t\t+'<input type=\"checkbox\" value=\"5\" class=\"elfinder-tabstop\" id=\"{id}-execute-{level}-perm\"{checked-x}> <label for=\"{id}-execute-{level}-perm\">'+msg.execute+'</label><br>'
\t};

\tthis.shortcuts = [{
\t\t//pattern     : 'ctrl+p'
\t}];

\tthis.getstate = function(sel) {
\t\tvar fm = this.fm;
\t\tsel = sel || fm.selected();
\t\tif (sel.length == 0) {
\t\t\tsel = [ fm.cwd().hash ];
\t\t}
\t\treturn this.checkstate(this.files(sel)) ? 0 : -1;
\t};
\t
\tthis.checkstate = function(sel) {
\t\tvar cnt = sel.length;
\t\tif (!cnt) return false;
\t\tvar chk = \$.grep(sel, function(f) {
\t\t\treturn (f.isowner && f.perm && isPerm(f.perm) && (cnt == 1 || f.mime != 'directory')) ? true : false;
\t\t}).length;
\t\treturn (cnt == chk)? true : false;
\t};

\tthis.exec = function(select) {
\t\tvar hashes  = this.hashes(select),
\t\t\tfiles   = this.files(hashes);
\t\tif (! files.length) {
\t\t\thashes = [ this.fm.cwd().hash ];
\t\t\tfiles   = this.files(hashes);
\t\t}
\t\tvar fm  = this.fm,
\t\tdfrd    = \$.Deferred().always(function() {
\t\t\tfm.enable();
\t\t}),
\t\ttpl     = this.tpl,
\t\tcnt     = files.length,
\t\tfile    = files[0],
\t\tid = fm.namespace + '-perm-' + file.hash,
\t\tview    = tpl.main,
\t\tchecked = ' checked=\"checked\"',
\t\tbuttons = function() {
\t\t\tvar buttons = {};
\t\t\tbuttons[fm.i18n('btnApply')] = save;
\t\t\tbuttons[fm.i18n('btnCancel')] = function() { dialog.elfinderdialog('close'); };
\t\t\treturn buttons;
\t\t},
\t\tsave = function() {
\t\t\tvar perm = \$.trim(\$('#'+id+'-perm').val()),
\t\t\t\treqData;
\t\t\t
\t\t\tif (!isPerm(perm)) return false;
\t\t\t
\t\t\tdialog.elfinderdialog('close');
\t\t\t
\t\t\treqData = {
\t\t\t\tcmd     : 'chmod',
\t\t\t\ttargets : hashes,
\t\t\t\tmode    : perm
\t\t\t};
\t\t\tfm.request({
\t\t\t\tdata : reqData,
\t\t\t\tnotify : {type : 'chmod', cnt : cnt}
\t\t\t})
\t\t\t.fail(function(error) {
\t\t\t\tdfrd.reject(error);
\t\t\t})
\t\t\t.done(function(data) {
\t\t\t\tif (data.changed && data.changed.length) {
\t\t\t\t\tdata.undo = {
\t\t\t\t\t\tcmd : 'chmod',
\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\tvar reqs = [];
\t\t\t\t\t\t\t\$.each(prevVals, function(perm, hashes) {
\t\t\t\t\t\t\t\treqs.push(fm.request({
\t\t\t\t\t\t\t\t\tdata : {cmd : 'chmod', targets : hashes, mode : perm},
\t\t\t\t\t\t\t\t\tnotify : {type : 'undo', cnt : hashes.length}
\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\treturn \$.when.apply(null, reqs);
\t\t\t\t\t\t}
\t\t\t\t\t};
\t\t\t\t\tdata.redo = {
\t\t\t\t\t\tcmd : 'chmod',
\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\tdata : reqData,
\t\t\t\t\t\t\t\tnotify : {type : 'redo', cnt : hashes.length}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t};
\t\t\t\t}
\t\t\t\tdfrd.resolve(data);
\t\t\t});
\t\t},
\t\tsetperm = function() {
\t\t\tvar perm = '';
\t\t\tvar _perm;
\t\t\tfor (var i = 0; i < 3; i++){
\t\t\t\t_perm = 0;
\t\t\t\tif (\$(\"#\"+id+\"-read-\"+level[i]+'-perm').is(':checked')) {
\t\t\t\t\t_perm = (_perm | 4);
\t\t\t\t}
\t\t\t\tif (\$(\"#\"+id+\"-write-\"+level[i]+'-perm').is(':checked')) {
\t\t\t\t\t_perm = (_perm | 2);
\t\t\t\t}
\t\t\t\tif (\$(\"#\"+id+\"-execute-\"+level[i]+'-perm').is(':checked')) {
\t\t\t\t\t_perm = (_perm | 1);
\t\t\t\t}
\t\t\t\tperm += _perm.toString(8);
\t\t\t}
\t\t\t\$('#'+id+'-perm').val(perm);
\t\t},
\t\tsetcheck = function(perm) {
\t\t\tvar _perm;
\t\t\tfor (var i = 0; i < 3; i++){
\t\t\t\t_perm = parseInt(perm.slice(i, i+1), 8);
\t\t\t\t\$(\"#\"+id+\"-read-\"+level[i]+'-perm').prop(\"checked\", false);
\t\t\t\t\$(\"#\"+id+\"-write-\"+level[i]+'-perm').prop(\"checked\", false);
\t\t\t\t\$(\"#\"+id+\"-execute-\"+level[i]+'-perm').prop(\"checked\", false);
\t\t\t\tif ((_perm & 4) == 4) {
\t\t\t\t\t\$(\"#\"+id+\"-read-\"+level[i]+'-perm').prop(\"checked\", true);
\t\t\t\t}
\t\t\t\tif ((_perm & 2) == 2) {
\t\t\t\t\t\$(\"#\"+id+\"-write-\"+level[i]+'-perm').prop(\"checked\", true);
\t\t\t\t}
\t\t\t\tif ((_perm & 1) == 1) {
\t\t\t\t\t\$(\"#\"+id+\"-execute-\"+level[i]+'-perm').prop(\"checked\", true);
\t\t\t\t}
\t\t\t}
\t\t\tsetperm();
\t\t},
\t\tmakeperm = function(files) {
\t\t\tvar perm = '777', ret = '', chk, _chk, _perm;
\t\t\tvar len = files.length;
\t\t\tfor (var i2 = 0; i2 < len; i2++) {
\t\t\t\tchk = getPerm(files[i2].perm);
\t\t\t\tif (! prevVals[chk]) {
\t\t\t\t\tprevVals[chk] = [];
\t\t\t\t}
\t\t\t\tprevVals[chk].push(files[i2].hash);
\t\t\t\tret = '';
\t\t\t\tfor (var i = 0; i < 3; i++){
\t\t\t\t\t_chk = parseInt(chk.slice(i, i+1), 8);
\t\t\t\t\t_perm = parseInt(perm.slice(i, i+1), 8);
\t\t\t\t\tif ((_chk & 4) != 4 && (_perm & 4) == 4) {
\t\t\t\t\t\t_perm -= 4;
\t\t\t\t\t}
\t\t\t\t\tif ((_chk & 2) != 2 && (_perm & 2) == 2) {
\t\t\t\t\t\t_perm -= 2;
\t\t\t\t\t}
\t\t\t\t\tif ((_chk & 1) != 1 && (_perm & 1) == 1) {
\t\t\t\t\t\t_perm -= 1;
\t\t\t\t\t}
\t\t\t\t\tret += _perm.toString(8);
\t\t\t\t}
\t\t\t\tperm = ret;
\t\t\t}
\t\t\treturn perm;
\t\t},
\t\tmakeName = function(name) {
\t\t\treturn name? ':'+name : '';
\t\t},
\t\tmakeDataTable = function(perm, f) {
\t\t\tvar _perm, fieldset;
\t\t\tvar value = '';
\t\t\tvar dataTable = tpl.dataTable;
\t\t\tfor (var i = 0; i < 3; i++){
\t\t\t\t_perm = parseInt(perm.slice(i, i+1), 8);
\t\t\t\tvalue += _perm.toString(8);
\t\t\t\tfieldset = tpl.fieldset.replace('{f_title}', fm.i18n(level[i])).replace('{name}', makeName(f[level[i]])).replace(/\\{level\\}/g, level[i]);
\t\t\t\tdataTable = dataTable.replace('{'+i+'}', fieldset)
\t\t\t\t                     .replace('{checked-r}', ((_perm & 4) == 4)? checked : '')
\t\t\t\t                     .replace('{checked-w}', ((_perm & 2) == 2)? checked : '')
\t\t\t\t                     .replace('{checked-x}', ((_perm & 1) == 1)? checked : '');
\t\t\t}
\t\t\tdataTable = dataTable.replace('{value}', value).replace('{valueCaption}', msg['perm']);
\t\t\treturn dataTable;
\t\t},
\t\tgetPerm = function(perm){
\t\t\tif (isNaN(parseInt(perm, 8))) {
\t\t\t\tvar mode_array = perm.split('');
\t\t\t\tvar a = [];

\t\t\t\tfor (var i = 0, l = mode_array.length; i < l; i++) {
\t\t\t\t\tif (i === 0 || i === 3 || i === 6) {
\t\t\t\t\t\tif (mode_array[i].match(/[r]/i)) {
\t\t\t\t\t\t\ta.push(1);
\t\t\t\t\t\t} else if (mode_array[i].match(/[-]/)) {
\t\t\t\t\t\t\ta.push(0);
\t\t\t\t\t\t}
\t\t\t\t\t} else if ( i === 1 || i === 4 || i === 7) {
\t\t\t\t\t\t if (mode_array[i].match(/[w]/i)) {
\t\t\t\t\t\t\ta.push(1);
\t\t\t\t\t\t} else if (mode_array[i].match(/[-]/)) {
\t\t\t\t\t\t\ta.push(0);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tif (mode_array[i].match(/[x]/i)) {
\t\t\t\t\t\t\ta.push(1);
\t\t\t\t\t\t} else if (mode_array[i].match(/[-]/)) {
\t\t\t\t\t\t\ta.push(0);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t
\t\t\t\ta.splice(3, 0, \",\");
\t\t\t\ta.splice(7, 0, \",\");

\t\t\t\tvar b = a.join(\"\");
\t\t\t\tvar b_array = b.split(\",\");
\t\t\t\tvar c = [];
\t\t\t
\t\t\t\tfor (var j = 0, m = b_array.length; j < m; j++) {
\t\t\t\t\tvar p = parseInt(b_array[j], 2).toString(8);
\t\t\t\t\tc.push(p);
\t\t\t\t}

\t\t\t\tperm = c.join('');
\t\t\t} else {
\t\t\t\tperm = parseInt(perm, 8).toString(8);
\t\t\t}
\t\t\treturn perm;
\t\t},
\t\topts    = {
\t\t\ttitle : this.title,
\t\t\twidth : 'auto',
\t\t\tbuttons : buttons(),
\t\t\tclose : function() { \$(this).elfinderdialog('destroy'); }
\t\t},
\t\tdialog = fm.getUI().find('#'+id),
\t\tprevVals = {},
\t\ttmb = '', title, dataTable;

\t\tif (dialog.length) {
\t\t\tdialog.elfinderdialog('toTop');
\t\t\treturn \$.Deferred().resolve();
\t\t}

\t\tview  = view.replace('{class}', cnt > 1 ? 'elfinder-cwd-icon-group' : fm.mime2class(file.mime));
\t\tif (cnt > 1) {
\t\t\ttitle = tpl.groupTitle.replace('{items}', fm.i18n('items')).replace('{num}', cnt);
\t\t} else {
\t\t\ttitle = tpl.itemTitle.replace('{name}', file.name).replace('{kind}', fm.mime2kind(file));
\t\t\ttmb = fm.tmb(file);
\t\t}

\t\tdataTable = makeDataTable(makeperm(files), files.length == 1? files[0] : {});

\t\tview = view.replace('{title}', title).replace('{dataTable}', dataTable).replace(/{id}/g, id);

\t\tdialog = this.fmDialog(view, opts);
\t\tdialog.attr('id', id);

\t\t// load thumbnail
\t\tif (tmb) {
\t\t\t\$('<img/>')
\t\t\t\t.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\"); })
\t\t\t\t.attr('src', tmb.url);
\t\t}

\t\t\$('#' + id + '-table-perm :checkbox').on('click', function(){setperm('perm');});
\t\t\$('#' + id + '-perm').on('keydown', function(e) {
\t\t\tvar c = e.keyCode;
\t\t\tif (c == \$.ui.keyCode.ENTER) {
\t\t\t\te.stopPropagation();
\t\t\t\tsave();
\t\t\t\treturn;
\t\t\t}
\t\t}).on('focus', function(e){
\t\t\t\$(this).trigger('select');
\t\t}).on('keyup', function(e) {
\t\t\tif (\$(this).val().length == 3) {
\t\t\t\t\$(this).trigger('select');
\t\t\t\tsetcheck(\$(this).val());
\t\t\t}
\t\t});
\t\t
\t\treturn dfrd;
\t};
};


/*
 * File: /js/commands/colwidth.js
 */

/**
 * @class  elFinder command \"colwidth\"
 * CWD list table columns width to auto
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.colwidth = function() {
\t\tthis.alwaysEnabled = true;
\tthis.updateOnSelect = false;
\t
\tthis.getstate = function() {
\t\treturn this.fm.getUI('cwd').find('table').css('table-layout') === 'fixed' ? 0 : -1;
\t};
\t
\tthis.exec = function() {
\t\tthis.fm.getUI('cwd').trigger('colwidth');
\t\treturn \$.Deferred().resolve();
\t};
\t
};

/*
 * File: /js/commands/copy.js
 */

/**
 * @class elFinder command \"copy\".
 * Put files in filemanager clipboard.
 *
 * @type  elFinder.command
 * @author  Dmitry (dio) Levashov
 */
elFinder.prototype.commands.copy = function() {
\t\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+c ctrl+insert'
\t}];
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;

\t\treturn cnt && \$.grep(sel, function(f) { return f.read ? true : false; }).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar fm   = this.fm,
\t\t\tdfrd = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\tfm.error(error);
\t\t\t\t});

\t\t\$.each(this.files(hashes), function(i, file) {
\t\t\tif (! file.read) {
\t\t\t\treturn !dfrd.reject(['errCopy', file.name, 'errPerm']);
\t\t\t}
\t\t});
\t\t
\t\treturn dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(fm.clipboard(this.hashes(hashes)));
\t};

};


/*
 * File: /js/commands/cut.js
 */

/**
 * @class elFinder command \"copy\".
 * Put files in filemanager clipboard.
 *
 * @type  elFinder.command
 * @author  Dmitry (dio) Levashov
 */
elFinder.prototype.commands.cut = function() {
\t\tvar fm = this.fm;
\t
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+x shift+insert'
\t}];
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;
\t\t
\t\treturn cnt && \$.grep(sel, function(f) { return f.read && ! f.locked && ! fm.isRoot(f) ? true : false; }).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar dfrd = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\tfm.error(error);
\t\t\t\t});

\t\t\$.each(this.files(hashes), function(i, file) {
\t\t\tif (!(file.read && ! file.locked && ! fm.isRoot(file)) ) {
\t\t\t\treturn !dfrd.reject(['errCopy', file.name, 'errPerm']);
\t\t\t}
\t\t\tif (file.locked) {
\t\t\t\treturn !dfrd.reject(['errLocked', file.name]);
\t\t\t}
\t\t});
\t\t
\t\treturn dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(fm.clipboard(this.hashes(hashes), true));
\t};

};


/*
 * File: /js/commands/download.js
 */

/**
 * @class elFinder command \"download\". 
 * Download selected files.
 * Only for new api
 *
 * @author Dmitry (dio) Levashov, dio@std42.ru
 **/
elFinder.prototype.commands.zipdl = function() {};
elFinder.prototype.commands.download = function() {
\t\tvar self   = this,
\t\tfm     = this.fm,
\t\tczipdl = null,
\t\tzipOn  = false,
\t\tmixed  = false,
\t\tdlntf  = false,
\t\tcpath  = window.location.pathname || '/',
\t\tfilter = function(hashes, inExec) {
\t\t\tvar volumeid, mixedCmd;
\t\t\t
\t\t\tif (czipdl !== null) {
\t\t\t\tif (fm.searchStatus.state > 1) {
\t\t\t\t\tmixed = fm.searchStatus.mixed;
\t\t\t\t} else if (fm.leafRoots[fm.cwd().hash]) {
\t\t\t\t\tvolumeid = fm.cwd().volumeid;
\t\t\t\t\t\$.each(hashes, function(i, h) {
\t\t\t\t\t\tif (h.indexOf(volumeid) !== 0) {
\t\t\t\t\t\t\tmixed = true;
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tzipOn = (fm.isCommandEnabled('zipdl', hashes[0]));
\t\t\t}

\t\t\tif (mixed) {
\t\t\t\tmixedCmd = czipdl? 'zipdl' : 'download';
\t\t\t\thashes = \$.grep(hashes, function(h) {
\t\t\t\t\tvar f = fm.file(h),
\t\t\t\t\t\tres = (! f || (! czipdl && f.mime === 'directory') || ! fm.isCommandEnabled(mixedCmd, h))? false : true;
\t\t\t\t\tif (f && inExec && ! res) {
\t\t\t\t\t\tfm.cwdHash2Elm(f.hash).trigger('unselect');
\t\t\t\t\t}
\t\t\t\t\treturn res;
\t\t\t\t});
\t\t\t\tif (! hashes.length) {
\t\t\t\t\treturn [];
\t\t\t\t}
\t\t\t} else {
\t\t\t\tif (!fm.isCommandEnabled('download', hashes[0])) {
\t\t\t\t\treturn [];
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\treturn \$.grep(self.files(hashes), function(f) { 
\t\t\t\tvar res = (! f.read || (! zipOn && f.mime == 'directory')) ? false : true;
\t\t\t\tif (inExec && ! res) {
\t\t\t\t\tfm.cwdHash2Elm(f.hash).trigger('unselect');
\t\t\t\t}
\t\t\t\treturn res;
\t\t\t});
\t\t};
\t
\tthis.linkedCmds = ['zipdl'];
\t
\tthis.shortcuts = [{
\t\tpattern     : 'shift+enter'
\t}];
\t
\tthis.getstate = function(select) {
\t\tvar sel    = this.hashes(select),
\t\t\tcnt    = sel.length,
\t\t\tmaxReq = this.options.maxRequests || 10,
\t\t\tmixed  = false,
\t\t\tcroot  = '';
\t\t
\t\tif (cnt < 1) {
\t\t\treturn -1;
\t\t}
\t\tcnt = filter(sel).length;
\t\t
\t\treturn  (cnt && (zipOn || (cnt <= maxReq && ((!fm.UA.IE && !fm.UA.Mobile) || cnt == 1))) ? 0 : -1);
\t};
\t
\tfm.bind('contextmenu', function(e){
\t\tvar fm = self.fm,
\t\t\thelper = null,
\t\t\ttargets, file, link,
\t\t\tgetExtra = function(file) {
\t\t\t\tvar link = file.url || fm.url(file.hash);
\t\t\t\treturn {
\t\t\t\t\ticon: 'link',
\t\t\t\t\tnode: \$('<a></a>')
\t\t\t\t\t\t.attr({href: link, target: '_blank', title: fm.i18n('link')})
\t\t\t\t\t\t.text(file.name)
\t\t\t\t\t\t.on('mousedown click touchstart touchmove touchend contextmenu', function(e){
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('dragstart', function(e) {
\t\t\t\t\t\t\tvar dt = e.dataTransfer || e.originalEvent.dataTransfer || null;
\t\t\t\t\t\t\thelper = null;
\t\t\t\t\t\t\tif (dt) {
\t\t\t\t\t\t\t\tvar icon  = function(f) {
\t\t\t\t\t\t\t\t\t\tvar mime = f.mime, i, tmb = fm.tmb(f);
\t\t\t\t\t\t\t\t\t\ti = '<div class=\"elfinder-cwd-icon '+fm.mime2class(mime)+' ui-corner-all\"></div>';
\t\t\t\t\t\t\t\t\t\tif (tmb) {
\t\t\t\t\t\t\t\t\t\t\ti = \$(i).addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\").get(0).outerHTML;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\treturn i;
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\tdt.effectAllowed = 'copyLink';
\t\t\t\t\t\t\t\tif (dt.setDragImage) {
\t\t\t\t\t\t\t\t\thelper = \$('<div class=\"elfinder-drag-helper html5-native\">').append(icon(file)).appendTo(\$(document.body));
\t\t\t\t\t\t\t\t\tdt.setDragImage(helper.get(0), 50, 47);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (!fm.UA.IE) {
\t\t\t\t\t\t\t\t\tdt.setData('elfinderfrom', window.location.href + file.phash);
\t\t\t\t\t\t\t\t\tdt.setData('elfinderfrom:' + dt.getData('elfinderfrom'), '');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('dragend', function(e) {
\t\t\t\t\t\t\thelper && helper.remove();
\t\t\t\t\t\t})
\t\t\t\t};
\t\t\t};
\t\tself.extra = null;
\t\tif (e.data) {
\t\t\ttargets = e.data.targets || [];
\t\t\tif (targets.length === 1 && (file = fm.file(targets[0])) && file.mime !== 'directory') {
\t\t\t\tif (file.url != '1') {
\t\t\t\t\tself.extra = getExtra(file);
\t\t\t\t} else {
\t\t\t\t\t// Get URL ondemand
\t\t\t\t\tvar node;
\t\t\t\t\tself.extra = {
\t\t\t\t\t\ticon: 'link',
\t\t\t\t\t\tnode: \$('<a></a>')
\t\t\t\t\t\t\t.attr({href: '#', title: fm.i18n('getLink'), draggable: 'false'})
\t\t\t\t\t\t\t.text(file.name)
\t\t\t\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tvar parent = node.parent();
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\tparent.removeClass('ui-state-disabled').addClass('elfinder-button-icon-spinner');
\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\t\tparent.removeClass('elfinder-button-icon-spinner');
\t\t\t\t\t\t\t\t\tif (data.url) {
\t\t\t\t\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\t\t\t\t\trfile.url = data.url;
\t\t\t\t\t\t\t\t\t\tnode.replaceWith(getExtra(file).node);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tparent.addClass('ui-state-disabled');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});

\t\t\t\t\t\t\t})
\t\t\t\t\t};
\t\t\t\t\tnode = self.extra.node;
\t\t\t\t\tnode.ready(function(){
\t\t\t\t\t\trequestAnimationFrame(function(){
\t\t\t\t\t\t\tnode.parent().addClass('ui-state-disabled').css('pointer-events', 'auto');
\t\t\t\t\t\t});
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t}
\t}).one('open', function() {
\t\tif (fm.api >= 2.1012) {
\t\t\tczipdl = fm.getCommand('zipdl');
\t\t}
\t\tdlntf = fm.cookieEnabled && fm.api > 2.1038 && !fm.isCORS;
\t});
\t
\tthis.exec = function(select) {
\t\tvar hashes  = this.hashes(select),
\t\t\tfm      = this.fm,
\t\t\tbase    = fm.options.url,
\t\t\tfiles   = filter(hashes, true),
\t\t\tdfrd    = \$.Deferred(),
\t\t\tiframes = '',
\t\t\tcdata   = '',
\t\t\ttargets = {},
\t\t\ti, url,
\t\t\tlinkdl  = false,
\t\t\tgetTask = function(hashes) {
\t\t\t\treturn function() {
\t\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\t\troot = fm.file(fm.root(hashes[0])),
\t\t\t\t\t\tsingle = (hashes.length === 1),
\t\t\t\t\t\tvolName = root? (root.i18 || root.name) : null,
\t\t\t\t\t\tdir, dlName, phash;
\t\t\t\t\tif (single) {
\t\t\t\t\t\tif (dir = fm.file(hashes[0])) {
\t\t\t\t\t\t\tdlName = (dir.i18 || dir.name);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\t\$.each(hashes, function() {
\t\t\t\t\t\t\tvar d = fm.file(this);
\t\t\t\t\t\t\tif (d && (!phash || phash === d.phash)) {
\t\t\t\t\t\t\t\tphash = d.phash;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tphash = null;
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tif (phash && (dir = fm.file(phash))) {
\t\t\t\t\t\t\tdlName = (dir.i18 || dir.name) + '-' + hashes.length;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (dlName) {
\t\t\t\t\t\tvolName = dlName;
\t\t\t\t\t}
\t\t\t\t\tvolName && (volName = ' (' + volName + ')');
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata : {cmd : 'zipdl', targets : hashes},
\t\t\t\t\t\tnotify : {type : 'zipdl', cnt : 1, hideCnt : true, msg : fm.i18n('ntfzipdl') + volName},
\t\t\t\t\t\tcancel : true,
\t\t\t\t\t\teachCancel : true,
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t}).done(function(e) {
\t\t\t\t\t\tvar zipdl, dialog, btn = {}, dllink, form, iframe, m,
\t\t\t\t\t\t\tuniq = 'dlw' + (+new Date()),
\t\t\t\t\t\t\tzipdlFn = function(url) {
\t\t\t\t\t\t\t\tdllink = \$('<a></a>')
\t\t\t\t\t\t\t\t\t.attr('href', url)
\t\t\t\t\t\t\t\t\t.attr('download', fm.escape(dlName))
\t\t\t\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t\t\t\t\tdialog && dialog.elfinderdialog('destroy');
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (linkdl) {
\t\t\t\t\t\t\t\t\tdllink.attr('target', '_blank')
\t\t\t\t\t\t\t\t\t\t.append('<span class=\"elfinder-button-icon elfinder-button-icon-download\"></span>'+fm.escape(dlName));
\t\t\t\t\t\t\t\t\tbtn[fm.i18n('btnCancel')] = function() {
\t\t\t\t\t\t\t\t\t\tdialog.elfinderdialog('destroy');
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\tdialog = self.fmDialog(dllink, {
\t\t\t\t\t\t\t\t\t\ttitle: fm.i18n('link'),
\t\t\t\t\t\t\t\t\t\tbuttons: btn,
\t\t\t\t\t\t\t\t\t\twidth: '200px',
\t\t\t\t\t\t\t\t\t\tdestroyOnClose: true,
\t\t\t\t\t\t\t\t\t\tclose: function() {
\t\t\t\t\t\t\t\t\t\t\t(dfd.state() !== 'resolved') && dfd.resolve();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tclick(dllink.hide().appendTo('body').get(0));
\t\t\t\t\t\t\t\t\tdllink.remove();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\tif (e.error) {
\t\t\t\t\t\t\tfm.error(e.error);
\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t} else if (e.zipdl) {
\t\t\t\t\t\t\tzipdl = e.zipdl;
\t\t\t\t\t\t\tif (dlName) {
\t\t\t\t\t\t\t\tm = fm.splitFileExtention(zipdl.name || '');
\t\t\t\t\t\t\t\tdlName += m[1]? ('.' + m[1]) : '.zip';
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tdlName = zipdl.name;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (html5dl || linkdl) {
\t\t\t\t\t\t\t\turl = fm.options.url + (fm.options.url.indexOf('?') === -1 ? '?' : '&')
\t\t\t\t\t\t\t\t+ 'cmd=zipdl&download=1';
\t\t\t\t\t\t\t\t\$.each([hashes[0], zipdl.file, dlName, zipdl.mime], function(key, val) {
\t\t\t\t\t\t\t\t\turl += '&targets%5B%5D='+encodeURIComponent(val);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\$.each(fm.customData, function(key, val) {
\t\t\t\t\t\t\t\t\turl += '&'+encodeURIComponent(key)+'='+encodeURIComponent(val);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\turl += '&'+encodeURIComponent(dlName);
\t\t\t\t\t\t\t\tif (fm.hasParrotHeaders()) {
\t\t\t\t\t\t\t\t\tfm.getBinaryByUrl({url: url}, function(blob) {
\t\t\t\t\t\t\t\t\t\tif (blob instanceof Blob) {
\t\t\t\t\t\t\t\t\t\t\turl = (window.URL || window.webkitURL).createObjectURL(blob);
\t\t\t\t\t\t\t\t\t\t\tzipdlFn(url);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tfm.error(['errUploadTransfer', fm.i18n('kindZIP')]);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tzipdlFn(url);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tform = \$('<form action=\"'+fm.options.url+'\" method=\"post\" target=\"'+uniq+'\" style=\"display:none\"></form>')
\t\t\t\t\t\t\t\t.append('<input type=\"hidden\" name=\"cmd\" value=\"zipdl\"/>')
\t\t\t\t\t\t\t\t.append('<input type=\"hidden\" name=\"download\" value=\"1\"/>');
\t\t\t\t\t\t\t\t\$.each([hashes[0], zipdl.file, dlName, zipdl.mime], function(key, val) {
\t\t\t\t\t\t\t\t\tform.append('<input type=\"hidden\" name=\"targets[]\" value=\"'+fm.escape(val)+'\"/>');
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\$.each(fm.customData, function(key, val) {
\t\t\t\t\t\t\t\t\tform.append('<input type=\"hidden\" name=\"'+key+'\" value=\"'+fm.escape(val)+'\"/>');
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tform.attr('target', uniq).appendTo('body');
\t\t\t\t\t\t\t\tiframe = \$('<iframe style=\"display:none\" name=\"'+uniq+'\">')
\t\t\t\t\t\t\t\t\t.appendTo('body')
\t\t\t\t\t\t\t\t\t.ready(function() {
\t\t\t\t\t\t\t\t\t\tform.submit().remove();
\t\t\t\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\t\tiframe.remove();
\t\t\t\t\t\t\t\t\t\t}, 20000); // give 20 sec file to be saved
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}).fail(function(error) {
\t\t\t\t\t\terror && fm.error(error);
\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t});
\t\t\t\t\treturn dfd.promise();
\t\t\t\t};
\t\t\t},
\t\t\t// use MouseEvent to click element for Safari etc
\t\t\tclick = function(a) {
\t\t\t\tvar clickEv;
\t\t\t\tif (typeof MouseEvent === 'function') {
\t\t\t\t\tclickEv = new MouseEvent('click');
\t\t\t\t} else {
\t\t\t\t\tclickEv = document.createEvent('MouseEvents');
\t\t\t\t\tclickEv.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
\t\t\t\t}
\t\t\t\tfm.pauseUnloadCheck(true);
\t\t\t\ta.dispatchEvent(clickEv);
\t\t\t},
\t\t\tcheckCookie = function(id) {
\t\t\t\tvar name = 'elfdl' + id,
\t\t\t\t\tparts;
\t\t\t\tparts = document.cookie.split(name + \"=\");
\t\t\t\tif (parts.length === 2) {
\t\t\t\t\tntftm && clearTimeout(ntftm);
\t\t\t\t\tdocument.cookie = name + '=; path=' + cpath + '; max-age=0';
\t\t\t\t\tcloseNotify();
\t\t\t\t} else {
\t\t\t\t\tsetTimeout(function() { checkCookie(id); }, 200);
\t\t\t\t}
\t\t\t},
\t\t\tcloseNotify = function() {
\t\t\t\tif (fm.ui.notify.children('.elfinder-notify-download').length) {
\t\t\t\t\tfm.notify({
\t\t\t\t\t\ttype : 'download',
\t\t\t\t\t\tcnt : -1
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\treqids = [],
\t\t\tlink, html5dl, fileCnt, clickEv, cid, ntftm, reqid, getUrlDfrd, urls;
\t\t\t
\t\tif (!files.length) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tfileCnt = \$.grep(files, function(f) { return f.mime === 'directory'? false : true; }).length;
\t\tlink = \$('<a>').hide().appendTo('body');
\t\thtml5dl = (typeof link.get(0).download === 'string');
\t\t
\t\tif (zipOn && (fileCnt !== files.length || fileCnt >= (this.options.minFilesZipdl || 1))) {
\t\t\tlink.remove();
\t\t\tlinkdl = (!html5dl && fm.UA.Mobile);
\t\t\tif (mixed) {
\t\t\t\ttargets = {};
\t\t\t\t\$.each(files, function(i, f) {
\t\t\t\t\tvar p = f.hash.split('_', 2);
\t\t\t\t\tif (! targets[p[0]]) {
\t\t\t\t\t\ttargets[p[0]] = [ f.hash ];
\t\t\t\t\t} else {
\t\t\t\t\t\ttargets[p[0]].push(f.hash);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (!linkdl && fm.UA.Mobile && Object.keys(targets).length > 1) {
\t\t\t\t\tlinkdl = true;
\t\t\t\t}
\t\t\t} else {
\t\t\t\ttargets = [ \$.map(files, function(f) { return f.hash; }) ];
\t\t\t}
\t\t\tdfrd = fm.sequence(\$.map(targets, function(t) { return getTask(t); })).always(
\t\t\t\tfunction() {
\t\t\t\t\tfm.trigger('download', {files : files});
\t\t\t\t}
\t\t\t);
\t\t\treturn dfrd;
\t\t} else {
\t\t\treqids = [];
\t\t\tgetUrlDfrd = \$.Deferred().done(function(urls) {
\t\t\t\tfor (i = 0; i < urls.length; i++) {
\t\t\t\t\turl = urls[i];
\t\t\t\t\tif (dlntf && url.substr(0, fm.options.url.length) === fm.options.url) {
\t\t\t\t\t\treqid = fm.getRequestId();
\t\t\t\t\t\treqids.push(reqid);
\t\t\t\t\t\turl += '&cpath=' + cpath + '&reqid=' + reqid;
\t\t\t\t\t\tntftm = setTimeout(function() {
\t\t\t\t\t\t\tfm.notify({
\t\t\t\t\t\t\t\ttype : 'download',
\t\t\t\t\t\t\t\tcnt : 1,
\t\t\t\t\t\t\t\tcancel : (fm.UA.IE || fm.UA.Edge)? void(0) : function() {
\t\t\t\t\t\t\t\t\tif (reqids.length) {
\t\t\t\t\t\t\t\t\t\t\$.each(reqids, function() {
\t\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\t\tdata: {
\t\t\t\t\t\t\t\t\t\t\t\t\tcmd: 'abort',
\t\t\t\t\t\t\t\t\t\t\t\t\tid: this
\t\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\t\tpreventDefault: true
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\treqids = [];
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, fm.notifyDelay);
\t\t\t\t\t\tcheckCookie(reqid);
\t\t\t\t\t}
\t\t\t\t\tif (html5dl) {
\t\t\t\t\t\tclick(link.attr('href', url)
\t\t\t\t\t\t\t.attr('download', fm.escape(files[i].name))
\t\t\t\t\t\t\t.get(0)
\t\t\t\t\t\t);
\t\t\t\t\t} else {
\t\t\t\t\t\tif (fm.UA.Mobile) {
\t\t\t\t\t\t\tsetTimeout(function(){
\t\t\t\t\t\t\t\tif (! window.open(url)) {
\t\t\t\t\t\t\t\t\tfm.error('errPopup');
\t\t\t\t\t\t\t\t\tntftm && cleaerTimeout(ntftm);
\t\t\t\t\t\t\t\t\tcloseNotify();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}, 100);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tiframes += '<iframe class=\"downloader\" id=\"downloader-' + files[i].hash+'\" style=\"display:none\" src=\"'+url+'\"></iframe>';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tlink.remove();
\t\t\t\t\$(iframes)
\t\t\t\t\t.appendTo('body')
\t\t\t\t\t.ready(function() {
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\$(iframes).each(function() {
\t\t\t\t\t\t\t\t\$('#' + \$(this).attr('id')).remove();
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, 20000 + (10000 * i)); // give 20 sec + 10 sec for each file to be saved
\t\t\t\t\t});
\t\t\t\tfm.trigger('download', {files : files});
\t\t\t\tdfrd.resolve();
\t\t\t});
\t\t\tfileCnt = files.length;
\t\t\turls = [];
\t\t\tfor (i = 0; i < files.length; i++) {
\t\t\t\tfm.openUrl(files[i].hash, true, function(v) {
\t\t\t\t\tv && urls.push(v);
\t\t\t\t\tif (--fileCnt < 1) {
\t\t\t\t\t\tgetUrlDfrd.resolve(urls);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t\treturn dfrd;
\t\t}
\t};

};


/*
 * File: /js/commands/duplicate.js
 */

/**
 * @class elFinder command \"duplicate\"
 * Create file/folder copy with suffix \"copy Number\"
 *
 * @type  elFinder.command
 * @author  Dmitry (dio) Levashov
 */
elFinder.prototype.commands.duplicate = function() {
\t\tvar fm = this.fm;
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;

\t\treturn cnt && fm.cwd().write && \$.grep(sel, function(f) { return f.read && f.phash === fm.cwd().hash && ! fm.isRoot(f)? true : false; }).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar fm     = this.fm,
\t\t\tfiles  = this.files(hashes),
\t\t\tcnt    = files.length,
\t\t\tdfrd   = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t}), 
\t\t\targs = [];
\t\t\t
\t\tif (! cnt) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\t\$.each(files, function(i, file) {
\t\t\tif (!file.read || !fm.file(file.phash).write) {
\t\t\t\treturn !dfrd.reject(['errCopy', file.name, 'errPerm']);
\t\t\t}
\t\t});
\t\t
\t\tif (dfrd.state() == 'rejected') {
\t\t\treturn dfrd;
\t\t}
\t\t
\t\treturn fm.request({
\t\t\tdata   : {cmd : 'duplicate', targets : this.hashes(hashes)},
\t\t\tnotify : {type : 'copy', cnt : cnt},
\t\t\tnavigate : {
\t\t\t\ttoast : {
\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdduplicate')])}
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t};

};


/*
 * File: /js/commands/edit.js
 */

/**
 * @class elFinder command \"edit\". 
 * Edit text file in dialog window
 *
 * @author Dmitry (dio) Levashov, dio@std42.ru
 **/
elFinder.prototype.commands.edit = function() {
\t\tvar self  = this,
\t\tfm    = this.fm,
\t\tclsEditing = fm.res('class', 'editing'),
\t\tmimesSingle = [],
\t\tmimes = [],
\t\tallowAll = false,
\t\trtrim = function(str){
\t\t\treturn str.replace(/\\s+\$/, '');
\t\t},
\t\tgetEncSelect = function(heads) {
\t\t\tvar sel = \$('<select class=\"ui-corner-all\"></select>'),
\t\t\t\thval;
\t\t\tif (heads) {
\t\t\t\t\$.each(heads, function(i, head) {
\t\t\t\t\thval = fm.escape(head.value);
\t\t\t\t\tsel.append('<option value=\"'+hval+'\">'+(head.caption? fm.escape(head.caption) : hval)+'</option>');
\t\t\t\t});
\t\t\t}
\t\t\t\$.each(self.options.encodings, function(i, v) {
\t\t\t\tsel.append('<option value=\"'+v+'\">'+v+'</option>');
\t\t\t});
\t\t\treturn sel;
\t\t},
\t\tgetDlgWidth = function() {
\t\t\tvar win = fm.options.dialogContained? fm.getUI() : \$(window),
\t\t\t\tm, width;
\t\t\tif (typeof self.options.dialogWidth === 'string' && (m = self.options.dialogWidth.match(/(\\d+)%/))) {
\t\t\t\twidth = parseInt(win.width() * (m[1] / 100));
\t\t\t} else {
\t\t\t\twidth = parseInt(self.options.dialogWidth || 650);
\t\t\t}
\t\t\treturn Math.min(width, win.width());
\t\t},
\t\tgetDlgHeight = function() {
\t\t\tif (!self.options.dialogHeight) {
\t\t\t\treturn void(0);
\t\t\t}
\t\t\tvar win = fm.options.dialogContained? fm.getUI() : \$(window),
\t\t\t\tm, height;
\t\t\tif (typeof self.options.dialogHeight === 'string' && (m = self.options.dialogHeight.match(/(\\d+)%/))) {
\t\t\t\theight = parseInt(win.height() * (m[1] / 100));
\t\t\t} else {
\t\t\t\theight = parseInt(self.options.dialogHeight || win.height());
\t\t\t}
\t\t\treturn Math.min(height, win.height());
\t\t},

\t\t/**
\t\t * Return files acceptable to edit
\t\t *
\t\t * @param  Array  files hashes
\t\t * @return Array
\t\t **/
\t\tfilter = function(files) {
\t\t\tvar cnt = files.length,
\t\t\t\tmime, ext, skip;
\t\t\t
\t\t\tif (cnt > 1) {
\t\t\t\tmime = files[0].mime;
\t\t\t\text = files[0].name.replace(/^.*(\\.[^.]+)\$/, '\$1');
\t\t\t}
\t\t\treturn \$.grep(files, function(file) {
\t\t\t\tvar res;
\t\t\t\tif (skip || file.mime === 'directory') {
\t\t\t\t\treturn false;
\t\t\t\t}
\t\t\t\tres = file.read
\t\t\t\t\t&& (allowAll || fm.mimeIsText(file.mime) || \$.inArray(file.mime, cnt === 1? mimesSingle : mimes) !== -1) 
\t\t\t\t\t&& (!self.onlyMimes.length || \$.inArray(file.mime, self.onlyMimes) !== -1)
\t\t\t\t\t&& (cnt === 1 || (file.mime === mime && file.name.substr(ext.length * -1) === ext))
\t\t\t\t\t&& (fm.uploadMimeCheck(file.mime, file.phash)? true : false)
\t\t\t\t\t&& setEditors(file, cnt)
\t\t\t\t\t&& Object.keys(editors).length;
\t\t\t\tif (!res) {
\t\t\t\t\tskip = true;
\t\t\t\t}
\t\t\t\treturn res;
\t\t\t});
\t\t},

\t\tfileSync = function(hash) {
\t\t\tvar old = fm.file(hash),
\t\t\t\tf;
\t\t\tfm.request({
\t\t\t\tcmd: 'info',
\t\t\t\ttargets: [hash],
\t\t\t\tpreventDefault: true
\t\t\t}).done(function(data) {
\t\t\t\tvar changed;
\t\t\t\tif (data && data.files && data.files.length) {
\t\t\t\t\tf = data.files[0];
\t\t\t\t\tif (old.ts != f.ts || old.size != f.size) {
\t\t\t\t\t\tchanged = { changed: [ f ] };
\t\t\t\t\t\tfm.updateCache(changed);
\t\t\t\t\t\tfm.change(changed);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t},

\t\t/**
\t\t * Open dialog with textarea to edit file
\t\t *
\t\t * @param  String  id       dialog id
\t\t * @param  Object  file     file object
\t\t * @param  String  content  file content
\t\t * @return \$.Deferred
\t\t **/
\t\tdialog = function(id, file, content, encoding, editor, toasts) {

\t\t\tvar dfrd = \$.Deferred(),
\t\t\t\t_loaded = false,
\t\t\t\tloaded = function() {
\t\t\t\t\tif (!_loaded) {
\t\t\t\t\t\tfm.toast({
\t\t\t\t\t\t\tmode: 'warning',
\t\t\t\t\t\t\tmsg: fm.i18n('nowLoading')
\t\t\t\t\t\t});
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\treturn true;
\t\t\t\t},
\t\t\t\tmakeToasts = function() {
\t\t\t\t\t// make toast message
\t\t\t\t\tif (toasts && Array.isArray(toasts)) {
\t\t\t\t\t\t\$.each(toasts, function() {
\t\t\t\t\t\t\tthis.msg && fm.toast(this);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tsave = function() {
\t\t\t\t\tvar encord = selEncoding? selEncoding.val():void(0),
\t\t\t\t\t\tsaveDfd = \$.Deferred().fail(function(err) {
\t\t\t\t\t\t\tdialogNode.show().find('button.elfinder-btncnt-0,button.elfinder-btncnt-1').hide();
\t\t\t\t\t\t}),
\t\t\t\t\t\tconf, res, tm;
\t\t\t\t\tif (!loaded()) {
\t\t\t\t\t\treturn saveDfd.resolve();
\t\t\t\t\t}
\t\t\t\t\tif (ta.editor) {
\t\t\t\t\t\tta.editor.save(ta[0], ta.editor.instance);
\t\t\t\t\t\tconf = ta.editor.confObj;
\t\t\t\t\t\tif (conf.info && (conf.info.schemeContent || conf.info.arrayBufferContent)) {
\t\t\t\t\t\t\tencord = 'scheme';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tres = getContent();
\t\t\t\t\tsetOld(res);
\t\t\t\t\tif (res.promise) {
\t\t\t\t\t\ttm = setTimeout(function() {
\t\t\t\t\t\t\tfm.notify({
\t\t\t\t\t\t\t\ttype : 'chkcontent',
\t\t\t\t\t\t\t\tcnt : 1,
\t\t\t\t\t\t\t\thideCnt: true,
\t\t\t\t\t\t\t\tcancel : function() {
\t\t\t\t\t\t\t\t\tres.reject();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, 100);
\t\t\t\t\t\tres.always(function() {
\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\tfm.notify({ type : 'chkcontent', cnt: -1 });
\t\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\t\tdfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]);
\t\t\t\t\t\t}).fail(function(err) {
\t\t\t\t\t\t\tsaveDfd.reject(err);
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]);
\t\t\t\t\t}
\t\t\t\t\treturn saveDfd;
\t\t\t\t},
\t\t\t\tsaveon = function() {
\t\t\t\t\tif (!loaded()) { return; }
\t\t\t\t\tsave().fail(function(err) {
\t\t\t\t\t\terr && fm.error(err);
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\tcancel = function() {
\t\t\t\t\tta.elfinderdialog('close');
\t\t\t\t},
\t\t\t\tsavecl = function() {
\t\t\t\t\tif (!loaded()) { return; }
\t\t\t\t\tdialogNode.hide();
\t\t\t\t\tsave().done(function() {
\t\t\t\t\t\t_loaded = false;
\t\t\t\t\t\tdialogNode.show();
\t\t\t\t\t\tcancel();
\t\t\t\t\t}).fail(function(err) {
\t\t\t\t\t\tdialogNode.show();
\t\t\t\t\t\terr && fm.error(err);
\t\t\t\t\t});
\t\t\t\t},
\t\t\t\tsaveAs = function() {
\t\t\t\t\tif (!loaded()) { return; }
\t\t\t\t\tvar prevOld = old,
\t\t\t\t\t\tphash = file.phash,
\t\t\t\t\t\tfail = function(err) {
\t\t\t\t\t\t\tdialogs.addClass(clsEditing).fadeIn(function() {
\t\t\t\t\t\t\t\terr && fm.error(err);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\told = prevOld;
\t\t\t\t\t\t\tfm.disable();
\t\t\t\t\t\t},
\t\t\t\t\t\tmake = function() {
\t\t\t\t\t\t\tself.mime = saveAsFile.mime || file.mime;
\t\t\t\t\t\t\tself.prefix = (saveAsFile.name || file.name).replace(/ \\d+(\\.[^.]+)?\$/, '\$1');
\t\t\t\t\t\t\tself.requestCmd = 'mkfile';
\t\t\t\t\t\t\tself.nextAction = {};
\t\t\t\t\t\t\tself.data = {target : phash};
\t\t\t\t\t\t\t\$.proxy(fm.res('mixin', 'make'), self)()
\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\tvar oldHash;
\t\t\t\t\t\t\t\t\tif (data.added && data.added.length) {
\t\t\t\t\t\t\t\t\t\toldHash = ta.data('hash');
\t\t\t\t\t\t\t\t\t\tta.data('hash', data.added[0].hash);
\t\t\t\t\t\t\t\t\t\tsave().done(function() {
\t\t\t\t\t\t\t\t\t\t\t_loaded = false;
\t\t\t\t\t\t\t\t\t\t\tdialogNode.show();
\t\t\t\t\t\t\t\t\t\t\tcancel();
\t\t\t\t\t\t\t\t\t\t\tdialogs.fadeIn();
\t\t\t\t\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\t\t\t\t\tfm.exec('rm', [data.added[0].hash], { forceRm: true, quiet: true });
\t\t\t\t\t\t\t\t\t\t\tta.data('hash', oldHash);
\t\t\t\t\t\t\t\t\t\t\tdialogNode.find('button.elfinder-btncnt-2').hide();
\t\t\t\t\t\t\t\t\t\t\tfail();
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tfail();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.progress(function(err) {
\t\t\t\t\t\t\t\t\tif (err && err === 'errUploadMime') {
\t\t\t\t\t\t\t\t\t\tta.trigger('saveAsFail');
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.fail(fail)
\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\tdelete self.mime;
\t\t\t\t\t\t\t\t\tdelete self.prefix;
\t\t\t\t\t\t\t\t\tdelete self.nextAction;
\t\t\t\t\t\t\t\t\tdelete self.data;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tfm.trigger('unselectfiles', { files: [ file.hash ] });
\t\t\t\t\t\t},
\t\t\t\t\t\treqOpen = null,
\t\t\t\t\t\treqInfo = null,
\t\t\t\t\t\tdialogs = fm.getUI().children('.' + self.dialogClass + ':visible');
\t\t\t\t\t\tif (dialogNode.is(':hidden')) {
\t\t\t\t\t\t\tdialogs = dialogs.add(dialogNode);
\t\t\t\t\t\t}
\t\t\t\t\t\tdialogs.removeClass(clsEditing).fadeOut();
\t\t\t\t\t
\t\t\t\t\tfm.enable();
\t\t\t\t\t
\t\t\t\t\tif (fm.searchStatus.state < 2 && phash !== fm.cwd().hash) {
\t\t\t\t\t\treqOpen = fm.exec('open', [phash], {thash: phash});
\t\t\t\t\t} else if (!fm.file(phash)) {
\t\t\t\t\t\treqInfo = fm.request({cmd: 'info', targets: [phash]}); 
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\t\$.when([reqOpen, reqInfo]).done(function() {
\t\t\t\t\t\tif (reqInfo) {
\t\t\t\t\t\t\tfm.one('infodone', function() {
\t\t\t\t\t\t\t\tfm.file(phash)? make() : fail('errFolderNotFound');
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\treqOpen? fm.one('cwdrender', make) : make();
\t\t\t\t\t\t}
\t\t\t\t\t}).fail(fail);
\t\t\t\t},
\t\t\t\tchanged = function() {
\t\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\t\tres, tm;
\t\t\t\t\tif (!_loaded) {
\t\t\t\t\t\treturn dfd.resolve(false);
\t\t\t\t\t}
\t\t\t\t\tta.editor && ta.editor.save(ta[0], ta.editor.instance);
\t\t\t\t\tres = getContent();
\t\t\t\t\tif (res && res.promise) {
\t\t\t\t\t\ttm = setTimeout(function() {
\t\t\t\t\t\t\tfm.notify({
\t\t\t\t\t\t\t\ttype : 'chkcontent',
\t\t\t\t\t\t\t\tcnt : 1,
\t\t\t\t\t\t\t\thideCnt: true,
\t\t\t\t\t\t\t\tcancel : function() {
\t\t\t\t\t\t\t\t\tres.reject();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}, 100);
\t\t\t\t\t\tres.always(function() {
\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\tfm.notify({ type : 'chkcontent', cnt: -1 });
\t\t\t\t\t\t}).done(function(d) {
\t\t\t\t\t\t\tdfd.resolve(old !== d);
\t\t\t\t\t\t}).fail(function(err) {
\t\t\t\t\t\t\tdfd.resolve(err || (old === undefined? false : true));
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdfd.resolve(old !== res);
\t\t\t\t\t}
\t\t\t\t\treturn dfd;
\t\t\t\t},
\t\t\t\topts = {
\t\t\t\t\ttitle   : fm.escape(file.name),
\t\t\t\t\twidth   : getDlgWidth(),
\t\t\t\t\theight  : getDlgHeight(),
\t\t\t\t\tbuttons : {},
\t\t\t\t\tcssClass  : clsEditing,
\t\t\t\t\tmaxWidth  : 'window',
\t\t\t\t\tmaxHeight : 'window',
\t\t\t\t\tallowMinimize : true,
\t\t\t\t\tallowMaximize : true,
\t\t\t\t\topenMaximized : editorMaximized() || (editor && editor.info && editor.info.openMaximized),
\t\t\t\t\tbtnHoverFocus : false,
\t\t\t\t\tcloseOnEscape : false,
\t\t\t\t\tpropagationEvents : ['mousemove', 'mouseup', 'click'],
\t\t\t\t\tminimize : function() {
\t\t\t\t\t\tvar conf;
\t\t\t\t\t\tif (ta.editor && dialogNode.closest('.ui-dialog').is(':hidden')) {
\t\t\t\t\t\t\tconf = ta.editor.confObj;
\t\t\t\t\t\t\tif (conf.info && conf.info.syncInterval) {
\t\t\t\t\t\t\t\tfileSync(file.hash);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tclose   : function() {
\t\t\t\t\t\tvar close = function() {
\t\t\t\t\t\t\t\tvar conf;
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\tif (ta.editor) {
\t\t\t\t\t\t\t\t\tta.editor.close(ta[0], ta.editor.instance);
\t\t\t\t\t\t\t\t\tconf = ta.editor.confObj;
\t\t\t\t\t\t\t\t\tif (conf.info && conf.info.syncInterval) {
\t\t\t\t\t\t\t\t\t\tfileSync(file.hash);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tta.elfinderdialog('destroy');
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tonlySaveAs = (typeof saveAsFile.name !== 'undefined'),
\t\t\t\t\t\t\taccept = onlySaveAs? {
\t\t\t\t\t\t\t\tlabel    : 'btnSaveAs',
\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\trequestAnimationFrame(saveAs);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} : {
\t\t\t\t\t\t\t\tlabel    : 'btnSaveClose',
\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\tsave().done(function() {
\t\t\t\t\t\t\t\t\t\tclose();
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\tchanged().done(function(change) {
\t\t\t\t\t\t\tvar msgs = ['confirmNotSave'];
\t\t\t\t\t\t\tif (change) {
\t\t\t\t\t\t\t\tif (typeof change === 'string') {
\t\t\t\t\t\t\t\t\tmsgs.unshift(change);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.confirm({
\t\t\t\t\t\t\t\t\ttitle  : self.title,
\t\t\t\t\t\t\t\t\ttext   : msgs,
\t\t\t\t\t\t\t\t\taccept : accept,
\t\t\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\t\t\tlabel    : 'btnClose',
\t\t\t\t\t\t\t\t\t\tcallback : close
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tbuttons : onlySaveAs? null : [{
\t\t\t\t\t\t\t\t\t\tlabel    : 'btnSaveAs',
\t\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\trequestAnimationFrame(saveAs);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}]
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tclose();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t},
\t\t\t\t\topen    : function() {
\t\t\t\t\t\tvar loadRes, conf, interval;
\t\t\t\t\t\tta.initEditArea.call(ta, id, file, content, fm);
\t\t\t\t\t\tif (ta.editor) {
\t\t\t\t\t\t\tloadRes = ta.editor.load(ta[0]) || null;
\t\t\t\t\t\t\tif (loadRes && loadRes.done) {
\t\t\t\t\t\t\t\tloadRes.always(function() {
\t\t\t\t\t\t\t\t\t_loaded = true;
\t\t\t\t\t\t\t\t}).done(function(instance) {
\t\t\t\t\t\t\t\t\tta.editor.instance = instance;
\t\t\t\t\t\t\t\t\tta.editor.focus(ta[0], ta.editor.instance);
\t\t\t\t\t\t\t\t\tsetOld(getContent());
\t\t\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\t\t\tdialogNode.trigger('resize');
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}).fail(function(error) {
\t\t\t\t\t\t\t\t\terror && fm.error(error);
\t\t\t\t\t\t\t\t\tta.elfinderdialog('destroy');
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}).always(makeToasts);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t_loaded = true;
\t\t\t\t\t\t\t\tif (loadRes && (typeof loadRes === 'string' || Array.isArray(loadRes))) {
\t\t\t\t\t\t\t\t\tfm.error(loadRes);
\t\t\t\t\t\t\t\t\tta.elfinderdialog('destroy');
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tta.editor.instance = loadRes;
\t\t\t\t\t\t\t\tta.editor.focus(ta[0], ta.editor.instance);
\t\t\t\t\t\t\t\tsetOld(getContent());
\t\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\t\tdialogNode.trigger('resize');
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tmakeToasts();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tconf = ta.editor.confObj;
\t\t\t\t\t\t\tif (conf.info && conf.info.syncInterval) {
\t\t\t\t\t\t\t\tif (interval = parseInt(conf.info.syncInterval)) {
\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\tautoSync(interval);
\t\t\t\t\t\t\t\t\t}, interval);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t_loaded = true;
\t\t\t\t\t\t\tsetOld(getContent());
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tresize : function(e, data) {
\t\t\t\t\t\tta.editor && ta.editor.resize(ta[0], ta.editor.instance, e, data || {});
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tgetContent = function() {
\t\t\t\t\tvar res = ta.getContent.call(ta, ta[0]);
\t\t\t\t\tif (res === undefined || res === false || res === null) {
\t\t\t\t\t\tres = \$.Deferred().reject();
\t\t\t\t\t}
\t\t\t\t\treturn res;
\t\t\t\t},
\t\t\t\tsetOld = function(res) {
\t\t\t\t\tif (res && res.promise) {
\t\t\t\t\t\tres.done(function(d) {
\t\t\t\t\t\t\told = d;
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\told = res;
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tautoSync = function(interval) {
\t\t\t\t\tif (dialogNode.is(':visible')) {
\t\t\t\t\t\tfileSync(file.hash);
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tautoSync(interval);
\t\t\t\t\t\t}, interval);
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tstateChange = function() {
\t\t\t\t\tif (selEncoding) {
\t\t\t\t\t\tchanged().done(function(change) {
\t\t\t\t\t\t\tif (change) {
\t\t\t\t\t\t\t\tselEncoding.attr('title', fm.i18n('saveAsEncoding')).addClass('elfinder-edit-changed');
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tselEncoding.attr('title', fm.i18n('openAsEncoding')).removeClass('elfinder-edit-changed');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tsaveAsFile = {},
\t\t\t\tta, old, dialogNode, selEncoding, extEditor, maxW, syncInterval;
\t\t\t\t
\t\t\tif (editor) {
\t\t\t\tif (editor.html) {
\t\t\t\t\tta = \$(editor.html);
\t\t\t\t}
\t\t\t\textEditor = {
\t\t\t\t\tinit     : editor.init || null,
\t\t\t\t\tload     : editor.load,
\t\t\t\t\tgetContent : editor.getContent || null,
\t\t\t\t\tsave     : editor.save,
\t\t\t\t\tbeforeclose : typeof editor.beforeclose == 'function' ? editor.beforeclose : void 0,
\t\t\t\t\tclose    : typeof editor.close == 'function' ? editor.close : function() {},
\t\t\t\t\tfocus    : typeof editor.focus == 'function' ? editor.focus : function() {},
\t\t\t\t\tresize   : typeof editor.resize == 'function' ? editor.resize : function() {},
\t\t\t\t\tinstance : null,
\t\t\t\t\tdoSave   : saveon,
\t\t\t\t\tdoCancel : cancel,
\t\t\t\t\tdoClose  : savecl,
\t\t\t\t\tfile     : file,
\t\t\t\t\tfm       : fm,
\t\t\t\t\tconfObj  : editor,
\t\t\t\t\ttrigger  : function(evName, data) {
\t\t\t\t\t\tfm.trigger('editEditor' + evName, Object.assign({}, editor.info || {}, data));
\t\t\t\t\t}
\t\t\t\t};
\t\t\t}
\t\t\t
\t\t\tif (!ta) {
\t\t\t\tif (!fm.mimeIsText(file.mime)) {
\t\t\t\t\treturn dfrd.reject('errEditorNotFound');
\t\t\t\t}
\t\t\t\t(function() {
\t\t\t\t\tta = \$('<textarea class=\"elfinder-file-edit\" rows=\"20\" id=\"'+id+'-ta\"></textarea>')
\t\t\t\t\t\t.on('input propertychange', stateChange);
\t\t\t\t\t
\t\t\t\t\tif (!editor || !editor.info || editor.info.useTextAreaEvent) {
\t\t\t\t\t\tta.on('keydown', function(e) {
\t\t\t\t\t\t\tvar code = e.keyCode,
\t\t\t\t\t\t\t\tvalue, start;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\tif (code == \$.ui.keyCode.TAB) {
\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t// insert tab on tab press
\t\t\t\t\t\t\t\tif (this.setSelectionRange) {
\t\t\t\t\t\t\t\t\tvalue = this.value;
\t\t\t\t\t\t\t\t\tstart = this.selectionStart;
\t\t\t\t\t\t\t\t\tthis.value = value.substr(0, start) + \"\\t\" + value.substr(this.selectionEnd);
\t\t\t\t\t\t\t\t\tstart += 1;
\t\t\t\t\t\t\t\t\tthis.setSelectionRange(start, start);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (e.ctrlKey || e.metaKey) {
\t\t\t\t\t\t\t\t// close on ctrl+w/q
\t\t\t\t\t\t\t\tif (code == 'Q'.charCodeAt(0) || code == 'W'.charCodeAt(0)) {
\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\tcancel();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (code == 'S'.charCodeAt(0)) {
\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\tsaveon();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('mouseenter', function(){this.focus();});
\t\t\t\t\t}

\t\t\t\t\tta.initEditArea = function(id, file, content) {
\t\t\t\t\t\t// ta.hide() for performance tune. Need ta.show() in `load()` if use textarea node.
\t\t\t\t\t\tta.hide().val(content);
\t\t\t\t\t\tthis._setupSelEncoding(content);
\t\t\t\t\t};
\t\t\t\t})();
\t\t\t}

\t\t\t// extended function to setup selector of encoding for text editor
\t\t\tta._setupSelEncoding = function(content) {
\t\t\t\tvar heads = (encoding && encoding !== 'unknown')? [{value: encoding}] : [],
\t\t\t\t\twfake = \$('<select></select>').hide(),
\t\t\t\t\tsetSelW = function(init) {
\t\t\t\t\t\tinit && wfake.appendTo(selEncoding.parent());
\t\t\t\t\t\twfake.empty().append(\$('<option></option>').text(selEncoding.val()));
\t\t\t\t\t\tselEncoding.width(wfake.width());
\t\t\t\t\t};
\t\t\t\tif (content === '' || ! encoding || encoding !== 'UTF-8') {
\t\t\t\t\theads.push({value: 'UTF-8'});
\t\t\t\t}
\t\t\t\tselEncoding = getEncSelect(heads).on('touchstart', function(e) {
\t\t\t\t\t// for touch punch event handler
\t\t\t\t\te.stopPropagation();
\t\t\t\t}).on('change', function() {
\t\t\t\t\t// reload to change encoding if not edited
\t\t\t\t\tchanged().done(function(change) {
\t\t\t\t\t\tif (! change && getContent() !== '') {
\t\t\t\t\t\t\tcancel();
\t\t\t\t\t\t\tedit(file, selEncoding.val(), editor).fail(function(err) { err && fm.error(err); });
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tsetSelW();
\t\t\t\t}).on('mouseover', stateChange);
\t\t\t\tta.parent().next().prepend(\$('<div class=\"ui-dialog-buttonset elfinder-edit-extras\"></div>').append(selEncoding));
\t\t\t\tsetSelW(true);
\t\t\t};

\t\t\tta.data('hash', file.hash);
\t\t\t
\t\t\tif (extEditor) {
\t\t\t\tta.editor = extEditor;
\t\t\t\t
\t\t\t\tif (typeof extEditor.beforeclose === 'function') {
\t\t\t\t\topts.beforeclose = function() {
\t\t\t\t\t\treturn extEditor.beforeclose(ta[0], extEditor.instance);
\t\t\t\t\t};
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (typeof extEditor.init === 'function') {
\t\t\t\t\tta.initEditArea = extEditor.init;
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (typeof extEditor.getContent === 'function') {
\t\t\t\t\tta.getContent = extEditor.getContent;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (! ta.initEditArea) {
\t\t\t\tta.initEditArea = function() {};
\t\t\t}
\t\t\t
\t\t\tif (! ta.getContent) {
\t\t\t\tta.getContent = function() {
\t\t\t\t\treturn rtrim(ta.val());
\t\t\t\t};
\t\t\t}
\t\t\t
\t\t\tif (!editor || !editor.info || !editor.info.preventGet) {
\t\t\t\topts.buttons[fm.i18n('btnSave')]      = saveon;
\t\t\t\topts.buttons[fm.i18n('btnSaveClose')] = savecl;
\t\t\t\topts.buttons[fm.i18n('btnSaveAs')]    = saveAs;
\t\t\t\topts.buttons[fm.i18n('btnCancel')]    = cancel;
\t\t\t}
\t\t\t
\t\t\tif (editor && typeof editor.prepare === 'function') {
\t\t\t\teditor.prepare(ta, opts, file);
\t\t\t}
\t\t\t
\t\t\tdialogNode = self.fmDialog(ta, opts)
\t\t\t\t.attr('id', id)
\t\t\t\t.on('keydown keyup keypress', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t})
\t\t\t\t.css({ overflow: 'hidden', minHeight: '7em' })
\t\t\t\t.addClass('elfinder-edit-editor')
\t\t\t\t.closest('.ui-dialog')
\t\t\t\t.on('changeType', function(e, data) {
\t\t\t\t\tif (data.extention && data.mime) {
\t\t\t\t\t\tvar ext = data.extention,
\t\t\t\t\t\t\tmime = data.mime,
\t\t\t\t\t\t\tbtnSet = \$(this).children('.ui-dialog-buttonpane').children('.ui-dialog-buttonset');
\t\t\t\t\t\tbtnSet.children('.elfinder-btncnt-0,.elfinder-btncnt-1').hide();
\t\t\t\t\t\tsaveAsFile.name = fm.splitFileExtention(file.name)[0] + '.' + data.extention;
\t\t\t\t\t\tsaveAsFile.mime = data.mime;
\t\t\t\t\t\tif (!data.keepEditor) {
\t\t\t\t\t\t\tbtnSet.children('.elfinder-btncnt-2').trigger('click');
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t
\t\t\t// care to viewport scale change with mobile devices
\t\t\tmaxW = (fm.options.dialogContained? fm.getUI() : \$(window)).width();
\t\t\t(dialogNode.width() > maxW) && dialogNode.width(maxW);
\t\t\t
\t\t\treturn dfrd.promise();
\t\t},
\t\t
\t\t/**
\t\t * Get file content and
\t\t * open dialog with textarea to edit file content
\t\t *
\t\t * @param  String  file hash
\t\t * @return jQuery.Deferred
\t\t **/
\t\tedit = function(file, convert, editor) {
\t\t\tvar hash   = file.hash,
\t\t\t\topts   = fm.options,
\t\t\t\tdfrd   = \$.Deferred(), 
\t\t\t\tid     = 'edit-'+fm.namespace+'-'+file.hash,
\t\t\t\td      = fm.getUI().find('#'+id),
\t\t\t\tconv   = !convert? 0 : convert,
\t\t\t\tnoContent = false,
\t\t\t\treq, error, res;
\t\t\t
\t\t\t
\t\t\tif (d.length) {
\t\t\t\td.elfinderdialog('toTop');
\t\t\t\treturn dfrd.resolve();
\t\t\t}
\t\t\t
\t\t\tif (!file.read || (!file.write && (!editor.info || !editor.info.converter))) {
\t\t\t\terror = ['errOpen', file.name, 'errPerm'];
\t\t\t\treturn dfrd.reject(error);
\t\t\t}
\t\t\t
\t\t\tif (editor && editor.info) {
\t\t\t\tif (typeof editor.info.edit === 'function') {
\t\t\t\t\tres = editor.info.edit.call(fm, file, editor);
\t\t\t\t\tif (res.promise) {
\t\t\t\t\t\tres.done(function() {
\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t}).fail(function(error) {
\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tres? dfrd.resolve() : dfrd.reject();
\t\t\t\t\t}
\t\t\t\t\treturn dfrd;
\t\t\t\t}

\t\t\t\tnoContent = editor.info.preventGet || editor.info.noContent;
\t\t\t\tif (editor.info.urlAsContent || noContent) {
\t\t\t\t\treq = \$.Deferred();
\t\t\t\t\tif (editor.info.urlAsContent) {
\t\t\t\t\t\tfm.url(hash, { async: true, onetime: true, temporary: true }).done(function(url) {
\t\t\t\t\t\t\treq.resolve({content: url});
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\treq.resolve({});
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (conv) {
\t\t\t\t\t\tfile.encoding = conv;
\t\t\t\t\t\tfm.cache(file, 'change');
\t\t\t\t\t}
\t\t\t\t\treq = fm.request({
\t\t\t\t\t\tdata           : {cmd : 'get', target : hash, conv : conv, _t : file.ts},
\t\t\t\t\t\toptions        : {type: 'get', cache : true},
\t\t\t\t\t\tnotify         : {type : 'file', cnt : 1},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t});
\t\t\t\t}

\t\t\t\treq.done(function(data) {
\t\t\t\t\tvar selEncoding, reg, m, res;
\t\t\t\t\tif (data.doconv) {
\t\t\t\t\t\tfm.confirm({
\t\t\t\t\t\t\ttitle  : self.title,
\t\t\t\t\t\t\ttext   : data.doconv === 'unknown'? 'confirmNonUTF8' : 'confirmConvUTF8',
\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\tlabel    : 'btnConv',
\t\t\t\t\t\t\t\tcallback : function() {  
\t\t\t\t\t\t\t\t\tdfrd = edit(file, selEncoding.val(), editor);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\t\t\t\tcallback : function() { dfrd.reject(); }
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\toptionsCallback : function(options) {
\t\t\t\t\t\t\t\toptions.create = function() {
\t\t\t\t\t\t\t\t\tvar base = \$('<div class=\"elfinder-dialog-confirm-encoding\"></div>'),
\t\t\t\t\t\t\t\t\t\thead = {value: data.doconv},
\t\t\t\t\t\t\t\t\t\tdetected;
\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (data.doconv === 'unknown') {
\t\t\t\t\t\t\t\t\t\thead.caption = '-';
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tselEncoding = getEncSelect([head]);
\t\t\t\t\t\t\t\t\t\$(this).next().find('.ui-dialog-buttonset')
\t\t\t\t\t\t\t\t\t\t.prepend(base.append(\$('<label>'+fm.i18n('encoding')+' </label>').append(selEncoding)));
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tif (!noContent && fm.mimeIsText(file.mime)) {
\t\t\t\t\t\t\treg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\\\\$1')+';base64,)', 'i');
\t\t\t\t\t\t\tif (!editor.info.dataScheme) {
\t\t\t\t\t\t\t\tif (window.atob && (m = data.content.match(reg))) {
\t\t\t\t\t\t\t\t\tdata.content = atob(data.content.substr(m[1].length));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (window.btoa && !data.content.match(reg)) {
\t\t\t\t\t\t\t\t\tdata.content = 'data:'+file.mime+';base64,'+btoa(data.content);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tdialog(id, file, data.content, data.encoding, editor, data.toasts)
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tdfrd.resolve(data);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.progress(function(encoding, newHash, data, saveDfd) {
\t\t\t\t\t\t\t\tvar ta = this;
\t\t\t\t\t\t\t\tif (newHash) {
\t\t\t\t\t\t\t\t\thash = newHash;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\toptions : {type : 'post'},
\t\t\t\t\t\t\t\t\tdata : {
\t\t\t\t\t\t\t\t\t\tcmd     : 'put',
\t\t\t\t\t\t\t\t\t\ttarget  : hash,
\t\t\t\t\t\t\t\t\t\tencoding : encoding || data.encoding,
\t\t\t\t\t\t\t\t\t\tcontent : data
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tnotify : {type : 'save', cnt : 1},
\t\t\t\t\t\t\t\t\tsyncOnFail : true,
\t\t\t\t\t\t\t\t\tpreventFail : true,
\t\t\t\t\t\t\t\t\tnavigate : {
\t\t\t\t\t\t\t\t\t\ttarget : 'changed',
\t\t\t\t\t\t\t\t\t\ttoast : {
\t\t\t\t\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('btnSave')])}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t\tsaveDfd.reject();
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\trequestAnimationFrame(function(){
\t\t\t\t\t\t\t\t\t\tta.trigger('focus');
\t\t\t\t\t\t\t\t\t\tta.editor && ta.editor.focus(ta[0], ta.editor.instance);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tsaveDfd.resolve();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.fail(function(error) {
\t\t\t\t\tvar err = fm.parseError(error);
\t\t\t\t\terr = Array.isArray(err)? err[0] : err;
\t\t\t\t\tif (file.encoding) {
\t\t\t\t\t\tfile.encoding = '';
\t\t\t\t\t\tfm.cache(file, 'change');
\t\t\t\t\t}
\t\t\t\t\t(err !== 'errConvUTF8') && fm.sync();
\t\t\t\t\tdfrd.reject(error);
\t\t\t\t});
\t\t\t}

\t\t\treturn dfrd.promise();
\t\t},
\t\t
\t\t/**
\t\t * Current editors of selected files
\t\t * 
\t\t * @type Object
\t\t */
\t\teditors = {},
\t\t
\t\t/**
\t\t * Fallback editor (Simple text editor)
\t\t * 
\t\t * @type Object
\t\t */
\t\tfallbackEditor = {
\t\t\t// Simple Text (basic textarea editor)
\t\t\tinfo : {
\t\t\t\tid : 'textarea',
\t\t\t\tname : 'TextArea',
\t\t\t\tuseTextAreaEvent : true
\t\t\t},
\t\t\tload : function(textarea) {
\t\t\t\t// trigger event 'editEditorPrepare'
\t\t\t\tthis.trigger('Prepare', {
\t\t\t\t\tnode: textarea,
\t\t\t\t\teditorObj: void(0),
\t\t\t\t\tinstance: void(0),
\t\t\t\t\topts: {}
\t\t\t\t});
\t\t\t\ttextarea.setSelectionRange && textarea.setSelectionRange(0, 0);
\t\t\t\t\$(textarea).trigger('focus').show();
\t\t\t},
\t\t\tsave : function(){}
\t\t},

\t\t/**
\t\t * Set current editors
\t\t * 
\t\t * @param  Object  file object
\t\t * @param  Number  cnt  count of selected items
\t\t * @return Void
\t\t */
\t\tsetEditors = function(file, cnt) {
\t\t\tvar mimeMatch = function(fileMime, editorMimes){
\t\t\t\t\tif (!editorMimes) {
\t\t\t\t\t\treturn fm.mimeIsText(fileMime);
\t\t\t\t\t} else {
\t\t\t\t\t\tif (editorMimes[0] === '*' || \$.inArray(fileMime, editorMimes) !== -1) {
\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t}
\t\t\t\t\t\tvar i, l;
\t\t\t\t\t\tl = editorMimes.length;
\t\t\t\t\t\tfor (i = 0; i < l; i++) {
\t\t\t\t\t\t\tif (fileMime.indexOf(editorMimes[i]) === 0) {
\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\textMatch = function(fileName, editorExts){
\t\t\t\t\tif (!editorExts || !editorExts.length) {
\t\t\t\t\t\treturn true;
\t\t\t\t\t}
\t\t\t\t\tvar ext = fileName.replace(/^.+\\.([^.]+)|(.+)\$/, '\$1\$2').toLowerCase(),
\t\t\t\t\ti, l;
\t\t\t\t\tl = editorExts.length;
\t\t\t\t\tfor (i = 0; i < l; i++) {
\t\t\t\t\t\tif (ext === editorExts[i].toLowerCase()) {
\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\treturn false;
\t\t\t\t},
\t\t\t\toptEditors = self.options.editors || [],
\t\t\t\tcwdWrite = fm.cwd().write;
\t\t\t
\t\t\tstored = fm.storage('storedEditors') || {};
\t\t\teditors = {};
\t\t\tif (!optEditors.length) {
\t\t\t\toptEditors = [fallbackEditor];
\t\t\t}
\t\t\t\$.each(optEditors, function(i, editor) {
\t\t\t\tvar name;
\t\t\t\tif ((cnt === 1 || !editor.info.single)
\t\t\t\t\t\t&& ((!editor.info || !editor.info.converter)? file.write : cwdWrite)
\t\t\t\t\t\t&& (file.size > 0 || (!editor.info.converter && editor.info.canMakeEmpty !== false && fm.mimesCanMakeEmpty[file.mime]))
\t\t\t\t\t\t&& (!editor.info.maxSize || file.size <= editor.info.maxSize)
\t\t\t\t\t\t&& mimeMatch(file.mime, editor.mimes || null)
\t\t\t\t\t\t&& extMatch(file.name, editor.exts || null)
\t\t\t\t\t\t&& typeof editor.load == 'function'
\t\t\t\t\t\t&& typeof editor.save == 'function') {
\t\t\t\t\t
\t\t\t\t\tname = editor.info.name? editor.info.name : ('Editor ' + i);
\t\t\t\t\teditor.id = editor.info.id? editor.info.id : ('editor' + i),
\t\t\t\t\teditor.name = name;
\t\t\t\t\teditor.i18n = fm.i18n(name);
\t\t\t\t\teditors[editor.id] = editor;
\t\t\t\t}
\t\t\t});
\t\t\treturn Object.keys(editors).length? true : false;
\t\t},
\t\tstore = function(mime, editor) {
\t\t\tif (mime && editor) {
\t\t\t\tif (!\$.isPlainObject(stored)) {
\t\t\t\t\tstored = {};
\t\t\t\t}
\t\t\t\tstored[mime] = editor.id;
\t\t\t\tfm.storage('storedEditors', stored);
\t\t\t\tfm.trigger('selectfiles', {files : fm.selected()});
\t\t\t}
\t\t},
\t\tuseStoredEditor = function() {
\t\t\tvar d = fm.storage('useStoredEditor');
\t\t\treturn d? (d > 0) : self.options.useStoredEditor;
\t\t},
\t\teditorMaximized = function() {
\t\t\tvar d = fm.storage('editorMaximized');
\t\t\treturn d? (d > 0) : self.options.editorMaximized;
\t\t},
\t\tgetSubMenuRaw = function(files, callback) {
\t\t\tvar subMenuRaw = [];
\t\t\t\$.each(editors, function(id, ed) {
\t\t\t\tsubMenuRaw.push(
\t\t\t\t\t{
\t\t\t\t\t\tlabel    : fm.escape(ed.i18n),
\t\t\t\t\t\ticon     : ed.info && ed.info.icon? ed.info.icon : 'edit',
\t\t\t\t\t\toptions  : { iconImg: ed.info && ed.info.iconImg? fm.baseUrl + ed.info.iconImg : void(0) },
\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\tstore(files[0].mime, ed);
\t\t\t\t\t\t\tcallback && callback.call(ed);
\t\t\t\t\t\t}
\t\t\t\t\t}\t\t
\t\t\t\t);
\t\t\t});
\t\t\treturn subMenuRaw;
\t\t},
\t\tgetStoreId = function(name) {
\t\t\t// for compatibility to previous version
\t\t\treturn name.toLowerCase().replace(/ +/g, '');
\t\t},
\t\tgetStoredEditor = function(mime) {
\t\t\tvar name = stored[mime];
\t\t\treturn name && Object.keys(editors).length? editors[getStoreId(name)] : void(0);
\t\t},
\t\tinfoRequest = function() {

\t\t},
\t\tstored;
\t
\t// make public method
\tthis.getEncSelect = getEncSelect;

\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+e'
\t}];
\t
\tthis.init = function() {
\t\tvar self = this,
\t\t\tfm   = this.fm,
\t\t\topts = this.options,
\t\t\tcmdChecks = [],
\t\t\tccData, dfd;
\t\t
\t\tthis.onlyMimes = this.options.mimes || [];
\t\t
\t\tfm.one('open', function() {
\t\t\t// editors setup
\t\t\tif (opts.editors && Array.isArray(opts.editors)) {
\t\t\t\tfm.trigger('canMakeEmptyFile', {mimes: Object.keys(fm.storage('mkfileTextMimes') || {}).concat(opts.makeTextMimes || ['text/plain'])});
\t\t\t\t\$.each(opts.editors, function(i, editor) {
\t\t\t\t\tif (editor.info && editor.info.cmdCheck) {
\t\t\t\t\t\tcmdChecks.push(editor.info.cmdCheck);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (cmdChecks.length) {
\t\t\t\t\tif (fm.api >= 2.1030) {
\t\t\t\t\t\tdfd = fm.request({
\t\t\t\t\t\t\tdata : {
\t\t\t\t\t\t\t\tcmd: 'editor',
\t\t\t\t\t\t\t\tname: cmdChecks,
\t\t\t\t\t\t\t\tmethod: 'enabled'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t}).done(function(d) {
\t\t\t\t\t\t\tccData = d;
\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\tccData = {};
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tccData = {};
\t\t\t\t\t\tdfd = \$.Deferred().resolve();
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tdfd = \$.Deferred().resolve();
\t\t\t\t}
\t\t\t\t
\t\t\t\tdfd.always(function() {
\t\t\t\t\tif (ccData) {
\t\t\t\t\t\topts.editors = \$.grep(opts.editors, function(e) {
\t\t\t\t\t\t\tif (e.info && e.info.cmdCheck) {
\t\t\t\t\t\t\t\treturn ccData[e.info.cmdCheck]? true : false;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\treturn true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\t\$.each(opts.editors, function(i, editor) {
\t\t\t\t\t\tif (editor.setup && typeof editor.setup === 'function') {
\t\t\t\t\t\t\teditor.setup.call(editor, opts, fm);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (!editor.disabled) {
\t\t\t\t\t\t\tif (editor.mimes && Array.isArray(editor.mimes)) {
\t\t\t\t\t\t\t\tmimesSingle = mimesSingle.concat(editor.mimes);
\t\t\t\t\t\t\t\tif (!editor.info || !editor.info.single) {
\t\t\t\t\t\t\t\t\tmimes = mimes.concat(editor.mimes);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (!allowAll && editor.mimes && editor.mimes[0] === '*') {
\t\t\t\t\t\t\t\tallowAll = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (!editor.info) {
\t\t\t\t\t\t\t\teditor.info = {};
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (editor.info.integrate) {
\t\t\t\t\t\t\t\tfm.trigger('helpIntegration', Object.assign({cmd: 'edit'}, editor.info.integrate));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (editor.info.canMakeEmpty) {
\t\t\t\t\t\t\t\tfm.trigger('canMakeEmptyFile', {mimes: Array.isArray(editor.info.canMakeEmpty)? editor.info.canMakeEmpty : editor.mimes});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tmimesSingle = (\$.uniqueSort || \$.unique)(mimesSingle);
\t\t\t\t\tmimes = (\$.uniqueSort || \$.unique)(mimes);
\t\t\t\t\t
\t\t\t\t\topts.editors = \$.grep(opts.editors, function(e) {
\t\t\t\t\t\treturn e.disabled? false : true;
\t\t\t\t\t});
\t\t\t\t});
\t\t\t}
\t\t})
\t\t.bind('select', function() {
\t\t\teditors = null;
\t\t})
\t\t.bind('contextmenucreate', function(e) {
\t\t\tvar file, editor,
\t\t\t\tsingle = function(editor) {
\t\t\t\t\tvar title = self.title;
\t\t\t\t\tfm.one('contextmenucreatedone', function() {
\t\t\t\t\t\tself.title = title;
\t\t\t\t\t});
\t\t\t\t\tself.title = fm.escape(editor.i18n);
\t\t\t\t\tif (editor.info && editor.info.iconImg) {
\t\t\t\t\t\tself.contextmenuOpts = {
\t\t\t\t\t\t\ticonImg: fm.baseUrl + editor.info.iconImg
\t\t\t\t\t\t};
\t\t\t\t\t}
\t\t\t\t\tdelete self.variants;
\t\t\t\t};
\t\t\t
\t\t\tself.contextmenuOpts = void(0);
\t\t\tif (e.data.type === 'files' && self.enabled()) {
\t\t\t\tfile = fm.file(e.data.targets[0]);
\t\t\t\tif (setEditors(file, e.data.targets.length)) {
\t\t\t\t\tif (Object.keys(editors).length > 1) {
\t\t\t\t\t\tif (!useStoredEditor() || !(editor = getStoredEditor(file.mime))) {
\t\t\t\t\t\t\tdelete self.extra;
\t\t\t\t\t\t\tself.variants = [];
\t\t\t\t\t\t\t\$.each(editors, function(id, editor) {
\t\t\t\t\t\t\t\tself.variants.push([{ editor: editor }, editor.i18n, editor.info && editor.info.iconImg? fm.baseUrl + editor.info.iconImg : 'edit']);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tsingle(editor);
\t\t\t\t\t\t\tself.extra = {
\t\t\t\t\t\t\t\ticon: 'menu',
\t\t\t\t\t\t\t\tnode: \$('<span></span>')
\t\t\t\t\t\t\t\t\t.attr({title: fm.i18n('select')})
\t\t\t\t\t\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\t\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tvar node = \$(this);
\t\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\t\t\t\t\t\traw: getSubMenuRaw(fm.selectedFiles(), function() {
\t\t\t\t\t\t\t\t\t\t\t\tvar hashes = fm.selected();
\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('edit', hashes, {editor: this});
\t\t\t\t\t\t\t\t\t\t\t\tfm.trigger('selectfiles', {files : hashes});
\t\t\t\t\t\t\t\t\t\t\t}),
\t\t\t\t\t\t\t\t\t\t\tx: node.offset().left,
\t\t\t\t\t\t\t\t\t\t\ty: node.offset().top
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t};
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tsingle(editors[Object.keys(editors)[0]]);
\t\t\t\t\t\tdelete self.extra;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t})
\t\t.bind('canMakeEmptyFile', function(e) {
\t\t\tif (e.data && e.data.resetTexts) {
\t\t\t\tvar defs = fm.arrayFlip(self.options.makeTextMimes || ['text/plain']),
\t\t\t\t\thides = self.getMkfileHides();

\t\t\t\t\$.each((fm.storage('mkfileTextMimes') || {}), function(mime, type) {
\t\t\t\t\tif (!defs[mime]) {
\t\t\t\t\t\tdelete fm.mimesCanMakeEmpty[mime];
\t\t\t\t\t\tdelete hides[mime];
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tfm.storage('mkfileTextMimes', null);
\t\t\t\tif (Object.keys(hides).length) {
\t\t\t\t\tfm.storage('mkfileHides', hides);
\t\t\t\t} else {
\t\t\t\t\tfm.storage('mkfileHides', null);
\t\t\t\t}
\t\t\t}
\t\t});
\t};
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;

\t\treturn cnt && filter(sel).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(select, opts) {
\t\tvar fm    = this.fm, 
\t\t\tfiles = filter(this.files(select)),
\t\t\thashes = \$.map(files, function(f) { return f.hash; }),
\t\t\tlist  = [],
\t\t\teditor = opts && opts.editor? opts.editor : null,
\t\t\tnode = \$(opts && opts._currentNode? opts._currentNode : fm.cwdHash2Elm(hashes[0])),
\t\t\tgetEditor = function() {
\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\tstoredId;
\t\t\t\t
\t\t\t\tif (!editor && Object.keys(editors).length > 1) {
\t\t\t\t\tif (useStoredEditor() && (editor = getStoredEditor(files[0].mime))) {
\t\t\t\t\t\treturn dfd.resolve(editor);
\t\t\t\t\t}
\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\traw: getSubMenuRaw(files, function() {
\t\t\t\t\t\t\tdfd.resolve(this);
\t\t\t\t\t\t}),
\t\t\t\t\t\tx: node.offset().left,
\t\t\t\t\t\ty: node.offset().top + 22,
\t\t\t\t\t\topened: function() {
\t\t\t\t\t\t\tfm.one('closecontextmenu',function() {
\t\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\t\tif (dfd.state() === 'pending') {
\t\t\t\t\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tfm.trigger('selectfiles', {files : hashes});
\t\t\t\t\t
\t\t\t\t\treturn dfd;
\t\t\t\t} else {
\t\t\t\t\tObject.keys(editors).length > 1 && editor && store(files[0].mime, editor);
\t\t\t\t\treturn dfd.resolve(editor? editor : (Object.keys(editors).length? editors[Object.keys(editors)[0]] : null));
\t\t\t\t}
\t\t\t},
\t\t\tdfrd = \$.Deferred(),
\t\t\tfile;

\t\tif (editors === null) {
\t\t\tsetEditors(files[0], hashes.length);
\t\t}
\t\t
\t\tif (!node.length) {
\t\t\tnode = fm.getUI('cwd');
\t\t}
\t\t
\t\tgetEditor().done(function(editor) {
\t\t\twhile ((file = files.shift())) {
\t\t\t\tlist.push(edit(file, (file.encoding || void(0)), editor).fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t}));
\t\t\t}
\t\t\t
\t\t\tif (list.length) { 
\t\t\t\t\$.when.apply(null, list).done(function() {
\t\t\t\t\tdfrd.resolve();
\t\t\t\t}).fail(function() {
\t\t\t\t\tdfrd.reject();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfrd.reject();
\t\t\t}
\t\t}).fail(function() {
\t\t\tdfrd.reject();
\t\t});
\t\t
\t\treturn dfrd;
\t};

\tthis.getMkfileHides = function() {
\t\treturn fm.storage('mkfileHides') || fm.arrayFlip(self.options.mkfileHideMimes || []);
\t};

};


/*
 * File: /js/commands/empty.js
 */

/**
 * @class elFinder command \"empty\".
 * Empty the folder
 *
 * @type  elFinder.command
 * @author  Naoki Sawada
 */
elFinder.prototype.commands.empty = function() {
\t\tvar self, fm,
\t\tselFiles = function(select) {
\t\t\tvar sel = self.files(select);
\t\t\tif (!sel.length) {
\t\t\t\tsel = [ fm.cwd() ];
\t\t\t}
\t\t\treturn sel;
\t\t};
\t
\tthis.linkedCmds = ['rm'];
\t
\tthis.init = function() {
\t\t// lazy assign to make possible to become superclass
\t\tself = this;
\t\tfm = this.fm;
\t};

\tthis.getstate = function(select) {
\t\tvar sel = selFiles(select),
\t\t\tcnt;
\t\t
\t\tcnt = sel.length;
\t\treturn \$.grep(sel, function(f) { return f.read && f.write && f.mime === 'directory' ? true : false; }).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar dirs = selFiles(hashes),
\t\t\tcnt  = dirs.length,
\t\t\tdfrd = \$.Deferred()
\t\t\t\t.done(function() {
\t\t\t\t\tvar data = {changed: {}};
\t\t\t\t\tfm.toast({msg: fm.i18n(['\"'+success.join('\", ')+'\"', 'complete', fm.i18n('cmdempty')])});
\t\t\t\t\t\$.each(dirs, function(i, dir) {
\t\t\t\t\t\tdata.changed[dir.hash] = dir;
\t\t\t\t\t});
\t\t\t\t\tfm.change(data);
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\tvar cwd = fm.cwd().hash;
\t\t\t\t\tfm.trigger('selectfiles', {files: \$.map(dirs, function(d) { return cwd === d.phash? d.hash : null; })});
\t\t\t\t}),
\t\t\tsuccess = [],
\t\t\tdone = function(res) {
\t\t\t\tif (typeof res === 'number') {
\t\t\t\t\tsuccess.push(dirs[res].name);
\t\t\t\t\tdelete dirs[res].dirs;
\t\t\t\t} else {
\t\t\t\t\tres && fm.error(res);
\t\t\t\t}
\t\t\t\t(--cnt < 1) && dfrd[success.length? 'resolve' : 'reject']();
\t\t\t};

\t\t\$.each(dirs, function(i, dir) {
\t\t\tvar tm;
\t\t\tif (!(dir.write && dir.mime === 'directory')) {
\t\t\t\tdone(['errEmpty', dir.name, 'errPerm']);
\t\t\t\treturn null;
\t\t\t}
\t\t\tif (!fm.isCommandEnabled('rm', dir.hash)) {
\t\t\t\tdone(['errCmdNoSupport', '\"rm\"']);
\t\t\t\treturn null;
\t\t\t}
\t\t\ttm = setTimeout(function() {
\t\t\t\tfm.notify({type : 'search', cnt : 1, hideCnt : cnt > 1? false : true});
\t\t\t}, fm.notifyDelay);
\t\t\tfm.request({
\t\t\t\tdata : {cmd  : 'open', target : dir.hash},
\t\t\t\tpreventDefault : true,
\t\t\t\tasNotOpen : true
\t\t\t}).done(function(data) {
\t\t\t\tvar targets = [];
\t\t\t\ttm && clearTimeout(tm);
\t\t\t\tif (fm.ui.notify.children('.elfinder-notify-search').length) {
\t\t\t\t\tfm.notify({type : 'search', cnt : -1, hideCnt : cnt > 1? false : true});
\t\t\t\t}
\t\t\t\tif (data && data.files && data.files.length) {
\t\t\t\t\tif (data.files.length > fm.maxTargets) {
\t\t\t\t\t\tdone(['errEmpty', dir.name, 'errMaxTargets', fm.maxTargets]);
\t\t\t\t\t} else {
\t\t\t\t\t\tfm.updateCache(data);
\t\t\t\t\t\t\$.each(data.files, function(i, f) {
\t\t\t\t\t\t\tif (!f.write || f.locked) {
\t\t\t\t\t\t\t\tdone(['errEmpty', dir.name, 'errRm', f.name, 'errPerm']);
\t\t\t\t\t\t\t\ttargets = [];
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\ttargets.push(f.hash);
\t\t\t\t\t\t});
\t\t\t\t\t\tif (targets.length) {
\t\t\t\t\t\t\tfm.exec('rm', targets, { _userAction : true, addTexts : [ fm.i18n('folderToEmpty', dir.name) ] })
\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\tfm.trigger('unselectfiles', {files: fm.selected()});
\t\t\t\t\t\t\t\tdone(fm.parseError(error) || '');
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function() { done(i); });
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tfm.toast({ mode: 'warning', msg: fm.i18n('filderIsEmpty', dir.name)});
\t\t\t\t\tdone('');
\t\t\t\t}
\t\t\t}).fail(function(error) {
\t\t\t\tdone(fm.parseError(error) || '');
\t\t\t});
\t\t});
\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/extract.js
 */

/**
 * @class  elFinder command \"extract\"
 * Extract files from archive
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.extract = function() {
\t\tvar self    = this,
\t\tfm      = self.fm,
\t\tmimes   = [],
\t\tfilter  = function(files) {
\t\t\treturn \$.grep(files, function(file) { 
\t\t\t\treturn file.read && \$.inArray(file.mime, mimes) !== -1 ? true : false;
\t\t\t});
\t\t};
\t
\tthis.variants = [];
\tthis.disableOnSearch = true;
\t
\t// Update mimes list on open/reload
\tfm.bind('open reload', function() {
\t\tmimes = fm.option('archivers')['extract'] || [];
\t\tif (fm.api > 2) {
\t\t\tself.variants = [[{makedir: true}, fm.i18n('cmdmkdir')], [{}, fm.i18n('btnCwd')]];
\t\t} else {
\t\t\tself.variants = [[{}, fm.i18n('btnCwd')]];
\t\t}
\t\tself.change();
\t});
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;
\t\t
\t\treturn cnt && this.fm.cwd().write && filter(sel).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes, opts) {
\t\tvar files    = this.files(hashes),
\t\t\tdfrd     = \$.Deferred(),
\t\t\tcnt      = files.length,
\t\t\tmakedir  = opts && opts.makedir ? 1 : 0,
\t\t\ti, error,
\t\t\tdecision;

\t\tvar overwriteAll = false;
\t\tvar omitAll = false;
\t\tvar mkdirAll = 0;

\t\tvar names = \$.map(fm.files(hashes), function(file) { return file.name; });
\t\tvar map = {};
\t\t\$.grep(fm.files(hashes), function(file) {
\t\t\tmap[file.name] = file;
\t\t\treturn false;
\t\t});
\t\t
\t\tvar decide = function(decision) {
\t\t\tswitch (decision) {
\t\t\t\tcase 'overwrite_all' :
\t\t\t\t\toverwriteAll = true;
\t\t\t\t\tbreak;
\t\t\t\tcase 'omit_all':
\t\t\t\t\tomitAll = true;
\t\t\t\t\tbreak;
\t\t\t}
\t\t};

\t\tvar unpack = function(file) {
\t\t\tif (!(file.read && fm.file(file.phash).write)) {
\t\t\t\terror = ['errExtract', file.name, 'errPerm'];
\t\t\t\tfm.error(error);
\t\t\t\tdfrd.reject(error);
\t\t\t} else if (\$.inArray(file.mime, mimes) === -1) {
\t\t\t\terror = ['errExtract', file.name, 'errNoArchive'];
\t\t\t\tfm.error(error);
\t\t\t\tdfrd.reject(error);
\t\t\t} else {
\t\t\t\tfm.request({
\t\t\t\t\tdata:{cmd:'extract', target:file.hash, makedir:makedir},
\t\t\t\t\tnotify:{type:'extract', cnt:1},
\t\t\t\t\tsyncOnFail:true,
\t\t\t\t\tnavigate:{
\t\t\t\t\t\ttoast : makedir? {
\t\t\t\t\t\t\tincwd    : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}},
\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}}
\t\t\t\t\t\t} : {
\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')])}
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.fail(function (error) {
\t\t\t\t\tif (dfrd.state() != 'rejected') {
\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.done(function () {
\t\t\t\t});
\t\t\t}
\t\t};
\t\t
\t\tvar confirm = function(files, index) {
\t\t\tvar file = files[index],
\t\t\tname = fm.splitFileExtention(file.name)[0],
\t\t\texisted = (\$.inArray(name, names) >= 0),
\t\t\tnext = function(){
\t\t\t\tif((index+1) < cnt) {
\t\t\t\t\tconfirm(files, index+1);
\t\t\t\t} else {
\t\t\t\t\tdfrd.resolve();
\t\t\t\t}
\t\t\t};
\t\t\tif (!makedir && existed && map[name].mime != 'directory') {
\t\t\t\tfm.confirm(
\t\t\t\t\t{
\t\t\t\t\t\ttitle : fm.i18n('ntfextract'),
\t\t\t\t\t\ttext  : ['errExists', name, 'confirmRepl'],
\t\t\t\t\t\taccept:{
\t\t\t\t\t\t\tlabel : 'btnYes',
\t\t\t\t\t\t\tcallback:function (all) {
\t\t\t\t\t\t\t\tdecision = all ? 'overwrite_all' : 'overwrite';
\t\t\t\t\t\t\t\tdecide(decision);
\t\t\t\t\t\t\t\tif(!overwriteAll && !omitAll) {
\t\t\t\t\t\t\t\t\tif('overwrite' == decision) {
\t\t\t\t\t\t\t\t\t\tunpack(file);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif((index+1) < cnt) {
\t\t\t\t\t\t\t\t\t\tconfirm(files, index+1);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else if(overwriteAll) {
\t\t\t\t\t\t\t\t\tfor (i = index; i < cnt; i++) {
\t\t\t\t\t\t\t\t\t\tunpack(files[i]);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\treject : {
\t\t\t\t\t\t\tlabel : 'btnNo',
\t\t\t\t\t\t\tcallback:function (all) {
\t\t\t\t\t\t\t\tdecision = all ? 'omit_all' : 'omit';
\t\t\t\t\t\t\t\tdecide(decision);
\t\t\t\t\t\t\t\tif(!overwriteAll && !omitAll && (index+1) < cnt) {
\t\t\t\t\t\t\t\t\tconfirm(files, index+1);
\t\t\t\t\t\t\t\t} else if (omitAll) {
\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\tlabel : 'btnCancel',
\t\t\t\t\t\t\tcallback:function () {
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tall : ((index+1) < cnt)
\t\t\t\t\t}
\t\t\t\t);
\t\t\t} else if (!makedir) {
\t\t\t\tif (mkdirAll == 0) {
\t\t\t\t\tfm.confirm({
\t\t\t\t\t\ttitle : fm.i18n('cmdextract'),
\t\t\t\t\t\ttext  : [fm.i18n('cmdextract')+' \"'+file.name+'\"', 'confirmRepl'],
\t\t\t\t\t\taccept:{
\t\t\t\t\t\t\tlabel : 'btnYes',
\t\t\t\t\t\t\tcallback:function (all) {
\t\t\t\t\t\t\t\tall && (mkdirAll = 1);
\t\t\t\t\t\t\t\tunpack(file);
\t\t\t\t\t\t\t\tnext();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\treject : {
\t\t\t\t\t\t\tlabel : 'btnNo',
\t\t\t\t\t\t\tcallback:function (all) {
\t\t\t\t\t\t\t\tall && (mkdirAll = -1);
\t\t\t\t\t\t\t\tnext();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\tlabel : 'btnCancel',
\t\t\t\t\t\t\tcallback:function () {
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tall : ((index+1) < cnt)
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\t(mkdirAll > 0) && unpack(file);
\t\t\t\t\tnext();
\t\t\t\t}
\t\t\t} else {
\t\t\t\tunpack(file);
\t\t\t\tnext();
\t\t\t}
\t\t};
\t\t
\t\tif (!(this.enabled() && cnt && mimes.length)) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tif(cnt > 0) {
\t\t\tconfirm(files, 0);
\t\t}

\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/forward.js
 */

/**
 * @class  elFinder command \"forward\"
 * Open next visited folder
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.forward = function() {
\t\tthis.alwaysEnabled = true;
\tthis.updateOnSelect = true;
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+right'
\t}];
\t
\tthis.getstate = function() {
\t\treturn this.fm.history.canForward() ? 0 : -1;
\t};
\t
\tthis.exec = function() {
\t\treturn this.fm.history.forward();
\t};
\t
}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/fullscreen.js
 */

/**
 * @class  elFinder command \"fullscreen\"
 * elFinder node to full scrren mode
 *
 * @author Naoki Sawada
 **/

elFinder.prototype.commands.fullscreen = function() {
\t\tvar self   = this,
\t\tfm     = this.fm,
\t\tupdate = function(e, data) {
\t\t\te.preventDefault();
\t\t\te.stopPropagation();
\t\t\tif (data && data.fullscreen) {
\t\t\t\tself.update(void(0), (data.fullscreen === 'on'));
\t\t\t}
\t\t};

\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.syncTitleOnChange = true;
\tthis.value = false;

\tthis.options = {
\t\tui : 'fullscreenbutton'
\t};

\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function() {
\t\tvar node = fm.getUI().get(0),
\t\t\tfull = (node === fm.toggleFullscreen(node));
\t\tself.title = fm.i18n(full ? 'reinstate' : 'cmdfullscreen');
\t\tself.update(void(0), full);
\t\treturn \$.Deferred().resolve();
\t};
\t
\tfm.bind('init', function() {
\t\tfm.getUI().off('resize.' + fm.namespace, update).on('resize.' + fm.namespace, update);
\t});
};


/*
 * File: /js/commands/getfile.js
 */

/**
 * @class elFinder command \"getfile\". 
 * Return selected files info into outer callback.
 * For use elFinder with wysiwyg editors etc.
 *
 * @author Dmitry (dio) Levashov, dio@std42.ru
 **/
(elFinder.prototype.commands.getfile = function() {
\t\tvar self   = this,
\t\tfm     = this.fm,
\t\tfilter = function(files) {
\t\t\tvar o = self.options;

\t\t\tfiles = \$.grep(files, function(file) {
\t\t\t\treturn (file.mime != 'directory' || o.folders) && file.read ? true : false;
\t\t\t});

\t\t\treturn o.multiple || files.length == 1 ? files : [];
\t\t};
\t
\tthis.alwaysEnabled = true;
\tthis.callback      = fm.options.getFileCallback;
\tthis._disabled     = typeof(this.callback) == 'function';
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;
\t\t\t
\t\treturn this.callback && cnt && filter(sel).length == cnt ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar fm    = this.fm,
\t\t\topts  = this.options,
\t\t\tfiles = this.files(hashes),
\t\t\tcnt   = files.length,
\t\t\turl   = fm.option('url'),
\t\t\ttmb   = fm.option('tmbUrl'),
\t\t\tdfrd  = \$.Deferred()
\t\t\t\t.done(function(data) {
\t\t\t\t\tvar res,
\t\t\t\t\t\tdone = function() {
\t\t\t\t\t\t\tif (opts.oncomplete == 'close') {
\t\t\t\t\t\t\t\tfm.hide();
\t\t\t\t\t\t\t} else if (opts.oncomplete == 'destroy') {
\t\t\t\t\t\t\t\tfm.destroy();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\tfail = function(error) {
\t\t\t\t\t\t\tif (opts.onerror == 'close') {
\t\t\t\t\t\t\t\tfm.hide();
\t\t\t\t\t\t\t} else if (opts.onerror == 'destroy') {
\t\t\t\t\t\t\t\tfm.destroy();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\terror && fm.error(error);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t
\t\t\t\t\tfm.trigger('getfile', {files : data});
\t\t\t\t\t
\t\t\t\t\ttry {
\t\t\t\t\t\tres = self.callback(data, fm);
\t\t\t\t\t} catch(e) {
\t\t\t\t\t\tfail(['Error in `getFileCallback`.', e.message]);
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (typeof res === 'object' && typeof res.done === 'function') {
\t\t\t\t\t\tres.done(done).fail(fail);
\t\t\t\t\t} else {
\t\t\t\t\t\tdone();
\t\t\t\t\t}
\t\t\t\t}),
\t\t\tresult = function(file) {
\t\t\t\treturn opts.onlyURL
\t\t\t\t\t? opts.multiple ? \$.map(files, function(f) { return f.url; }) : files[0].url
\t\t\t\t\t: opts.multiple ? files : files[0];
\t\t\t},
\t\t\treq = [], 
\t\t\ti, file, dim;

\t\tfor (i = 0; i < cnt; i++) {
\t\t\tfile = files[i];
\t\t\tif (file.mime == 'directory' && !opts.folders) {
\t\t\t\treturn dfrd.reject();
\t\t\t}
\t\t\tfile.baseUrl = url;
\t\t\tif (file.url == '1') {
\t\t\t\treq.push(fm.request({
\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\tnotify : {type : 'url', cnt : 1, hideCnt : true},
\t\t\t\t\tpreventDefault : true
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tif (data.url) {
\t\t\t\t\t\tvar rfile = fm.file(this.hash);
\t\t\t\t\t\trfile.url = this.url = data.url;
\t\t\t\t\t}
\t\t\t\t}.bind(file)));
\t\t\t} else {
\t\t\t\tfile.url = fm.url(file.hash);
\t\t\t}
\t\t\tif (! opts.onlyURL) {
\t\t\t\tif (opts.getPath) {
\t\t\t\t\tfile.path = fm.path(file.hash);
\t\t\t\t\tif (file.path === '' && file.phash) {
\t\t\t\t\t\t// get parents
\t\t\t\t\t\t(function() {
\t\t\t\t\t\t\tvar dfd  = \$.Deferred();
\t\t\t\t\t\t\treq.push(dfd);
\t\t\t\t\t\t\tfm.path(file.hash, false, {})
\t\t\t\t\t\t\t\t.done(function(path) {
\t\t\t\t\t\t\t\t\tfile.path = path;
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\t\tfile.path = '';
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\tdfd.resolve();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t})();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tif (file.tmb && file.tmb != 1) {
\t\t\t\t\tfile.tmb = tmb + file.tmb;
\t\t\t\t}
\t\t\t\tif (!file.width && !file.height) {
\t\t\t\t\tif (file.dim) {
\t\t\t\t\t\tdim = file.dim.split('x');
\t\t\t\t\t\tfile.width = dim[0];
\t\t\t\t\t\tfile.height = dim[1];
\t\t\t\t\t} else if (opts.getImgSize && file.mime.indexOf('image') !== -1) {
\t\t\t\t\t\treq.push(fm.request({
\t\t\t\t\t\t\tdata : {cmd : 'dim', target : file.hash},
\t\t\t\t\t\t\tnotify : {type : 'dim', cnt : 1, hideCnt : true},
\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t})
\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\tif (data.dim) {
\t\t\t\t\t\t\t\tvar dim = data.dim.split('x');
\t\t\t\t\t\t\t\tvar rfile = fm.file(this.hash);
\t\t\t\t\t\t\t\trfile.width = this.width = dim[0];
\t\t\t\t\t\t\t\trfile.height = this.height = dim[1];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}.bind(file)));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}
\t\t
\t\tif (req.length) {
\t\t\t\$.when.apply(null, req).always(function() {
\t\t\t\tdfrd.resolve(result(files));
\t\t\t});
\t\t\treturn dfrd;
\t\t}
\t\t
\t\treturn dfrd.resolve(result(files));
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/help.js
 */

/**
 * @class  elFinder command \"help\"
 * \"About\" dialog
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.help = function() {
\t\tvar fm   = this.fm,
\t\tself = this,
\t\tlinktpl = '<div class=\"elfinder-help-link\"> <a href=\"{url}\">{link}</a></div>',
\t\tlinktpltgt = '<div class=\"elfinder-help-link\"> <a href=\"{url}\" target=\"_blank\">{link}</a></div>',
\t\tatpl    = '<div class=\"elfinder-help-team\"><div>{author}</div>{work}</div>',
\t\turl     = /\\{url\\}/,
\t\tlink    = /\\{link\\}/,
\t\tauthor  = /\\{author\\}/,
\t\twork    = /\\{work\\}/,
\t\tr       = 'replace',
\t\tprim    = 'ui-priority-primary',
\t\tsec     = 'ui-priority-secondary',
\t\tlic     = 'elfinder-help-license',
\t\ttab     = '<li class=\"' + fm.res('class', 'tabstab') + ' elfinder-help-tab-{id}\"><a href=\"#'+fm.namespace+'-help-{id}\" class=\"ui-tabs-anchor\">{title}</a></li>',
\t\thtml    = ['<div class=\"ui-tabs ui-widget ui-widget-content ui-corner-all elfinder-help\">', 
\t\t\t\t'<ul class=\"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-top\">'],
\t\tstpl    = '<div class=\"elfinder-help-shortcut\"><div class=\"elfinder-help-shortcut-pattern\">{pattern}</div> {descrip}</div>',
\t\tsep     = '<div class=\"elfinder-help-separator\"></div>',
\t\tselfUrl = \$('base').length? document.location.href.replace(/#.*\$/, '') : '',
\t\tclTabActive = fm.res('class', 'tabsactive'),
\t\t
\t\tgetTheme = function() {
\t\t\tvar src;
\t\t\tif (fm.theme && fm.theme.author) {
\t\t\t\tsrc = atpl[r]('elfinder-help-team', 'elfinder-help-team elfinder-help-term-theme')[r](author, fm.i18n(fm.theme.author) + (fm.theme.email? ' &lt;'+fm.theme.email+'&gt;' : ''))[r](work, fm.i18n('theme') + ' ('+fm.i18n(fm.theme.name)+')');
\t\t\t} else {
\t\t\t\tsrc = '<div class=\"elfinder-help-team elfinder-help-term-theme\" style=\"display:none\"></div>';
\t\t\t}
\t\t\treturn src;
\t\t},

\t\tabout = function() {
\t\t\thtml.push('<div id=\"'+fm.namespace+'-help-about\" class=\"ui-tabs-panel ui-widget-content ui-corner-bottom\"><div class=\"elfinder-help-logo\"></div>');
\t\t\thtml.push('<h3>elFinder</h3>');
\t\t\thtml.push('<div class=\"'+prim+'\">'+fm.i18n('webfm')+'</div>');
\t\t\thtml.push('<div class=\"'+sec+'\">'+fm.i18n('ver')+': '+fm.version+'</div>');
\t\t\thtml.push('<div class=\"'+sec+'\">'+fm.i18n('protocolver')+': <span class=\"apiver\"></span></div>');
\t\t\thtml.push('<div class=\"'+sec+'\">jQuery/jQuery UI: '+\$().jquery+'/'+\$.ui.version+'</div>');

\t\t\thtml.push(sep);
\t\t\t
\t\t\thtml.push(linktpltgt[r](url, 'https://studio-42.github.io/elFinder/')[r](link, fm.i18n('homepage')));
\t\t\thtml.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder/wiki')[r](link, fm.i18n('docs')));
\t\t\thtml.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder')[r](link, fm.i18n('github')));
\t\t\t//html.push(linktpltgt[r](url, 'http://twitter.com/elrte_elfinder')[r](link, fm.i18n('twitter')));
\t\t\t
\t\t\thtml.push(sep);
\t\t\t
\t\t\thtml.push('<div class=\"'+prim+'\">'+fm.i18n('team')+'</div>');
\t\t\t
\t\t\thtml.push(atpl[r](author, 'Dmitry \"dio\" Levashov &lt;dio@std42.ru&gt;')[r](work, fm.i18n('chiefdev')));
\t\t\thtml.push(atpl[r](author, 'Naoki Sawada &lt;hypweb+elfinder@gmail.com&gt;')[r](work, fm.i18n('developer')));
\t\t\thtml.push(atpl[r](author, 'Troex Nevelin &lt;troex@fury.scancode.ru&gt;')[r](work, fm.i18n('maintainer')));
\t\t\thtml.push(atpl[r](author, 'Alexey Sukhotin &lt;strogg@yandex.ru&gt;')[r](work, fm.i18n('contributor')));
\t\t\t
\t\t\tif (fm.i18[fm.lang].translator) {
\t\t\t\t\$.each(fm.i18[fm.lang].translator.split(', '), function() {
\t\t\t\t\thtml.push(atpl[r](author, \$.trim(this))[r](work, fm.i18n('translator')+' ('+fm.i18[fm.lang].language+')'));
\t\t\t\t});\t
\t\t\t}
\t\t\t
\t\t\thtml.push(getTheme());

\t\t\thtml.push(sep);
\t\t\thtml.push('<div class=\"'+lic+'\">'+fm.i18n('icons')+': Pixelmixer, <a href=\"http://p.yusukekamiyamane.com\" target=\"_blank\">Fugue</a>, <a href=\"https://icons8.com\" target=\"_blank\">Icons8</a></div>');
\t\t\t
\t\t\thtml.push(sep);
\t\t\thtml.push('<div class=\"'+lic+'\">Licence: 3-clauses BSD Licence</div>');
\t\t\thtml.push('<div class=\"'+lic+'\">Copyright © 2009-2020, Studio 42</div>');
\t\t\thtml.push('<div class=\"'+lic+'\">„ …'+fm.i18n('dontforget')+' ”</div>');
\t\t\thtml.push('</div>');
\t\t},
\t\tshortcuts = function() {
\t\t\tvar sh = fm.shortcuts();
\t\t\t// shortcuts tab
\t\t\thtml.push('<div id=\"'+fm.namespace+'-help-shortcuts\" class=\"ui-tabs-panel ui-widget-content ui-corner-bottom\">');
\t\t\t
\t\t\tif (sh.length) {
\t\t\t\thtml.push('<div class=\"ui-widget-content elfinder-help-shortcuts\">');
\t\t\t\t\$.each(sh, function(i, s) {
\t\t\t\t\thtml.push(stpl.replace(/\\{pattern\\}/, s[0]).replace(/\\{descrip\\}/, s[1]));
\t\t\t\t});
\t\t\t
\t\t\t\thtml.push('</div>');
\t\t\t} else {
\t\t\t\thtml.push('<div class=\"elfinder-help-disabled\">'+fm.i18n('shortcutsof')+'</div>');
\t\t\t}
\t\t\t
\t\t\t
\t\t\thtml.push('</div>');
\t\t\t
\t\t},
\t\thelp = function() {
\t\t\t// help tab
\t\t\thtml.push('<div id=\"'+fm.namespace+'-help-help\" class=\"ui-tabs-panel ui-widget-content ui-corner-bottom\">');
\t\t\thtml.push('<a href=\"https://github.com/Studio-42/elFinder/wiki\" target=\"_blank\" class=\"elfinder-dont-panic\"><span>DON\\'T PANIC</span></a>');
\t\t\thtml.push('</div>');
\t\t\t// end help
\t\t},
\t\tuseInteg = false,
\t\tintegrations = function() {
\t\t\tuseInteg = true;
\t\t\thtml.push('<div id=\"'+fm.namespace+'-help-integrations\" class=\"ui-tabs-panel ui-widget-content ui-corner-bottom\"></div>');
\t\t},
\t\tuseDebug = false,
\t\tdebug = function() {
\t\t\tuseDebug = true;
\t\t\t// debug tab
\t\t\thtml.push('<div id=\"'+fm.namespace+'-help-debug\" class=\"ui-tabs-panel ui-widget-content ui-corner-bottom\">');
\t\t\thtml.push('<div class=\"ui-widget-content elfinder-help-debug\"><ul></ul></div>');
\t\t\thtml.push('</div>');
\t\t\t// end debug
\t\t},
\t\tdebugRender = function() {
\t\t\tvar render = function(elm, obj) {
\t\t\t\t\$.each(obj, function(k, v) {
\t\t\t\t\telm.append(\$('<dt></dt>').text(k));
\t\t\t\t\tif (typeof v === 'undefined') {
\t\t\t\t\t\telm.append(\$('<dd></dd>').append(\$('<span></span>').text('undfined')));
\t\t\t\t\t} else if (typeof v === 'object' && !v) {
\t\t\t\t\t\telm.append(\$('<dd></dd>').append(\$('<span></span>').text('null')));
\t\t\t\t\t} else if (typeof v === 'object' && (\$.isPlainObject(v) || v.length)) {
\t\t\t\t\t\telm.append( \$('<dd></dd>').append(render(\$('<dl></dl>'), v)));
\t\t\t\t\t} else {
\t\t\t\t\t\telm.append(\$('<dd></dd>').append(\$('<span></span>').text((v && typeof v === 'object')? '[]' : (v? v : '\"\"'))));
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\treturn elm;
\t\t\t},
\t\t\tcnt = debugUL.children('li').length,
\t\t\ttargetL, target, tabId,
\t\t\tinfo, lastUL, lastDIV;
\t\t\t
\t\t\tif (self.debug.options || self.debug.debug) {
\t\t\t\tif (cnt >= 5) {
\t\t\t\t\tlastUL = debugUL.children('li:last');
\t\t\t\t\tlastDIV = debugDIV.children('div:last');
\t\t\t\t\tif (lastDIV.is(':hidden')) {
\t\t\t\t\t\tlastUL.remove();
\t\t\t\t\t\tlastDIV.remove();
\t\t\t\t\t} else {
\t\t\t\t\t\tlastUL.prev().remove();
\t\t\t\t\t\tlastDIV.prev().remove();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\ttabId = fm.namespace + '-help-debug-' + (+new Date());
\t\t\t\ttargetL = \$('<li></li>').html('<a href=\"'+selfUrl+'#'+tabId+'\">'+self.debug.debug.cmd+'</a>').prependTo(debugUL);
\t\t\t\ttarget = \$('<div id=\"'+tabId+'\"></div>').data('debug', self.debug);
\t\t\t\t
\t\t\t\ttargetL.on('click.debugrender', function() {
\t\t\t\t\tvar debug = target.data('debug');
\t\t\t\t\ttarget.removeData('debug');
\t\t\t\t\tif (debug) {
\t\t\t\t\t\ttarget.hide();
\t\t\t\t\t\tif (debug.debug) {
\t\t\t\t\t\t\tinfo = \$('<fieldset>').append(\$('<legend></legend>').text('debug'), render(\$('<dl></dl>'), debug.debug));
\t\t\t\t\t\t\ttarget.append(info);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (debug.options) {
\t\t\t\t\t\t\tinfo = \$('<fieldset>').append(\$('<legend></legend>').text('options'), render(\$('<dl></dl>'), debug.options));
\t\t\t\t\t\t\ttarget.append(info);
\t\t\t\t\t\t}
\t\t\t\t\t\ttarget.show();
\t\t\t\t\t}
\t\t\t\t\ttargetL.off('click.debugrender');
\t\t\t\t});
\t\t\t\t
\t\t\t\tdebugUL.after(target);
\t\t\t\t
\t\t\t\topened && debugDIV.tabs('refresh');
\t\t\t}
\t\t},
\t\tcontent = '',
\t\topened, tabInteg, integDIV, tabDebug, debugDIV, debugUL;
\t
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.state = -1;
\t
\tthis.shortcuts = [{
\t\tpattern     : 'f1',
\t\tdescription : this.title
\t}];
\t
\tfm.bind('load', function() {
\t\tvar parts = self.options.view || ['about', 'shortcuts', 'help', 'integrations', 'debug'],
\t\t\ti, helpSource, tabBase, tabNav, tabs, delta;
\t\t
\t\t// remove 'preference' tab, it moved to command 'preference'
\t\tif ((i = \$.inArray('preference', parts)) !== -1) {
\t\t\tparts.splice(i, 1);
\t\t}
\t\t
\t\t// debug tab require jQueryUI Tabs Widget
\t\tif (! \$.fn.tabs) {
\t\t\tif ((i = \$.inArray(parts, 'debug')) !== -1) {
\t\t\t\tparts.splice(i, 1);
\t\t\t}
\t\t}
\t\t
\t\t\$.each(parts, function(i, title) {
\t\t\thtml.push(tab[r](/\\{id\\}/g, title)[r](/\\{title\\}/, fm.i18n(title)));
\t\t});
\t\t
\t\thtml.push('</ul>');

\t\t\$.inArray('about', parts) !== -1 && about();
\t\t\$.inArray('shortcuts', parts) !== -1 && shortcuts();
\t\tif (\$.inArray('help', parts) !== -1) {
\t\t\thelpSource = fm.i18nBaseUrl + 'help/%s.html.js';
\t\t\thelp();
\t\t}
\t\t\$.inArray('integrations', parts) !== -1 && integrations();
\t\t\$.inArray('debug', parts) !== -1 && debug();
\t\t
\t\thtml.push('</div>');
\t\tcontent = \$(html.join(''));
\t\t
\t\tcontent.find('.ui-tabs-nav li')
\t\t\t.on('mouseenter mouseleave', function(e) {
\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
\t\t\t})
\t\t\t.on('focus blur', 'a', function(e) {
\t\t\t\t\$(e.delegateTarget).toggleClass('ui-state-focus', e.type === 'focusin');
\t\t\t})
\t\t\t.children()
\t\t\t.on('click', function(e) {
\t\t\t\tvar link = \$(this);
\t\t\t\t
\t\t\t\te.preventDefault();
\t\t\t\te.stopPropagation();
\t\t\t\t
\t\t\t\tlink.parent().addClass(clTabActive).siblings().removeClass(clTabActive);
\t\t\t\tcontent.children('.ui-tabs-panel').hide().filter(link.attr('href')).show();
\t\t\t})
\t\t\t.filter(':first').trigger('click');
\t\t
\t\tif (useInteg) {
\t\t\ttabInteg = content.find('.elfinder-help-tab-integrations').hide();
\t\t\tintegDIV = content.find('#'+fm.namespace+'-help-integrations').hide().append(\$('<div class=\"elfinder-help-integrations-desc\"></div>').html(fm.i18n('integrationWith')));
\t\t\tfm.bind('helpIntegration', function(e) {
\t\t\t\tvar ul = integDIV.children('ul:first'),
\t\t\t\t\tdata, elm, cmdUL, cmdCls;
\t\t\t\tif (e.data) {
\t\t\t\t\tif (\$.isPlainObject(e.data)) {
\t\t\t\t\t\tdata = Object.assign({
\t\t\t\t\t\t\tlink: '',
\t\t\t\t\t\t\ttitle: '',
\t\t\t\t\t\t\tbanner: ''
\t\t\t\t\t\t}, e.data);
\t\t\t\t\t\tif (data.title || data.link) {
\t\t\t\t\t\t\tif (!data.title) {
\t\t\t\t\t\t\t\tdata.title = data.link;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (data.link) {
\t\t\t\t\t\t\t\telm = \$('<a></a>').attr('href', data.link).attr('target', '_blank').text(data.title);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\telm = \$('<span></span>').text(data.title);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (data.banner) {
\t\t\t\t\t\t\t\telm = \$('<span></span>').append(\$('<img/>').attr(data.banner), elm);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\telm = \$(e.data);
\t\t\t\t\t\telm.filter('a').each(function() {
\t\t\t\t\t\t\tvar tgt = \$(this);
\t\t\t\t\t\t\tif (!tgt.attr('target')) {
\t\t\t\t\t\t\t\ttgt.attr('target', '_blank');;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tif (elm) {
\t\t\t\t\t\ttabInteg.show();
\t\t\t\t\t\tif (!ul.length) {
\t\t\t\t\t\t\tul = \$('<ul class=\"elfinder-help-integrations\"></ul>').appendTo(integDIV);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (data && data.cmd) {
\t\t\t\t\t\t\tcmdCls = 'elfinder-help-integration-' + data.cmd;
\t\t\t\t\t\t\tcmdUL = ul.find('ul.' + cmdCls);
\t\t\t\t\t\t\tif (!cmdUL.length) {
\t\t\t\t\t\t\t\tcmdUL = \$('<ul class=\"'+cmdCls+'\"></ul>');
\t\t\t\t\t\t\t\tul.append(\$('<li></li>').append(\$('<span></span>').html(fm.i18n('cmd'+data.cmd))).append(cmdUL));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telm = cmdUL.append(\$('<li></li>').append(elm));
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tul.append(\$('<li></li>').append(elm));
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}).bind('themechange', function() {
\t\t\t\tcontent.find('div.elfinder-help-term-theme').replaceWith(getTheme());
\t\t\t});
\t\t}

\t\t// debug
\t\tif (useDebug) {
\t\t\ttabDebug = content.find('.elfinder-help-tab-debug').hide();
\t\t\tdebugDIV = content.find('#'+fm.namespace+'-help-debug').children('div:first');
\t\t\tdebugUL = debugDIV.children('ul:first').on('click', function(e) {
\t\t\t\te.preventDefault();
\t\t\t\te.stopPropagation();
\t\t\t});

\t\t\tself.debug = {};
\t
\t\t\tfm.bind('backenddebug', function(e) {
\t\t\t\t// CAUTION: DO NOT TOUCH `e.data`
\t\t\t\tif (useDebug && e.data && e.data.debug) {
\t\t\t\t\tself.debug = { options : e.data.options, debug : Object.assign({ cmd : fm.currentReqCmd }, e.data.debug) };
\t\t\t\t\tif (self.dialog) {
\t\t\t\t\t\tdebugRender();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t}

\t\tcontent.find('#'+fm.namespace+'-help-about').find('.apiver').text(fm.api);
\t\tself.dialog = self.fmDialog(content, {
\t\t\t\ttitle : self.title,
\t\t\t\twidth : 530,
\t\t\t\tmaxWidth: 'window',
\t\t\t\tmaxHeight: 'window',
\t\t\t\tautoOpen : false,
\t\t\t\tdestroyOnClose : false,
\t\t\t\tclose : function() {
\t\t\t\t\tif (useDebug) {
\t\t\t\t\t\ttabDebug.hide();
\t\t\t\t\t\tdebugDIV.tabs('destroy');
\t\t\t\t\t}
\t\t\t\t\topened = false;
\t\t\t\t}
\t\t\t})
\t\t\t.on('click', function(e) {
\t\t\t\te.stopPropagation();
\t\t\t})
\t\t\t.css({
\t\t\t\toverflow: 'hidden'
\t\t\t});
\t\t
\t\ttabBase = self.dialog.children('.ui-tabs');
\t\ttabNav = tabBase.children('.ui-tabs-nav:first');
\t\ttabs = tabBase.children('.ui-tabs-panel');
\t\tdelta = self.dialog.outerHeight(true) - self.dialog.height();
\t\tself.dialog.closest('.ui-dialog').on('resize', function() {
\t\t\ttabs.height(self.dialog.height() - delta - tabNav.outerHeight(true) - 20);
\t\t});
\t\t
\t\tif (helpSource) {
\t\t\tself.dialog.one('initContents', function() {
\t\t\t\t\$.ajax({
\t\t\t\t\turl: self.options.helpSource? self.options.helpSource : helpSource.replace('%s', fm.lang),
\t\t\t\t\tdataType: 'html'
\t\t\t\t}).done(function(source) {
\t\t\t\t\t\$('#'+fm.namespace+'-help-help').html(source);
\t\t\t\t}).fail(function() {
\t\t\t\t\t\$.ajax({
\t\t\t\t\t\turl: helpSource.replace('%s', 'en'),
\t\t\t\t\t\tdataType: 'html'
\t\t\t\t\t}).done(function(source) {
\t\t\t\t\t\t\$('#'+fm.namespace+'-help-help').html(source);
\t\t\t\t\t});
\t\t\t\t});
\t\t\t});
\t\t}
\t\t
\t\tself.state = 0;

\t\tfm.trigger('helpBuilded', self.dialog);
\t}).one('open', function() {
\t\tvar debug = false;
\t\tfm.one('backenddebug', function() {
\t\t\tdebug =true;
\t\t}).one('opendone', function() {
\t\t\trequestAnimationFrame(function() {
\t\t\t\tif (! debug && useDebug) {
\t\t\t\t\tuseDebug = false;
\t\t\t\t\ttabDebug.hide();
\t\t\t\t\tdebugDIV.hide();
\t\t\t\t\tdebugUL.hide();
\t\t\t\t}
\t\t\t});
\t\t});
\t});
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function(sel, opts) {
\t\tvar tab = opts? opts.tab : void(0),
\t\t\tdebugShow = function() {
\t\t\t\tif (useDebug) {
\t\t\t\t\tdebugDIV.tabs();
\t\t\t\t\tdebugUL.find('a:first').trigger('click');
\t\t\t\t\ttabDebug.show();
\t\t\t\t\topened = true;
\t\t\t\t}
\t\t\t};
\t\tdebugShow();
\t\tthis.dialog.trigger('initContents').elfinderdialog('open').find((tab? '.elfinder-help-tab-'+tab : '.ui-tabs-nav li') + ' a:first').trigger('click');
\t\treturn \$.Deferred().resolve();
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/hidden.js
 */

/**
 * @class  elFinder command \"hidden\"
 * Always hidden command for uiCmdMap
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.hidden = function() {
\t\tthis.hidden = true;
\tthis.updateOnSelect = false;
\tthis.getstate = function() {
\t\treturn -1;
\t};
};

/*
 * File: /js/commands/hide.js
 */

/**
 * @class elFinder command \"hide\".
 * folders/files to hide as personal setting.
 *
 * @type  elFinder.command
 * @author  Naoki Sawada
 */
elFinder.prototype.commands.hide = function() {
\t
\tvar self = this,
\t\tnameCache = {},
\t\thideData, hideCnt, cMenuType, sOrigin;

\tthis.syncTitleOnChange = true;

\tthis.shortcuts = [{
\t\tpattern : 'ctrl+shift+dot',
\t\tdescription : this.fm.i18n('toggleHidden')
\t}];

\tthis.init = function() {
\t\tvar fm = this.fm;
\t\t
\t\thideData = fm.storage('hide') || {items: {}};
\t\thideCnt = Object.keys(hideData.items).length;

\t\tthis.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden');
\t\tself.update(void(0), self.title);
\t};

\tthis.fm.bind('select contextmenucreate closecontextmenu', function(e, fm) {
\t\tvar sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
\t\tif (e.type === 'select' && e.data) {
\t\t\tsOrigin = e.data.origin;
\t\t} else if (e.type === 'contextmenucreate') {
\t\t\tcMenuType = e.data.type;
\t\t}
\t\tif (!sel.length || (((e.type !== 'contextmenucreate' && sOrigin !== 'navbar') || cMenuType === 'cwd') && sel[0] === fm.cwd().hash)) {
\t\t\tself.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden');
\t\t} else {
\t\t\tself.title = fm.i18n('cmdhide');
\t\t}
\t\tif (e.type !== 'closecontextmenu') {
\t\t\tself.update(cMenuType === 'cwd'? (hideCnt? 0 : -1) : void(0), self.title);
\t\t} else {
\t\t\tcMenuType = '';
\t\t\trequestAnimationFrame(function() {
\t\t\t\tself.update(void(0), self.title);
\t\t\t});
\t\t}
\t});

\tthis.getstate = function(sel) {
\t\treturn (this.fm.cookieEnabled && cMenuType !== 'cwd' && (sel || this.fm.selected()).length) || hideCnt? 0 : -1;
\t};

\tthis.exec = function(hashes, opts) {
\t\tvar fm = this.fm,
\t\t\tdfrd = \$.Deferred()
\t\t\t\t.done(function() {
\t\t\t\t\tfm.trigger('hide', {items: items, opts: opts});
\t\t\t\t})
\t\t\t\t.fail(function(error) {
\t\t\t\t\tfm.error(error);
\t\t\t\t}),
\t\t\to = opts || {},
\t\t\titems = o.targets? o.targets : (hashes || fm.selected()),
\t\t\tadded = [],
\t\t\tremoved = [],
\t\t\tnotifyto, files, res;

\t\thideData = fm.storage('hide') || {};
\t\tif (!\$.isPlainObject(hideData)) {
\t\t\thideData = {};
\t\t}
\t\tif (!\$.isPlainObject(hideData.items)) {
\t\t\thideData.items = {};
\t\t}
\t\tif (opts._currentType === 'shortcut' || !items.length || (opts._currentType !== 'navbar' && sOrigin !=='navbar' && items[0] === fm.cwd().hash)) {
\t\t\tif (hideData.show) {
\t\t\t\to.hide = true;
\t\t\t} else if (Object.keys(hideData.items).length) {
\t\t\t\to.show = true;
\t\t\t}
\t\t}
\t\tif (o.reset) {
\t\t\to.show = true;
\t\t\thideCnt = 0;
\t\t}
\t\tif (o.show || o.hide) {
\t\t\tif (o.show) {
\t\t\t\thideData.show = true;
\t\t\t} else {
\t\t\t\tdelete hideData.show;
\t\t\t}
\t\t\tif (o.show) {
\t\t\t\tfm.storage('hide', o.reset? null : hideData);
\t\t\t\tself.title = fm.i18n('hideHidden');
\t\t\t\tself.update(o.reset? -1 : void(0), self.title);
\t\t\t\t\$.each(hideData.items, function(h) {
\t\t\t\t\tvar f = fm.file(h, true);
\t\t\t\t\tif (f && (fm.searchStatus.state || !f.phash || fm.file(f.phash))) {
\t\t\t\t\t\tadded.push(f);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tif (added.length) {
\t\t\t\t\tfm.updateCache({added: added});
\t\t\t\t\tfm.add({added: added});
\t\t\t\t}
\t\t\t\tif (o.reset) {
\t\t\t\t\thideData = {items: {}};
\t\t\t\t}
\t\t\t\treturn dfrd.resolve();
\t\t\t}
\t\t\titems = Object.keys(hideData.items);
\t\t}

\t\tif (items.length) {
\t\t\t\$.each(items, function(i, h) {
\t\t\t\tvar f;
\t\t\t\tif (!hideData.items[h]) {
\t\t\t\t\tf = fm.file(h);
\t\t\t\t\tif (f) {
\t\t\t\t\t\tnameCache[h] = f.i18 || f.name;
\t\t\t\t\t}
\t\t\t\t\thideData.items[h] = nameCache[h]? nameCache[h] : h;
\t\t\t\t}
\t\t\t});
\t\t\thideCnt = Object.keys(hideData.items).length;
\t\t\tfiles = this.files(items);
\t\t\tfm.storage('hide', hideData);
\t\t\tfm.remove({removed: items});
\t\t\tif (hideData.show) {
\t\t\t\tthis.exec(void(0), {hide: true});
\t\t\t}
\t\t\tif (!o.hide) {
\t\t\t\tres = {};
\t\t\t\tres.undo = {
\t\t\t\t\tcmd : 'hide',
\t\t\t\t\tcallback : function() {
\t\t\t\t\t\tvar nData = fm.storage('hide');
\t\t\t\t\t\tif (nData) {
\t\t\t\t\t\t\t\$.each(items, function(i, h) {
\t\t\t\t\t\t\t\tdelete nData.items[h];
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\thideCnt = Object.keys(nData.items).length;
\t\t\t\t\t\t\tfm.storage('hide', nData);
\t\t\t\t\t\t\tfm.trigger('hide', {items: items, opts: {}});
\t\t\t\t\t\t\tself.update(hideCnt? 0 : -1);
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.updateCache({added: files});
\t\t\t\t\t\tfm.add({added: files});
\t\t\t\t\t}
\t\t\t\t};
\t\t\t\tres.redo = {
\t\t\t\t\tcmd : 'hide',
\t\t\t\t\tcallback : function() {
\t\t\t\t\t\treturn fm.exec('hide', void(0), {targets: items});
\t\t\t\t\t}
\t\t\t\t};
\t\t\t}
\t\t}

\t\treturn dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(res);
\t};
};


/*
 * File: /js/commands/home.js
 */

(elFinder.prototype.commands.home = function() {
\t\tthis.title = 'Home';
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+home ctrl+shift+up',
\t\tdescription : 'Home'
\t}];
\t
\tthis.getstate = function() {
\t\tvar root = this.fm.root(),
\t\t\tcwd  = this.fm.cwd().hash;
\t\t\t
\t\treturn root && cwd && root != cwd ? 0: -1;
\t};
\t
\tthis.exec = function() {
\t\treturn this.fm.exec('open', this.fm.root());
\t};
\t

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/info.js
 */

/**
 * @class elFinder command \"info\". 
 * Display dialog with file properties.
 *
 * @author Dmitry (dio) Levashov, dio@std42.ru
 **/
(elFinder.prototype.commands.info = function() {
\t\tvar m   = 'msg',
\t\tfm  = this.fm,
\t\tspclass = 'elfinder-spinner',
\t\tbtnclass = 'elfinder-info-button',
\t\tmsg = {
\t\t\tcalc     : fm.i18n('calc'),
\t\t\tsize     : fm.i18n('size'),
\t\t\tunknown  : fm.i18n('unknown'),
\t\t\tpath     : fm.i18n('path'),
\t\t\taliasfor : fm.i18n('aliasfor'),
\t\t\tmodify   : fm.i18n('modify'),
\t\t\tperms    : fm.i18n('perms'),
\t\t\tlocked   : fm.i18n('locked'),
\t\t\tdim      : fm.i18n('dim'),
\t\t\tkind     : fm.i18n('kind'),
\t\t\tfiles    : fm.i18n('files'),
\t\t\tfolders  : fm.i18n('folders'),
\t\t\troots    : fm.i18n('volumeRoots'),
\t\t\titems    : fm.i18n('items'),
\t\t\tyes      : fm.i18n('yes'),
\t\t\tno       : fm.i18n('no'),
\t\t\tlink     : fm.i18n('link'),
\t\t\towner    : fm.i18n('owner'),
\t\t\tgroup    : fm.i18n('group'),
\t\t\tperm     : fm.i18n('perm'),
\t\t\tgetlink  : fm.i18n('getLink')
\t\t},
\t\tapplyZWSP = function(str, remove) {
\t\t\tif (remove) {
\t\t\t\treturn str.replace(/\\u200B/g, '');
\t\t\t} else {
\t\t\t\treturn str.replace(/(\\/|\\\\)/g, \"\$1\\u200B\");
\t\t\t}
\t\t};
\t
\tthis.items = ['size', 'aliasfor', 'path', 'link', 'dim', 'modify', 'perms', 'locked', 'owner', 'group', 'perm'];
\tif (this.options.custom && Object.keys(this.options.custom).length) {
\t\t\$.each(this.options.custom, function(name, details) {
\t\t\tdetails.label && this.items.push(details.label);
\t\t});
\t}

\tthis.tpl = {
\t\tmain       : '<div class=\"ui-helper-clearfix elfinder-info-title {dirclass}\"><span class=\"elfinder-cwd-icon {class} ui-corner-all\"{style}></span>{title}</div><table class=\"elfinder-info-tb\">{content}</table>',
\t\titemTitle  : '<strong>{name}</strong><span class=\"elfinder-info-kind\">{kind}</span>',
\t\tgroupTitle : '<strong>{items}: {num}</strong>',
\t\trow        : '<tr><td class=\"elfinder-info-label\">{label} : </td><td class=\"{class}\">{value}</td></tr>',
\t\tspinner    : '<span>{text}</span> <span class=\"'+spclass+' '+spclass+'-{name}\"></span>'
\t};
\t
\tthis.alwaysEnabled = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+i'
\t}];
\t
\tthis.init = function() {
\t\t\$.each(msg, function(k, v) {
\t\t\tmsg[k] = fm.i18n(v);
\t\t});
\t};
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar files   = this.files(hashes);
\t\tif (! files.length) {
\t\t\tfiles   = this.files([ this.fm.cwd().hash ]);
\t\t}
\t\tvar self    = this,
\t\t\tfm      = this.fm,
\t\t\to       = this.options,
\t\t\ttpl     = this.tpl,
\t\t\trow     = tpl.row,
\t\t\tcnt     = files.length,
\t\t\tcontent = [],
\t\t\tview    = tpl.main,
\t\t\tl       = '{label}',
\t\t\tv       = '{value}',
\t\t\treqs    = [],
\t\t\treqDfrd = null,
\t\t\topts    = {
\t\t\t\ttitle : fm.i18n('selectionInfo'),
\t\t\t\twidth : 'auto',
\t\t\t\tclose : function() {
\t\t\t\t\t\$(this).elfinderdialog('destroy');
\t\t\t\t\tif (reqDfrd && reqDfrd.state() === 'pending') {
\t\t\t\t\t\treqDfrd.reject();
\t\t\t\t\t}
\t\t\t\t\t\$.grep(reqs, function(r) {
\t\t\t\t\t\tr && r.state() === 'pending' && r.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\tcount = [],
\t\t\treplSpinner = function(msg, name, className) {
\t\t\t\tdialog.find('.'+spclass+'-'+name).parent().html(msg).addClass(className || '');
\t\t\t},
\t\t\tid = fm.namespace+'-info-'+\$.map(files, function(f) { return f.hash; }).join('-'),
\t\t\tdialog = fm.getUI().find('#'+id),
\t\t\tcustomActions = [],
\t\t\tstyle = '',
\t\t\thashClass = 'elfinder-font-mono elfinder-info-hash',
\t\t\tgetHashAlgorisms = [],
\t\t\tndialog  = fm.ui.notify,
\t\t\tsize, tmb, file, title, dcnt, rdcnt, path, hideItems, hashProg;

\t\tif (ndialog.is(':hidden') && ndialog.children('.elfinder-notify').length) {
\t\t\tndialog.elfinderdialog('open').height('auto');
\t\t}

\t\tif (!cnt) {
\t\t\treturn \$.Deferred().reject();
\t\t}
\t\t\t
\t\tif (dialog.length) {
\t\t\tdialog.elfinderdialog('toTop');
\t\t\treturn \$.Deferred().resolve();
\t\t}
\t\t
\t\thideItems = fm.storage('infohides') || fm.arrayFlip(o.hideItems, true);

\t\tif (cnt === 1) {
\t\t\tfile = files[0];
\t\t\t
\t\t\tif (file.icon) {
\t\t\t\tstyle = ' '+fm.getIconStyle(file);
\t\t\t}
\t\t\t
\t\t\tview  = view.replace('{dirclass}', file.csscls? fm.escape(file.csscls) : '').replace('{class}', fm.mime2class(file.mime)).replace('{style}', style);
\t\t\ttitle = tpl.itemTitle.replace('{name}', fm.escape(file.i18 || file.name)).replace('{kind}', '<span title=\"'+fm.escape(file.mime)+'\">'+fm.mime2kind(file)+'</span>');

\t\t\ttmb = fm.tmb(file);
\t\t\t
\t\t\tif (!file.read) {
\t\t\t\tsize = msg.unknown;
\t\t\t} else if (file.mime != 'directory' || file.alias) {
\t\t\t\tsize = fm.formatSize(file.size);
\t\t\t} else {
\t\t\t\tsize = tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size');
\t\t\t\tcount.push(file.hash);
\t\t\t}
\t\t\t
\t\t\t!hideItems.size && content.push(row.replace(l, msg.size).replace(v, size));
\t\t\t!hideItems.aleasfor && file.alias && content.push(row.replace(l, msg.aliasfor).replace(v, file.alias));
\t\t\tif (!hideItems.path) {
\t\t\t\tif (path = fm.path(file.hash, true)) {
\t\t\t\t\tcontent.push(row.replace(l, msg.path).replace(v, applyZWSP(fm.escape(path))).replace('{class}', 'elfinder-info-path'));
\t\t\t\t} else {
\t\t\t\t\tcontent.push(row.replace(l, msg.path).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'path')).replace('{class}', 'elfinder-info-path'));
\t\t\t\t\treqs.push(fm.path(file.hash, true, {notify: null})
\t\t\t\t\t.fail(function() {
\t\t\t\t\t\treplSpinner(msg.unknown, 'path');
\t\t\t\t\t})
\t\t\t\t\t.done(function(path) {
\t\t\t\t\t\treplSpinner(applyZWSP(path), 'path');
\t\t\t\t\t}));
\t\t\t\t}
\t\t\t}
\t\t\tif (!hideItems.link && file.read) {
\t\t\t\tvar href,
\t\t\t\tname_esc = fm.escape(file.name);
\t\t\t\tif (file.url == '1') {
\t\t\t\t\tcontent.push(row.replace(l, msg.link).replace(v, '<button class=\"'+btnclass+' '+spclass+'-url\">'+msg.getlink+'</button>'));
\t\t\t\t} else {
\t\t\t\t\tif (file.url) {
\t\t\t\t\t\thref = file.url;
\t\t\t\t\t} else if (file.mime === 'directory') {
\t\t\t\t\t\tif (o.nullUrlDirLinkSelf && file.url === null) {
\t\t\t\t\t\t\tvar loc = window.location;
\t\t\t\t\t\t\thref = loc.pathname + loc.search + '#elf_' + file.hash;
\t\t\t\t\t\t} else if (file.url !== '' && fm.option('url', (!fm.isRoot(file) && file.phash) || file.hash)) {
\t\t\t\t\t\t\thref = fm.url(file.hash);
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\thref = fm.url(file.hash);
\t\t\t\t\t}
\t\t\t\t\thref && content.push(row.replace(l, msg.link).replace(v,  '<a href=\"'+href+'\" target=\"_blank\">'+name_esc+'</a>'));
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (!hideItems.dim) {
\t\t\t\tif (file.dim) { // old api
\t\t\t\t\tcontent.push(row.replace(l, msg.dim).replace(v, file.dim));
\t\t\t\t} else if (file.mime.indexOf('image') !== -1) {
\t\t\t\t\tif (file.width && file.height) {
\t\t\t\t\t\tcontent.push(row.replace(l, msg.dim).replace(v, file.width+'x'+file.height));
\t\t\t\t\t} else if (file.size && file.size !== '0') {
\t\t\t\t\t\tcontent.push(row.replace(l, msg.dim).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'dim')));
\t\t\t\t\t\treqs.push(fm.request({
\t\t\t\t\t\t\tdata : {cmd : 'dim', target : file.hash},
\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t})
\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\treplSpinner(msg.unknown, 'dim');
\t\t\t\t\t\t})
\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\treplSpinner(data.dim || msg.unknown, 'dim');
\t\t\t\t\t\t\tif (data.dim) {
\t\t\t\t\t\t\t\tvar dim = data.dim.split('x');
\t\t\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\t\t\trfile.width = dim[0];
\t\t\t\t\t\t\t\trfile.height = dim[1];
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t!hideItems.modify && content.push(row.replace(l, msg.modify).replace(v, fm.formatDate(file)));
\t\t\t!hideItems.perms && content.push(row.replace(l, msg.perms).replace(v, fm.formatPermissions(file)));
\t\t\t!hideItems.locked && content.push(row.replace(l, msg.locked).replace(v, file.locked ? msg.yes : msg.no));
\t\t\t!hideItems.owner && file.owner && content.push(row.replace(l, msg.owner).replace(v, file.owner));
\t\t\t!hideItems.group && file.group && content.push(row.replace(l, msg.group).replace(v, file.group));
\t\t\t!hideItems.perm && file.perm && content.push(row.replace(l, msg.perm).replace(v, fm.formatFileMode(file.perm)));
\t\t\t
\t\t\t// Get MD5, SHA hashes
\t\t\tif (window.ArrayBuffer && (fm.options.cdns.sparkmd5 || fm.options.cdns.jssha) && file.mime !== 'directory' && file.size > 0 && (!o.showHashMaxsize || file.size <= o.showHashMaxsize)) {
\t\t\t\tgetHashAlgorisms = [];
\t\t\t\t\$.each(fm.storage('hashchekcer') || o.showHashAlgorisms, function(i, n) {
\t\t\t\t\tif (!file[n]) {
\t\t\t\t\t\tcontent.push(row.replace(l, fm.i18n(n)).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', n)));
\t\t\t\t\t\tgetHashAlgorisms.push(n);
\t\t\t\t\t} else {
\t\t\t\t\t\tcontent.push(row.replace(l, fm.i18n(n)).replace(v, file[n]).replace('{class}', hashClass));
\t\t\t\t\t}
\t\t\t\t});

\t\t\t\tif (getHashAlgorisms.length) {
\t\t\t\t\thashProg = \$('<div class=\"elfinder-quicklook-info-progress\"></div>');
\t\t\t\t\treqs.push(
\t\t\t\t\t\tfm.getContentsHashes(file.hash, getHashAlgorisms, o.showHashOpts, { progressBar : hashProg }).progress(function(hashes) {
\t\t\t\t\t\t\t\$.each(getHashAlgorisms, function(i, n) {
\t\t\t\t\t\t\t\tif (hashes[n]) {
\t\t\t\t\t\t\t\t\treplSpinner(hashes[n], n, hashClass);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\t\$.each(getHashAlgorisms, function(i, n) {
\t\t\t\t\t\t\t\treplSpinner(msg.unknown, n);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t})
\t\t\t\t\t);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\t// Add custom info fields
\t\t\tif (o.custom) {
\t\t\t\t\$.each(o.custom, function(name, details) {
\t\t\t\t\tif (
\t\t\t\t\t  !hideItems[details.label]
\t\t\t\t\t    &&
\t\t\t\t\t  (!details.mimes || \$.grep(details.mimes, function(m){return (file.mime === m || file.mime.indexOf(m+'/') === 0)? true : false;}).length)
\t\t\t\t\t    &&
\t\t\t\t\t  (!details.hashRegex || file.hash.match(details.hashRegex))
\t\t\t\t\t) {
\t\t\t\t\t\t// Add to the content
\t\t\t\t\t\tcontent.push(row.replace(l, fm.i18n(details.label)).replace(v , details.tpl.replace('{id}', id)));
\t\t\t\t\t\t// Register the action
\t\t\t\t\t\tif (details.action && (typeof details.action == 'function')) {
\t\t\t\t\t\t\tcustomActions.push(details.action);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t} else {
\t\t\tview  = view.replace('{class}', 'elfinder-cwd-icon-group');
\t\t\ttitle = tpl.groupTitle.replace('{items}', msg.items).replace('{num}', cnt);
\t\t\tdcnt  = \$.grep(files, function(f) { return f.mime == 'directory' ? true : false ; }).length;
\t\t\tif (!dcnt) {
\t\t\t\tsize = 0;
\t\t\t\t\$.each(files, function(h, f) { 
\t\t\t\t\tvar s = parseInt(f.size);
\t\t\t\t\t
\t\t\t\t\tif (s >= 0 && size >= 0) {
\t\t\t\t\t\tsize += s;
\t\t\t\t\t} else {
\t\t\t\t\t\tsize = 'unknown';
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tcontent.push(row.replace(l, msg.kind).replace(v, msg.files));
\t\t\t\t!hideItems.size && content.push(row.replace(l, msg.size).replace(v, fm.formatSize(size)));
\t\t\t} else {
\t\t\t\trdcnt = \$.grep(files, function(f) { return f.mime === 'directory' && (! f.phash || f.isroot)? true : false ; }).length;
\t\t\t\tdcnt -= rdcnt;
\t\t\t\tcontent.push(row.replace(l, msg.kind).replace(v, (rdcnt === cnt || dcnt === cnt)? msg[rdcnt? 'roots' : 'folders'] : \$.map({roots: rdcnt, folders: dcnt, files: cnt - rdcnt - dcnt}, function(c, t) { return c? msg[t]+' '+c : null; }).join(', ')));
\t\t\t\t!hideItems.size && content.push(row.replace(l, msg.size).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size')));
\t\t\t\tcount = \$.map(files, function(f) { return f.hash; });
\t\t\t\t
\t\t\t}
\t\t}
\t\t
\t\tview = view.replace('{title}', title).replace('{content}', content.join('').replace(/{class}/g, ''));
\t\t
\t\tdialog = self.fmDialog(view, opts);
\t\tdialog.attr('id', id).one('mousedown', '.elfinder-info-path', function() {
\t\t\t\$(this).html(applyZWSP(\$(this).html(), true));
\t\t});

\t\tif (getHashAlgorisms.length) {
\t\t\thashProg.appendTo(dialog.find('.'+spclass+'-'+getHashAlgorisms[0]).parent());
\t\t}

\t\tif (fm.UA.Mobile && \$.fn.tooltip) {
\t\t\tdialog.children('.ui-dialog-content .elfinder-info-title').tooltip({
\t\t\t\tclasses: {
\t\t\t\t\t'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
\t\t\t\t},
\t\t\t\ttooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
\t\t\t\ttrack: true
\t\t\t});
\t\t}

\t\tif (file && file.url == '1') {
\t\t\tdialog.on('click', '.'+spclass+'-url', function(){
\t\t\t\t\$(this).parent().html(tpl.spinner.replace('{text}', fm.i18n('ntfurl')).replace('{name}', 'url'));
\t\t\t\tfm.request({
\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\tpreventDefault : true
\t\t\t\t})
\t\t\t\t.fail(function() {
\t\t\t\t\treplSpinner(name_esc, 'url');
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tif (data.url) {
\t\t\t\t\t\treplSpinner('<a href=\"'+data.url+'\" target=\"_blank\">'+name_esc+'</a>' || name_esc, 'url');
\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\trfile.url = data.url;
\t\t\t\t\t} else {
\t\t\t\t\t\treplSpinner(name_esc, 'url');
\t\t\t\t\t}
\t\t\t\t});
\t\t\t});
\t\t}

\t\t// load thumbnail
\t\tif (tmb) {
\t\t\t\$('<img/>')
\t\t\t\t.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\"); })
\t\t\t\t.attr('src', tmb.url);
\t\t}
\t\t
\t\t// send request to count total size
\t\tif (count.length) {
\t\t\treqDfrd = fm.getSize(count).done(function(data) {
\t\t\t\treplSpinner(data.formated, 'size');
\t\t\t}).fail(function() {
\t\t\t\treplSpinner(msg.unknown, 'size');
\t\t\t});
\t\t}
\t\t
\t\t// call custom actions
\t\tif (customActions.length) {
\t\t\t\$.each(customActions, function(i, action) {
\t\t\t\ttry {
\t\t\t\t\taction(file, fm, dialog);
\t\t\t\t} catch(e) {
\t\t\t\t\tfm.debug('error', e);
\t\t\t\t}
\t\t\t});
\t\t}
\t\t
\t\treturn \$.Deferred().resolve();
\t};
\t
}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/mkdir.js
 */

/**
 * @class  elFinder command \"mkdir\"
 * Create new folder
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.mkdir = function() {
\t\tvar fm   = this.fm,
\t\tself = this,
\t\tcurOrg;
\t
\tthis.value           = '';
\tthis.disableOnSearch = true;
\tthis.updateOnSelect  = false;
\tthis.syncTitleOnChange = true;
\tthis.mime            = 'directory';
\tthis.prefix          = 'untitled folder';
\tthis.exec            = function(select, cOpts) {
\t\tvar onCwd;

\t\tif (select && select.length && cOpts && cOpts._currentType && cOpts._currentType === 'navbar') {
\t\t\tthis.origin = cOpts._currentType;
\t\t\tthis.data = {
\t\t\t\ttarget: select[0]
\t\t\t};
\t\t} else {
\t\t\tonCwd = fm.cwd().hash === select[0];
\t\t\tthis.origin = curOrg && !onCwd? curOrg : 'cwd';
\t\t\tdelete this.data;
\t\t}
\t\tif (! select && ! this.options.intoNewFolderToolbtn) {
\t\t\tfm.getUI('cwd').trigger('unselectall');
\t\t}
\t\t//this.move = (!onCwd && curOrg !== 'navbar' && fm.selected().length)? true : false;
\t\tthis.move = this.value === fm.i18n('cmdmkdirin');
\t\treturn \$.proxy(fm.res('mixin', 'make'), self)();
\t};
\t
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+shift+n'
\t}];

\tthis.init = function() {
\t\tif (this.options.intoNewFolderToolbtn) {
\t\t\tthis.syncTitleOnChange = true;
\t\t}
\t};
\t
\tfm.bind('select contextmenucreate closecontextmenu', function(e) {
\t\tvar sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
\t\t
\t\tself.className = 'mkdir';
\t\tcurOrg = e.data && sel.length? (e.data.origin || e.data.type || '') : '';
\t\tif (!self.options.intoNewFolderToolbtn && curOrg === '') {
\t\t\tcurOrg = 'cwd';
\t\t}
\t\tif (sel.length && curOrg !== 'navbar' && curOrg !== 'cwd' && fm.cwd().hash !== sel[0]) {
\t\t\tself.title = fm.i18n('cmdmkdirin');
\t\t\tself.className += ' elfinder-button-icon-mkdirin';
\t\t} else {
\t\t\tself.title = fm.i18n('cmdmkdir');
\t\t}
\t\tif (e.type !== 'closecontextmenu') {
\t\t\tself.update(void(0), self.title);
\t\t} else {
\t\t\trequestAnimationFrame(function() {
\t\t\t\tself.update(void(0), self.title);
\t\t\t});
\t\t}
\t});
\t
\tthis.getstate = function(select) {
\t\tvar cwd = fm.cwd(),
\t\t\tsel = (curOrg === 'navbar' || (select && select[0] !== cwd.hash))? this.files(select || fm.selected()) : [],
\t\t\tcnt = sel.length;

\t\tif (curOrg === 'navbar') {
\t\t\treturn cnt && sel[0].write && sel[0].read? 0 : -1;  
\t\t} else {
\t\t\treturn cwd.write && (!cnt || \$.grep(sel, function(f) { return f.read && ! f.locked? true : false; }).length == cnt)? 0 : -1;
\t\t}
\t};

};


/*
 * File: /js/commands/mkfile.js
 */

/**
 * @class  elFinder command \"mkfile\"
 * Create new empty file
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.mkfile = function() {
\t\tvar self = this;

\tthis.disableOnSearch = true;
\tthis.updateOnSelect  = false;
\tthis.mime            = 'text/plain';
\tthis.prefix          = 'untitled file.txt';
\tthis.variants        = [];

\tthis.getTypeName = function(mime, type) {
\t\tvar fm = self.fm,
\t\t\tname;
\t\tif (name = fm.messages['kind' + fm.kinds[mime]]) {
\t\t\tname = fm.i18n(['extentiontype', type.toUpperCase(), name]);
\t\t} else {
\t\t\tname = fm.i18n(['extentionfile', type.toUpperCase()]);
\t\t}
\t\treturn name;
\t};

\tthis.fm.bind('open reload canMakeEmptyFile', function() {
\t\tvar fm = self.fm,
\t\t\thides = fm.getCommand('edit').getMkfileHides();
\t\tself.variants = [];
\t\tif (fm.mimesCanMakeEmpty) {
\t\t\t\$.each(fm.mimesCanMakeEmpty, function(mime, type) {
\t\t\t\ttype && !hides[mime] && fm.uploadMimeCheck(mime) && self.variants.push([mime, self.getTypeName(mime, type)]);
\t\t\t});
\t\t}
\t\tself.change();
\t});

\tthis.getstate = function() {
\t\treturn this.fm.cwd().write ? 0 : -1;
\t};

\tthis.exec = function(_dum, mime) {
\t\tvar fm = self.fm,
\t\t\ttype, err;
\t\tif (type = fm.mimesCanMakeEmpty[mime]) {
\t\t\tif (fm.uploadMimeCheck(mime)) {
\t\t\t\tthis.mime = mime;
\t\t\t\tthis.prefix = fm.i18n(['untitled file', type]);
\t\t\t\treturn \$.proxy(fm.res('mixin', 'make'), self)();
\t\t\t}
\t\t\terr = ['errMkfile', self.getTypeName(mime, type)];
\t\t}
\t\treturn \$.Deferred().reject(err);
\t};
};


/*
 * File: /js/commands/netmount.js
 */

/**
 * @class  elFinder command \"netmount\"
 * Mount network volume with user credentials.
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.netmount = function() {
\t\tvar self = this,
\t\thasMenus = false,
\t\tcontent;

\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;

\tthis.drivers = [];
\t
\tthis.handlers = {
\t\tload : function() {
\t\t\tvar fm = self.fm;
\t\t\tif (fm.cookieEnabled) {
\t\t\t\tfm.one('open', function() {
\t\t\t\t\tself.drivers = fm.netDrivers;
\t\t\t\t\tif (self.drivers.length) {
\t\t\t\t\t\t\$.each(self.drivers, function() {
\t\t\t\t\t\t\tvar d = self.options[this];
\t\t\t\t\t\t\tif (d) {
\t\t\t\t\t\t\t\thasMenus = true;
\t\t\t\t\t\t\t\tif (d.integrateInfo) {
\t\t\t\t\t\t\t\t\tfm.trigger('helpIntegration', Object.assign({cmd: 'netmount'}, d.integrateInfo));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t}
\t};

\tthis.getstate = function() {
\t\treturn hasMenus ? 0 : -1;
\t};
\t
\tthis.exec = function() {
\t\tvar fm = self.fm,
\t\t\tdfrd = \$.Deferred(),
\t\t\to = self.options,
\t\t\tcreate = function() {
\t\t\t\tvar winFocus = function() {
\t\t\t\t\t\tinputs.protocol.trigger('change', 'winfocus');
\t\t\t\t\t},
\t\t\t\t\tinputs = {
\t\t\t\t\t\tprotocol : \$('<select></select>')
\t\t\t\t\t\t.on('change', function(e, data){
\t\t\t\t\t\t\tvar protocol = this.value;
\t\t\t\t\t\t\tcontent.find('.elfinder-netmount-tr').hide();
\t\t\t\t\t\t\tcontent.find('.elfinder-netmount-tr-'+protocol).show();
\t\t\t\t\t\t\tdialogNode && dialogNode.children('.ui-dialog-buttonpane:first').find('button').show();
\t\t\t\t\t\t\tif (typeof o[protocol].select == 'function') {
\t\t\t\t\t\t\t\to[protocol].select(fm, e, data);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t})
\t\t\t\t\t\t.addClass('ui-corner-all')
\t\t\t\t\t},
\t\t\t\t\topts = {
\t\t\t\t\t\ttitle          : fm.i18n('netMountDialogTitle'),
\t\t\t\t\t\tresizable      : true,
\t\t\t\t\t\tmodal          : true,
\t\t\t\t\t\tdestroyOnClose : false,
\t\t\t\t\t\topen           : function() {
\t\t\t\t\t\t\t\$(window).on('focus.'+fm.namespace, winFocus);
\t\t\t\t\t\t\tinputs.protocol.trigger('change');
\t\t\t\t\t\t},
\t\t\t\t\t\tclose          : function() { 
\t\t\t\t\t\t\tdfrd.state() == 'pending' && dfrd.reject();
\t\t\t\t\t\t\t\$(window).off('focus.'+fm.namespace, winFocus);
\t\t\t\t\t\t},
\t\t\t\t\t\tbuttons        : {}
\t\t\t\t\t},
\t\t\t\t\tdoMount = function() {
\t\t\t\t\t\tvar protocol = inputs.protocol.val(),
\t\t\t\t\t\t\tdata = {cmd : 'netmount', protocol: protocol},
\t\t\t\t\t\t\tcur = o[protocol],
\t\t\t\t\t\t\tmnt2res;
\t\t\t\t\t\t\$.each(content.find('input.elfinder-netmount-inputs-'+protocol), function(name, input) {
\t\t\t\t\t\t\tvar val, elm;
\t\t\t\t\t\t\telm = \$(input);
\t\t\t\t\t\t\tif (elm.is(':radio,:checkbox')) {
\t\t\t\t\t\t\t\tif (elm.is(':checked')) {
\t\t\t\t\t\t\t\t\tval = \$.trim(elm.val());
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tval = \$.trim(elm.val());
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (val) {
\t\t\t\t\t\t\t\tdata[input.name] = val;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});

\t\t\t\t\t\tif (!data.host) {
\t\t\t\t\t\t\treturn fm.trigger('error', {error : 'errNetMountHostReq', opts : {modal: true}});
\t\t\t\t\t\t}

\t\t\t\t\t\tif (data.mnt2res) {
\t\t\t\t\t\t\tmnt2res = true;
\t\t\t\t\t\t}

\t\t\t\t\t\tfm.request({data : data, notify : {type : 'netmount', cnt : 1, hideCnt : true}})
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tvar pdir;
\t\t\t\t\t\t\t\tif (data.added && data.added.length) {
\t\t\t\t\t\t\t\t\tmnt2res && inputs.protocol.trigger('change', 'reset');
\t\t\t\t\t\t\t\t\tif (data.added[0].phash) {
\t\t\t\t\t\t\t\t\t\tif (pdir = fm.file(data.added[0].phash)) {
\t\t\t\t\t\t\t\t\t\t\tif (! pdir.dirs) {
\t\t\t\t\t\t\t\t\t\t\t\tpdir.dirs = 1;
\t\t\t\t\t\t\t\t\t\t\t\tfm.change({ changed: [ pdir ] });
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tfm.one('netmountdone', function() {
\t\t\t\t\t\t\t\t\t\tfm.exec('open', data.added[0].hash);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\tif (cur.fail && typeof cur.fail == 'function') {
\t\t\t\t\t\t\t\t\tcur.fail(fm, fm.parseError(error));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t});
\t
\t\t\t\t\t\tself.dialog.elfinderdialog('close');
\t\t\t\t\t},
\t\t\t\t\tform = \$('<form autocomplete=\"off\"></form>').on('keydown', 'input', function(e) {
\t\t\t\t\t\tvar comp = true,
\t\t\t\t\t\t\tnext;
\t\t\t\t\t\tif (e.keyCode === \$.ui.keyCode.ENTER) {
\t\t\t\t\t\t\t\$.each(form.find('input:visible:not(.elfinder-input-optional)'), function() {
\t\t\t\t\t\t\t\tif (\$(this).val() === '') {
\t\t\t\t\t\t\t\t\tcomp = false;
\t\t\t\t\t\t\t\t\tnext = \$(this);
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tif (comp) {
\t\t\t\t\t\t\t\tdoMount();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tnext.trigger('focus');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}),
\t\t\t\t\thidden  = \$('<div></div>'),
\t\t\t\t\tdialog;

\t\t\t\tcontent = \$('<table class=\"elfinder-info-tb elfinder-netmount-tb\"></table>')
\t\t\t\t\t.append(\$('<tr></tr>').append(\$('<td>'+fm.i18n('protocol')+'</td>')).append(\$('<td></td>').append(inputs.protocol)));

\t\t\t\t\$.each(self.drivers, function(i, protocol) {
\t\t\t\t\tif (o[protocol]) {
\t\t\t\t\t\tinputs.protocol.append('<option value=\"'+protocol+'\">'+fm.i18n(o[protocol].name || protocol)+'</option>');
\t\t\t\t\t\t\$.each(o[protocol].inputs, function(name, input) {
\t\t\t\t\t\t\tinput.attr('name', name);
\t\t\t\t\t\t\tif (input.attr('type') != 'hidden') {
\t\t\t\t\t\t\t\tinput.addClass('ui-corner-all elfinder-netmount-inputs-'+protocol);
\t\t\t\t\t\t\t\tcontent.append(\$('<tr></tr>').addClass('elfinder-netmount-tr elfinder-netmount-tr-'+protocol).append(\$('<td>'+fm.i18n(name)+'</td>')).append(\$('<td></td>').append(input)));
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tinput.addClass('elfinder-netmount-inputs-'+protocol);
\t\t\t\t\t\t\t\thidden.append(input);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\to[protocol].protocol = inputs.protocol;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t
\t\t\t\tcontent.append(hidden);
\t\t\t\t
\t\t\t\tcontent.find('.elfinder-netmount-tr').hide();
\t\t\t\tcontent.find('.elfinder-netmount-tr-' + self.drivers[0]).show();

\t\t\t\topts.buttons[fm.i18n('btnMount')] = doMount;

\t\t\t\topts.buttons[fm.i18n('btnCancel')] = function() {
\t\t\t\t\tself.dialog.elfinderdialog('close');
\t\t\t\t};
\t\t\t\t
\t\t\t\tcontent.find('select,input').addClass('elfinder-tabstop');
\t\t\t\t
\t\t\t\tdialog = self.fmDialog(form.append(content), opts).ready(function() {
\t\t\t\t\tinputs.protocol.trigger('change');
\t\t\t\t\tdialog.elfinderdialog('posInit');
\t\t\t\t});
\t\t\t\tdialogNode = dialog.closest('.ui-dialog');
\t\t\t\treturn dialog;
\t\t\t},
\t\t\tdialogNode;
\t\t
\t\tif (!self.dialog) {
\t\t\tself.dialog = create();
\t\t} else {
\t\t\tself.dialog.elfinderdialog('open');
\t\t}

\t\treturn dfrd.promise();
\t};

\tself.fm.bind('netmount', function(e) {
\t\tvar d = e.data || null,
\t\t\to = self.options,
\t\t\tdone = function() {
\t\t\t\tif (o[d.protocol] && typeof o[d.protocol].done == 'function') {
\t\t\t\t\to[d.protocol].done(self.fm, d);
\t\t\t\t\tcontent.find('select,input').addClass('elfinder-tabstop');
\t\t\t\t\tself.dialog.elfinderdialog('tabstopsInit');
\t\t\t\t}
\t\t\t};
\t\tif (d && d.protocol) {
\t\t\tif (d.mode && d.mode === 'redirect') {
\t\t\t\t// To support of third-party cookie blocking (ITP) on CORS
\t\t\t\t// On iOS and iPadOS 13.4 and Safari 13.1 on macOS, the session cannot be continued when redirecting OAuth in CORS mode
\t\t\t\tself.fm.request({
\t\t\t\t\tdata : {cmd : 'netmount', protocol : d.protocol, host: d.host, user : 'init', pass : 'return', options: d.options}, 
\t\t\t\t\tpreventDefault : true
\t\t\t\t}).done(function(data) {
\t\t\t\t\td = JSON.parse(data.body);
\t\t\t\t\tdone();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdone();
\t\t\t}
\t\t}
\t});

};

elFinder.prototype.commands.netunmount = function() {
\tvar self = this;

\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;

\tthis.drivers = [];
\t
\tthis.handlers = {
\t\tload : function() {
\t\t\tthis.drivers = this.fm.netDrivers;
\t\t}
\t};

\tthis.getstate = function(sel) {
\t\tvar fm = this.fm,
\t\t\tfile;
\t\treturn !!sel && this.drivers.length && !this._disabled && (file = fm.file(sel[0])) && file.netkey ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar self   = this,
\t\t\tfm     = this.fm,
\t\t\tdfrd   = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t}),
\t\t\tdrive  = fm.file(hashes[0]),
\t\t\tchildrenRoots = function(hash) {
\t\t\t\tvar roots = [],
\t\t\t\t\twork;
\t\t\t\tif (fm.leafRoots) {
\t\t\t\t\twork = [];
\t\t\t\t\t\$.each(fm.leafRoots, function(phash, hashes) {
\t\t\t\t\t\tvar parents = fm.parents(phash),
\t\t\t\t\t\t\tidx, deep;
\t\t\t\t\t\tif ((idx = \$.inArray(hash, parents)) !== -1) {
\t\t\t\t\t\t\tidx = parents.length - idx;
\t\t\t\t\t\t\t\$.each(hashes, function(i, h) {
\t\t\t\t\t\t\t\twork.push({i: idx, hash: h});
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tif (work.length) {
\t\t\t\t\t\twork.sort(function(a, b) { return a.i < b.i; });
\t\t\t\t\t\t\$.each(work, function(i, o) {
\t\t\t\t\t\t\troots.push(o.hash);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn roots;
\t\t\t};

\t\tif (this._disabled) {
\t\t\treturn dfrd.reject();
\t\t}

\t\tif (dfrd.state() == 'pending') {
\t\t\tfm.confirm({
\t\t\t\ttitle  : self.title,
\t\t\t\ttext   : fm.i18n('confirmUnmount', drive.name),
\t\t\t\taccept : {
\t\t\t\t\tlabel    : 'btnUnmount',
\t\t\t\t\tcallback : function() {  
\t\t\t\t\t\tvar target =  drive.hash,
\t\t\t\t\t\t\troots = childrenRoots(target),
\t\t\t\t\t\t\trequests = [],
\t\t\t\t\t\t\tremoved = [],
\t\t\t\t\t\t\tdoUmount = function() {
\t\t\t\t\t\t\t\t\$.when(requests).done(function() {
\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\tdata   : {cmd  : 'netmount', protocol : 'netunmount', host: drive.netkey, user : target, pass : 'dum'}, 
\t\t\t\t\t\t\t\t\t\tnotify : {type : 'netunmount', cnt : 1, hideCnt : true},
\t\t\t\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\tdrive.volumeid && delete fm.volumeExpires[drive.volumeid];
\t\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}).fail(function(error) {
\t\t\t\t\t\t\t\t\tif (removed.length) {
\t\t\t\t\t\t\t\t\t\tfm.remove({ removed: removed });
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t};
\t\t\t\t\t\t
\t\t\t\t\t\tif (roots.length) {
\t\t\t\t\t\t\tfm.confirm({
\t\t\t\t\t\t\t\ttitle : self.title,
\t\t\t\t\t\t\t\ttext  : (function() {
\t\t\t\t\t\t\t\t\tvar msgs = ['unmountChildren'];
\t\t\t\t\t\t\t\t\t\$.each(roots, function(i, hash) {
\t\t\t\t\t\t\t\t\t\tmsgs.push([fm.file(hash).name]);
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\treturn msgs;
\t\t\t\t\t\t\t\t})(),
\t\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\t\tlabel : 'btnUnmount',
\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\$.each(roots, function(i, hash) {
\t\t\t\t\t\t\t\t\t\t\tvar d = fm.file(hash);
\t\t\t\t\t\t\t\t\t\t\tif (d.netkey) {
\t\t\t\t\t\t\t\t\t\t\t\trequests.push(fm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\tdata   : {cmd  : 'netmount', protocol : 'netunmount', host: d.netkey, user : d.hash, pass : 'dum'}, 
\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'netunmount', cnt : 1, hideCnt : true},
\t\t\t\t\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\t\t\t\t\t\t\t\tif (data.removed) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\td.volumeid && delete fm.volumeExpires[d.volumeid];
\t\t\t\t\t\t\t\t\t\t\t\t\t\tremoved = removed.concat(data.removed);
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tdoUmount();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\t\tlabel : 'btnCancel',
\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\trequests = null;
\t\t\t\t\t\t\tdoUmount();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcancel : {
\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\tcallback : function() { dfrd.reject(); }
\t\t\t\t}
\t\t\t});
\t\t}
\t\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/open.js
 */

/**
 * @class  elFinder command \"open\"
 * Enter folder or open files in new windows
 *
 * @author Dmitry (dio) Levashov
 **/  
(elFinder.prototype.commands.open = function() {
\t\tvar fm = this.fm,
\t\tself = this;
\tthis.alwaysEnabled = true;
\tthis.noChangeDirOnRemovedCwd = true;
\t
\tthis._handlers = {
\t\tdblclick : function(e) {
\t\t\tvar arg = e.data && e.data.file? [ e.data.file ]: void(0);
\t\t\tif (self.getstate(arg) === 0) {
\t\t\t\te.preventDefault();
\t\t\t\tfm.exec('open', arg);
\t\t\t}
\t\t},
\t\t'select enable disable reload' : function(e) { this.update(e.type == 'disable' ? -1 : void(0));  }
\t};
\t
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+down numpad_enter'+(fm.OS != 'mac' && ' enter')
\t}];

\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;
\t\t
\t\treturn cnt == 1 
\t\t\t? (sel[0].read ? 0 : -1)
\t\t\t: (cnt && !fm.UA.Mobile) ? (\$.grep(sel, function(file) { return file.mime == 'directory' || ! file.read ? false : true;}).length == cnt ? 0 : -1) : -1;
\t};
\t
\tthis.exec = function(hashes, cOpts) {
\t\tvar dfrd  = \$.Deferred().fail(function(error) { error && fm.error(error); }),
\t\t\tfiles = this.files(hashes),
\t\t\tcnt   = files.length,
\t\t\tthash = (typeof cOpts == 'object')? cOpts.thash : false,
\t\t\topts  = this.options,
\t\t\tinto  = opts.into || 'window',
\t\t\tfile, url, s, w, imgW, imgH, winW, winH, reg, link, html5dl, inline,
\t\t\tselAct, cmd;

\t\tif (!cnt && !thash) {
\t\t\t{
\t\t\t\treturn dfrd.reject();
\t\t\t}
\t\t}

\t\t// open folder
\t\tif (thash || (cnt == 1 && (file = files[0]) && file.mime == 'directory')) {
\t\t\tif (!thash && file && !file.read) {
\t\t\t\treturn dfrd.reject(['errOpen', file.name, 'errPerm']);
\t\t\t} else {
\t\t\t\tif (fm.keyState.ctrlKey && (fm.keyState.shiftKey || typeof fm.options.getFileCallback !== 'function')) {
\t\t\t\t\tif (fm.getCommand('opennew')) {
\t\t\t\t\t\treturn fm.exec('opennew', [thash? thash : file.hash]);
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\treturn fm.request({
\t\t\t\t\tdata   : {cmd  : 'open', target : thash || file.hash},
\t\t\t\t\tnotify : {type : 'open', cnt : 1, hideCnt : true},
\t\t\t\t\tsyncOnFail : true,
\t\t\t\t\tlazy : false
\t\t\t\t});
\t\t\t}
\t\t}
\t\t
\t\tfiles = \$.grep(files, function(file) { return file.mime != 'directory' ? true : false; });
\t\t
\t\t// nothing to open or files and folders selected - do nothing
\t\tif (cnt != files.length) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tvar doOpen = function() {
\t\t\tvar openCB = function(url) {
\t\t\t\t\tvar link = \$('<a>').hide().appendTo(\$('body'));
\t\t\t\t\tif (fm.UA.Mobile || !inline) {
\t\t\t\t\t\tif (html5dl) {
\t\t\t\t\t\t\tif (!inline) {
\t\t\t\t\t\t\t\tlink.attr('download', file.name);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tlink.attr('target', '_blank');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tlink.attr('href', url).get(0).click();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\twnd = window.open(url);
\t\t\t\t\t\t\tif (!wnd) {
\t\t\t\t\t\t\t\treturn dfrd.reject('errPopup');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tgetOnly = (typeof opts.method === 'string' && opts.method.toLowerCase() === 'get');
\t\t\t\t\t\tif (!getOnly
\t\t\t\t\t\t\t&& url.indexOf(fm.options.url) === 0
\t\t\t\t\t\t\t&& fm.customData
\t\t\t\t\t\t\t&& Object.keys(fm.customData).length
\t\t\t\t\t\t\t// Since playback by POST request can not be done in Chrome, media allows GET request
\t\t\t\t\t\t\t&& !file.mime.match(/^(?:video|audio)/)
\t\t\t\t\t\t) {
\t\t\t\t\t\t\t// Send request as 'POST' method to hide custom data at location bar
\t\t\t\t\t\t\turl = '';
\t\t\t\t\t\t}
\t\t\t\t\t\tif (into === 'window') {
\t\t\t\t\t\t\t// set window size for image if set
\t\t\t\t\t\t\timgW = winW = Math.round(2 * screen.availWidth / 3);
\t\t\t\t\t\t\timgH = winH = Math.round(2 * screen.availHeight / 3);
\t\t\t\t\t\t\tif (parseInt(file.width) && parseInt(file.height)) {
\t\t\t\t\t\t\t\timgW = parseInt(file.width);
\t\t\t\t\t\t\t\timgH = parseInt(file.height);
\t\t\t\t\t\t\t} else if (file.dim) {
\t\t\t\t\t\t\t\ts = file.dim.split('x');
\t\t\t\t\t\t\t\timgW = parseInt(s[0]);
\t\t\t\t\t\t\t\timgH = parseInt(s[1]);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (winW >= imgW && winH >= imgH) {
\t\t\t\t\t\t\t\twinW = imgW;
\t\t\t\t\t\t\t\twinH = imgH;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif ((imgW - winW) > (imgH - winH)) {
\t\t\t\t\t\t\t\t\twinH = Math.round(imgH * (winW / imgW));
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\twinW = Math.round(imgW * (winH / imgH));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tw = 'width='+winW+',height='+winH;
\t\t\t\t\t\t\twnd = window.open(url, target, w + ',top=50,left=50,scrollbars=yes,resizable=yes,titlebar=no');
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (into === 'tabs') {
\t\t\t\t\t\t\t\ttarget = file.hash;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\twnd = window.open('about:blank', target);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (!wnd) {
\t\t\t\t\t\t\treturn dfrd.reject('errPopup');
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (url === '') {
\t\t\t\t\t\t\tvar form = document.createElement(\"form\");
\t\t\t\t\t\t\tform.action = fm.options.url;
\t\t\t\t\t\t\tform.method = 'POST';
\t\t\t\t\t\t\tform.target = target;
\t\t\t\t\t\t\tform.style.display = 'none';
\t\t\t\t\t\t\tvar params = Object.assign({}, fm.customData, {
\t\t\t\t\t\t\t\tcmd: 'file',
\t\t\t\t\t\t\t\ttarget: file.hash,
\t\t\t\t\t\t\t\t_t: file.ts || parseInt(+new Date()/1000)
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\$.each(params, function(key, val)
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\tvar input = document.createElement(\"input\");
\t\t\t\t\t\t\t\tinput.name = key;
\t\t\t\t\t\t\t\tinput.value = val;
\t\t\t\t\t\t\t\tform.appendChild(input);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tdocument.body.appendChild(form);
\t\t\t\t\t\t\tform.submit();
\t\t\t\t\t\t} else if (into !== 'window') {
\t\t\t\t\t\t\twnd.location = url;
\t\t\t\t\t\t}
\t\t\t\t\t\t\$(wnd).trigger('focus');
\t\t\t\t\t}
\t\t\t\t\tlink.remove();
\t\t\t\t},
\t\t\t\twnd, target, getOnly;
\t\t\t
\t\t\ttry {
\t\t\t\treg = new RegExp(fm.option('dispInlineRegex'), 'i');
\t\t\t} catch(e) {
\t\t\t\treg = false;
\t\t\t}
\t
\t\t\t// open files
\t\t\thtml5dl  = (typeof \$('<a>').get(0).download === 'string');
\t\t\tcnt = files.length;
\t\t\twhile (cnt--) {
\t\t\t\ttarget = 'elf_open_window';
\t\t\t\tfile = files[cnt];
\t\t\t\t
\t\t\t\tif (!file.read) {
\t\t\t\t\treturn dfrd.reject(['errOpen', file.name, 'errPerm']);
\t\t\t\t}
\t\t\t\t
\t\t\t\tinline = (reg && file.mime.match(reg));
\t\t\t\tfm.openUrl(file.hash, !inline, openCB);
\t\t\t}
\t\t\treturn dfrd.resolve(hashes);
\t\t};
\t\t
\t\tif (cnt > 1) {
\t\t\tfm.confirm({
\t\t\t\ttitle: 'openMulti',
\t\t\t\ttext : ['openMultiConfirm', cnt + ''],
\t\t\t\taccept : {
\t\t\t\t\tlabel : 'cmdopen',
\t\t\t\t\tcallback : function() { doOpen(); }
\t\t\t\t},
\t\t\t\tcancel : {
\t\t\t\t\tlabel : 'btnCancel',
\t\t\t\t\tcallback : function() { 
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tbuttons : (fm.getCommand('zipdl') && fm.isCommandEnabled('zipdl', fm.cwd().hash))? [
\t\t\t\t\t{
\t\t\t\t\t\tlabel : 'cmddownload',
\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\tfm.exec('download', hashes);
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t] : []
\t\t\t});
\t\t} else {
\t\t\tselAct = fm.storage('selectAction') || opts.selectAction;
\t\t\tif (selAct) {
\t\t\t\t\$.each(selAct.split('/'), function() {
\t\t\t\t\tvar cmdName = this.valueOf();
\t\t\t\t\tif (cmdName !== 'open' && (cmd = fm.getCommand(cmdName)) && cmd.enabled()) {
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\tcmd = null;
\t\t\t\t});
\t\t\t\tif (cmd) {
\t\t\t\t\treturn fm.exec(cmd.name);
\t\t\t\t}
\t\t\t}
\t\t\tdoOpen();
\t\t}
\t\t
\t\treturn dfrd;
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/opendir.js
 */

/**
 * @class  elFinder command \"opendir\"
 * Enter parent folder
 *
 * @author Naoki Sawada
 **/  
elFinder.prototype.commands.opendir = function() {
\t\tthis.alwaysEnabled = true;
\t
\tthis.getstate = function() {
\t\tvar sel = this.fm.selected(),
\t\t\tcnt = sel.length,
\t\t\twz;
\t\tif (cnt !== 1) {
\t\t\treturn -1;
\t\t}
\t\twz = this.fm.getUI('workzone');
\t\treturn wz.hasClass('elfinder-search-result')? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar fm    = this.fm,
\t\t\tdfrd  = \$.Deferred(),
\t\t\tfiles = this.files(hashes),
\t\t\tcnt   = files.length,
\t\t\thash, pcheck = null;

\t\tif (!cnt || !files[0].phash) {
\t\t\treturn dfrd.reject();
\t\t}

\t\thash = files[0].phash;
\t\tfm.trigger('searchend', { noupdate: true });
\t\tfm.request({
\t\t\tdata   : {cmd  : 'open', target : hash},
\t\t\tnotify : {type : 'open', cnt : 1, hideCnt : true},
\t\t\tsyncOnFail : false
\t\t});
\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/opennew.js
 */

/**
 * @class  elFinder command \"opennew\"
 * Open folder in new window
 *
 * @author Naoki Sawada
 **/  
elFinder.prototype.commands.opennew = function() {
\t\tvar fm = this.fm;

\tthis.shortcuts = [{
\t\tpattern  : (typeof(fm.options.getFileCallback) === 'function'? 'shift+' : '') + 'ctrl+enter'
\t}];

\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length;
\t\t
\t\treturn cnt === 1 
\t\t\t? (sel[0].mime === 'directory' && sel[0].read? 0 : -1) 
\t\t\t: -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar dfrd  = \$.Deferred(),
\t\t\tfiles = this.files(hashes),
\t\t\tcnt   = files.length,
\t\t\topts  = this.options,
\t\t\tfile, loc, url, win;

\t\t// open folder to new tab (window)
\t\tif (cnt === 1 && (file = files[0]) && file.mime === 'directory') {
\t\t\tloc = window.location;
\t\t\tif (opts.url) {
\t\t\t\turl = opts.url;
\t\t\t} else {
\t\t\t\turl = loc.pathname;
\t\t\t}
\t\t\tif (opts.useOriginQuery) {
\t\t\t\tif (!url.match(/\\?/)) {
\t\t\t\t\turl += loc.search;
\t\t\t\t} else if (loc.search) {
\t\t\t\t\turl += '&' + loc.search.substr(1);
\t\t\t\t}
\t\t\t}
\t\t\turl += '#elf_' + file.hash;
\t\t\twin = window.open(url, '_blank');
\t\t\tsetTimeout(function() {
\t\t\t\twin.focus();
\t\t\t}, 1000);
\t\t\treturn dfrd.resolve();
\t\t} else {
\t\t\treturn dfrd.reject();
\t\t}
\t};
};


/*
 * File: /js/commands/paste.js
 */

/**
 * @class  elFinder command \"paste\"
 * Paste filesfrom clipboard into directory.
 * If files pasted in its parent directory - files duplicates will created
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.paste = function() {
\t\tthis.updateOnSelect  = false;
\t
\tthis.handlers = {
\t\tchangeclipboard : function() { this.update(); }
\t};

\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+v shift+insert'
\t}];
\t
\tthis.getstate = function(dst) {
\t\tif (this._disabled) {
\t\t\treturn -1;
\t\t}
\t\tif (dst) {
\t\t\tif (Array.isArray(dst)) {
\t\t\t\tif (dst.length != 1) {
\t\t\t\t\treturn -1;
\t\t\t\t}
\t\t\t\tdst = this.fm.file(dst[0]);
\t\t\t}
\t\t} else {
\t\t\tdst = this.fm.cwd();
\t\t}

\t\treturn this.fm.clipboard().length && dst.mime == 'directory' && dst.write ? 0 : -1;
\t};
\t
\tthis.exec = function(select, cOpts) {
\t\tvar self   = this,
\t\t\tfm     = self.fm,
\t\t\topts   = cOpts || {},
\t\t\tdst    = select ? this.files(select)[0] : fm.cwd(),
\t\t\tfiles  = fm.clipboard(),
\t\t\tcnt    = files.length,
\t\t\tcut    = cnt ? files[0].cut : false,
\t\t\tcmd    = opts._cmd? opts._cmd : (cut? 'move' : 'copy'),
\t\t\terror  = 'err' + cmd.charAt(0).toUpperCase() + cmd.substr(1),
\t\t\tfpaste = [],
\t\t\tfcopy  = [],
\t\t\tdfrd   = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\tfm.unlockfiles({files : \$.map(files, function(f) { return f.hash; })});
\t\t\t\t}),
\t\t\tcopy  = function(files) {
\t\t\t\treturn files.length && fm._commands.duplicate
\t\t\t\t\t? fm.exec('duplicate', files)
\t\t\t\t\t: \$.Deferred().resolve();
\t\t\t},
\t\t\tpaste = function(files) {
\t\t\t\tvar dfrd      = \$.Deferred(),
\t\t\t\t\texisted   = [],
\t\t\t\t\thashes  = {},
\t\t\t\t\tintersect = function(files, names) {
\t\t\t\t\t\tvar ret = [], 
\t\t\t\t\t\t\ti   = files.length;

\t\t\t\t\t\twhile (i--) {
\t\t\t\t\t\t\t\$.inArray(files[i].name, names) !== -1 && ret.unshift(i);
\t\t\t\t\t\t}
\t\t\t\t\t\treturn ret;
\t\t\t\t\t},
\t\t\t\t\tconfirm   = function(ndx) {
\t\t\t\t\t\tvar i    = existed[ndx],
\t\t\t\t\t\t\tfile = files[i],
\t\t\t\t\t\t\tlast = ndx == existed.length-1;

\t\t\t\t\t\tif (!file) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}

\t\t\t\t\t\tfm.confirm({
\t\t\t\t\t\t\ttitle  : fm.i18n(cmd + 'Files'),
\t\t\t\t\t\t\ttext   : ['errExists', file.name, cmd === 'restore'? 'confirmRest' : 'confirmRepl'], 
\t\t\t\t\t\t\tall    : !last,
\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\tlabel    : 'btnYes',
\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t: paste(files);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\treject : {
\t\t\t\t\t\t\t\tlabel    : 'btnNo',
\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\tvar i;

\t\t\t\t\t\t\t\t\tif (all) {
\t\t\t\t\t\t\t\t\t\ti = existed.length;
\t\t\t\t\t\t\t\t\t\twhile (ndx < i--) {
\t\t\t\t\t\t\t\t\t\t\tfiles[existed[i]].remove = true;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tfiles[existed[ndx]].remove = true;
\t\t\t\t\t\t\t\t\t}

\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t: paste(files);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tbuttons : [
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\tlabel : 'btnBackup',
\t\t\t\t\t\t\t\t\tcallback : function(all) {
\t\t\t\t\t\t\t\t\t\tvar i;
\t\t\t\t\t\t\t\t\t\tif (all) {
\t\t\t\t\t\t\t\t\t\t\ti = existed.length;
\t\t\t\t\t\t\t\t\t\t\twhile (ndx < i--) {
\t\t\t\t\t\t\t\t\t\t\t\tfiles[existed[i]].rename = true;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tfiles[existed[ndx]].rename = true;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t!last && !all
\t\t\t\t\t\t\t\t\t\t\t? confirm(++ndx)
\t\t\t\t\t\t\t\t\t\t\t: paste(files);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t]
\t\t\t\t\t\t});
\t\t\t\t\t},
\t\t\t\t\tvalid     = function(names) {
\t\t\t\t\t\tvar exists = {}, existedArr;
\t\t\t\t\t\tif (names) {
\t\t\t\t\t\t\tif (Array.isArray(names)) {
\t\t\t\t\t\t\t\tif (names.length) {
\t\t\t\t\t\t\t\t\tif (typeof names[0] == 'string') {
\t\t\t\t\t\t\t\t\t\t// elFinder <= 2.1.6 command `is` results
\t\t\t\t\t\t\t\t\t\texisted = intersect(files, names);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\$.each(names, function(i, v) {
\t\t\t\t\t\t\t\t\t\t\texists[v.name] = v.hash;
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\texisted = intersect(files, \$.map(exists, function(h, n) { return n; }));
\t\t\t\t\t\t\t\t\t\t\$.each(files, function(i, file) {
\t\t\t\t\t\t\t\t\t\t\tif (exists[file.name]) {
\t\t\t\t\t\t\t\t\t\t\t\thashes[exists[file.name]] = file.name;
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\texistedArr = [];
\t\t\t\t\t\t\t\texisted = \$.map(names, function(n) {
\t\t\t\t\t\t\t\t\tif (typeof n === 'string') {
\t\t\t\t\t\t\t\t\t\treturn n;
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t// support to >=2.1.11 plugin Normalizer, Sanitizer
\t\t\t\t\t\t\t\t\t\texistedArr = existedArr.concat(n);
\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (existedArr.length) {
\t\t\t\t\t\t\t\t\texisted = existed.concat(existedArr);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\texisted = intersect(files, existed);
\t\t\t\t\t\t\t\thashes = names;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\texisted.length ? confirm(0) : paste(files);
\t\t\t\t\t},
\t\t\t\t\tpaste     = function(selFiles) {
\t\t\t\t\t\tvar renames = [],
\t\t\t\t\t\t\tfiles  = \$.grep(selFiles, function(file) { 
\t\t\t\t\t\t\t\tif (file.rename) {
\t\t\t\t\t\t\t\t\trenames.push(file.name);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\treturn !file.remove ? true : false;
\t\t\t\t\t\t\t}),
\t\t\t\t\t\t\tcnt    = files.length,
\t\t\t\t\t\t\tgroups = {},
\t\t\t\t\t\t\targs   = [],
\t\t\t\t\t\t\ttargets, reqData;

\t\t\t\t\t\tif (!cnt) {
\t\t\t\t\t\t\treturn dfrd.resolve();
\t\t\t\t\t\t}

\t\t\t\t\t\ttargets = \$.map(files, function(f) { return f.hash; });
\t\t\t\t\t\t
\t\t\t\t\t\treqData = {cmd : 'paste', dst : dst.hash, targets : targets, cut : cut ? 1 : 0, renames : renames, hashes : hashes, suffix : fm.options.backupSuffix};
\t\t\t\t\t\tif (fm.api < 2.1) {
\t\t\t\t\t\t\treqData.src = files[0].phash;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\tdata   : reqData,
\t\t\t\t\t\t\t\tnotify : {type : cmd, cnt : cnt},
\t\t\t\t\t\t\t\tcancel : true,
\t\t\t\t\t\t\t\tnavigate : { 
\t\t\t\t\t\t\t\t\ttoast  : opts.noToast? {} : {
\t\t\t\t\t\t\t\t\t\tinbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd' + cmd)]), action: {
\t\t\t\t\t\t\t\t\t\t\tcmd: 'open',
\t\t\t\t\t\t\t\t\t\t\tmsg: 'cmdopendir',
\t\t\t\t\t\t\t\t\t\t\tdata: [dst.hash],
\t\t\t\t\t\t\t\t\t\t\tdone: 'select',
\t\t\t\t\t\t\t\t\t\t\tcwdNot: dst.hash
\t\t\t\t\t\t\t\t\t\t}}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tvar dsts = {},
\t\t\t\t\t\t\t\t\tadded = data.added && data.added.length? data.added : null;
\t\t\t\t\t\t\t\tif (cut && added) {
\t\t\t\t\t\t\t\t\t// undo/redo
\t\t\t\t\t\t\t\t\t\$.each(files, function(i, f) {
\t\t\t\t\t\t\t\t\t\tvar phash = f.phash,
\t\t\t\t\t\t\t\t\t\t\tsrcHash = function(name) {
\t\t\t\t\t\t\t\t\t\t\t\tvar hash;
\t\t\t\t\t\t\t\t\t\t\t\t\$.each(added, function(i, f) {
\t\t\t\t\t\t\t\t\t\t\t\t\tif (f.name === name) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\thash = f.hash;
\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\treturn hash;
\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\tshash = srcHash(f.name);
\t\t\t\t\t\t\t\t\t\tif (shash) {
\t\t\t\t\t\t\t\t\t\t\tif (dsts[phash]) {
\t\t\t\t\t\t\t\t\t\t\t\tdsts[phash].push(shash);
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tdsts[phash] = [ shash ];
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tif (Object.keys(dsts).length) {
\t\t\t\t\t\t\t\t\t\tdata.undo = {
\t\t\t\t\t\t\t\t\t\t\tcmd : 'move',
\t\t\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\t\tvar reqs = [];
\t\t\t\t\t\t\t\t\t\t\t\t\$.each(dsts, function(dst, targets) {
\t\t\t\t\t\t\t\t\t\t\t\t\treqs.push(fm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata : {cmd : 'paste', dst : dst, targets : targets, cut : 1},
\t\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'undo', cnt : targets.length}
\t\t\t\t\t\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\treturn \$.when.apply(null, reqs);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\tdata.redo = {
\t\t\t\t\t\t\t\t\t\t\tcmd : 'move',
\t\t\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\tdata : reqData,
\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'redo', cnt : cnt}
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdfrd.resolve(data);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.fail(function(flg) {
\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\tif (flg === 0) {
\t\t\t\t\t\t\t\t\t// canceling
\t\t\t\t\t\t\t\t\tfm.sync();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\tfm.unlockfiles({files : files});
\t\t\t\t\t\t\t});
\t\t\t\t\t},
\t\t\t\t\tinternames;

\t\t\t\tif (!fm.isCommandEnabled(self.name, dst.hash) || !files.length) {
\t\t\t\t\treturn dfrd.resolve();
\t\t\t\t}
\t\t\t\t
\t\t\t\tif (fm.oldAPI) {
\t\t\t\t\tpaste(files);
\t\t\t\t} else {
\t\t\t\t\t
\t\t\t\t\tif (!fm.option('copyOverwrite', dst.hash)) {
\t\t\t\t\t\tpaste(files);
\t\t\t\t\t} else {
\t\t\t\t\t\tinternames = \$.map(files, function(f) { return f.name; });
\t\t\t\t\t\tdst.hash == fm.cwd().hash
\t\t\t\t\t\t\t? valid(\$.map(fm.files(), function(file) { return file.phash == dst.hash ? {hash: file.hash, name: file.name} : null; }))
\t\t\t\t\t\t\t: fm.request({
\t\t\t\t\t\t\t\tdata : {cmd : 'ls', target : dst.hash, intersect : internames},
\t\t\t\t\t\t\t\tnotify : {type : 'prepare', cnt : 1, hideCnt : true},
\t\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.always(function(data) {
\t\t\t\t\t\t\t\tvalid(data.list);
\t\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn dfrd;
\t\t\t},
\t\t\tparents, fparents, cutDfrd;


\t\tif (!cnt || !dst || dst.mime != 'directory') {
\t\t\treturn dfrd.reject();
\t\t}
\t\t\t
\t\tif (!dst.write)\t{
\t\t\treturn dfrd.reject([error, files[0].name, 'errPerm']);
\t\t}
\t\t
\t\tparents = fm.parents(dst.hash);
\t\t
\t\t\$.each(files, function(i, file) {
\t\t\tif (!file.read) {
\t\t\t\treturn !dfrd.reject([error, file.name, 'errPerm']);
\t\t\t}
\t\t\t
\t\t\tif (cut && file.locked) {
\t\t\t\treturn !dfrd.reject(['errLocked', file.name]);
\t\t\t}
\t\t\t
\t\t\tif (\$.inArray(file.hash, parents) !== -1) {
\t\t\t\treturn !dfrd.reject(['errCopyInItself', file.name]);
\t\t\t}
\t\t\t
\t\t\tif (file.mime && file.mime !== 'directory' && ! fm.uploadMimeCheck(file.mime, dst.hash)) {
\t\t\t\treturn !dfrd.reject([error, file.name, 'errUploadMime']);
\t\t\t}
\t\t\t
\t\t\tfparents = fm.parents(file.hash);
\t\t\tfparents.pop();
\t\t\tif (\$.inArray(dst.hash, fparents) !== -1) {
\t\t\t\t
\t\t\t\tif (\$.grep(fparents, function(h) { var d = fm.file(h); return d.phash == dst.hash && d.name == file.name ? true : false; }).length) {
\t\t\t\t\treturn !dfrd.reject(['errReplByChild', file.name]);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tif (file.phash == dst.hash) {
\t\t\t\tfcopy.push(file.hash);
\t\t\t} else {
\t\t\t\tfpaste.push({
\t\t\t\t\thash  : file.hash,
\t\t\t\t\tphash : file.phash,
\t\t\t\t\tname  : file.name
\t\t\t\t});
\t\t\t}
\t\t});

\t\tif (dfrd.state() === 'rejected') {
\t\t\treturn dfrd;
\t\t}

\t\tcutDfrd = \$.Deferred();
\t\tif (cut && self.options.moveConfirm) {
\t\t\tfm.confirm({
\t\t\t\ttitle  : 'moveFiles',
\t\t\t\ttext   : fm.i18n('confirmMove', dst.i18 || dst.name),
\t\t\t\taccept : {
\t\t\t\t\tlabel    : 'btnYes',
\t\t\t\t\tcallback : function() {  
\t\t\t\t\t\tcutDfrd.resolve();
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcancel : {
\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\tcallback : function() {
\t\t\t\t\t\tcutDfrd.reject();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t} else {
\t\t\tcutDfrd.resolve();
\t\t}

\t\tcutDfrd.done(function() {
\t\t\t\$.when(
\t\t\t\tcopy(fcopy),
\t\t\t\tpaste(fpaste)
\t\t\t)
\t\t\t.done(function(cr, pr) {
\t\t\t\tdfrd.resolve(pr && pr.undo? pr : void(0));
\t\t\t})
\t\t\t.fail(function() {
\t\t\t\tdfrd.reject();
\t\t\t})
\t\t\t.always(function() {
\t\t\t\tcut && fm.clipboard([]);
\t\t\t});
\t\t}).fail(function() {
\t\t\tdfrd.reject();
\t\t});
\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/places.js
 */

/**
 * @class  elFinder command \"places\"
 * Regist to Places
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.places = function() {
\t\tvar self   = this,
\tfm     = this.fm,
\tfilter = function(hashes) {
\t\treturn \$.grep(self.files(hashes), function(f) { return f.mime == 'directory' ? true : false; });
\t},
\tplaces = null;
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.hashes(select),
\t\tcnt = sel.length;
\t\t
\t\treturn  places && cnt && cnt == filter(sel).length ? 0 : -1;
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar files = this.files(hashes);
\t\tplaces.trigger('regist', [ files ]);
\t\treturn \$.Deferred().resolve();
\t};
\t
\tfm.one('load', function(){
\t\tplaces = fm.ui.places;
\t});

};


/*
 * File: /js/commands/preference.js
 */

/**
 * @class  elFinder command \"preference\"
 * \"Preference\" dialog
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.preference = function() {
\tvar self    = this,
\t\tfm      = this.fm,
\t\tr       = 'replace',
\t\ttab     = '<li class=\"' + fm.res('class', 'tabstab') + ' elfinder-preference-tab-{id}\"><a href=\"#'+fm.namespace+'-preference-{id}\" id=\"'+fm.namespace+'-preference-tab-{id}\" class=\"ui-tabs-anchor {class}\">{title}</a></li>',
\t\tbase    = \$('<div class=\"ui-tabs ui-widget ui-widget-content ui-corner-all elfinder-preference\">'), 
\t\tul      = \$('<ul class=\"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-top\">'),
\t\ttabs    = \$('<div class=\"elfinder-preference-tabs ui-tabs-panel ui-widget-content ui-corner-bottom\"></div>'),
\t\tsep     = '<div class=\"elfinder-preference-separator\"></div>',
\t\tselfUrl = \$('base').length? document.location.href.replace(/#.*\$/, '') : '',
\t\tselectTab = function(tab) {
\t\t\t\$('#'+fm.namespace+'-preference-tab-'+tab).trigger('mouseover').trigger('click');
\t\t\topenTab = tab;
\t\t},
\t\tclTabActive = fm.res('class', 'tabsactive'),
\t\tbuild   = function() {
\t\t\tvar cats = self.options.categories || {
\t\t\t\t\t'language' : ['language'],
\t\t\t\t\t'theme' : ['theme'],
\t\t\t\t\t'toolbar' : ['toolbarPref'],
\t\t\t\t\t'workspace' : ['iconSize','columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden'],
\t\t\t\t\t'dialog' : ['autoFocusDialog'],
\t\t\t\t\t'selectionInfo' : ['infoItems', 'hashChecker'],
\t\t\t\t\t'reset' : ['clearBrowserData'],
\t\t\t\t\t'all' : true
\t\t\t\t},
\t\t\t\tforms = self.options.prefs || ['language', 'theme', 'toolbarPref', 'iconSize', 'columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden', 'infoItems', 'hashChecker', 'autoFocusDialog', 'clearBrowserData'];
\t\t\t
\t\t\tif (!fm.cookieEnabled) {
\t\t\t\tdelete cats.language;
\t\t\t}

\t\t\tforms = fm.arrayFlip(forms, true);
\t\t\t
\t\t\tif (fm.options.getFileCallback) {
\t\t\t\tdelete forms.selectAction;
\t\t\t}
\t\t\tif (!fm.UA.Fullscreen) {
\t\t\t\tdelete forms.useFullscreen;
\t\t\t}

\t\t\tforms.language && (forms.language = (function() {
\t\t\t\tvar langSel = \$('<select></select>').on('change', function() {
\t\t\t\t\t\tvar lang = \$(this).val();
\t\t\t\t\t\tfm.storage('lang', lang);
\t\t\t\t\t\t\$('#'+fm.id).elfinder('reload');
\t\t\t\t\t}),
\t\t\t\t\toptTags = [],
\t\t\t\t\tlangs = self.options.langs || {
\t\t\t\t\t\tar: 'العربية',
\t\t\t\t\t\tbg: 'Български',
\t\t\t\t\t\tca: 'Català',
\t\t\t\t\t\tcs: 'Čeština',
\t\t\t\t\t\tda: 'Dansk',
\t\t\t\t\t\tde: 'Deutsch',
\t\t\t\t\t\tel: 'Ελληνικά',
\t\t\t\t\t\ten: 'English',
\t\t\t\t\t\tes: 'Español',
\t\t\t\t\t\tfa: 'فارسی',
\t\t\t\t\t\tfo: 'Føroyskt',
\t\t\t\t\t\tfr: 'Français',
\t\t\t\t\t\tfr_CA: 'Français (Canada)',
\t\t\t\t\t\the: 'עברית',
\t\t\t\t\t\thr: 'Hrvatski',
\t\t\t\t\t\thu: 'Magyar',
\t\t\t\t\t\tid: 'Bahasa Indonesia',
\t\t\t\t\t\tit: 'Italiano',
\t\t\t\t\t\tja: '日本語',
\t\t\t\t\t\tko: '한국어',
\t\t\t\t\t\tnl: 'Nederlands',
\t\t\t\t\t\tno: 'Norsk',
\t\t\t\t\t\tpl: 'Polski',
\t\t\t\t\t\tpt_BR: 'Português',
\t\t\t\t\t\tro: 'Română',
\t\t\t\t\t\tru: 'Pусский',
\t\t\t\t\t\tsi: 'සිංහල',
\t\t\t\t\t\tsk: 'Slovenčina',
\t\t\t\t\t\tsl: 'Slovenščina',
\t\t\t\t\t\tsr: 'Srpski',
\t\t\t\t\t\tsv: 'Svenska',
\t\t\t\t\t\ttr: 'Türkçe',
\t\t\t\t\t\tug_CN: 'ئۇيغۇرچە',
\t\t\t\t\t\tuk: 'Український',
\t\t\t\t\t\tvi: 'Tiếng Việt',
\t\t\t\t\t\tzh_CN: '简体中文',
\t\t\t\t\t\tzh_TW: '正體中文'
\t\t\t\t\t};
\t\t\t\tif (!fm.cookieEnabled) {
\t\t\t\t\treturn \$();
\t\t\t\t}
\t\t\t\t\$.each(langs, function(lang, name) {
\t\t\t\t\toptTags.push('<option value=\"'+lang+'\">'+name+'</option>');
\t\t\t\t});
\t\t\t\treturn langSel.append(optTags.join('')).val(fm.lang);
\t\t\t})());
\t\t\t
\t\t\tforms.theme && (forms.theme = (function() {
\t\t\t\tvar cnt = fm.options.themes? Object.keys(fm.options.themes).length : 0;
\t\t\t\tif (cnt === 0 || (cnt === 1 && fm.options.themes.default)) {
\t\t\t\t\treturn null;
\t\t\t\t}
\t\t\t\tvar themeSel = \$('<select></select>').on('change', function() {
\t\t\t\t\t\tvar theme = \$(this).val();
\t\t\t\t\t\tfm.changeTheme(theme).storage('theme', theme);
\t\t\t\t\t}),
\t\t\t\t\toptTags = [],
\t\t\t\t\ttpl = {
\t\t\t\t\t\timage: '<img class=\"elfinder-preference-theme elfinder-preference-theme-image\" src=\"\$2\" />',
\t\t\t\t\t\tlink: '<a href=\"\$1\" target=\"_blank\" title=\"\$3\">\$2</a>',
\t\t\t\t\t\tdata: '<dt>\$1</dt><dd><span class=\"elfinder-preference-theme elfinder-preference-theme-\$0\">\$2</span></dd>'
\t\t\t\t\t},
\t\t\t\t\titems = ['image', 'description', 'author', 'email', 'license'],
\t\t\t\t\trender = function(key, data) {
\t\t\t\t\t},
\t\t\t\t\tdefBtn = \$('<button class=\"ui-button ui-corner-all ui-widget elfinder-preference-theme-default\"></button>').text(fm.i18n('default')).on('click', function(e) {
\t\t\t\t\t\tthemeSel.val('default').trigger('change');
\t\t\t\t\t}),
\t\t\t\t\tlist = \$('<div class=\"elfinder-reference-hide-taball\"></div>').on('click', 'button', function() {
\t\t\t\t\t\t\tvar val = \$(this).data('themeid');
\t\t\t\t\t\t\tthemeSel.val(val).trigger('change');
\t\t\t\t\t});

\t\t\t\tif (!fm.options.themes.default) {
\t\t\t\t\tthemeSel.append('<option value=\"default\">'+fm.i18n('default')+'</option>');
\t\t\t\t}
\t\t\t\t\$.each(fm.options.themes, function(id, val) {
\t\t\t\t\tvar opt = \$('<option class=\"elfinder-theme-option-'+id+'\" value=\"'+id+'\">'+fm.i18n(id)+'</option>'),
\t\t\t\t\t\tdsc = \$('<fieldset class=\"ui-widget ui-widget-content ui-corner-all elfinder-theme-list-'+id+'\"><legend>'+fm.i18n(id)+'</legend><div><span class=\"elfinder-spinner\"></span></div></fieldset>'),
\t\t\t\t\t\ttm;
\t\t\t\t\tthemeSel.append(opt);
\t\t\t\t\tlist.append(dsc);
\t\t\t\t\ttm = setTimeout(function() {
\t\t\t\t\t\tdsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id]));
\t\t\t\t\t}, 10000);
\t\t\t\t\tfm.getTheme(id).always(function() {
\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\tvar link, val = \$(), dl = \$('<dl></dl>');
\t\t\t\t\t\tlink = data.link? tpl.link.replace(/\\\$1/g, data.link).replace(/\\\$3/g, fm.i18n('website')) : '\$2';
\t\t\t\t\t\tif (data.name) {
\t\t\t\t\t\t\topt.html(fm.i18n(data.name));
\t\t\t\t\t\t}
\t\t\t\t\t\tdsc.children('legend').html(link.replace(/\\\$2/g, fm.i18n(data.name) || id));
\t\t\t\t\t\t\$.each(items, function(i, key) {
\t\t\t\t\t\t\tvar t = tpl[key] || tpl.data,
\t\t\t\t\t\t\t\telm;
\t\t\t\t\t\t\tif (data[key]) {
\t\t\t\t\t\t\t\telm = t.replace(/\\\$0/g, fm.escape(key)).replace(/\\\$1/g, fm.i18n(key)).replace(/\\\$2/g, fm.i18n(data[key]));
\t\t\t\t\t\t\t\tif (key === 'image' && data.link) {
\t\t\t\t\t\t\t\t\telm = \$(elm).on('click', function() {
\t\t\t\t\t\t\t\t\t\tthemeSel.val(id).trigger('change');
\t\t\t\t\t\t\t\t\t}).attr('title', fm.i18n('select'));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tdl.append(elm);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tval = val.add(dl);
\t\t\t\t\t\tval = val.add(\$('<div class=\"elfinder-preference-theme-btn\"></div>').append(\$('<button class=\"ui-button ui-corner-all ui-widget\"></button>').data('themeid', id).html(fm.i18n('select'))));
\t\t\t\t\t\tdsc.find('span.elfinder-spinner').replaceWith(val);
\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\tdsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id]));
\t\t\t\t\t});
\t\t\t\t});
\t\t\t\treturn \$('<div></div>').append(themeSel.val(fm.theme && fm.theme.id? fm.theme.id : 'default'), defBtn, list);
\t\t\t})());

\t\t\tforms.toolbarPref && (forms.toolbarPref = (function() {
\t\t\t\tvar pnls = \$.map(fm.options.uiOptions.toolbar, function(v) {
\t\t\t\t\t\treturn \$.isArray(v)? v : null;
\t\t\t\t\t}),
\t\t\t\t\ttags = [],
\t\t\t\t\thides = fm.storage('toolbarhides') || {};
\t\t\t\t\$.each(pnls, function() {
\t\t\t\t\tvar cmd = this,
\t\t\t\t\t\tname = fm.i18n('cmd'+cmd);
\t\t\t\t\tif (name === 'cmd'+cmd) {
\t\t\t\t\t\tname = fm.i18n(cmd);
\t\t\t\t\t}
\t\t\t\t\ttags.push('<span class=\"elfinder-preference-toolbar-item\"><label><input type=\"checkbox\" value=\"'+cmd+'\" '+(hides[cmd]? '' : 'checked')+'/>'+name+'</label></span>');
\t\t\t\t});
\t\t\t\treturn \$(tags.join(' ')).on('change', 'input', function() {
\t\t\t\t\tvar v = \$(this).val(),
\t\t\t\t\t\to = \$(this).is(':checked');
\t\t\t\t\tif (!o && !hides[v]) {
\t\t\t\t\t\thides[v] = true;
\t\t\t\t\t} else if (o && hides[v]) {
\t\t\t\t\t\tdelete hides[v];
\t\t\t\t\t}
\t\t\t\t\tfm.storage('toolbarhides', hides);
\t\t\t\t\tfm.trigger('toolbarpref');
\t\t\t\t});
\t\t\t})());
\t\t\t
\t\t\tforms.iconSize && (forms.iconSize = (function() {
\t\t\t\tvar max = fm.options.uiOptions.cwd.iconsView.sizeMax || 3,
\t\t\t\t\tsize = fm.storage('iconsize') || fm.options.uiOptions.cwd.iconsView.size || 0,
\t\t\t\t\tsld = \$('<div class=\"touch-punch\"></div>').slider({
\t\t\t\t\t\tclasses: {
\t\t\t\t\t\t\t'ui-slider-handle': 'elfinder-tabstop',
\t\t\t\t\t\t},
\t\t\t\t\t\tvalue: size,
\t\t\t\t\t\tmax: max,
\t\t\t\t\t\tslide: function(e, ui) {
\t\t\t\t\t\t\tfm.getUI('cwd').trigger('iconpref', {size: ui.value});
\t\t\t\t\t\t},
\t\t\t\t\t\tchange: function(e, ui) {
\t\t\t\t\t\t\tfm.storage('iconsize', ui.value);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\tfm.getUI('cwd').on('iconpref', function(e, data) {
\t\t\t\t\tsld.slider('option', 'value', data.size);
\t\t\t\t});
\t\t\t\treturn sld;
\t\t\t})());

\t\t\tforms.columnPref && (forms.columnPref = (function() {
\t\t\t\tvar cols = fm.options.uiOptions.cwd.listView.columns,
\t\t\t\t\ttags = [],
\t\t\t\t\thides = fm.storage('columnhides') || {};
\t\t\t\t\$.each(cols, function() {
\t\t\t\t\tvar key = this,
\t\t\t\t\t\tname = fm.getColumnName(key);
\t\t\t\t\ttags.push('<span class=\"elfinder-preference-column-item\"><label><input type=\"checkbox\" value=\"'+key+'\" '+(hides[key]? '' : 'checked')+'/>'+name+'</label></span>');
\t\t\t\t});
\t\t\t\treturn \$(tags.join(' ')).on('change', 'input', function() {
\t\t\t\t\tvar v = \$(this).val(),
\t\t\t\t\t\to = \$(this).is(':checked');
\t\t\t\t\tif (!o && !hides[v]) {
\t\t\t\t\t\thides[v] = true;
\t\t\t\t\t} else if (o && hides[v]) {
\t\t\t\t\t\tdelete hides[v];
\t\t\t\t\t}
\t\t\t\t\tfm.storage('columnhides', hides);
\t\t\t\t\tfm.trigger('columnpref', { repaint: true });
\t\t\t\t});
\t\t\t})());
\t\t\t
\t\t\tforms.selectAction && (forms.selectAction = (function() {
\t\t\t\tvar actSel = \$('<select></select>').on('change', function() {
\t\t\t\t\t\tvar act = \$(this).val();
\t\t\t\t\t\tfm.storage('selectAction', act === 'default'? null : act);
\t\t\t\t\t}),
\t\t\t\t\toptTags = [],
\t\t\t\t\tacts = self.options.selectActions,
\t\t\t\t\tdefAct = fm.getCommand('open').options.selectAction || 'open';
\t\t\t\t
\t\t\t\tif (\$.inArray(defAct, acts) === -1) {
\t\t\t\t\tacts.unshift(defAct);
\t\t\t\t}
\t\t\t\t\$.each(acts, function(i, act) {
\t\t\t\t\tvar names = \$.map(act.split('/'), function(cmd) {
\t\t\t\t\t\tvar name = fm.i18n('cmd'+cmd);
\t\t\t\t\t\tif (name === 'cmd'+cmd) {
\t\t\t\t\t\t\tname = fm.i18n(cmd);
\t\t\t\t\t\t}
\t\t\t\t\t\treturn name;
\t\t\t\t\t});
\t\t\t\t\toptTags.push('<option value=\"'+act+'\">'+names.join('/')+'</option>');
\t\t\t\t});
\t\t\t\treturn actSel.append(optTags.join('')).val(fm.storage('selectAction') || defAct);
\t\t\t})());
\t\t\t
\t\t\tforms.makefileTypes && (forms.makefileTypes = (function() {
\t\t\t\tvar hides = fm.getCommand('edit').getMkfileHides(),
\t\t\t\t\tgetTag = function() {
\t\t\t\t\t\tvar tags = [];
\t\t\t\t\t\t// re-assign hides
\t\t\t\t\t\thides = fm.getCommand('edit').getMkfileHides();
\t\t\t\t\t\t\$.each(fm.mimesCanMakeEmpty, function(mime, type) {
\t\t\t\t\t\t\tvar name = fm.getCommand('mkfile').getTypeName(mime, type);
\t\t\t\t\t\t\ttags.push('<span class=\"elfinder-preference-column-item\" title=\"'+fm.escape(name)+'\"><label><input type=\"checkbox\" value=\"'+mime+'\" '+(hides[mime]? '' : 'checked')+'/>'+type+'</label></span>');
\t\t\t\t\t\t});
\t\t\t\t\t\treturn tags.join(' ');
\t\t\t\t\t},
\t\t\t\t\telm = \$('<div></div>').on('change', 'input', function() {
\t\t\t\t\t\tvar v = \$(this).val(),
\t\t\t\t\t\t\to = \$(this).is(':checked');
\t\t\t\t\t\tif (!o && !hides[v]) {
\t\t\t\t\t\t\thides[v] = true;
\t\t\t\t\t\t} else if (o && hides[v]) {
\t\t\t\t\t\t\tdelete hides[v];
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.storage('mkfileHides', hides);
\t\t\t\t\t\tfm.trigger('canMakeEmptyFile');
\t\t\t\t\t}).append(getTag()),
\t\t\t\t\tadd = \$('<div></div>').append(
\t\t\t\t\t\t\$('<input type=\"text\" placeholder=\"'+fm.i18n('typeOfTextfile')+'\"/>').on('keydown', function(e) {
\t\t\t\t\t\t\t(e.keyCode === \$.ui.keyCode.ENTER) && \$(this).next().trigger('click');
\t\t\t\t\t\t}),
\t\t\t\t\t\t\$('<button class=\"ui-button\"></button>').html(fm.i18n('add')).on('click', function() {
\t\t\t\t\t\t\tvar input = \$(this).prev(),
\t\t\t\t\t\t\t\tval = input.val(),
\t\t\t\t\t\t\t\tuiToast = fm.getUI('toast'),
\t\t\t\t\t\t\t\terr = function() {
\t\t\t\t\t\t\t\t\tuiToast.appendTo(input.closest('.ui-dialog'));
\t\t\t\t\t\t\t\t\tfm.toast({
\t\t\t\t\t\t\t\t\t\tmsg: fm.i18n('errUsupportType'),
\t\t\t\t\t\t\t\t\t\tmode: 'warning',
\t\t\t\t\t\t\t\t\t\tonHidden: function() {
\t\t\t\t\t\t\t\t\t\t\tuiToast.children().length === 1 && uiToast.appendTo(fm.getUI());
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tinput.trigger('focus');
\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\ttmpMimes;
\t\t\t\t\t\t\tif (!val.match(/\\//)) {
\t\t\t\t\t\t\t\tval = fm.arrayFlip(fm.mimeTypes)[val];
\t\t\t\t\t\t\t\tif (!val) {
\t\t\t\t\t\t\t\t\treturn err();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tinput.val(val);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (!fm.mimeIsText(val) || !fm.mimeTypes[val]) {
\t\t\t\t\t\t\t\treturn err();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tfm.trigger('canMakeEmptyFile', {mimes: [val], unshift: true});
\t\t\t\t\t\t\ttmpMimes = {};
\t\t\t\t\t\t\ttmpMimes[val] = fm.mimeTypes[val];
\t\t\t\t\t\t\tfm.storage('mkfileTextMimes', Object.assign(tmpMimes, fm.storage('mkfileTextMimes') || {}));
\t\t\t\t\t\t\tinput.val('');
\t\t\t\t\t\t\tuiToast.appendTo(input.closest('.ui-dialog'));
\t\t\t\t\t\t\tfm.toast({
\t\t\t\t\t\t\t\tmsg: fm.i18n(['complete', val + ' (' + tmpMimes[val] + ')']),
\t\t\t\t\t\t\t\tonHidden: function() {
\t\t\t\t\t\t\t\t\tuiToast.children().length === 1 && uiToast.appendTo(fm.getUI());
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}),
\t\t\t\t\t\t\$('<button class=\"ui-button\"></button>').html(fm.i18n('reset')).on('click', function() {
\t\t\t\t\t\t\tfm.one('canMakeEmptyFile', {done: function() {
\t\t\t\t\t\t\t\telm.empty().append(getTag());
\t\t\t\t\t\t\t}});
\t\t\t\t\t\t\tfm.trigger('canMakeEmptyFile', {resetTexts: true});
\t\t\t\t\t\t})
\t\t\t\t\t),
\t\t\t\t\ttm;
\t\t\t\tfm.bind('canMakeEmptyFile', {done: function(e) {
\t\t\t\t\tif (e.data && e.data.mimes && e.data.mimes.length) {
\t\t\t\t\t\telm.empty().append(getTag());
\t\t\t\t\t}
\t\t\t\t}});
\t\t\t\treturn \$('<div></div>').append(elm, add);
\t\t\t})());

\t\t\tforms.useStoredEditor && (forms.useStoredEditor = \$('<input type=\"checkbox\"/>').prop('checked', (function() {
\t\t\t\tvar s = fm.storage('useStoredEditor');
\t\t\t\treturn s? (s > 0) : fm.options.commandsOptions.edit.useStoredEditor;
\t\t\t})()).on('change', function(e) {
\t\t\t\tfm.storage('useStoredEditor', \$(this).is(':checked')? 1 : -1);
\t\t\t}));

\t\t\tforms.editorMaximized && (forms.editorMaximized = \$('<input type=\"checkbox\"/>').prop('checked', (function() {
\t\t\t\tvar s = fm.storage('editorMaximized');
\t\t\t\treturn s? (s > 0) : fm.options.commandsOptions.edit.editorMaximized;
\t\t\t})()).on('change', function(e) {
\t\t\t\tfm.storage('editorMaximized', \$(this).is(':checked')? 1 : -1);
\t\t\t}));

\t\t\tforms.useFullscreen && (forms.useFullscreen = \$('<input type=\"checkbox\"/>').prop('checked', (function() {
\t\t\t\tvar s = fm.storage('useFullscreen');
\t\t\t\treturn s? (s > 0) : fm.options.commandsOptions.fullscreen.mode === 'screen';
\t\t\t})()).on('change', function(e) {
\t\t\t\tfm.storage('useFullscreen', \$(this).is(':checked')? 1 : -1);
\t\t\t}));

\t\t\tif (forms.showHidden) {
\t\t\t\t(function() {
\t\t\t\t\tvar setTitle = function() {
\t\t\t\t\t\t\tvar s = fm.storage('hide'),
\t\t\t\t\t\t\t\tt = [],
\t\t\t\t\t\t\t\tv;
\t\t\t\t\t\t\tif (s && s.items) {
\t\t\t\t\t\t\t\t\$.each(s.items, function(h, n) {
\t\t\t\t\t\t\t\t\tt.push(fm.escape(n));
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telms.prop('disabled', !t.length)[t.length? 'removeClass' : 'addClass']('ui-state-disabled');
\t\t\t\t\t\t\tv = t.length? t.join('\\n') : '';
\t\t\t\t\t\t\tforms.showHidden.attr('title',v);
\t\t\t\t\t\t\tuseTooltip && forms.showHidden.tooltip('option', 'content', v.replace(/\\n/g, '<br>')).tooltip('close');
\t\t\t\t\t\t},
\t\t\t\t\t\tchk = \$('<input type=\"checkbox\"/>').prop('checked', (function() {
\t\t\t\t\t\t\tvar s = fm.storage('hide');
\t\t\t\t\t\t\treturn s && s.show;
\t\t\t\t\t\t})()).on('change', function(e) {
\t\t\t\t\t\t\tvar o = {};
\t\t\t\t\t\t\to[\$(this).is(':checked')? 'show' : 'hide'] = true;
\t\t\t\t\t\t\tfm.exec('hide', void(0), o);
\t\t\t\t\t\t}),
\t\t\t\t\t\tbtn = \$('<button class=\"ui-button ui-corner-all ui-widget\"></button>').append(fm.i18n('reset')).on('click', function() {
\t\t\t\t\t\t\tfm.exec('hide', void(0), {reset: true});
\t\t\t\t\t\t\t\$(this).parent().find('input:first').prop('checked', false);
\t\t\t\t\t\t\tsetTitle();
\t\t\t\t\t\t}),
\t\t\t\t\t\telms = \$().add(chk).add(btn),
\t\t\t\t\t\tuseTooltip;
\t\t\t\t\t
\t\t\t\t\tforms.showHidden = \$('<div></div>').append(chk, btn);
\t\t\t\t\tfm.bind('hide', function(e) {
\t\t\t\t\t\tvar d = e.data;
\t\t\t\t\t\tif (!d.opts || (!d.opts.show && !d.opts.hide)) {
\t\t\t\t\t\t\tsetTitle();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tif (fm.UA.Mobile && \$.fn.tooltip) {
\t\t\t\t\t\tuseTooltip = true;
\t\t\t\t\t\tforms.showHidden.tooltip({
\t\t\t\t\t\t\tclasses: {
\t\t\t\t\t\t\t\t'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
\t\t\t\t\t\t\ttrack: true
\t\t\t\t\t\t}).css('user-select', 'none');
\t\t\t\t\t\tbtn.css('user-select', 'none');
\t\t\t\t\t}
\t\t\t\t\tsetTitle();
\t\t\t\t})();
\t\t\t}
\t\t\t
\t\t\tforms.infoItems && (forms.infoItems = (function() {
\t\t\t\tvar items = fm.getCommand('info').items,
\t\t\t\t\ttags = [],
\t\t\t\t\thides = fm.storage('infohides') || fm.arrayFlip(fm.options.commandsOptions.info.hideItems, true);
\t\t\t\t\$.each(items, function() {
\t\t\t\t\tvar key = this,
\t\t\t\t\t\tname = fm.i18n(key);
\t\t\t\t\ttags.push('<span class=\"elfinder-preference-info-item\"><label><input type=\"checkbox\" value=\"'+key+'\" '+(hides[key]? '' : 'checked')+'/>'+name+'</label></span>');
\t\t\t\t});
\t\t\t\treturn \$(tags.join(' ')).on('change', 'input', function() {
\t\t\t\t\tvar v = \$(this).val(),
\t\t\t\t\t\to = \$(this).is(':checked');
\t\t\t\t\tif (!o && !hides[v]) {
\t\t\t\t\t\thides[v] = true;
\t\t\t\t\t} else if (o && hides[v]) {
\t\t\t\t\t\tdelete hides[v];
\t\t\t\t\t}
\t\t\t\t\tfm.storage('infohides', hides);
\t\t\t\t\tfm.trigger('infopref', { repaint: true });
\t\t\t\t});
\t\t\t})());
\t\t\t
\t\t\tforms.hashChecker && fm.hashCheckers.length && (forms.hashChecker = (function() {
\t\t\t\tvar tags = [],
\t\t\t\t\tenabled = fm.arrayFlip(fm.storage('hashchekcer') || fm.options.commandsOptions.info.showHashAlgorisms, true);
\t\t\t\t\$.each(fm.hashCheckers, function() {
\t\t\t\t\tvar cmd = this,
\t\t\t\t\t\tname = fm.i18n(cmd);
\t\t\t\t\ttags.push('<span class=\"elfinder-preference-hashchecker-item\"><label><input type=\"checkbox\" value=\"'+cmd+'\" '+(enabled[cmd]? 'checked' : '')+'/>'+name+'</label></span>');
\t\t\t\t});
\t\t\t\treturn \$(tags.join(' ')).on('change', 'input', function() {
\t\t\t\t\tvar v = \$(this).val(),
\t\t\t\t\t\to = \$(this).is(':checked');
\t\t\t\t\tif (o) {
\t\t\t\t\t\tenabled[v] = true;
\t\t\t\t\t} else if (enabled[v]) {
\t\t\t\t\t\tdelete enabled[v];
\t\t\t\t\t}
\t\t\t\t\tfm.storage('hashchekcer', \$.grep(fm.hashCheckers, function(v) {
\t\t\t\t\t\treturn enabled[v];
\t\t\t\t\t}));
\t\t\t\t});
\t\t\t})());

\t\t\tforms.autoFocusDialog && (forms.autoFocusDialog = \$('<input type=\"checkbox\"/>').prop('checked', (function() {
\t\t\t\tvar s = fm.storage('autoFocusDialog');
\t\t\t\treturn s? (s > 0) : fm.options.uiOptions.dialog.focusOnMouseOver;
\t\t\t})()).on('change', function(e) {
\t\t\t\tfm.storage('autoFocusDialog', \$(this).is(':checked')? 1 : -1);
\t\t\t}));
\t\t\t
\t\t\tforms.clearBrowserData && (forms.clearBrowserData = \$('<button></button>').text(fm.i18n('reset')).button().on('click', function(e) {
\t\t\t\te.preventDefault();
\t\t\t\tfm.storage();
\t\t\t\t\$('#'+fm.id).elfinder('reload');
\t\t\t}));
\t\t\t
\t\t\t\$.each(cats, function(id, prefs) {
\t\t\t\tvar dls, found;
\t\t\t\tif (prefs === true) {
\t\t\t\t\tfound = 1;
\t\t\t\t} else if (prefs) {
\t\t\t\t\tdls = \$();
\t\t\t\t\t\$.each(prefs, function(i, n) {
\t\t\t\t\t\tvar f, title, chks = '', cbox;
\t\t\t\t\t\tif (f = forms[n]) {
\t\t\t\t\t\t\tfound = 2;
\t\t\t\t\t\t\ttitle = fm.i18n(n);
\t\t\t\t\t\t\tcbox = \$(f).filter('input[type=\"checkbox\"]');
\t\t\t\t\t\t\tif (!cbox.length) {
\t\t\t\t\t\t\t\tcbox = \$(f).find('input[type=\"checkbox\"]');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (cbox.length === 1) {
\t\t\t\t\t\t\t\tif (!cbox.attr('id')) {
\t\t\t\t\t\t\t\t\tcbox.attr('id', 'elfinder-preference-'+n+'-checkbox');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\ttitle = '<label for=\"'+cbox.attr('id')+'\">'+title+'</label>';
\t\t\t\t\t\t\t} else if (cbox.length > 1) {
\t\t\t\t\t\t\t\tchks = ' elfinder-preference-checkboxes';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdls = dls.add(\$('<dt class=\"elfinder-preference-'+n+chks+'\">'+title+'</dt>')).add(\$('<dd class=\"elfinder-preference-'+n+chks+'\"></dd>').append(f));
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (found) {
\t\t\t\t\tul.append(tab[r](/\\{id\\}/g, id)[r](/\\{title\\}/, fm.i18n(id))[r](/\\{class\\}/, openTab === id? 'elfinder-focus' : ''));
\t\t\t\t\tif (found === 2) {
\t\t\t\t\t\ttabs.append(
\t\t\t\t\t\t\t\$('<div id=\"'+fm.namespace+'-preference-'+id+'\" class=\"elfinder-preference-content\"></div>')
\t\t\t\t\t\t\t.hide()
\t\t\t\t\t\t\t.append(\$('<dl></dl>').append(dls))
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});

\t\t\tul.on('click', 'a', function(e) {
\t\t\t\tvar t = \$(e.target),
\t\t\t\t\th = t.attr('href');
\t\t\t\te.preventDefault();
\t\t\t\te.stopPropagation();

\t\t\t\tul.children().removeClass(clTabActive);
\t\t\t\tt.removeClass('ui-state-hover').parent().addClass(clTabActive);

\t\t\t\tif (h.match(/all\$/)) {
\t\t\t\t\ttabs.addClass('elfinder-preference-taball').children().show();
\t\t\t\t} else {
\t\t\t\t\ttabs.removeClass('elfinder-preference-taball').children().hide();
\t\t\t\t\t\$(h).show();
\t\t\t\t}
\t\t\t}).on('focus blur', 'a', function(e) {
\t\t\t\t\$(this).parent().toggleClass('ui-state-focus', e.type === 'focusin');
\t\t\t}).on('mouseenter mouseleave', 'li', function(e) {
\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
\t\t\t});

\t\t\ttabs.find('a,input,select,button').addClass('elfinder-tabstop');
\t\t\tbase.append(ul, tabs);

\t\t\tdialog = self.fmDialog(base, {
\t\t\t\ttitle : self.title,
\t\t\t\twidth : self.options.width || 600,
\t\t\t\theight: self.options.height || 400,
\t\t\t\tmaxWidth: 'window',
\t\t\t\tmaxHeight: 'window',
\t\t\t\tautoOpen : false,
\t\t\t\tdestroyOnClose : false,
\t\t\t\tallowMinimize : false,
\t\t\t\topen : function() {
\t\t\t\t\topenTab && selectTab(openTab);
\t\t\t\t\topenTab = null;
\t\t\t\t},
\t\t\t\tresize : function() {
\t\t\t\t\ttabs.height(dialog.height() - ul.outerHeight(true) - (tabs.outerHeight(true) - tabs.height()) - 5);
\t\t\t\t}
\t\t\t})
\t\t\t.on('click', function(e) {
\t\t\t\te.stopPropagation();
\t\t\t})
\t\t\t.css({
\t\t\t\toverflow: 'hidden'
\t\t\t});

\t\t\tdialog.closest('.ui-dialog')
\t\t\t.css({
\t\t\t\toverflow: 'hidden'
\t\t\t})
\t\t\t.addClass('elfinder-bg-translucent');
\t\t\t
\t\t\topenTab = 'all';
\t\t},
\t\tdialog, openTab;

\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+comma',
\t\tdescription : this.title
\t}];

\tthis.alwaysEnabled  = true;
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function(sel, cOpts) {
\t\t!dialog && build();
\t\tif (cOpts) {
\t\t\tif (cOpts.tab) {
\t\t\t\tselectTab(cOpts.tab);
\t\t\t} else if (cOpts._currentType === 'cwd') {
\t\t\t\tselectTab('workspace');
\t\t\t}
\t\t}
\t\tdialog.elfinderdialog('open');
\t\treturn \$.Deferred().resolve();
\t};

};

/*
 * File: /js/commands/quicklook.js
 */

/**
 * @class  elFinder command \"quicklook\"
 * Fast preview for some files types
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.quicklook = function() {
\t\tvar self       = this,
\t\tfm         = self.fm,
\t\t/**
\t\t * window closed state
\t\t *
\t\t * @type Number
\t\t **/
\t\tclosed     = 0,
\t\t/**
\t\t * window animated state
\t\t *
\t\t * @type Number
\t\t **/
\t\tanimated   = 1,
\t\t/**
\t\t * window opened state
\t\t *
\t\t * @type Number
\t\t **/
\t\topened     = 2,
\t\t/**
\t\t * window docked state
\t\t *
\t\t * @type Number
\t\t **/
\t\tdocked     = 3,
\t\t/**
\t\t * window docked and hidden state
\t\t *
\t\t * @type Number
\t\t **/
\t\tdockedhidden = 4,
\t\t/**
\t\t * window state
\t\t *
\t\t * @type Number
\t\t **/
\t\tstate      = closed,
\t\t/**
\t\t * Event name of update
\t\t * for fix conflicts with Prototype.JS
\t\t * 
\t\t * `@see https://github.com/Studio-42/elFinder/pull/2346
\t\t * @type String
\t\t **/
\t\tevUpdate = Element.update? 'quicklookupdate' : 'update',
\t\t/**
\t\t * navbar icon class
\t\t *
\t\t * @type String
\t\t **/
\t\tnavicon    = 'elfinder-quicklook-navbar-icon',
\t\t/**
\t\t * navbar \"fullscreen\" icon class
\t\t *
\t\t * @type String
\t\t **/
\t\tfullscreen = 'elfinder-quicklook-fullscreen',
\t\t/**
\t\t * info wrapper class
\t\t * 
\t\t * @type String
\t\t */
\t\tinfocls    = 'elfinder-quicklook-info-wrapper',
\t\t/**
\t\t * Triger keydown/keypress event with left/right arrow key code
\t\t *
\t\t * @param  Number  left/right arrow key code
\t\t * @return void
\t\t **/
\t\tnavtrigger = function(code) {
\t\t\t\$(document).trigger(\$.Event('keydown', { keyCode: code, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
\t\t},
\t\t/**
\t\t * Return css for closed window
\t\t *
\t\t * @param  jQuery  file node in cwd
\t\t * @return void
\t\t **/
\t\tclosedCss = function(node) {
\t\t\tvar elf = fm.getUI().offset(),
\t\t\t\tbase = (function() {
\t\t\t\t\tvar target = node.find('.elfinder-cwd-file-wrapper');
\t\t\t\t\treturn target.length? target : node;
\t\t\t\t})(),
\t\t\t\tbaseOffset = base.offset() || { top: 0, left: 0 };
\t\t\treturn {
\t\t\t\topacity : 0,
\t\t\t\twidth   : base.width(),
\t\t\t\theight  : base.height() - 30,
\t\t\t\ttop     : baseOffset.top - elf.top,
\t\t\t\tleft    : baseOffset.left  - elf.left
\t\t\t};
\t\t},
\t\t/**
\t\t * Return css for opened window
\t\t *
\t\t * @return void
\t\t **/
\t\topenedCss = function() {
\t\t\tvar contain = self.options.contain || fm.options.dialogContained,
\t\t\t\twin = contain? fm.getUI() : \$(window),
\t\t\t\telf = fm.getUI().offset(),
\t\t\t\tw = Math.min(width, win.width()-10),
\t\t\t\th = Math.min(height, win.height()-80);
\t\t\treturn {
\t\t\t\topacity : 1,
\t\t\t\twidth  : w,
\t\t\t\theight : h,
\t\t\t\ttop    : parseInt((win.height() - h - 60) / 2 + (contain? 0 : win.scrollTop() - elf.top)),
\t\t\t\tleft   : parseInt((win.width() - w) / 2 + (contain? 0 : win.scrollLeft() - elf.left))
\t\t\t};
\t\t},
\t\t
\t\tmediaNode = {},
\t\tsupport = function(codec, name) {
\t\t\tvar node  = name || codec.substr(0, codec.indexOf('/')),
\t\t\t\tmedia = mediaNode[node]? mediaNode[node] : (mediaNode[node] = document.createElement(node)),
\t\t\t\tvalue = false;
\t\t\t
\t\t\ttry {
\t\t\t\tvalue = media.canPlayType && media.canPlayType(codec);
\t\t\t} catch(e) {}
\t\t\t
\t\t\treturn (value && value !== '' && value != 'no')? true : false;
\t\t},
\t\t
\t\tplatformWin = (window.navigator.platform.indexOf('Win') != -1),
\t\t
\t\t/**
\t\t * Opened window width (from config)
\t\t *
\t\t * @type Number
\t\t **/
\t\twidth, 
\t\t/**
\t\t * Opened window height (from config)
\t\t *
\t\t * @type Number
\t\t **/
\t\theight, 
\t\t/**
\t\t * Previous style before docked
\t\t *
\t\t * @type String
\t\t **/
\t\tprevStyle,
\t\t/**
\t\t * elFinder node
\t\t *
\t\t * @type jQuery
\t\t **/
\t\tparent, 
\t\t/**
\t\t * elFinder current directory node
\t\t *
\t\t * @type jQuery
\t\t **/
\t\tcwd, 
\t\t/**
\t\t * Current directory hash
\t\t *
\t\t * @type String
\t\t **/
\t\tcwdHash,
\t\tdockEnabled = false,
\t\tnavdrag = false,
\t\tnavmove = false,
\t\tnavtm   = null,
\t\tleftKey = \$.ui.keyCode.LEFT,
\t\trightKey = \$.ui.keyCode.RIGHT,
\t\tcoverEv = 'mousemove touchstart ' + ('onwheel' in document? 'wheel' : 'onmousewheel' in document? 'mousewheel' : 'DOMMouseScroll'),
\t\ttitle   = \$('<span class=\"elfinder-dialog-title elfinder-quicklook-title\"></span>'),
\t\ticon    = \$('<div></div>'),
\t\tinfo    = \$('<div class=\"elfinder-quicklook-info\"></div>'),//.hide(),
\t\tcover   = \$('<div class=\"ui-front elfinder-quicklook-cover\"></div>'),
\t\tfsicon  = \$('<div class=\"'+navicon+' '+navicon+'-fullscreen\"></div>')
\t\t\t.on('click touchstart', function(e) {
\t\t\t\tif (navmove) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\t
\t\t\t\tvar win     = self.window,
\t\t\t\t\tfull    = win.hasClass(fullscreen),
\t\t\t\t\t\$window = \$(window),
\t\t\t\t\tresize  = function() { self.preview.trigger('changesize'); };
\t\t\t\t\t
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\t
\t\t\t\tif (full) {
\t\t\t\t\tnavStyle = '';
\t\t\t\t\tnavShow();
\t\t\t\t\twin.toggleClass(fullscreen)
\t\t\t\t\t.css(win.data('position'));
\t\t\t\t\t\$window.trigger(self.resize).off(self.resize, resize);
\t\t\t\t\tnavbar.off('mouseenter mouseleave');
\t\t\t\t\tcover.off(coverEv);
\t\t\t\t} else {
\t\t\t\t\twin.toggleClass(fullscreen)
\t\t\t\t\t.data('position', {
\t\t\t\t\t\tleft   : win.css('left'), 
\t\t\t\t\t\ttop    : win.css('top'), 
\t\t\t\t\t\twidth  : win.width(), 
\t\t\t\t\t\theight : win.height(),
\t\t\t\t\t\tdisplay: 'block'
\t\t\t\t\t})
\t\t\t\t\t.removeAttr('style');

\t\t\t\t\t\$(window).on(self.resize, resize)
\t\t\t\t\t.trigger(self.resize);

\t\t\t\t\tcover.on(coverEv, function(e) {
\t\t\t\t\t\tif (! navdrag) {
\t\t\t\t\t\t\tif (e.type === 'mousemove' || e.type === 'touchstart') {
\t\t\t\t\t\t\t\tnavShow();
\t\t\t\t\t\t\t\tnavtm = setTimeout(function() {
\t\t\t\t\t\t\t\t\tif (fm.UA.Mobile || navbar.parent().find('.elfinder-quicklook-navbar:hover').length < 1) {
\t\t\t\t\t\t\t\t\t\tnavbar.fadeOut('slow', function() {
\t\t\t\t\t\t\t\t\t\t\tcover.show();
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}, 3000);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (cover.is(':visible')) {
\t\t\t\t\t\t\t\tcoverHide();
\t\t\t\t\t\t\t\tcover.data('tm', setTimeout(function() {
\t\t\t\t\t\t\t\t\tcover.show();
\t\t\t\t\t\t\t\t}, 3000));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}).show().trigger('mousemove');
\t\t\t\t\t
\t\t\t\t\tnavbar.on('mouseenter mouseleave', function(e) {
\t\t\t\t\t\tif (! navdrag) {
\t\t\t\t\t\t\tif (e.type === 'mouseenter') {
\t\t\t\t\t\t\t\tnavShow();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tcover.trigger('mousemove');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (fm.zIndex) {
\t\t\t\t\twin.css('z-index', fm.zIndex + 1);
\t\t\t\t}
\t\t\t\tif (fm.UA.Mobile) {
\t\t\t\t\tnavbar.attr('style', navStyle);
\t\t\t\t} else {
\t\t\t\t\tnavbar.attr('style', navStyle).draggable(full ? 'destroy' : {
\t\t\t\t\t\tstart: function() {
\t\t\t\t\t\t\tnavdrag = true;
\t\t\t\t\t\t\tnavmove = true;
\t\t\t\t\t\t\tcover.show();
\t\t\t\t\t\t\tnavShow();
\t\t\t\t\t\t},
\t\t\t\t\t\tstop: function() {
\t\t\t\t\t\t\tnavdrag = false;
\t\t\t\t\t\t\tnavStyle = self.navbar.attr('style');
\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\tnavmove = false;
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t\$(this).toggleClass(navicon+'-fullscreen-off');
\t\t\t\tvar collection = win;
\t\t\t\tif (parent.is('.ui-resizable')) {
\t\t\t\t\tcollection = collection.add(parent);
\t\t\t\t}
\t\t\t\tcollection.resizable(full ? 'enable' : 'disable').removeClass('ui-state-disabled');

\t\t\t\twin.trigger('viewchange');
\t\t\t}
\t\t),
\t\t
\t\tupdateOnSel = function() {
\t\t\tself.update(void(0), (function() {
\t\t\t\tvar fm = self.fm,
\t\t\t\t\tfiles = fm.selectedFiles(),
\t\t\t\t\tcnt = files.length,
\t\t\t\t\tinDock = self.docked(),
\t\t\t\t\tgetInfo = function() {
\t\t\t\t\t\tvar ts = 0;
\t\t\t\t\t\t\$.each(files, function(i, f) {
\t\t\t\t\t\t\tvar t = parseInt(f.ts);
\t\t\t\t\t\t\tif (ts >= 0) {
\t\t\t\t\t\t\t\tif (t > ts) {
\t\t\t\t\t\t\t\t\tts = t;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tts = 'unknown';
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\treturn {
\t\t\t\t\t\t\thash : files[0].hash  + '/' + (+new Date()),
\t\t\t\t\t\t\tname : fm.i18n('items') + ': ' + cnt,
\t\t\t\t\t\t\tmime : 'group',
\t\t\t\t\t\t\tsize : spinner,
\t\t\t\t\t\t\tts   : ts,
\t\t\t\t\t\t\tfiles : \$.map(files, function(f) { return f.hash; }),
\t\t\t\t\t\t\tgetSize : true
\t\t\t\t\t\t};
\t\t\t\t\t};
\t\t\t\tif (! cnt) {
\t\t\t\t\tcnt = 1;
\t\t\t\t\tfiles = [fm.cwd()];
\t\t\t\t}
\t\t\t\treturn (cnt === 1)? files[0] : getInfo();
\t\t\t})());
\t\t},
\t\t
\t\tnavShow = function() {
\t\t\tif (self.window.hasClass(fullscreen)) {
\t\t\t\tnavtm && clearTimeout(navtm);
\t\t\t\tnavtm = null;
\t\t\t\t// if use `show()` it make infinite loop with old jQuery (jQuery/jQuery UI: 1.8.0/1.9.0)
\t\t\t\t// see #1478 https://github.com/Studio-42/elFinder/issues/1478
\t\t\t\tnavbar.stop(true, true).css('display', 'block');
\t\t\t\tcoverHide();
\t\t\t}
\t\t},
\t\t
\t\tcoverHide = function() {
\t\t\tcover.data('tm') && clearTimeout(cover.data('tm'));
\t\t\tcover.removeData('tm');
\t\t\tcover.hide();
\t\t},
\t\t\t
\t\tprev = \$('<div class=\"'+navicon+' '+navicon+'-prev\"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(leftKey); return false; }),
\t\tnext = \$('<div class=\"'+navicon+' '+navicon+'-next\"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(rightKey); return false; }),
\t\tnavbar  = \$('<div class=\"elfinder-quicklook-navbar\"></div>')
\t\t\t.append(prev)
\t\t\t.append(fsicon)
\t\t\t.append(next)
\t\t\t.append('<div class=\"elfinder-quicklook-navbar-separator\"></div>')
\t\t\t.append(\$('<div class=\"'+navicon+' '+navicon+'-close\"></div>').on('click touchstart', function(e) { ! navmove && self.window.trigger('close'); return false; }))
\t\t,
\t\ttitleClose = \$('<span class=\"ui-front ui-icon elfinder-icon-close ui-icon-closethick\"></span>').on('mousedown', function(e) {
\t\t\te.stopPropagation();
\t\t\tself.window.trigger('close');
\t\t}),
\t\ttitleDock = \$('<span class=\"ui-front ui-icon elfinder-icon-minimize ui-icon-minusthick\"></span>').on('mousedown', function(e) {
\t\t\te.stopPropagation();
\t\t\tif (! self.docked()) {
\t\t\t\tself.window.trigger('navdockin');
\t\t\t} else {
\t\t\t\tself.window.trigger('navdockout');
\t\t\t}
\t\t}),
\t\tspinner = '<span class=\"elfinder-spinner-text\">' + fm.i18n('calc') + '</span>' + '<span class=\"elfinder-spinner\"></span>',
\t\tnavStyle = '',
\t\tinit = true,
\t\tdockHeight,\tgetSize, tm4cwd, dockedNode, selectTm;

\t/**
\t * Any flags for each plugin
\t */
\tthis.flags = {};
\t
\tthis.cover = cover;
\tthis.evUpdate = evUpdate;
\t(this.navbar = navbar)._show = navShow;
\tthis.resize = 'resize.'+fm.namespace;
\tthis.info = \$('<div></div>').addClass(infocls)
\t\t.append(icon)
\t\t.append(info);
\tthis.autoPlay = function() {
\t\tif (self.opened()) {
\t\t\treturn !! self.options[self.docked()? 'dockAutoplay' : 'autoplay'];
\t\t}
\t\treturn false;
\t};
\tthis.preview = \$('<div class=\"elfinder-quicklook-preview ui-helper-clearfix\"></div>')
\t\t// clean info/icon
\t\t.on('change', function() {
\t\t\tnavShow();
\t\t\tnavbar.attr('style', navStyle);
\t\t\tself.docked() && navbar.hide();
\t\t\tself.preview.attr('style', '').removeClass('elfinder-overflow-auto');
\t\t\tself.info.attr('style', '').hide();
\t\t\tself.cover.removeClass('elfinder-quicklook-coverbg');
\t\t\ticon.removeAttr('class').attr('style', '');
\t\t\tinfo.html('');
\t\t})
\t\t// update info/icon
\t\t.on(evUpdate, function(e) {
\t\t\tvar preview = self.preview,
\t\t\t\tfile    = e.file,
\t\t\t\ttpl     = '<div class=\"elfinder-quicklook-info-data\">{value}</div>',
\t\t\t\tupdate  = function() {
\t\t\t\t\tvar win = self.window.css('overflow', 'hidden');
\t\t\t\t\tname = fm.escape(file.i18 || file.name);
\t\t\t\t\t!file.read && e.stopImmediatePropagation();
\t\t\t\t\tself.window.data('hash', file.hash);
\t\t\t\t\tself.preview.off('changesize').trigger('change').children().remove();
\t\t\t\t\ttitle.html(name);
\t\t\t\t\t
\t\t\t\t\tprev.css('visibility', '');
\t\t\t\t\tnext.css('visibility', '');
\t\t\t\t\tif (file.hash === fm.cwdId2Hash(cwd.find('[id]:not(.elfinder-cwd-parent):first').attr('id'))) {
\t\t\t\t\t\tprev.css('visibility', 'hidden');
\t\t\t\t\t}
\t\t\t\t\tif (file.hash === fm.cwdId2Hash(cwd.find('[id]:last').attr('id'))) {
\t\t\t\t\t\tnext.css('visibility', 'hidden');
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (file.mime === 'directory') {
\t\t\t\t\t\tgetSizeHashes = [ file.hash ];
\t\t\t\t\t} else if (file.mime === 'group' && file.getSize) {
\t\t\t\t\t\tgetSizeHashes = file.files;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tinfo.html(
\t\t\t\t\t\ttpl.replace(/\\{value\\}/, name)
\t\t\t\t\t\t+ tpl.replace(/\\{value\\}/, fm.mime2kind(file))
\t\t\t\t\t\t+ tpl.replace(/\\{value\\}/, getSizeHashes.length ? spinner : fm.formatSize(file.size))
\t\t\t\t\t\t+ tpl.replace(/\\{value\\}/, fm.i18n('modify')+': '+ fm.formatDate(file))
\t\t\t\t\t);
\t\t\t\t\t
\t\t\t\t\tif (getSizeHashes.length) {
\t\t\t\t\t\tgetSize = fm.getSize(getSizeHashes).done(function(data) {
\t\t\t\t\t\t\tinfo.find('span.elfinder-spinner').parent().html(data.formated);
\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\tinfo.find('span.elfinder-spinner').parent().html(fm.i18n('unknown'));
\t\t\t\t\t\t}).always(function() {
\t\t\t\t\t\t\tgetSize = null;
\t\t\t\t\t\t});
\t\t\t\t\t\tgetSize._hash = file.hash;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\ticon.addClass('elfinder-cwd-icon ui-corner-all '+fm.mime2class(file.mime));
\t\t\t\t\t
\t\t\t\t\tif (file.icon) {
\t\t\t\t\t\ticon.css(fm.getIconStyle(file, true));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tself.info.attr('class', infocls);
\t\t\t\t\tif (file.csscls) {
\t\t\t\t\t\tself.info.addClass(file.csscls);
\t\t\t\t\t}
\t
\t\t\t\t\tif (file.read && (tmb = fm.tmb(file))) {
\t\t\t\t\t\t\$('<img/>')
\t\t\t\t\t\t\t.hide()
\t\t\t\t\t\t\t.appendTo(self.preview)
\t\t\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\t\t\ticon.addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\");
\t\t\t\t\t\t\t\t\$(this).remove();
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.attr('src', tmb.url);
\t\t\t\t\t}
\t\t\t\t\tself.info.delay(100).fadeIn(10);
\t\t\t\t\tif (self.window.hasClass(fullscreen)) {
\t\t\t\t\t\tcover.trigger('mousemove');
\t\t\t\t\t}
\t\t\t\t\twin.css('overflow', '');
\t\t\t\t},
\t\t\t\ttmb, name, getSizeHashes = [];

\t\t\tif (file && ! Object.keys(file).length) {
\t\t\t\tfile = fm.cwd();
\t\t\t}
\t\t\tif (file && getSize && getSize.state() === 'pending' && getSize._hash !== file.hash) {
\t\t\t\tgetSize.reject();
\t\t\t}
\t\t\tif (file && (e.forceUpdate || self.window.data('hash') !== file.hash)) {
\t\t\t\tupdate();
\t\t\t} else { 
\t\t\t\te.stopImmediatePropagation();
\t\t\t}
\t\t});

\tthis.window = \$('<div class=\"ui-front ui-helper-reset ui-widget elfinder-quicklook touch-punch\" style=\"position:absolute\"></div>')
\t\t.hide()
\t\t.addClass(fm.UA.Touch? 'elfinder-touch' : '')
\t\t.on('click', function(e) {
\t\t\tvar win = this;
\t\t\te.stopPropagation();
\t\t\tif (state === opened) {
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tstate === opened && fm.toFront(win);
\t\t\t\t});
\t\t\t}
\t\t})
\t\t.append(
\t\t\t\$('<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-top ui-helper-clearfix elfinder-quicklook-titlebar\"></div>')
\t\t\t.append(
\t\t\t\t\$('<span class=\"ui-widget-header ui-dialog-titlebar-close ui-corner-all elfinder-titlebar-button elfinder-quicklook-titlebar-icon'+(platformWin? ' elfinder-titlebar-button-right' : '')+'\"></span>').append(
\t\t\t\t\ttitleClose, titleDock
\t\t\t\t),
\t\t\t\ttitle
\t\t\t),
\t\t\tthis.preview,
\t\t\tself.info.hide(),
\t\t\tcover.hide(),
\t\t\tnavbar
\t\t)
\t\t.draggable({handle : 'div.elfinder-quicklook-titlebar'})
\t\t.on('open', function(e, clcss) {
\t\t\tvar win  = self.window, 
\t\t\t\tfile = self.value,
\t\t\t\tnode = fm.getUI('cwd'),
\t\t\t\topen = function(status) {
\t\t\t\t\tstate = status;
\t\t\t\t\tself.update(1, self.value);
\t\t\t\t\tself.change();
\t\t\t\t\twin.trigger('resize.' + fm.namespace);
\t\t\t\t};

\t\t\tif (!init && state === closed) {
\t\t\t\tif (file && file.hash !== cwdHash) {
\t\t\t\t\tnode = fm.cwdHash2Elm(file.hash.split('/', 2)[0]);
\t\t\t\t}
\t\t\t\tnavStyle = '';
\t\t\t\tnavbar.attr('style', '');
\t\t\t\tstate = animated;
\t\t\t\tnode.trigger('scrolltoview');
\t\t\t\tcoverHide();
\t\t\t\twin.css(clcss || closedCss(node))
\t\t\t\t\t.show()
\t\t\t\t\t.animate(openedCss(), 550, function() {
\t\t\t\t\t\topen(opened);
\t\t\t\t\t\tnavShow();
\t\t\t\t\t});
\t\t\t\tfm.toFront(win);
\t\t\t} else if (state === dockedhidden) {
\t\t\t\tfm.getUI('navdock').data('addNode')(dockedNode);
\t\t\t\topen(docked);
\t\t\t\tself.preview.trigger('changesize');
\t\t\t\tfm.storage('previewDocked', '1');
\t\t\t\tif (fm.getUI('navdock').width() === 0) {
\t\t\t\t\twin.trigger('navdockout');
\t\t\t\t}
\t\t\t}
\t\t})
\t\t.on('close', function(e, dfd) {
\t\t\tvar win     = self.window,
\t\t\t\tpreview = self.preview.trigger('change'),
\t\t\t\tfile    = self.value,
\t\t\t\thash    = (win.data('hash') || '').split('/', 2)[0],
\t\t\t\tclose   = function(status, winhide) {
\t\t\t\t\tstate = status;
\t\t\t\t\twinhide && fm.toHide(win);
\t\t\t\t\tpreview.children().remove();
\t\t\t\t\tself.update(0, self.value);
\t\t\t\t\twin.data('hash', '');
\t\t\t\t\tdfd && dfd.resolve();
\t\t\t\t},
\t\t\t\tnode;
\t\t\t\t
\t\t\tif (self.opened()) {
\t\t\t\tgetSize && getSize.state() === 'pending' && getSize.reject();
\t\t\t\tif (! self.docked()) {
\t\t\t\t\tstate = animated;
\t\t\t\t\twin.hasClass(fullscreen) && fsicon.click();
\t\t\t\t\t(hash && (node = cwd.find('#'+hash)).length)
\t\t\t\t\t\t? win.animate(closedCss(node), 500, function() {
\t\t\t\t\t\t\tpreview.off('changesize');
\t\t\t\t\t\t\tclose(closed, true);
\t\t\t\t\t\t})
\t\t\t\t\t\t: close(closed, true);
\t\t\t\t} else {
\t\t\t\t\tdockedNode = fm.getUI('navdock').data('removeNode')(self.window.attr('id'), 'detach');
\t\t\t\t\tclose(dockedhidden);
\t\t\t\t\tfm.storage('previewDocked', '2');
\t\t\t\t}
\t\t\t}
\t\t})
\t\t.on('navdockin', function(e, data) {
\t\t\tvar w      = self.window,
\t\t\t\tbox    = fm.getUI('navdock'),
\t\t\t\theight = dockHeight || box.width(),
\t\t\t\topts   = data || {};
\t\t\t
\t\t\tif (init) {
\t\t\t\topts.init = true;
\t\t\t}
\t\t\tstate = docked;
\t\t\tprevStyle = w.attr('style');
\t\t\tw.toggleClass('ui-front').removeClass('ui-widget').draggable('disable').resizable('disable').removeAttr('style').css({
\t\t\t\twidth: '100%',
\t\t\t\theight: height,
\t\t\t\tboxSizing: 'border-box',
\t\t\t\tpaddingBottom: 0,
\t\t\t\tzIndex: 'unset'
\t\t\t});
\t\t\tnavbar.hide();
\t\t\ttitleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize');
\t\t\t
\t\t\tfm.toHide(w, true);
\t\t\tbox.data('addNode')(w, opts);
\t\t\t
\t\t\tself.preview.trigger('changesize');
\t\t\t
\t\t\tfm.storage('previewDocked', '1');
\t\t})
\t\t.on('navdockout', function(e) {
\t\t\tvar w   = self.window,
\t\t\t\tbox = fm.getUI('navdock'),
\t\t\t\tdfd = \$.Deferred(),
\t\t\t\tclcss = closedCss(self.preview);
\t\t\t
\t\t\tdockHeight = w.outerHeight();
\t\t\tbox.data('removeNode')(w.attr('id'), fm.getUI());
\t\t\tw.toggleClass('ui-front').addClass('ui-widget').draggable('enable').resizable('enable').attr('style', prevStyle);
\t\t\ttitleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize');
\t\t\t
\t\t\tstate = closed;
\t\t\tw.trigger('open', clcss);
\t\t\t
\t\t\tfm.storage('previewDocked', '0');
\t\t})
\t\t.on('resize.' + fm.namespace, function() {
\t\t\tself.preview.trigger('changesize'); 
\t\t});

\t/**
\t * This command cannot be disable by backend
\t *
\t * @type Boolean
\t **/
\tthis.alwaysEnabled = true;
\t
\t/**
\t * Selected file
\t *
\t * @type Object
\t **/
\tthis.value = null;
\t
\tthis.handlers = {
\t\t// save selected file
\t\tselect : function(e, d) {
\t\t\tselectTm && cancelAnimationFrame(selectTm);
\t\t\tif (! e.data || ! e.data.selected || ! e.data.selected.length) {
\t\t\t\tselectTm = requestAnimationFrame(function() {
\t\t\t\t\tself.opened() && updateOnSel();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tself.opened() && updateOnSel();
\t\t\t}
\t\t},
\t\terror  : function() { self.window.is(':visible') && self.window.trigger('close'); },
\t\t'searchshow searchhide' : function() { this.opened() && this.window.trigger('close'); },
\t\tnavbarshow : function() {
\t\t\trequestAnimationFrame(function() {
\t\t\t\tself.docked() && self.preview.trigger('changesize');
\t\t\t});
\t\t},
\t\tdestroy : function() { self.window.remove(); }
\t};
\t
\tthis.shortcuts = [{
\t\tpattern     : 'space'
\t}];
\t
\tthis.support = {
\t\taudio : {
\t\t\togg : support('audio/ogg;'),
\t\t\twebm: support('audio/webm;'),
\t\t\tmp3 : support('audio/mpeg;'),
\t\t\twav : support('audio/wav;'),
\t\t\tm4a : support('audio/mp4;') || support('audio/x-m4a;') || support('audio/aac;'),
\t\t\tflac: support('audio/flac;'),
\t\t\tamr : support('audio/amr;')
\t\t},
\t\tvideo : {
\t\t\togg  : support('video/ogg;'),
\t\t\twebm : support('video/webm;'),
\t\t\tmp4  : support('video/mp4;'),
\t\t\tmkv  : support('video/x-matroska;') || support('video/webm;'),
\t\t\t'3gp': support('video/3gpp;') || support('video/mp4;'), // try as mp4
\t\t\tm3u8 : support('application/x-mpegURL', 'video') || support('application/vnd.apple.mpegURL', 'video'),
\t\t\tmpd  : support('application/dash+xml', 'video')
\t\t}
\t};
\t// for GC
\tmediaNode = {};
\t
\t/**
\t * Return true if quickLoock window is hiddenReturn true if quickLoock window is visible and not animated
\t *
\t * @return Boolean
\t **/
\tthis.closed = function() {
\t\treturn (state == closed || state == dockedhidden);
\t};
\t
\t/**
\t * Return true if quickLoock window is visible and not animated
\t *
\t * @return Boolean
\t **/
\tthis.opened = function() {
\t\treturn state == opened || state == docked;
\t};
\t
\t/**
\t * Return true if quickLoock window is in NavDock
\t *
\t * @return Boolean
\t **/
\tthis.docked = function() {
\t\treturn state == docked;
\t};
\t
\t/**
\t * Adds an integration into help dialog.
\t *
\t * @param Object opts  options
\t */
\tthis.addIntegration = function(opts) {
\t\trequestAnimationFrame(function() {
\t\t\tfm.trigger('helpIntegration', Object.assign({cmd: 'quicklook'}, opts));
\t\t});
\t};

\t/**
\t * Init command.
\t * Add default plugins and init other plugins
\t *
\t * @return Object
\t **/
\tthis.init = function() {
\t\tvar o       = this.options, 
\t\t\twin     = this.window,
\t\t\tpreview = this.preview,
\t\t\ti, p, cwdDispInlineRegex;
\t\t
\t\twidth  = o.width  > 0 ? parseInt(o.width)  : 450;\t
\t\theight = o.height > 0 ? parseInt(o.height) : 300;
\t\tif (o.dockHeight !== 'auto') {
\t\t\tdockHeight = parseInt(o.dockHeight);
\t\t\tif (! dockHeight) {
\t\t\t\tdockHeight = void(0);
\t\t\t}
\t\t}

\t\tfm.one('load', function() {
\t\t\t
\t\t\tdockEnabled = fm.getUI('navdock').data('dockEnabled');
\t\t\t
\t\t\t! dockEnabled && titleDock.hide();
\t\t\t
\t\t\tparent = fm.getUI();
\t\t\tcwd    = fm.getUI('cwd');

\t\t\tif (fm.zIndex) {
\t\t\t\twin.css('z-index', fm.zIndex + 1);
\t\t\t}
\t\t\t
\t\t\twin.appendTo(parent);
\t\t\t
\t\t\t// close window on escape
\t\t\t\$(document).on('keydown.'+fm.namespace, function(e) {
\t\t\t\te.keyCode == \$.ui.keyCode.ESCAPE && self.opened() && ! self.docked() && win.hasClass('elfinder-frontmost') && win.trigger('close');
\t\t\t});
\t\t\t
\t\t\twin.resizable({ 
\t\t\t\thandles   : 'se', 
\t\t\t\tminWidth  : 350, 
\t\t\t\tminHeight : 120, 
\t\t\t\tresize    : function() { 
\t\t\t\t\t// use another event to avoid recursion in fullscreen mode
\t\t\t\t\t// may be there is clever solution, but i cant find it :(
\t\t\t\t\tpreview.trigger('changesize'); 
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tself.change(function() {
\t\t\t\tif (self.opened()) {
\t\t\t\t\tif (self.value) {
\t\t\t\t\t\tif (self.value.tmb && self.value.tmb == 1) {
\t\t\t\t\t\t\t// try re-get file object
\t\t\t\t\t\t\tself.value = Object.assign({}, fm.file(self.value.hash));
\t\t\t\t\t\t}
\t\t\t\t\t\tpreview.trigger(\$.Event(evUpdate, {file : self.value}));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tpreview.on(evUpdate, function(e) {
\t\t\t\tvar file, hash, serach;
\t\t\t\t
\t\t\t\tif (file = e.file) {
\t\t\t\t\thash = file.hash;
\t\t\t\t\tserach = (fm.searchStatus.mixed && fm.searchStatus.state > 1);
\t\t\t\t
\t\t\t\t\tif (file.mime !== 'directory') {
\t\t\t\t\t\tif (parseInt(file.size) || file.mime.match(o.mimeRegexNotEmptyCheck)) {
\t\t\t\t\t\t\t// set current dispInlineRegex
\t\t\t\t\t\t\tself.dispInlineRegex = cwdDispInlineRegex;
\t\t\t\t\t\t\tif (serach || fm.optionsByHashes[hash]) {
\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\tself.dispInlineRegex = new RegExp(fm.option('dispInlineRegex', hash), 'i');
\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tself.dispInlineRegex = new RegExp(!fm.isRoot(file)? fm.option('dispInlineRegex', file.phash) : fm.options.dispInlineRegex, 'i');
\t\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\t\tself.dispInlineRegex = /^\$/;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t//  do not preview of file that size = 0
\t\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tself.dispInlineRegex = /^\$/;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tself.info.show();
\t\t\t\t} else {
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t}
\t\t\t});

\t\t\t\$.each(fm.commands.quicklook.plugins || [], function(i, plugin) {
\t\t\t\tif (typeof(plugin) == 'function') {
\t\t\t\t\tnew plugin(self);
\t\t\t\t}
\t\t\t});
\t\t}).one('open', function() {
\t\t\tvar dock = Number(fm.storage('previewDocked') || o.docked),
\t\t\t\twin;
\t\t\tif (dockEnabled && dock >= 1) {
\t\t\t\twin = self.window;
\t\t\t\tself.exec();
\t\t\t\twin.trigger('navdockin', { init : true });
\t\t\t\tif (dock === 2) {
\t\t\t\t\twin.trigger('close');
\t\t\t\t} else {
\t\t\t\t\tself.update(void(0), fm.cwd());
\t\t\t\t\tself.change();
\t\t\t\t}
\t\t\t}
\t\t\tinit = false;
\t\t}).bind('open', function() {
\t\t\tcwdHash = fm.cwd().hash;
\t\t\tself.value = fm.cwd();
\t\t\t// set current volume dispInlineRegex
\t\t\ttry {
\t\t\t\tcwdDispInlineRegex = new RegExp(fm.option('dispInlineRegex'), 'i');
\t\t\t} catch(e) {
\t\t\t\tcwdDispInlineRegex = /^\$/;
\t\t\t}
\t\t}).bind('change', function(e) {
\t\t\tif (e.data && e.data.changed && self.opened()) {
\t\t\t\t\$.each(e.data.changed, function() {
\t\t\t\t\tif (self.window.data('hash') === this.hash) {
\t\t\t\t\t\tself.window.data('hash', null);
\t\t\t\t\t\tself.preview.trigger(evUpdate);
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t}).bind('navdockresizestart navdockresizestop', function(e) {
\t\t\tcover[e.type === 'navdockresizestart'? 'show' : 'hide']();
\t\t});
\t};
\t
\tthis.getstate = function() {
\t\treturn self.opened()? 1 : 0;
\t};
\t
\tthis.exec = function() {
\t\tself.closed() && updateOnSel();
\t\tself.enabled() && self.window.trigger(self.opened() ? 'close' : 'open');
\t\treturn \$.Deferred().resolve();
\t};

\tthis.hideinfo = function() {
\t\tthis.info.stop(true, true).hide();
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/quicklook.plugins.js
 */

elFinder.prototype.commands.quicklook.plugins = [
\t
\t/**
\t * Images preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar mimes   = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'],
\t\t\tgetDimSize = ql.fm.returnBytes((ql.options.getDimThreshold || 0)),
\t\t\tpreview = ql.preview,
\t\t\tWebP, flipMime;
\t\t
\t\t// webp support
\t\tWebP = new Image();
\t\tWebP.onload = WebP.onerror = function() {
\t\t\tif (WebP.height == 2) {
\t\t\t\tmimes.push('image/webp');
\t\t\t}
\t\t};
\t\tWebP.src='data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
\t\t
\t\t// what kind of images we can display
\t\t\$.each(navigator.mimeTypes, function(i, o) {
\t\t\tvar mime = o.type;
\t\t\t
\t\t\tif (mime.indexOf('image/') === 0 && \$.inArray(mime, mimes)) {
\t\t\t\tmimes.push(mime);
\t\t\t} 
\t\t});
\t\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar fm   = ql.fm,
\t\t\t\tfile = e.file,
\t\t\t\tshowed = false,
\t\t\t\tdimreq = null,
\t\t\t\tsetdim  = function(dim) {
\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\trfile.width = dim[0];
\t\t\t\t\trfile.height = dim[1];
\t\t\t\t},
\t\t\t\tshow = function() {
\t\t\t\t\tvar elm, varelm, memSize, width, height, prop;
\t\t\t\t\t
\t\t\t\t\tdimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject();
\t\t\t\t\tif (showed) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tshowed = true;
\t\t\t\t\t
\t\t\t\t\telm = img.get(0);
\t\t\t\t\tmemSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()});
\t\t\t\t
\t\t\t\t\tmemSize && img.removeAttr('width').removeAttr('height');
\t\t\t\t\t
\t\t\t\t\twidth  = file.width || elm.naturalWidth || elm.width || img.width();
\t\t\t\t\theight = file.height || elm.naturalHeight || elm.height || img.height();
\t\t\t\t\tif (!file.width || !file.height) {
\t\t\t\t\t\tsetdim([width, height]);
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tmemSize && img.width(memSize.w).height(memSize.h);

\t\t\t\t\tprop = (width/height).toFixed(2);
\t\t\t\t\tpreview.on('changesize', function() {
\t\t\t\t\t\tvar pw = parseInt(preview.width()),
\t\t\t\t\t\t\tph = parseInt(preview.height()),
\t\t\t\t\t\t\tw, h;
\t\t\t\t\t
\t\t\t\t\t\tif (prop < (pw/ph).toFixed(2)) {
\t\t\t\t\t\t\th = ph;
\t\t\t\t\t\t\tw = Math.floor(h * prop);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tw = pw;
\t\t\t\t\t\t\th = Math.floor(w/prop);
\t\t\t\t\t\t}
\t\t\t\t\t\timg.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
\t\t\t\t\t
\t\t\t\t\t})
\t\t\t\t\t.trigger('changesize');
\t\t\t\t\t
\t\t\t\t\t//show image
\t\t\t\t\timg.fadeIn(100);
\t\t\t\t},
\t\t\t\thideInfo = function() {
\t\t\t\t\tloading.remove();
\t\t\t\t\t// hide info/icon
\t\t\t\t\tql.hideinfo();
\t\t\t\t},
\t\t\t\turl, img, loading, prog, m, opDfd;

\t\t\tif (!flipMime) {
\t\t\t\tflipMime = fm.arrayFlip(mimes);
\t\t\t}
\t\t\tif (flipMime[file.mime] && ql.dispInlineRegex.test(file.mime)) {
\t\t\t\t// this is our file - stop event propagation
\t\t\t\te.stopImmediatePropagation();

\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);

\t\t\t\timg = \$('<img/>')
\t\t\t\t\t.hide()
\t\t\t\t\t.appendTo(preview)
\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\thideInfo();
\t\t\t\t\t\tshow();
\t\t\t\t\t})
\t\t\t\t\t.on('error', function() {
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t});
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\timg.attr('src', url);
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});

\t\t\t\tif (file.width && file.height) {
\t\t\t\t\tshow();
\t\t\t\t} else if (file.size > getDimSize) {
\t\t\t\t\tdimreq = fm.request({
\t\t\t\t\t\tdata : {cmd : 'dim', target : file.hash},
\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tif (data.dim) {
\t\t\t\t\t\t\tvar dim = data.dim.split('x');
\t\t\t\t\t\t\tfile.width = dim[0];
\t\t\t\t\t\t\tfile.height = dim[1];
\t\t\t\t\t\t\tsetdim(dim);
\t\t\t\t\t\t\tshow();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t});
\t},
\t
\t/**
\t * TIFF image preview
\t *
\t * @param  object  ql  elFinder.commands.quicklook
\t */
\tfunction(ql) {
\t\t\t\tvar fm   = ql.fm,
\t\t\tmime = 'image/tiff',
\t\t\tpreview = ql.preview;
\t\tif (window.Worker && window.Uint8Array) {
\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file = e.file,
\t\t\t\t\terr = function(e) {
\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\tfm.debug('error', e);
\t\t\t\t\t},
\t\t\t\t\tsetdim = function(dim) {
\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\trfile.width = dim[0];
\t\t\t\t\t\trfile.height = dim[1];
\t\t\t\t\t},
\t\t\t\t\tloading, prog, url, base, wk, opDfd;
\t\t\t\tif (file.mime === mime) {
\t\t\t\t\te.stopImmediatePropagation();

\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t});

\t\t\t\t\topDfd = fm.getContents(file.hash, 'arraybuffer', { progressBar: prog }).done(function(data) {
\t\t\t\t\t\tif (data) {
\t\t\t\t\t\t\tbase = \$('<div></div>').css({width:'100%',height:'100%'}).hide().appendTo(preview);
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\twk = fm.getWorker();
\t\t\t\t\t\t\t\twk.onmessage = function(res) {
\t\t\t\t\t\t\t\t\tvar data = res.data,
\t\t\t\t\t\t\t\t\t\tcv, co, id, prop;
\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\tcv = document.createElement('canvas');
\t\t\t\t\t\t\t\t\tco = cv.getContext('2d');
\t\t\t\t\t\t\t\t\tcv.width = data.width;
\t\t\t\t\t\t\t\t\tcv.height = data.height;
\t\t\t\t\t\t\t\t\tid = co.createImageData(data.width, data.height);
\t\t\t\t\t\t\t\t\t(id).data.set(new Uint8Array(data.image));
\t\t\t\t\t\t\t\t\tco.putImageData(id, 0, 0);
\t\t\t\t\t\t\t\t\tbase.append(cv).show();
\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\tprop = (data.width/data.height).toFixed(2);
\t\t\t\t\t\t\t\t\tpreview.on('changesize', function() {
\t\t\t\t\t\t\t\t\t\tvar pw = parseInt(preview.width()),
\t\t\t\t\t\t\t\t\t\t\tph = parseInt(preview.height()),
\t\t\t\t\t\t\t\t\t\t\tw, h;
\t\t\t\t\t\t\t\t\t\tif (prop < (pw/ph).toFixed(2)) {
\t\t\t\t\t\t\t\t\t\t\th = ph;
\t\t\t\t\t\t\t\t\t\t\tw = Math.floor(h * prop);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tw = pw;
\t\t\t\t\t\t\t\t\t\t\th = Math.floor(w/prop);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\$(cv).width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
\t\t\t\t\t\t\t\t\t}).trigger('changesize');
\t\t\t\t\t\t\t\t\tif (!file.width || !file.height) {
\t\t\t\t\t\t\t\t\t\tsetdim([data.width, data.height]);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\twk.onerror = err;
\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\tscripts: [fm.options.cdns.tiff, fm.getWorkerUrl('quicklook.tiff.js')],
\t\t\t\t\t\t\t\t\tdata: { data: data }
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\terr(e);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\terr();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t});
\t\t}
\t},

\t/**
\t * PSD(Adobe Photoshop data) preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(['image/vnd.adobe.photoshop', 'image/x-photoshop']),
\t\t\tpreview = ql.preview,
\t\t\tload    = function(url, img, loading) {
\t\t\t\ttry {
\t\t\t\t\tfm.replaceXhrSend();
\t\t\t\t\tPSD.fromURL(url).then(function(psd) {
\t\t\t\t\t\tvar prop;
\t\t\t\t\t\timg.attr('src', psd.image.toBase64());
\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\tprop = (img.width()/img.height()).toFixed(2);
\t\t\t\t\t\t\tpreview.on('changesize', function() {
\t\t\t\t\t\t\t\tvar pw = parseInt(preview.width()),
\t\t\t\t\t\t\t\t\tph = parseInt(preview.height()),
\t\t\t\t\t\t\t\t\tw, h;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (prop < (pw/ph).toFixed(2)) {
\t\t\t\t\t\t\t\t\th = ph;
\t\t\t\t\t\t\t\t\tw = Math.floor(h * prop);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tw = pw;
\t\t\t\t\t\t\t\t\th = Math.floor(w/prop);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\timg.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
\t\t\t\t\t\t\t}).trigger('changesize');
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t// hide info/icon
\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t//show image
\t\t\t\t\t\t\timg.fadeIn(100);
\t\t\t\t\t\t});
\t\t\t\t\t}, function() {
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\timg.remove();
\t\t\t\t\t});
\t\t\t\t\tfm.restoreXhrSend();
\t\t\t\t} catch(e) {
\t\t\t\t\tfm.restoreXhrSend();
\t\t\t\t\tloading.remove();
\t\t\t\t\timg.remove();
\t\t\t\t}
\t\t\t},
\t\t\tPSD;
\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file,
\t\t\t\turl, img, loading, prog, m,
\t\t\t\t_define, _require, opDfd;

\t\t\tif (mimes[file.mime] && fm.options.cdns.psd && ! fm.UA.ltIE10 && ql.dispInlineRegex.test(file.mime)) {
\t\t\t\t// this is our file - stop event propagation
\t\t\t\te.stopImmediatePropagation();

\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\topDfd = fm.openUrl(file.hash, 'sameorigin', function(url) {
\t\t\t\t\tif (url) {
\t\t\t\t\t\timg = \$('<img/>').hide().appendTo(preview);
\t\t\t\t\t\tif (PSD) {
\t\t\t\t\t\t\tload(url, img, loading);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t_define = window.define;
\t\t\t\t\t\t\t_require = window.require;
\t\t\t\t\t\t\twindow.require = null;
\t\t\t\t\t\t\twindow.define = null;
\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t[ fm.options.cdns.psd ],
\t\t\t\t\t\t\t\tfunction() {
\t\t\t\t\t\t\t\t\tPSD = require('psd');
\t\t\t\t\t\t\t\t\t_define? (window.define = _define) : (delete window.define);
\t\t\t\t\t\t\t\t\t_require? (window.require = _require) : (delete window.require);
\t\t\t\t\t\t\t\t\tload(url, img, loading);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t}
\t\t});
\t},
\t
\t/**
\t * HTML preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(['text/html', 'application/xhtml+xml']),
\t\t\tpreview = ql.preview;
\t\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file, jqxhr, loading, prog;
\t\t\t
\t\t\tif (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
\t\t\t\te.stopImmediatePropagation();

\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);

\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\tjqxhr.state() == 'pending' && jqxhr.reject();
\t\t\t\t}).addClass('elfinder-overflow-auto');
\t\t\t\t
\t\t\t\tjqxhr = fm.request({
\t\t\t\t\tdata           : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
\t\t\t\t\toptions        : {type: 'get', cache : true},
\t\t\t\t\tpreventDefault : true,
\t\t\t\t\tprogressBar    : prog
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tql.hideinfo();
\t\t\t\t\tvar doc = \$('<iframe class=\"elfinder-quicklook-preview-html\"></iframe>').appendTo(preview)[0].contentWindow.document;
\t\t\t\t\tdoc.open();
\t\t\t\t\tdoc.write(data.content);
\t\t\t\t\tdoc.close();
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\tloading.remove();
\t\t\t\t});
\t\t\t}
\t\t});
\t},
\t
\t/**
\t * MarkDown preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(['text/x-markdown']),
\t\t\tpreview = ql.preview,
\t\t\tmarked  = null,
\t\t\tshow = function(data, loading) {
\t\t\t\tql.hideinfo();
\t\t\t\tvar doc = \$('<iframe class=\"elfinder-quicklook-preview-html\"></iframe>').appendTo(preview)[0].contentWindow.document;
\t\t\t\tdoc.open();
\t\t\t\tdoc.write(marked(data.content));
\t\t\t\tdoc.close();
\t\t\t\tloading.remove();
\t\t\t},
\t\t\terror = function(loading) {
\t\t\t\tmarked = false;
\t\t\t\tloading.remove();
\t\t\t};
\t\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file, jqxhr, loading, prog;
\t\t\t
\t\t\tif (mimes[file.mime] && fm.options.cdns.marked && marked !== false && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
\t\t\t\te.stopImmediatePropagation();

\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);

\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\tjqxhr.state() == 'pending' && jqxhr.reject();
\t\t\t\t}).addClass('elfinder-overflow-auto');
\t\t\t\t
\t\t\t\tjqxhr = fm.request({
\t\t\t\t\tdata           : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
\t\t\t\t\toptions        : {type: 'get', cache : true},
\t\t\t\t\tpreventDefault : true,
\t\t\t\t\tprogressBar    : prog
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tif (marked || window.marked) {
\t\t\t\t\t\tif (!marked) {
\t\t\t\t\t\t\tmarked = window.marked;
\t\t\t\t\t\t}
\t\t\t\t\t\tshow(data, loading);
\t\t\t\t\t} else {
\t\t\t\t\t\tfm.loadScript([fm.options.cdns.marked],
\t\t\t\t\t\t\tfunction(res) { 
\t\t\t\t\t\t\t\tmarked = res || window.marked || false;
\t\t\t\t\t\t\t\tdelete window.marked;
\t\t\t\t\t\t\t\tif (marked) {
\t\t\t\t\t\t\t\t\tshow(data, loading);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\terror(loading);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\terror: function() {
\t\t\t\t\t\t\t\t\terror(loading);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.fail(function() {
\t\t\t\t\terror(loading);
\t\t\t\t});
\t\t\t}
\t\t});
\t},

\t/**
\t * PDF/ODT/ODS/ODP preview with ViewerJS
\t * 
\t * @param elFinder.commands.quicklook
\t */
\t function(ql) {
\t\tif (ql.options.viewerjs) {
\t\t\tvar fm      = ql.fm,
\t\t\t\tpreview = ql.preview,
\t\t\t\topts    = ql.options.viewerjs,
\t\t\t\tmimes   = opts.url? fm.arrayFlip(opts.mimes || []) : [],
\t\t\t\twin     = ql.window,
\t\t\t\tnavi    = ql.navbar,
\t\t\t\tsetNavi = function() {
\t\t\t\t\tnavi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '30px' : '');
\t\t\t\t};

\t\t\tif (opts.url) {
\t\t\t\tpreview.on('update', function(e) {
\t\t\t\t\tvar file = e.file, node, loading, prog, opDfd;

\t\t\t\t\tif (mimes[file.mime] && (file.mime !== 'application/pdf' || !opts.pdfNative || !ql.flags.pdfNative)) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t\topDfd = fm.openUrl(file.hash, 'sameorigin', function(url) {
\t\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\t\tnode = \$('<iframe class=\"elfinder-quicklook-preview-iframe\"></iframe>')
\t\t\t\t\t\t\t\t\t.css('background-color', 'transparent')
\t\t\t\t\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\t\tnode.css('background-color', '#fff');
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.on('error', function() {
\t\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.appendTo(preview)
\t\t\t\t\t\t\t\t\t.attr('src', opts.url + '#' + url);

\t\t\t\t\t\t\t\twin.on('viewchange.viewerjs', setNavi);
\t\t\t\t\t\t\t\tsetNavi();

\t\t\t\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\t\t\t\twin.off('viewchange.viewerjs');
\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\tnode.off('load').remove();
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}, { progressBar: prog });
\t\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t}
\t},

\t/**
\t * PDF preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmime    = 'application/pdf',
\t\t\tpreview = ql.preview,
\t\t\tactive  = false,
\t\t\turlhash = '',
\t\t\tfirefox, toolbar;
\t\t\t
\t\tif ((fm.UA.Safari && fm.OS === 'mac' && !fm.UA.iOS) || fm.UA.IE || fm.UA.Firefox) {
\t\t\tactive = true;
\t\t} else {
\t\t\t\$.each(navigator.plugins, function(i, plugins) {
\t\t\t\t\$.each(plugins, function(i, plugin) {
\t\t\t\t\tif (plugin.type === mime) {
\t\t\t\t\t\treturn !(active = true);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t});
\t\t}

\t\tql.flags.pdfNative = active;
\t\tif (active) {
\t\t\tif (typeof ql.options.pdfToolbar !== 'undefined' && !ql.options.pdfToolbar) {
\t\t\t\turlhash = '#toolbar=0';
\t\t\t}
\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file = e.file,
\t\t\t\t\topDfd;
\t\t\t\t
\t\t\t\tif (active && file.mime === mime && ql.dispInlineRegex.test(file.mime)) {
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\tql.cover.addClass('elfinder-quicklook-coverbg');
\t\t\t\t\t\t\t\$('<object class=\"elfinder-quicklook-preview-pdf\" data=\"'+url+urlhash+'\" type=\"application/pdf\" ></object>')
\t\t\t\t\t\t\t\t.on('error', function(e) {
\t\t\t\t\t\t\t\t\tactive = false;
\t\t\t\t\t\t\t\t\tql.update(void(0), fm.cwd());
\t\t\t\t\t\t\t\t\tql.update(void(0), file);
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.appendTo(preview);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t});
\t\t}
\t},
\t
\t/**
\t * Flash preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmime    = 'application/x-shockwave-flash',
\t\t\tpreview = ql.preview,
\t\t\tactive  = false;

\t\t\$.each(navigator.plugins, function(i, plugins) {
\t\t\t\$.each(plugins, function(i, plugin) {
\t\t\t\tif (plugin.type === mime) {
\t\t\t\t\treturn !(active = true);
\t\t\t\t}
\t\t\t});
\t\t});
\t\t
\t\tactive && preview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file,
\t\t\t\tnode, opDfd;
\t\t\t\t
\t\t\tif (file.mime === mime && ql.dispInlineRegex.test(file.mime)) {
\t\t\t\te.stopImmediatePropagation();
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tif (url) {
\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\tnode = \$('<embed class=\"elfinder-quicklook-preview-flash\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" src=\"'+url+'\" quality=\"high\" type=\"application/x-shockwave-flash\" wmode=\"transparent\" />')
\t\t\t\t\t\t\t.appendTo(preview);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t}
\t\t});
\t},
\t
\t/**
\t * HTML5 audio preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm       = ql.fm,
\t\t\tpreview  = ql.preview,
\t\t\tmimes    = {
\t\t\t\t'audio/mpeg'    : 'mp3',
\t\t\t\t'audio/mpeg3'   : 'mp3',
\t\t\t\t'audio/mp3'     : 'mp3',
\t\t\t\t'audio/x-mpeg3' : 'mp3',
\t\t\t\t'audio/x-mp3'   : 'mp3',
\t\t\t\t'audio/x-wav'   : 'wav',
\t\t\t\t'audio/wav'     : 'wav',
\t\t\t\t'audio/x-m4a'   : 'm4a',
\t\t\t\t'audio/aac'     : 'm4a',
\t\t\t\t'audio/mp4'     : 'm4a',
\t\t\t\t'audio/x-mp4'   : 'm4a',
\t\t\t\t'audio/ogg'     : 'ogg',
\t\t\t\t'audio/webm'    : 'webm',
\t\t\t\t'audio/flac'    : 'flac',
\t\t\t\t'audio/x-flac'  : 'flac',
\t\t\t\t'audio/amr'     : 'amr'
\t\t\t},
\t\t\tnode, curHash,
\t\t\twin  = ql.window,
\t\t\tnavi = ql.navbar,
\t\t\tAMR, autoplay,
\t\t\tcontrolsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList=\"' + fm.escape(ql.options.mediaControlsList) + '\"' : '',
\t\t\tsetNavi = function() {
\t\t\t\tnavi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
\t\t\t},
\t\t\tgetNode = function(src, hash) {
\t\t\t\treturn \$('<audio class=\"elfinder-quicklook-preview-audio ui-front\" controls' + controlsList + ' preload=\"auto\" autobuffer><source src=\"'+src+'\" ></source></audio>')
\t\t\t\t\t.on('change', function(e) {
\t\t\t\t\t\t// Firefox fire change event on seek or volume change
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t})
\t\t\t\t\t.on('error', function(e) {
\t\t\t\t\t\tnode && node.data('hash') === hash && reset();
\t\t\t\t\t})
\t\t\t\t\t.data('hash', hash)
\t\t\t\t\t.appendTo(preview);
\t\t\t},
\t\t\tamrToWavUrl = function(hash) {
\t\t\t\tvar dfd = \$.Deferred(),
\t\t\t\t\tloader = \$.Deferred().done(function() {
\t\t\t\t\t\tvar opDfd;
\t\t\t\t\t\topDfd = fm.getContents(hash, 'arraybuffer', { progressBar: prog }).done(function(data) {
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tvar buffer = AMR.toWAV(new Uint8Array(data));
\t\t\t\t\t\t\t\tif (buffer) {
\t\t\t\t\t\t\t\t\tdfd.resolve(URL.createObjectURL(new Blob([buffer], { type: 'audio/x-wav' })));
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t\t});
\t\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t\t});
\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\tAMR = false;
\t\t\t\t\t\tdfd.reject();
\t\t\t\t\t}),
\t\t\t\t\t_AMR;
\t\t\t\tif (window.TextEncoder && window.URL && URL.createObjectURL && typeof AMR === 'undefined') {
\t\t\t\t\t// previous window.AMR
\t\t\t\t\t_AMR = window.AMR;
\t\t\t\t\tdelete window.AMR;
\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t[ fm.options.cdns.amr ],
\t\t\t\t\t\tfunction() { 
\t\t\t\t\t\t\tAMR = window.AMR? window.AMR : false;
\t\t\t\t\t\t\t// restore previous window.AMR
\t\t\t\t\t\t\twindow.AMR = _AMR;
\t\t\t\t\t\t\tloader[AMR? 'resolve':'reject']();
\t\t\t\t\t\t},
\t\t\t\t\t\t{
\t\t\t\t\t\t\terror: function() {
\t\t\t\t\t\t\t\tloader.reject();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t);
\t\t\t\t} else {
\t\t\t\t\tloader[AMR? 'resolve':'reject']();
\t\t\t\t}
\t\t\t\treturn dfd;
\t\t\t},
\t\t\tplay = function(player) {
\t\t\t\tvar hash = node.data('hash'),
\t\t\t\t\tplayPromise;
\t\t\t\tautoplay && (playPromise = player.play());
\t\t\t\t// uses \"playPromise['catch']\" instead \"playPromise.catch\" to support Old IE
\t\t\t\tif (playPromise && playPromise['catch']) {
\t\t\t\t\tplayPromise['catch'](function(e) {
\t\t\t\t\t\tif (!player.paused) {
\t\t\t\t\t\t\tnode && node.data('hash') === hash && reset();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\treset = function() {
\t\t\t\tif (node && node.parent().length) {
\t\t\t\t\tvar elm = node[0],
\t\t\t\t\t\turl = node.children('source').attr('src');
\t\t\t\t\twin.off('viewchange.audio');
\t\t\t\t\ttry {
\t\t\t\t\t\telm.pause();
\t\t\t\t\t\tnode.empty();
\t\t\t\t\t\tif (url.match(/^blob:/)) {
\t\t\t\t\t\t\tURL.revokeObjectURL(url);
\t\t\t\t\t\t}
\t\t\t\t\t\telm.src = '';
\t\t\t\t\t\telm.load();
\t\t\t\t\t} catch(e) {}
\t\t\t\t\tnode.remove();
\t\t\t\t\tnode = null;
\t\t\t\t}
\t\t\t},
\t\t\tloading, prog;

\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file,
\t\t\t\ttype = mimes[file.mime],
\t\t\t\thtml5, opDfd;

\t\t\tif (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && ((html5 = ql.support.audio[type]) || (type === 'amr'))) {
\t\t\t\tautoplay = ql.autoPlay();
\t\t\t\tcurHash = file.hash;
\t\t\t\tif (!html5) {
\t\t\t\t\tif (fm.options.cdns.amr && type === 'amr' && AMR !== false) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t\tnode = getNode('', curHash);
\t\t\t\t\t\tamrToWavUrl(file.hash).done(function(url) {
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\tif (curHash === file.hash) {
\t\t\t\t\t\t\t\tvar elm = node[0];
\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\tnode.children('source').attr('src', url);
\t\t\t\t\t\t\t\t\telm.pause();
\t\t\t\t\t\t\t\t\telm.load();
\t\t\t\t\t\t\t\t\tplay(elm);
\t\t\t\t\t\t\t\t\twin.on('viewchange.audio', setNavi);
\t\t\t\t\t\t\t\t\tsetNavi();
\t\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\t\tURL.revokeObjectURL(url);
\t\t\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tURL.revokeObjectURL(url);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\topDfd = fm.openUrl(curHash, false, function(url) {
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\tnode = getNode(url, curHash);
\t\t\t\t\t\t\tplay(node[0]);
\t\t\t\t\t\t\twin.on('viewchange.audio', setNavi);
\t\t\t\t\t\t\tsetNavi();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t}
\t\t\t\t\t}, { progressBar: prog });
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t}
\t\t}).one('change', reset);
\t},
\t
\t/**
\t * HTML5 video preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm       = ql.fm,
\t\t\tpreview  = ql.preview,
\t\t\tmimes    = {
\t\t\t\t'video/mp4'       : 'mp4',
\t\t\t\t'video/x-m4v'     : 'mp4',
\t\t\t\t'video/quicktime' : 'mp4',
\t\t\t\t'video/mpeg'      : 'mpeg',
\t\t\t\t'video/ogg'       : 'ogg',
\t\t\t\t'application/ogg' : 'ogg',
\t\t\t\t'video/webm'      : 'webm',
\t\t\t\t'video/x-matroska': 'mkv',
\t\t\t\t'video/3gpp'      : '3gp',
\t\t\t\t'application/vnd.apple.mpegurl' : 'm3u8',
\t\t\t\t'application/x-mpegurl' : 'm3u8',
\t\t\t\t'application/dash+xml'  : 'mpd',
\t\t\t\t'video/x-flv'     : 'flv',
\t\t\t\t'video/x-msvideo' : 'avi'
\t\t\t},
\t\t\tnode,
\t\t\twin  = ql.window,
\t\t\tnavi = ql.navbar,
\t\t\tcHls, cDash, pDash, cFlv, cVideojs, autoplay, tm, loading, prog,
\t\t\tcontrolsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList=\"' + fm.escape(ql.options.mediaControlsList) + '\"' : '',
\t\t\tsetNavi = function() {
\t\t\t\tif (fm.UA.iOS) {
\t\t\t\t\tif (win.hasClass('elfinder-quicklook-fullscreen')) {
\t\t\t\t\t\tpreview.css('height', '-webkit-calc(100% - 50px)');
\t\t\t\t\t\tnavi._show();
\t\t\t\t\t} else {
\t\t\t\t\t\tpreview.css('height', '');
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tnavi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
\t\t\t\t}
\t\t\t},
\t\t\trender = function(file, opts) {
\t\t\t\tvar errTm = function(e) {
\t\t\t\t\t\tif (err > 1) {
\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\ttm = setTimeout(function() {
\t\t\t\t\t\t\t\t!canPlay && reset(true);
\t\t\t\t\t\t\t}, 800);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\terr = 0, 
\t\t\t\t\tcanPlay;
\t\t\t\t//reset();
\t\t\t\tpDash = null;
\t\t\t\topts = opts || {};
\t\t\t\tql.hideinfo();
\t\t\t\tnode = \$('<video class=\"elfinder-quicklook-preview-video\" controls' + controlsList + ' preload=\"auto\" autobuffer playsinline>'
\t\t\t\t\t\t+'</video>')
\t\t\t\t\t.on('change', function(e) {
\t\t\t\t\t\t// Firefox fire change event on seek or volume change
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t})
\t\t\t\t\t.on('timeupdate progress', errTm)
\t\t\t\t\t.on('canplay', function() {
\t\t\t\t\t\tcanPlay = true;
\t\t\t\t\t})
\t\t\t\t\t.data('hash', file.hash);
\t\t\t\t// can not handling error event with jQuery `on` event handler
\t\t\t\tnode[0].addEventListener('error', function(e) {
\t\t\t\t\tif (opts.src && fm.convAbsUrl(opts.src) === fm.convAbsUrl(e.target.src)) {
\t\t\t\t\t\t++err;
\t\t\t\t\t\terrTm();
\t\t\t\t\t}
\t\t\t\t}, true);

\t\t\t\tif (opts.src) {
\t\t\t\t\tnode.append('<source src=\"'+opts.src+'\" type=\"'+file.mime+'\"></source><source src=\"'+opts.src+'\"></source>');
\t\t\t\t}
\t\t\t\t
\t\t\t\tnode.appendTo(preview);

\t\t\t\twin.on('viewchange.video', setNavi);
\t\t\t\tsetNavi();
\t\t\t},
\t\t\tloadHls = function(file) {
\t\t\t\tvar hls, opDfd;
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tloading.remove();
\t\t\t\t\tif (url) {
\t\t\t\t\t\trender(file);
\t\t\t\t\t\thls = new cHls();
\t\t\t\t\t\thls.loadSource(url);
\t\t\t\t\t\thls.attachMedia(node[0]);
\t\t\t\t\t\tif (autoplay) {
\t\t\t\t\t\t\thls.on(cHls.Events.MANIFEST_PARSED, function() {
\t\t\t\t\t\t\t\tplay(node[0]);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t},
\t\t\tloadDash = function(file) {
\t\t\t\tvar opDfd;
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tvar debug;
\t\t\t\t\tloading.remove();
\t\t\t\t\tif (url) {
\t\t\t\t\t\trender(file);
\t\t\t\t\t\tpDash = window.dashjs.MediaPlayer().create();
\t\t\t\t\t\tdebug = pDash.getDebug();
\t\t\t\t\t\tif (debug.setLogLevel) {
\t\t\t\t\t\t\tdebug.setLogLevel(dashjs.Debug.LOG_LEVEL_FATAL);
\t\t\t\t\t\t} else if (debug.setLogToBrowserConsole) {
\t\t\t\t\t\t\tdebug.setLogToBrowserConsole(false);
\t\t\t\t\t\t}
\t\t\t\t\t\tpDash.initialize(node[0], url, autoplay);
\t\t\t\t\t\tpDash.on('error', function(e) {
\t\t\t\t\t\t\treset(true);
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t},
\t\t\tloadFlv = function(file) {
\t\t\t\tvar opDfd
\t\t\t\tif (!cFlv.isSupported()) {
\t\t\t\t\tcFlv = false;
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tloading.remove();
\t\t\t\t\tif (url) {
\t\t\t\t\t\tvar player = cFlv.createPlayer({
\t\t\t\t\t\t\ttype: 'flv',
\t\t\t\t\t\t\turl: url
\t\t\t\t\t\t});
\t\t\t\t\t\trender(file);
\t\t\t\t\t\tplayer.on(cFlv.Events.ERROR, function() {
\t\t\t\t\t\t\tplayer.destroy();
\t\t\t\t\t\t\treset(true);
\t\t\t\t\t\t});
\t\t\t\t\t\tplayer.attachMediaElement(node[0]);
\t\t\t\t\t\tplayer.load();
\t\t\t\t\t\tplay(player);
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t},
\t\t\tloadVideojs = function(file) {
\t\t\t\tvar opDfd;
\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tloading.remove();
\t\t\t\t\tif (url) {
\t\t\t\t\t\trender(file);
\t\t\t\t\t\tnode[0].src = url;
\t\t\t\t\t\tcVideojs(node[0], {
\t\t\t\t\t\t\tsrc: url
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t},
\t\t\tplay = function(player) {
\t\t\t\tvar hash = node.data('hash'),
\t\t\t\t\tplayPromise;
\t\t\t\tautoplay && (playPromise = player.play());
\t\t\t\t// uses \"playPromise['catch']\" instead \"playPromise.catch\" to support Old IE
\t\t\t\tif (playPromise && playPromise['catch']) {
\t\t\t\t\tplayPromise['catch'](function(e) {
\t\t\t\t\t\tif (!player.paused) {
\t\t\t\t\t\t\tnode && node.data('hash') === hash && reset(true);
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\treset = function(showInfo) {
\t\t\t\ttm && clearTimeout(tm);
\t\t\t\tif (node && node.parent().length) {
\t\t\t\t\tvar elm = node[0];
\t\t\t\t\twin.off('viewchange.video');
\t\t\t\t\tpDash && pDash.reset();
\t\t\t\t\ttry {
\t\t\t\t\t\telm.pause();
\t\t\t\t\t\tnode.empty();
\t\t\t\t\t\telm.src = '';
\t\t\t\t\t\telm.load();
\t\t\t\t\t} catch(e) {}
\t\t\t\t\tnode.remove();
\t\t\t\t\tnode = null;
\t\t\t\t}
\t\t\t\tshowInfo && ql.info.show();
\t\t\t};

\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file,
\t\t\t\tmime = file.mime.toLowerCase(),
\t\t\t\ttype = mimes[mime],
\t\t\t\tstock, playPromise, opDfd;
\t\t\t
\t\t\tif (mimes[mime] && ql.dispInlineRegex.test(file.mime) /*&& (((type === 'm3u8' || (type === 'mpd' && !fm.UA.iOS) || type === 'flv') && !fm.UA.ltIE10) || ql.support.video[type])*/) {
\t\t\t\tautoplay = ql.autoPlay();
\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>');
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\tif (ql.support.video[type] && (type !== 'm3u8' || fm.UA.Safari)) {
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\tloading.appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\topDfd = fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\trender(file, { src: url });
\t\t\t\t\t\t\tplay(node[0]);
\t\t\t\t\t\t}
\t\t\t\t\t}, { progressBar: prog });
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tif (cHls !== false && fm.options.cdns.hls && type === 'm3u8') {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading.appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tif (cHls) {
\t\t\t\t\t\t\tloadHls(file);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tstock = window.Hls;
\t\t\t\t\t\t\tdelete window.Hls;
\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t[ fm.options.cdns.hls ],
\t\t\t\t\t\t\t\tfunction(res) { 
\t\t\t\t\t\t\t\t\tcHls = res || window.Hls || false;
\t\t\t\t\t\t\t\t\twindow.Hls = stock;
\t\t\t\t\t\t\t\t\tcHls && loadHls(file);
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\t\terror : function() {
\t\t\t\t\t\t\t\t\t\tcHls = false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t);
\t\t\t\t\t\t}
\t\t\t\t\t} else if (cDash !== false && fm.options.cdns.dash && type === 'mpd') {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading.appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tif (cDash) {
\t\t\t\t\t\t\tloadDash(file);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t[ fm.options.cdns.dash ],
\t\t\t\t\t\t\t\tfunction() {
\t\t\t\t\t\t\t\t\t// dashjs require window.dashjs in global scope
\t\t\t\t\t\t\t\t\tcDash = window.dashjs? true : false;
\t\t\t\t\t\t\t\t\tcDash && loadDash(file);
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\t\terror : function() {
\t\t\t\t\t\t\t\t\t\tcDash = false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t);
\t\t\t\t\t\t}
\t\t\t\t\t} else if (cFlv !== false && fm.options.cdns.flv && type === 'flv') {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading.appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tif (cFlv) {
\t\t\t\t\t\t\tloadFlv(file);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tstock = window.flvjs;
\t\t\t\t\t\t\tdelete window.flvjs;
\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t[ fm.options.cdns.flv ],
\t\t\t\t\t\t\t\tfunction(res) { 
\t\t\t\t\t\t\t\t\tcFlv = res || window.flvjs || false;
\t\t\t\t\t\t\t\t\twindow.flvjs = stock;
\t\t\t\t\t\t\t\t\tcFlv && loadFlv(file);
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\t\terror : function() {
\t\t\t\t\t\t\t\t\t\tcFlv = false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t);
\t\t\t\t\t\t}
\t\t\t\t\t} else if (fm.options.cdns.videojs) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tloading.appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tif (cVideojs) {
\t\t\t\t\t\t\tloadVideojs(file);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t[ fm.options.cdns.videojs + '/video.min.js' ],
\t\t\t\t\t\t\t\tfunction(res) { 
\t\t\t\t\t\t\t\t\tcVideojs = res || window.videojs || false;
\t\t\t\t\t\t\t\t\t//window.flvjs = stock;
\t\t\t\t\t\t\t\t\tcVideojs && loadVideojs(file);
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\t\terror : function() {
\t\t\t\t\t\t\t\t\t\tcVideojs = false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t).loadCss([fm.options.cdns.videojs + '/video-js.min.css']);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t}).one('change', reset);
\t},
\t
\t/**
\t * Audio/video preview plugin using browser plugins
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar preview = ql.preview,
\t\t\tmimes   = [],
\t\t\tnode,
\t\t\twin  = ql.window,
\t\t\tnavi = ql.navbar;
\t\t\t
\t\t\$.each(navigator.plugins, function(i, plugins) {
\t\t\t\$.each(plugins, function(i, plugin) {
\t\t\t\t(plugin.type.indexOf('audio/') === 0 || plugin.type.indexOf('video/') === 0) && mimes.push(plugin.type);
\t\t\t});
\t\t});
\t\tmimes = ql.fm.arrayFlip(mimes);
\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file  = e.file,
\t\t\t\tmime  = file.mime,
\t\t\t\tvideo, opDfd, loading, prog,
\t\t\t\tsetNavi = function() {
\t\t\t\t\tnavi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : '');
\t\t\t\t};
\t\t\t
\t\t\tif (mimes[file.mime] && ql.dispInlineRegex.test(file.mime)) {
\t\t\t\te.stopImmediatePropagation();
\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\topDfd = ql.fm.openUrl(file.hash, false, function(url) {
\t\t\t\t\tloading.remove();
\t\t\t\t\tif (url) {
\t\t\t\t\t\t(video = mime.indexOf('video/') === 0) && ql.hideinfo();
\t\t\t\t\t\tnode = \$('<embed src=\"'+url+'\" type=\"'+mime+'\" class=\"elfinder-quicklook-preview-'+(video ? 'video' : 'audio')+'\"/>')
\t\t\t\t\t\t\t.appendTo(preview);
\t\t\t\t\t\t
\t\t\t\t\t\twin.on('viewchange.embed', setNavi);
\t\t\t\t\t\tsetNavi();
\t\t\t\t\t}
\t\t\t\t}, { progressBar: prog });
\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t});
\t\t\t}
\t\t}).one('change', function() {
\t\t\tif (node && node.parent().length) {
\t\t\t\twin.off('viewchange.embed');
\t\t\t\tnode.remove();
\t\t\t\tnode= null;
\t\t\t}
\t\t});
\t\t
\t},

\t/**
\t * Archive(zip|gzip|tar|bz2) preview plugin using https://github.com/imaya/zlib.js
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(['application/zip', 'application/x-gzip', 'application/x-tar', 'application/x-bzip2']),
\t\t\tpreview = ql.preview,
\t\t\tsizeMax = fm.returnBytes(ql.options.unzipMaxSize || 0),
\t\t\tZlib    = (fm.options.cdns.zlibUnzip && fm.options.cdns.zlibGunzip)? true : false,
\t\t\tbzip2   = fm.options.cdns.bzip2? true : false;

\t\tif (window.Worker && window.Uint8Array && window.DataView) {
\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file  = e.file,
\t\t\t\t\tisTar = (file.mime === 'application/x-tar'),
\t\t\t\t\tisBzip2 = (file.mime === 'application/x-bzip2'),
\t\t\t\t\tisZlib = (file.mime === 'application/zip' || file.mime === 'application/x-gzip');
\t\t\t\tif (mimes[file.mime] && (!sizeMax || file.size <= sizeMax) && (
\t\t\t\t\t\tisTar
\t\t\t\t\t\t|| (isBzip2 && bzip2)
\t\t\t\t\t\t|| (isZlib && Zlib)
\t\t\t\t\t)) {
\t\t\t\t\tvar jqxhr, wk, loading, prog, url,
\t\t\t\t\t\treq = function() {
\t\t\t\t\t\t\tjqxhr = fm.getContents(file.hash, 'arraybuffer', { progressBar: prog })
\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tvar unzip, filenames,
\t\t\t\t\t\t\t\t\terr = function(e) {
\t\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\t\tif (isZlib) {
\t\t\t\t\t\t\t\t\t\t\tZlib = false;
\t\t\t\t\t\t\t\t\t\t} else if (isBzip2) {
\t\t\t\t\t\t\t\t\t\t\tbzip2 = false;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tfm.debug('error', e);
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\twk = fm.getWorker();
\t\t\t\t\t\t\t\t\twk.onmessage = function(res) {
\t\t\t\t\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\t\tif (!res.data || res.data.error) {
\t\t\t\t\t\t\t\t\t\t\tnew Error(res.data && res.data.error? res.data.error : '');
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tmakeList(res.data.files);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\twk.onerror = err;
\t\t\t\t\t\t\t\t\tif (file.mime === 'application/x-tar') {
\t\t\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\t\t\tscripts: [fm.getWorkerUrl('quicklook.unzip.js')],
\t\t\t\t\t\t\t\t\t\t\tdata: { type: 'tar', bin: data }
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} else if (file.mime === 'application/zip') {
\t\t\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\t\t\tscripts: [fm.options.cdns.zlibUnzip, fm.getWorkerUrl('quicklook.unzip.js')],
\t\t\t\t\t\t\t\t\t\t\tdata: { type: 'zip', bin: data }
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} else if (file.mime === 'application/x-gzip') {
\t\t\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\t\t\tscripts: [fm.options.cdns.zlibGunzip, fm.getWorkerUrl('quicklook.unzip.js')],
\t\t\t\t\t\t\t\t\t\t\tdata: { type: 'gzip', bin: data }
\t\t\t\t\t\t\t\t\t\t});

\t\t\t\t\t\t\t\t\t} else if (file.mime === 'application/x-bzip2') {
\t\t\t\t\t\t\t\t\t\twk.postMessage({
\t\t\t\t\t\t\t\t\t\t\tscripts: [fm.options.cdns.bzip2, fm.getWorkerUrl('quicklook.unzip.js')],
\t\t\t\t\t\t\t\t\t\t\tdata: { type: 'bzip2', bin: data }
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} catch (e) {
\t\t\t\t\t\t\t\t\terr(e);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t},
\t\t\t\t\t\tmakeList = function(filenames) {
\t\t\t\t\t\t\tvar header, list, doc, tsize = 0;
\t\t\t\t\t\t\tif (filenames && filenames.length) {
\t\t\t\t\t\t\t\tfilenames = \$.map(filenames, function(str) {
\t\t\t\t\t\t\t\t\treturn fm.decodeRawString(str);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tfilenames.sort();
\t\t\t\t\t\t\t\tlist = fm.escape(filenames.join(\"\\n\").replace(/\\{formatSize\\((\\d+)\\)\\}/g, function(m, s) {
\t\t\t\t\t\t\t\t\ttsize += parseInt(s);
\t\t\t\t\t\t\t\t\treturn fm.formatSize(s);
\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t\theader = '<strong>'+fm.escape(file.mime)+'</strong> ('+fm.formatSize(file.size)+' / '+fm.formatSize(tsize)+')'+'<hr/>';
\t\t\t\t\t\t\t\tdoc = \$('<div class=\"elfinder-quicklook-preview-archive-wrapper\">'+header+'<pre class=\"elfinder-quicklook-preview-text\">'+list+'</pre></div>')
\t\t\t\t\t\t\t\t\t.on('touchstart', function(e) {
\t\t\t\t\t\t\t\t\t\tif (\$(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
\t\t\t\t\t\t\t\t\t\t\te.originalEvent._preventSwipeX = true;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.appendTo(preview);
\t\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t};

\t\t\t\t\t// this is our file - stop event propagation
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t
\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\tjqxhr.state() === 'pending' && jqxhr.reject();
\t\t\t\t\t\twk && wk.terminate();
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\treq();
\t\t\t\t}
\t\t\t});
\t\t}
\t},

\t/**
\t * RAR Archive preview plugin using https://github.com/43081j/rar.js
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(['application/x-rar']),
\t\t\tpreview = ql.preview,
\t\t\tRAR;

\t\tif (window.DataView) {
\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file = e.file;
\t\t\t\tif (mimes[file.mime] && fm.options.cdns.rar && RAR !== false) {
\t\t\t\t\tvar loading, prog, url, archive, abort,
\t\t\t\t\t\tgetList = function(url) {
\t\t\t\t\t\t\tif (abort) {
\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tarchive = RAR({
\t\t\t\t\t\t\t\t\tfile: url,
\t\t\t\t\t\t\t\t\ttype: 2,
\t\t\t\t\t\t\t\t\txhrHeaders: fm.customHeaders,
\t\t\t\t\t\t\t\t\txhrFields: fm.xhrFields
\t\t\t\t\t\t\t\t}, function(err) {
\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\tvar filenames = [],
\t\t\t\t\t\t\t\t\t\theader, doc;
\t\t\t\t\t\t\t\t\tif (abort || err) {
\t\t\t\t\t\t\t\t\t\t// An error occurred (not a rar, read error, etc)
\t\t\t\t\t\t\t\t\t\terr && fm.debug('error', err);
\t\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\$.each(archive.entries, function() {
\t\t\t\t\t\t\t\t\t\tfilenames.push(this.path + (this.size? ' (' + fm.formatSize(this.size) + ')' : ''));
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\tif (filenames.length) {
\t\t\t\t\t\t\t\t\t\tfilenames = \$.map(filenames, function(str) {
\t\t\t\t\t\t\t\t\t\t\treturn fm.decodeRawString(str);
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\tfilenames.sort();
\t\t\t\t\t\t\t\t\t\theader = '<strong>'+fm.escape(file.mime)+'</strong> ('+fm.formatSize(file.size)+')'+'<hr/>';
\t\t\t\t\t\t\t\t\t\tdoc = \$('<div class=\"elfinder-quicklook-preview-archive-wrapper\">'+header+'<pre class=\"elfinder-quicklook-preview-text\">'+fm.escape(filenames.join(\"\\n\"))+'</pre></div>')
\t\t\t\t\t\t\t\t\t\t\t.on('touchstart', function(e) {
\t\t\t\t\t\t\t\t\t\t\t\tif (\$(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
\t\t\t\t\t\t\t\t\t\t\t\t\te.originalEvent._preventSwipeX = true;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t.appendTo(preview);
\t\t\t\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t},
\t\t\t\t\t\terror = function() {
\t\t\t\t\t\t\tRAR = false;
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t},
\t\t\t\t\t\t_RAR, opDfd;

\t\t\t\t\t// this is our file - stop event propagation
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t
\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\tarchive && (archive.abort = true);
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\tabort = true;
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\topDfd = fm.openUrl(file.hash, 'sameorigin', function(url) {
\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\tif (RAR) {
\t\t\t\t\t\t\t\tgetList(url);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (window.RarArchive) {
\t\t\t\t\t\t\t\t\t_RAR = window.RarArchive;
\t\t\t\t\t\t\t\t\tdelete window.RarArchive;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.loadScript(
\t\t\t\t\t\t\t\t\t[ fm.options.cdns.rar ],
\t\t\t\t\t\t\t\t\tfunction() {
\t\t\t\t\t\t\t\t\t\tif (fm.hasRequire) {
\t\t\t\t\t\t\t\t\t\t\trequire(['rar'], function(RarArchive) {
\t\t\t\t\t\t\t\t\t\t\t\tRAR = RarArchive;
\t\t\t\t\t\t\t\t\t\t\t\tgetList(url);
\t\t\t\t\t\t\t\t\t\t\t}, error);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tif (RAR = window.RarArchive) {
\t\t\t\t\t\t\t\t\t\t\t\tif (_RAR) {
\t\t\t\t\t\t\t\t\t\t\t\t\twindow.RarArchive = _RAR;
\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\tdelete window.RarArchive;
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\tgetList(url);
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\terror();
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t{
\t\t\t\t\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\t\t\t\t\terror : error
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t}, { progressBar: prog, temporary: true });
\t\t\t\t\t// stop loading on change file if not loaded yet
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\topDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
\t\t\t\t\t});
\t\t\t\t}
\t\t\t});
\t\t}
\t},

\t/**
\t * CAD-Files and 3D-Models online viewer on sharecad.org
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = fm.arrayFlip(ql.options.sharecadMimes || []),
\t\t\tpreview = ql.preview,
\t\t\twin     = ql.window,
\t\t\tnode;
\t\t\t
\t\tif (ql.options.sharecadMimes.length) {
\t\t\tql.addIntegration({
\t\t\t\ttitle: 'ShareCAD.org CAD and 3D-Models viewer',
\t\t\t\tlink: 'https://sharecad.org/DWGOnlinePlugin'
\t\t\t});
\t\t}

\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file;
\t\t\tif (mimes[file.mime.toLowerCase()] && fm.option('onetimeUrl', file.hash)) {
\t\t\t\tvar win     = ql.window,
\t\t\t\t\tloading, prog, url;
\t\t\t\t
\t\t\t\te.stopImmediatePropagation();
\t\t\t\tif (file.url == '1') {
\t\t\t\t\tpreview.hide();
\t\t\t\t\t\$('<div class=\"elfinder-quicklook-info-data\"><button class=\"elfinder-info-button\">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\tvar self = \$(this);
\t\t\t\t\t\tself.html('<span class=\"elfinder-spinner\">');
\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\t\t\tpreventDefault : true,
\t\t\t\t\t\t\tprogressBar : prog
\t\t\t\t\t\t})
\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\tself.html('');
\t\t\t\t\t\t})
\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\t\tfile.url = rfile.url = data.url || '';
\t\t\t\t\t\t\tif (file.url) {
\t\t\t\t\t\t\t\tpreview.trigger({
\t\t\t\t\t\t\t\t\ttype: ql.evUpdate,
\t\t\t\t\t\t\t\t\tfile: file,
\t\t\t\t\t\t\t\t\tforceUpdate: true
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\tif (file.url !== '' && file.url != '1') {
\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\tnode.off('load').remove();
\t\t\t\t\t\tnode = null;
\t\t\t\t\t}).addClass('elfinder-overflow-auto');
\t\t\t\t\t
\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\t
\t\t\t\t\turl = fm.convAbsUrl(fm.url(file.hash));
\t\t\t\t\tnode = \$('<iframe class=\"elfinder-quicklook-preview-iframe\" scrolling=\"no\"></iframe>')
\t\t\t\t\t\t.css('background-color', 'transparent')
\t\t\t\t\t\t.appendTo(preview)
\t\t\t\t\t\t.on('load', function() {
\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\tql.preview.after(ql.info);
\t\t\t\t\t\t\t\$(this).css('background-color', '#fff').show();
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('error', function() {
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\tql.preview.after(ql.info);
\t\t\t\t\t\t})
\t\t\t\t\t\t.attr('src', '//sharecad.org/cadframe/load?url=' + encodeURIComponent(url));
\t\t\t\t\t
\t\t\t\t\tql.info.after(ql.preview);
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t});
\t},

\t/**
\t * KML preview with GoogleMaps API
\t *
\t * @param elFinder.commands.quicklook
\t */
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = {
\t\t\t\t'application/vnd.google-earth.kml+xml' : true,
\t\t\t\t'application/vnd.google-earth.kmz' : true
\t\t\t},
\t\t\tpreview = ql.preview,
\t\t\tgMaps, loadMap, wGmfail, fail, mapScr;

\t\tif (ql.options.googleMapsApiKey) {
\t\t\tql.addIntegration({
\t\t\t\ttitle: 'Google Maps',
\t\t\t\tlink: 'https://www.google.com/intl/' + fm.lang.replace('_', '-') + '/help/terms_maps.html'
\t\t\t});
\t\t\tgMaps = (window.google && google.maps);
\t\t\t// start load maps
\t\t\tloadMap = function(file, node, prog) {
\t\t\t\tvar mapsOpts = ql.options.googleMapsOpts.maps;
\t\t\t\tfm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) {
\t\t\t\t\tif (url) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tnew gMaps.KmlLayer(url, Object.assign({
\t\t\t\t\t\t\t\tmap: new gMaps.Map(node.get(0), mapsOpts)
\t\t\t\t\t\t\t}, ql.options.googleMapsOpts.kml));
\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tfail();
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tfail();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t};
\t\t\t// keep stored error handler if exists
\t\t\twGmfail = window.gm_authFailure;
\t\t\t// on error function
\t\t\tfail = function() {
\t\t\t\tmapScr = null;
\t\t\t};
\t\t\t// API script url
\t\t\tmapScr = 'https://maps.googleapis.com/maps/api/js?key=' + ql.options.googleMapsApiKey;
\t\t\t// error handler
\t\t\twindow.gm_authFailure = function() {
\t\t\t\tfail();
\t\t\t\twGmfail && wGmfail();
\t\t\t};

\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file = e.file;
\t\t\t\tif (mapScr && mimes[file.mime.toLowerCase()]) {
\t\t\t\t\tvar win     = ql.window,
\t\t\t\t\t\tgetLink = (file.url == '1' && !fm.option('onetimeUrl', file.hash)),
\t\t\t\t\t\tloading, prog, url, node;
\t\t\t\t
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);
\t\t\t\t\tif (getLink) {
\t\t\t\t\t\tpreview.hide();
\t\t\t\t\t\t\$('<div class=\"elfinder-quicklook-info-data\"><button class=\"elfinder-info-button\">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tvar self = \$(this);
\t\t\t\t\t\t\tself.html('<span class=\"elfinder-spinner\">');
\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\t\t\t\tpreventDefault : true,
\t\t\t\t\t\t\t\tprogressBar : prog
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\tself.html('');
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\t\t\tfile.url = rfile.url = data.url || '';
\t\t\t\t\t\t\t\tif (file.url) {
\t\t\t\t\t\t\t\t\tpreview.trigger({
\t\t\t\t\t\t\t\t\t\ttype: ql.evUpdate,
\t\t\t\t\t\t\t\t\t\tfile: file,
\t\t\t\t\t\t\t\t\t\tforceUpdate: true
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tif (file.url !== '' && !getLink) {
\t\t\t\t\t\tnode = \$('<div style=\"width:100%;height:100%;\"></div>').appendTo(preview);
\t\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t\tnode = null;
\t\t\t\t\t\t});
\t\t\t\t\t\tif (!gMaps) {
\t\t\t\t\t\t\tfm.loadScript([mapScr], function() {
\t\t\t\t\t\t\t\tgMaps = window.google && google.maps;
\t\t\t\t\t\t\t\tgMaps && loadMap(file, node, prog);
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tloadMap(file, node, prog);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t}
\t},

\t/**
\t * Any supported files preview plugin using (Google docs | MS Office) online viewer
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\t\tvar fm      = ql.fm,
\t\t\tmimes   = Object.assign(fm.arrayFlip(ql.options.googleDocsMimes || [], 'g'), fm.arrayFlip(ql.options.officeOnlineMimes || [], 'm')),
\t\t\tpreview = ql.preview,
\t\t\twin     = ql.window,
\t\t\tnavi    = ql.navbar,
\t\t\turls    = {
\t\t\t\tg: 'docs.google.com/gview?embedded=true&url=',
\t\t\t\tm: 'view.officeapps.live.com/op/embed.aspx?wdStartOn=0&src='
\t\t\t},
\t\t\tnavBottom = {
\t\t\t\tg: '56px',
\t\t\t\tm: '24px'
\t\t\t},
\t\t\tmLimits = {
\t\t\t\txls  : 5242880, // 5MB
\t\t\t\txlsb : 5242880,
\t\t\t\txlsx : 5242880,
\t\t\t\txlsm : 5242880,
\t\t\t\tother: 10485760 // 10MB
\t\t\t},
\t\t\tnode, enable;
\t\t
\t\tif (ql.options.googleDocsMimes.length) {
\t\t\tenable = true;
\t\t\tql.addIntegration({
\t\t\t\ttitle: 'Google Docs Viewer',
\t\t\t\tlink: 'https://docs.google.com/'
\t\t\t});
\t\t}
\t\tif (ql.options.officeOnlineMimes.length) {
\t\t\tenable = true;
\t\t\tql.addIntegration({
\t\t\t\ttitle: 'MS Online Doc Viewer',
\t\t\t\tlink: 'https://products.office.com/office-online/view-office-documents-online'
\t\t\t});
\t\t}

\t\tif (enable) {
\t\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\t\tvar file = e.file,
\t\t\t\t\ttype, dfd;
\t\t\t\t// 25MB is maximum filesize of Google Docs prevew
\t\t\t\tif (file.size <= 26214400 && (type = mimes[file.mime])) {
\t\t\t\t\tvar win     = ql.window,
\t\t\t\t\t\tsetNavi = function() {
\t\t\t\t\t\t\tnavi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? navBottom[type] : '');
\t\t\t\t\t\t},
\t\t\t\t\t\text     = fm.mimeTypes[file.mime],
\t\t\t\t\t\tgetLink = (file.url == '1' && !fm.option('onetimeUrl', file.hash)),
\t\t\t\t\t\tloading, prog, url, tm;
\t\t\t\t\t
\t\t\t\t\tif (type === 'm') {
\t\t\t\t\t\tif ((mLimits[ext] && file.size > mLimits[ext]) || file.size > mLimits.other) {
\t\t\t\t\t\t\ttype = 'g';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (getLink) {
\t\t\t\t\t\tpreview.hide();
\t\t\t\t\t\t\$('<div class=\"elfinder-quicklook-info-data\"><button class=\"elfinder-info-button\">'+fm.i18n('getLink')+'</button></div>').appendTo(ql.info.find('.elfinder-quicklook-info'))
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tvar self = \$(this);
\t\t\t\t\t\t\tself.html('<span class=\"elfinder-spinner\">');
\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\tdata : {cmd : 'url', target : file.hash},
\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\tself.html('');
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\t\t\tfile.url = rfile.url = data.url || '';
\t\t\t\t\t\t\t\tif (file.url) {
\t\t\t\t\t\t\t\t\tpreview.trigger({
\t\t\t\t\t\t\t\t\t\ttype: ql.evUpdate,
\t\t\t\t\t\t\t\t\t\tfile: file,
\t\t\t\t\t\t\t\t\t\tforceUpdate: true
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t\tif (file.url !== '' && !getLink) {
\t\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\t\tpreview.one('change', function() {
\t\t\t\t\t\t\tdfd && dfd.status && dfd.status() === 'pending' && dfd.reject();
\t\t\t\t\t\t\twin.off('viewchange.googledocs');
\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\tnode.off('load').remove();
\t\t\t\t\t\t\tnode = null;
\t\t\t\t\t\t}).addClass('elfinder-overflow-auto');
\t\t\t\t\t\t
\t\t\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);

\t\t\t\t\t\tnode = \$('<iframe class=\"elfinder-quicklook-preview-iframe\"></iframe>')
\t\t\t\t\t\t\t.css('background-color', 'transparent')
\t\t\t\t\t\t\t.appendTo(preview);

\t\t\t\t\t\tdfd = fm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) {
\t\t\t\t\t\t\tvar load = function() {
\t\t\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\t\t\tif (node && (!node.attr('src') || node.get(0).contentWindow.document/*maybe HTTP 204*/)) {
\t\t\t\t\t\t\t\t\t\t\tnode.attr('src', 'https://' + urls[type] + encodeURIComponent(url));
\t\t\t\t\t\t\t\t\t\t\t// Retry because Google Docs viewer sometimes returns HTTP 204
\t\t\t\t\t\t\t\t\t\t\ttm = setTimeout(load, 2000);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\tif (url) {
\t\t\t\t\t\t\t\tif (file.ts) {
\t\t\t\t\t\t\t\t\turl += (url.match(/\\?/)? '&' : '?') + '_t=' + file.ts;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tnode.on('load', function() {
\t\t\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\t\t\tql.hideinfo();
\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\tql.preview.after(ql.info);
\t\t\t\t\t\t\t\t\t\$(this).css('background-color', '#fff').show();
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('error', function() {
\t\t\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\t\tql.preview.after(ql.info);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tload();
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tloading.remove();
\t\t\t\t\t\t\t\tnode.remove();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});

\t\t\t\t\t\twin.on('viewchange.googledocs', setNavi);
\t\t\t\t\t\tsetNavi();
\t\t\t\t\t\tql.info.after(ql.preview);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t});
\t\t}
\t},

\t/**
\t * Texts preview plugin
\t *
\t * @param elFinder.commands.quicklook
\t **/
\tfunction(ql) {
\t\t\"use strict\";
\t\tvar fm      = ql.fm,
\t\t\tpreview = ql.preview,
\t\t\ttextLines = parseInt(ql.options.textInitialLines) || 150,
\t\t\tprettifyLines = parseInt(ql.options.prettifyMaxLines) || 500,
\t\t\tPR, _PR,
\t\t\terror = function() {
\t\t\t\tprettify = function() { return false; };
\t\t\t\t_PR && (window.PR = _PR);
\t\t\t\tPR = false;
\t\t\t},
\t\t\tprettify = function(node) {
\t\t\t\tif (fm.options.cdns.prettify) {
\t\t\t\t\tprettify = function(node) {
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tPRcheck(node);
\t\t\t\t\t\t}, 100);
\t\t\t\t\t\treturn 'pending';
\t\t\t\t\t};
\t\t\t\t\tif (window.PR) {
\t\t\t\t\t\t_PR = window.PR;
\t\t\t\t\t}
\t\t\t\t\tfm.loadScript([fm.options.cdns.prettify + (fm.options.cdns.prettify.match(/\\?/)? '&' : '?') + 'autorun=false'], function(wPR) {
\t\t\t\t\t\tPR = wPR || window.PR;
\t\t\t\t\t\tif (typeof PR === 'object') {
\t\t\t\t\t\t\tprettify = function() { return true; };
\t\t\t\t\t\t\tif (_PR) {
\t\t\t\t\t\t\t\twindow.PR = _PR;
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tdelete window.PR;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\texec(node);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\terror();
\t\t\t\t\t\t}
\t\t\t\t\t}, {
\t\t\t\t\t\ttryRequire: true,
\t\t\t\t\t\terror : error
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\terror();
\t\t\t\t}
\t\t\t},
\t\t\texec = function(node) {
\t\t\t\tif (node && !node.hasClass('prettyprinted')) {
\t\t\t\t\tnode.css('cursor', 'wait');
\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\tPR.prettyPrint && PR.prettyPrint(null, node.get(0));
\t\t\t\t\t\tnode.css('cursor', '');
\t\t\t\t\t});
\t\t\t\t}
\t\t\t},
\t\t\tPRcheck = function(node) {
\t\t\t\tvar status = prettify(node);
\t\t\t\tif (status === true) {
\t\t\t\t\texec(node);
\t\t\t\t}
\t\t\t};
\t\t
\t\tpreview.on(ql.evUpdate, function(e) {
\t\t\tvar file = e.file,
\t\t\t\tmime = file.mime,
\t\t\t\tjqxhr, loading, prog, encSelect;
\t\t\t
\t\t\tif (fm.mimeIsText(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax) && PR !== false) {
\t\t\t\te.stopImmediatePropagation();
\t\t\t\t
\t\t\t\tloading = \$('<div class=\"elfinder-quicklook-info-data\"><span class=\"elfinder-spinner-text\">'+fm.i18n('nowLoading')+'</span><span class=\"elfinder-spinner\"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
\t\t\t\tprog = \$('<div class=\"elfinder-quicklook-info-progress\"></div>').appendTo(loading);

\t\t\t\t// stop loading on change file if not loadin yet
\t\t\t\tpreview.one('change', function() {
\t\t\t\t\tjqxhr.state() == 'pending' && jqxhr.reject();
\t\t\t\t\tencSelect && encSelect.remove();
\t\t\t\t});
\t\t\t\t
\t\t\t\tjqxhr = fm.request({
\t\t\t\t\tdata           : {cmd : 'get', target : file.hash, conv : (file.encoding || 1), _t : file.ts},
\t\t\t\t\toptions        : {type: 'get', cache : true},
\t\t\t\t\tpreventDefault : true,
\t\t\t\t\tprogressBar    : prog
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tvar reg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\\\\$1')+';base64,)', 'i'),
\t\t\t\t\t\ttext = data.content,
\t\t\t\t\t\tpart, more, node, lines, m;
\t\t\t\t\tif (typeof text !== 'string') {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tql.hideinfo();
\t\t\t\t\tif (window.atob && (m = text.match(reg))) {
\t\t\t\t\t\ttext = atob(text.substr(m[1].length));
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tlines = text.match(/([^\\r\\n]{1,100}[\\r\\n]*)/g);
\t\t\t\t\tmore = lines.length - textLines;
\t\t\t\t\tif (more > 10) {
\t\t\t\t\t\tpart = lines.splice(0, textLines).join('');
\t\t\t\t\t} else {
\t\t\t\t\t\tmore = 0;
\t\t\t\t\t}

\t\t\t\t\tnode = \$('<div class=\"elfinder-quicklook-preview-text-wrapper\"><pre class=\"elfinder-quicklook-preview-text prettyprint\"></pre></div>');
\t\t\t\t\t
\t\t\t\t\tif (more) {
\t\t\t\t\t\tnode.append(\$('<div class=\"elfinder-quicklook-preview-charsleft\"><hr/><span>' + fm.i18n('linesLeft', fm.toLocaleString(more)) + '</span></div>')
\t\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\t\tvar top = node.scrollTop();
\t\t\t\t\t\t\t\t\$(this).remove();
\t\t\t\t\t\t\t\tnode.children('pre').removeClass('prettyprinted').text(text).scrollTop(top);
\t\t\t\t\t\t\t\tif (lines.length <= prettifyLines) {
\t\t\t\t\t\t\t\t\tPRcheck(node);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t);
\t\t\t\t\t}
\t\t\t\t\tnode.children('pre').text(part || text);
\t\t\t\t\t
\t\t\t\t\tnode.on('touchstart', function(e) {
\t\t\t\t\t\tif (\$(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) {
\t\t\t\t\t\t\te.originalEvent._preventSwipeX = true;
\t\t\t\t\t\t}
\t\t\t\t\t}).appendTo(preview);

\t\t\t\t\t// make toast message
\t\t\t\t\tif (data.toasts && Array.isArray(data.toasts)) {
\t\t\t\t\t\t\$.each(data.toasts, function() {
\t\t\t\t\t\t\tthis.msg && fm.toast(this);
\t\t\t\t\t\t});
\t\t\t\t\t}

\t\t\t\t\tPRcheck(node);
\t\t\t\t})
\t\t\t\t.always(function(data) {
\t\t\t\t\tvar cmdEdit, sel, head;
\t\t\t\t\tif (cmdEdit = fm.getCommand('edit')) {
\t\t\t\t\t\thead = [];
\t\t\t\t\t\tif (data && data.encoding) {
\t\t\t\t\t\t\thead.push({value: data.encoding});
\t\t\t\t\t\t}
\t\t\t\t\t\thead.push({value: 'UTF-8'});
\t\t\t\t\t\tsel = cmdEdit.getEncSelect(head);
\t\t\t\t\t\tsel.on('change', function() {
\t\t\t\t\t\t\tfile.encoding = sel.val();
\t\t\t\t\t\t\tfm.cache(file, 'change');
\t\t\t\t\t\t\tpreview.trigger({
\t\t\t\t\t\t\t\ttype: ql.evUpdate,
\t\t\t\t\t\t\t\tfile: file,
\t\t\t\t\t\t\t\tforceUpdate: true
\t\t\t\t\t\t\t});
\t\t\t\t\t\t});
\t\t\t\t\t\tencSelect = \$('<div class=\"elfinder-quicklook-encoding\"></div>').append(sel);
\t\t\t\t\t\tql.window.append(encSelect);
\t\t\t\t\t}
\t\t\t\t\tloading.remove();
\t\t\t\t});
\t\t\t}
\t\t});
\t}
];


/*
 * File: /js/commands/reload.js
 */

/**
 * @class  elFinder command \"reload\"
 * Sync files and folders
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.reload = function() {
\t\"use strict\";
\tvar self   = this,
\t\tsearch = false;
\t
\tthis.alwaysEnabled = true;
\tthis.updateOnSelect = true;
\t
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+shift+r f5'
\t}];
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.init = function() {
\t\tthis.fm.bind('search searchend', function() {
\t\t\tsearch = this.type == 'search';
\t\t});
\t};
\t
\tthis.fm.bind('contextmenu', function(){
\t\tvar fm = self.fm;
\t\tif (fm.options.sync >= 1000) {
\t\t\tself.extra = {
\t\t\t\ticon: 'accept',
\t\t\t\tnode: \$('<span></span>')
\t\t\t\t\t.attr({title: fm.i18n('autoSync')})
\t\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\$(this).parent()
\t\t\t\t\t\t\t.toggleClass('ui-state-disabled', fm.options.syncStart)
\t\t\t\t\t\t\t.parent().removeClass('ui-state-hover');
\t\t\t\t\t\tfm.options.syncStart = !fm.options.syncStart;
\t\t\t\t\t\tfm.autoSync(fm.options.syncStart? null : 'stop');
\t\t\t\t\t}).on('ready', function(){
\t\t\t\t\t\t\$(this).parent().toggleClass('ui-state-disabled', !fm.options.syncStart).css('pointer-events', 'auto');
\t\t\t\t\t})
\t\t\t};
\t\t}
\t});
\t
\tthis.exec = function() {
\t\tvar fm = this.fm;
\t\tif (!search) {
\t\t\tvar dfrd    = fm.sync(),
\t\t\t\ttimeout = setTimeout(function() {
\t\t\t\t\tfm.notify({type : 'reload', cnt : 1, hideCnt : true});
\t\t\t\t\tdfrd.always(function() { fm.notify({type : 'reload', cnt  : -1}); });
\t\t\t\t}, fm.notifyDelay);
\t\t\t\t
\t\t\treturn dfrd.always(function() { 
\t\t\t\tclearTimeout(timeout); 
\t\t\t\tfm.trigger('reload');
\t\t\t});
\t\t} else {
\t\t\t\$('div.elfinder-toolbar > div.'+fm.res('class', 'searchbtn') + ' > span.ui-icon-search').click();
\t\t}
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/rename.js
 */

/**
 * @class elFinder command \"rename\". 
 * Rename selected file.
 *
 * @author Dmitry (dio) Levashov, dio@std42.ru
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.rename = function() {
\t\"use strict\";

\t// set alwaysEnabled to allow root rename on client size
\tthis.alwaysEnabled = true;

\tthis.syncTitleOnChange = true;

\tvar self = this,
\t\tfm = self.fm,
\t\trequest = function(dfrd, targtes, file, name) {
\t\t\tvar sel = targtes? [file.hash].concat(targtes) : [file.hash],
\t\t\t\tcnt = sel.length,
\t\t\t\tdata = {}, rootNames;
\t\t\t
\t\t\tfm.lockfiles({files : sel});
\t\t\t
\t\t\tif (fm.isRoot(file) && !file.netkey) {
\t\t\t\tif (!(rootNames = fm.storage('rootNames'))) {
\t\t\t\t\trootNames = {};
\t\t\t\t}
\t\t\t\tif (name === '') {
\t\t\t\t\tif (rootNames[file.hash]) {
\t\t\t\t\t\tfile.name = file._name;
\t\t\t\t\t\tfile.i18 = file._i18;
\t\t\t\t\t\tdelete rootNames[file.hash];
\t\t\t\t\t\tdelete file._name;
\t\t\t\t\t\tdelete file._i18;
\t\t\t\t\t} else {
\t\t\t\t\t\tdfrd && dfrd.reject();
\t\t\t\t\t\tfm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tif (typeof file._name === 'undefined') {
\t\t\t\t\t\tfile._name = file.name;
\t\t\t\t\t\tfile._i18 = file.i18;
\t\t\t\t\t}
\t\t\t\t\tfile.name = rootNames[file.hash] = name;
\t\t\t\t\tdelete file.i18;
\t\t\t\t}
\t\t\t\tfm.storage('rootNames', rootNames);
\t\t\t\tdata = { changed: [file] };
\t\t\t\tfm.updateCache(data);
\t\t\t\tfm.change(data);
\t\t\t\tdfrd && dfrd.resolve(data);
\t\t\t\tfm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
\t\t\t\treturn;
\t\t\t}

\t\t\tdata = {
\t\t\t\tcmd : 'rename',
\t\t\t\tname : name,
\t\t\t\ttarget : file.hash
\t\t\t};

\t\t\tif (cnt > 1) {
\t\t\t\tdata['targets'] = targtes;
\t\t\t\tif (name.match(/\\*/)) {
\t\t\t\t\tdata['q'] = name;
\t\t\t\t}
\t\t\t}
\t\t\t
\t\t\tfm.request({
\t\t\t\t\tdata   : data,
\t\t\t\t\tnotify : {type : 'rename', cnt : cnt},
\t\t\t\t\tnavigate : {}
\t\t\t\t})
\t\t\t\t.fail(function(error) {
\t\t\t\t\tvar err = fm.parseError(error);
\t\t\t\t\tdfrd && dfrd.reject();
\t\t\t\t\tif (! err || ! Array.isArray(err) || err[0] !== 'errRename') {
\t\t\t\t\t\tfm.sync();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.done(function(data) {
\t\t\t\t\tvar cwdHash;
\t\t\t\t\tif (data.added && data.added.length && cnt === 1) {
\t\t\t\t\t\tdata.undo = {
\t\t\t\t\t\t\tcmd : 'rename',
\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\t\tdata   : {cmd : 'rename', target : data.added[0].hash, name : file.name},
\t\t\t\t\t\t\t\t\tnotify : {type : 'undo', cnt : 1}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t\tdata.redo = {
\t\t\t\t\t\t\tcmd : 'rename',
\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\t\tdata   : {cmd : 'rename', target : file.hash, name : name},
\t\t\t\t\t\t\t\t\tnotify : {type : 'rename', cnt : 1}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t};
\t\t\t\t\t}
\t\t\t\t\tdfrd && dfrd.resolve(data);
\t\t\t\t\tif (!(cwdHash = fm.cwd().hash) || cwdHash === file.hash) {
\t\t\t\t\t\tfm.exec('open', \$.map(data.added, function(f) {
\t\t\t\t\t\t\treturn (f.mime === 'directory')? f.hash : null;
\t\t\t\t\t\t})[0]);
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\tfm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
\t\t\t\t}
\t\t\t);
\t\t},
\t\tgetHint = function(name, target) {
\t\t\tvar sel = target || fm.selected(),
\t\t\t\tsplits = fm.splitFileExtention(name),
\t\t\t\tf1 = fm.file(sel[0]),
\t\t\t\tf2 = fm.file(sel[1]),
\t\t\t\text, hint, add;
\t\t\t
\t\t\text = splits[1]? ('.' + splits[1]) : '';
\t\t\tif (splits[1] && splits[0] === '*') {
\t\t\t\t// change extention
\t\t\t\thint =  '\"' + fm.splitFileExtention(f1.name)[0] + ext + '\", ';
\t\t\t\thint += '\"' + fm.splitFileExtention(f2.name)[0] + ext + '\"';
\t\t\t} else if (splits[0].length > 1) {
\t\t\t\tif (splits[0].substr(-1) === '*') {
\t\t\t\t\t// add prefix
\t\t\t\t\tadd = splits[0].substr(0, splits[0].length - 1);
\t\t\t\t\thint =  '\"' + add + f1.name+'\", ';
\t\t\t\t\thint += '\"' + add + f2.name+'\"';
\t\t\t\t} else if (splits[0].substr(0, 1) === '*') {
\t\t\t\t\t// add suffix
\t\t\t\t\tadd = splits[0].substr(1);
\t\t\t\t\thint =  '\"'+fm.splitFileExtention(f1.name)[0] + add + ext + '\", ';
\t\t\t\t\thint += '\"'+fm.splitFileExtention(f2.name)[0] + add + ext + '\"';
\t\t\t\t}
\t\t\t}
\t\t\tif (!hint) {
\t\t\t\thint = '\"'+splits[0] + '1' + ext + '\", \"' + splits[0] + '2' + ext + '\"';
\t\t\t}
\t\t\tif (sel.length > 2) {
\t\t\t\thint += ' ...';
\t\t\t}
\t\t\treturn hint;
\t\t},
\t\tbatchRename = function() {
\t\t\tvar sel = fm.selected(),
\t\t\t\ttplr = '<input name=\"type\" type=\"radio\" class=\"elfinder-tabstop\">',
\t\t\t\tmkChk = function(node, label) {
\t\t\t\t\treturn \$('<label class=\"elfinder-rename-batch-checks\">' + fm.i18n(label) + '</label>').prepend(node);
\t\t\t\t},
\t\t\t\tname = \$('<input type=\"text\" class=\"ui-corner-all elfinder-tabstop\">'),
\t\t\t\tnum  = \$(tplr),
\t\t\t\tprefix  = \$(tplr),
\t\t\t\tsuffix  = \$(tplr),
\t\t\t\textention  = \$(tplr),
\t\t\t\tchecks = \$('<div></div>').append(
\t\t\t\t\tmkChk(num, 'plusNumber'),
\t\t\t\t\tmkChk(prefix, 'asPrefix'),
\t\t\t\t\tmkChk(suffix, 'asSuffix'),
\t\t\t\t\tmkChk(extention, 'changeExtention')
\t\t\t\t),
\t\t\t\tpreview = \$('<div class=\"elfinder-rename-batch-preview\"></div>'),
\t\t\t\tnode = \$('<div class=\"elfinder-rename-batch\"></div>').append(
\t\t\t\t\t\t\$('<div class=\"elfinder-rename-batch-name\"></div>').append(name),
\t\t\t\t\t\t\$('<div class=\"elfinder-rename-batch-type\"></div>').append(checks),
\t\t\t\t\t\tpreview
\t\t\t\t\t),
\t\t\t\topts = {
\t\t\t\t\ttitle : fm.i18n('batchRename'),
\t\t\t\t\tmodal : true,
\t\t\t\t\tdestroyOnClose : true,
\t\t\t\t\twidth: Math.min(380, fm.getUI().width() - 20),
\t\t\t\t\tbuttons : {},
\t\t\t\t\topen : function() {
\t\t\t\t\t\tname.on('input', mkPrev).trigger('focus');
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tgetName = function() {
\t\t\t\t\tvar vName = name.val(),
\t\t\t\t\t\text = fm.splitFileExtention(fm.file(sel[0]).name)[1];
\t\t\t\t\tif (vName !== '' || num.is(':checked')) {
\t\t\t\t\t\tif (prefix.is(':checked')) {
\t\t\t\t\t\t\tvName += '*';
\t\t\t\t\t\t} else if (suffix.is(':checked')) {
\t\t\t\t\t\t\tvName = '*' + vName + '.' + ext;
\t\t\t\t\t\t} else if (extention.is(':checked')) {
\t\t\t\t\t\t\tvName = '*.' + vName;
\t\t\t\t\t\t} else if (ext) {
\t\t\t\t\t\t\tvName += '.' + ext;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\treturn vName;
\t\t\t\t},
\t\t\t\tmkPrev = function() {
\t\t\t\t\tvar vName = getName();
\t\t\t\t\tif (vName !== '') {
\t\t\t\t\t\tpreview.html(fm.i18n(['renameMultiple', sel.length, getHint(vName)]));
\t\t\t\t\t} else {
\t\t\t\t\t\tpreview.empty();
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tradios = checks.find('input:radio').on('change', mkPrev),
\t\t\t\tdialog;
\t\t\t
\t\t\topts.buttons[fm.i18n('btnApply')] = function() {
\t\t\t\tvar vName = getName(),
\t\t\t\t\tfile, targets;
\t\t\t\tif (vName !== '') {
\t\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\t\ttargets = sel;
\t\t\t\t\tfile = fm.file(targets.shift());
\t\t\t\t\trequest(void(0), targets, file, vName);
\t\t\t\t}
\t\t\t};
\t\t\topts.buttons[fm.i18n('btnCancel')] = function() {
\t\t\t\tdialog.elfinderdialog('close');
\t\t\t};
\t\t\tif (\$.fn.checkboxradio) {
\t\t\t\tradios.checkboxradio({
\t\t\t\t\tcreate: function(e, ui) {
\t\t\t\t\t\tif (this === num.get(0)) {
\t\t\t\t\t\t\tnum.prop('checked', true).change();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t});
\t\t\t} else {
\t\t\t\tchecks.buttonset({
\t\t\t\t\tcreate: function(e, ui) {
\t\t\t\t\t\tnum.prop('checked', true).change();
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t\tdialog = self.fmDialog(node, opts);
\t\t};
\t
\tthis.noChangeDirOnRemovedCwd = true;
\t
\tthis.shortcuts = [{
\t\tpattern : 'f2' + (fm.OS == 'mac' ? ' enter' : '')
\t}, {
\t\tpattern : 'shift+f2',
\t\tdescription : 'batchRename',
\t\tcallback : function() {
\t\t\tfm.selected().length > 1 && batchRename();
\t\t}
\t}];
\t
\tthis.getstate = function(select) {
\t\tvar sel = this.files(select),
\t\t\tcnt = sel.length,
\t\t\tphash, ext, mime, brk, state, isRoot;
\t\t
\t\tif (!cnt) {
\t\t\treturn -1;
\t\t}
\t\t
\t\tif (cnt > 1 && sel[0].phash) {
\t\t\tphash = sel[0].phash;
\t\t\text = fm.splitFileExtention(sel[0].name)[1].toLowerCase();
\t\t\tmime = sel[0].mime;
\t\t}
\t\tif (cnt === 1) {
\t\t\tisRoot = fm.isRoot(sel[0]);
\t\t}

\t\tstate = (cnt === 1 && ((fm.cookieEnabled && isRoot) || !sel[0].locked) || (fm.api > 2.1030 && cnt === \$.grep(sel, function(f) {
\t\t\tif (!brk && !f.locked && f.phash === phash && !fm.isRoot(f) && (mime === f.mime || ext === fm.splitFileExtention(f.name)[1].toLowerCase())) {
\t\t\t\treturn true;
\t\t\t} else {
\t\t\t\tbrk && (brk = true);
\t\t\t\treturn false;
\t\t\t}
\t\t}).length)) ? 0 : -1;
\t\t
\t\t// because alwaysEnabled = true, it need check disabled on connector 
\t\tif (!isRoot && state === 0 && fm.option('disabledFlip', sel[0].hash)['rename']) {
\t\t\tstate = -1;
\t\t}

\t\tif (state !== -1 && cnt > 1) {
\t\t\tself.extra = {
\t\t\t\ticon: 'preference',
\t\t\t\tnode: \$('<span></span>')
\t\t\t\t\t.attr({title: fm.i18n('batchRename')})
\t\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tfm.getUI().trigger('click'); // to close the context menu immediately
\t\t\t\t\t\tbatchRename();
\t\t\t\t\t})
\t\t\t};
\t\t} else {
\t\t\tdelete self.extra;
\t\t}
\t\t\t
\t\treturn state;
\t};
\t
\tthis.exec = function(hashes, cOpts) {
\t\tvar cwd      = fm.getUI('cwd'),
\t\t\tsel      = hashes || (fm.selected().length? fm.selected() : false) || [fm.cwd().hash],
\t\t\tcnt      = sel.length,
\t\t\tfile     = fm.file(sel.shift()),
\t\t\tfilename = '.elfinder-cwd-filename',
\t\t\topts     = cOpts || {},
\t\t\tincwd    = (fm.cwd().hash == file.hash),
\t\t\ttype     = (opts._currentType === 'navbar' || opts._currentType === 'files')? opts._currentType : (incwd? 'navbar' : 'files'),
\t\t\tnavbar   = (type !== 'files'),
\t\t\ttarget   = fm[navbar? 'navHash2Elm' : 'cwdHash2Elm'](file.hash),
\t\t\ttarea    = (!navbar && fm.storage('view') != 'list'),
\t\t\tsplit    = function(name) {
\t\t\t\tvar ext = fm.splitFileExtention(name)[1];
\t\t\t\treturn [name.substr(0, name.length - ext.length - 1), ext];
\t\t\t},
\t\t\tunselect = function() {
\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\tinput && input.trigger('blur');
\t\t\t\t});
\t\t\t},
\t\t\trest     = function(){
\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\toverlay.elfinderoverlay('hide').off('click close', cancel);
\t\t\t\t}
\t\t\t\tpnode.removeClass('ui-front')
\t\t\t\t\t.css('position', '')
\t\t\t\t\t.off('unselect.'+fm.namespace, unselect);
\t\t\t\tif (tarea) {
\t\t\t\t\tnode && node.css('max-height', '');
\t\t\t\t} else if (!navbar) {
\t\t\t\t\tpnode.css('width', '')
\t\t\t\t\t\t.parent('td').css('overflow', '');
\t\t\t\t}
\t\t\t}, colwidth,
\t\t\tdfrd     = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\tvar parent = input.parent(),
\t\t\t\t\t\tname   = fm.escape(file.i18 || file.name);

\t\t\t\t\tinput.off();
\t\t\t\t\tif (tarea) {
\t\t\t\t\t\tname = name.replace(/([_.])/g, '&#8203;\$1');
\t\t\t\t\t}
\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\tif (navbar) {
\t\t\t\t\t\t\tinput.replaceWith(name);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tif (parent.length) {
\t\t\t\t\t\t\t\tinput.remove();
\t\t\t\t\t\t\t\tparent.html(name);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\ttarget.find(filename).html(name);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\terror && fm.error(error);
\t\t\t\t})
\t\t\t\t.always(function() {
\t\t\t\t\trest();
\t\t\t\t\tfm.unbind('resize', resize);
\t\t\t\t\tfm.enable();
\t\t\t\t}),
\t\t\tblur = function(e) {
\t\t\t\tvar name   = \$.trim(input.val()),
\t\t\t\tsplits = fm.splitFileExtention(name),
\t\t\t\tvalid  = true,
\t\t\t\treq = function() {
\t\t\t\t\tinput.off();
\t\t\t\t\trest();
\t\t\t\t\tif (navbar) {
\t\t\t\t\t\tinput.replaceWith(fm.escape(name));
\t\t\t\t\t} else {
\t\t\t\t\t\tnode.html(fm.escape(name));
\t\t\t\t\t}
\t\t\t\t\trequest(dfrd, sel, file, name);
\t\t\t\t};

\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\tpnode.css('z-index', '');
\t\t\t\t}
\t\t\t\tif (name === '') {
\t\t\t\t\tif (!fm.isRoot(file)) {
\t\t\t\t\t\treturn cancel();
\t\t\t\t\t}
\t\t\t\t\tif (navbar) {
\t\t\t\t\t\tinput.replaceWith(fm.escape(file.name));
\t\t\t\t\t} else {
\t\t\t\t\t\tnode.html(fm.escape(file.name));
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\tif (!inError && pnode.length) {
\t\t\t\t\t
\t\t\t\t\tinput.off('blur');
\t\t\t\t\t
\t\t\t\t\tif (cnt === 1 && name === file.name) {
\t\t\t\t\t\treturn dfrd.reject();
\t\t\t\t\t}
\t\t\t\t\tif (fm.options.validName && fm.options.validName.test) {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tvalid = fm.options.validName.test(name);
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tvalid = false;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\tif (name === '.' || name === '..' || !valid) {
\t\t\t\t\t\tinError = true;
\t\t\t\t\t\tfm.error(file.mime === 'directory'? 'errInvDirname' : 'errInvName', {modal: true, close: function(){setTimeout(select, 120);}});
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\tif (cnt === 1 && fm.fileByName(name, file.phash)) {
\t\t\t\t\t\tinError = true;
\t\t\t\t\t\tfm.error(['errExists', name], {modal: true, close: function(){setTimeout(select, 120);}});
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t\t
\t\t\t\t\tif (cnt === 1) {
\t\t\t\t\t\treq();
\t\t\t\t\t} else {
\t\t\t\t\t\tfm.confirm({
\t\t\t\t\t\t\ttitle : 'cmdrename',
\t\t\t\t\t\t\ttext  : ['renameMultiple', cnt, getHint(name, [file.hash].concat(sel))],
\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\tlabel : 'btnYes',
\t\t\t\t\t\t\t\tcallback : req
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\tlabel : 'btnCancel',
\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\t\t\tinError = true;
\t\t\t\t\t\t\t\t\t\tselect();
\t\t\t\t\t\t\t\t\t}, 120);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\tfm.trigger('unselectfiles', {files: fm.selected()})
\t\t\t\t\t\t\t\t.trigger('selectfiles', {files : [file.hash].concat(sel)});
\t\t\t\t\t\t}, 120);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tinput = \$(tarea? '<textarea></textarea>' : '<input type=\"text\"/>')
\t\t\t\t.on('keyup text', function(){
\t\t\t\t\tif (tarea) {
\t\t\t\t\t\tthis.style.height = '1px';
\t\t\t\t\t\tthis.style.height = this.scrollHeight + 'px';
\t\t\t\t\t} else if (colwidth) {
\t\t\t\t\t\tthis.style.width = colwidth + 'px';
\t\t\t\t\t\tif (this.scrollWidth > colwidth) {
\t\t\t\t\t\t\tthis.style.width = this.scrollWidth + 10 + 'px';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('keydown', function(e) {
\t\t\t\t\te.stopImmediatePropagation();
\t\t\t\t\tif (e.keyCode == \$.ui.keyCode.ESCAPE) {
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t} else if (e.keyCode == \$.ui.keyCode.ENTER) {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tinput.trigger('blur');
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('mousedown click dblclick', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\tif (e.type === 'dblclick') {
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.on('blur', blur)
\t\t\t\t.on('dragenter dragleave dragover drop', function(e) {
\t\t\t\t\t// stop bubbling to prevent upload with native drop event
\t\t\t\t\te.stopPropagation();
\t\t\t\t}),
\t\t\tselect = function() {
\t\t\t\tvar name = fm.splitFileExtention(input.val())[0];
\t\t\t\tif (!inError && fm.UA.Mobile && !fm.UA.iOS) { // since iOS has a bug? (z-index not effect) so disable it
\t\t\t\t\toverlay.on('click close', cancel).elfinderoverlay('show');
\t\t\t\t\tpnode.css('z-index', overlay.css('z-index') + 1);
\t\t\t\t}
\t\t\t\t! fm.enabled() && fm.enable();
\t\t\t\tif (inError) {
\t\t\t\t\tinError = false;
\t\t\t\t\tinput.on('blur', blur);
\t\t\t\t}
\t\t\t\tinput.trigger('focus').trigger('select');
\t\t\t\tinput[0].setSelectionRange && input[0].setSelectionRange(0, name.length);
\t\t\t},
\t\t\tnode = navbar? target.contents().filter(function(){ return this.nodeType==3 && \$(this).parent().attr('id') === fm.navHash2Id(file.hash); })
\t\t\t\t\t: target.find(filename),
\t\t\tpnode = node.parent(),
\t\t\toverlay = fm.getUI('overlay'),
\t\t\tcancel = function(e) { 
\t\t\t\tif (!overlay.is(':hidden')) {
\t\t\t\t\tpnode.css('z-index', '');
\t\t\t\t}
\t\t\t\tif (! inError) {
\t\t\t\t\tdfrd.reject();
\t\t\t\t\tif (e) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t},
\t\t\tresize = function() {
\t\t\t\ttarget.trigger('scrolltoview', {blink : false});
\t\t\t},
\t\t\tinError = false;
\t\t
\t\tpnode.addClass('ui-front')
\t\t\t.css('position', 'relative')
\t\t\t.on('unselect.'+fm.namespace, unselect);
\t\tfm.bind('resize', resize);
\t\tif (navbar) {
\t\t\tnode.replaceWith(input.val(file.name));
\t\t} else {
\t\t\tif (tarea) {
\t\t\t\tnode.css('max-height', 'none');
\t\t\t} else if (!navbar) {
\t\t\t\tcolwidth = pnode.width();
\t\t\t\tpnode.width(colwidth - 15)
\t\t\t\t\t.parent('td').css('overflow', 'visible');
\t\t\t}
\t\t\tnode.empty().append(input.val(file.name));
\t\t}
\t\t
\t\tif (cnt > 1 && fm.api <= 2.1030) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tif (!file || !node.length) {
\t\t\treturn dfrd.reject('errCmdParams', this.title);
\t\t}
\t\t
\t\tif (file.locked && !fm.isRoot(file)) {
\t\t\treturn dfrd.reject(['errLocked', file.name]);
\t\t}
\t\t
\t\tfm.one('select', function() {
\t\t\tinput.parent().length && file && \$.inArray(file.hash, fm.selected()) === -1 && input.trigger('blur');
\t\t});
\t\t
\t\tinput.trigger('keyup');
\t\t
\t\tselect();
\t\t
\t\treturn dfrd;
\t};

\tfm.bind('select contextmenucreate closecontextmenu', function(e) {
\t\tvar sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected(),
\t\t\tfile;
\t\tif (sel && sel.length === 1 && (file = fm.file(sel[0])) && fm.isRoot(file)) {
\t\t\tself.title = fm.i18n('kindAlias') + ' (' + fm.i18n('preference') + ')';
\t\t} else {
\t\t\tself.title = fm.i18n('cmdrename');
\t\t}
\t\tif (e.type !== 'closecontextmenu') {
\t\t\tself.update(void(0), self.title);
\t\t} else {
\t\t\trequestAnimationFrame(function() {
\t\t\t\tself.update(void(0), self.title);
\t\t\t});
\t\t}
\t}).remove(function(e) {
\t\tvar rootNames;
\t\tif (e.data && e.data.removed && (rootNames = fm.storage('rootNames'))) {
\t\t\t\$.each(e.data.removed, function(i, h) {
\t\t\t\tif (rootNames[h]) {
\t\t\t\t\tdelete rootNames[h];
\t\t\t\t}
\t\t\t});
\t\t\tfm.storage('rootNames', rootNames);
\t\t}
\t});
};


/*
 * File: /js/commands/resize.js
 */

/**
 * @class  elFinder command \"resize\"
 * Open dialog to resize image
 *
 * @author Dmitry (dio) Levashov
 * @author Alexey Sukhotin
 * @author Naoki Sawada
 * @author Sergio Jovani
 **/
elFinder.prototype.commands.resize = function() {
\t\"use strict\";
\tvar fm = this.fm,
\t\tlosslessRotate = 0,
\t\tgetBounceBox = function(w, h, theta) {
\t\t\tvar srcPts = [
\t\t\t\t\t{x: w/2, y: h/2},
\t\t\t\t\t{x: -w/2, y: h/2},
\t\t\t\t\t{x: -w/2, y: -h/2},
\t\t\t\t\t{x: w/2, y: -h/2}
\t\t\t\t],
\t\t\t\tdstPts = [],
\t\t\t\tmin = {x: Number.MAX_VALUE, y: Number.MAX_VALUE},
\t\t\t\tmax = {x: Number.MIN_VALUE, y: Number.MIN_VALUE};
\t\t\t\$.each(srcPts, function(i, srcPt){
\t\t\t\tdstPts.push({
\t\t\t\t\tx: srcPt.x * Math.cos(theta) - srcPt.y * Math.sin(theta),
\t\t\t\t\ty: srcPt.x * Math.sin(theta) + srcPt.y * Math.cos(theta)
\t\t\t\t});
\t\t\t});
\t\t\t\$.each(dstPts, function(i, pt) {
\t\t\t\tmin.x = Math.min(min.x, pt.x);
\t\t\t\tmin.y = Math.min(min.y, pt.y);
\t\t\t\tmax.x = Math.max(max.x, pt.x);
\t\t\t\tmax.y = Math.max(max.y, pt.y);
\t\t\t});
\t\t\treturn {
\t\t\t\twidth: max.x - min.x, height: max.y - min.y
\t\t\t};
\t\t};
\t
\tthis.updateOnSelect = false;
\t
\tthis.getstate = function() {
\t\tvar sel = fm.selectedFiles();
\t\treturn sel.length == 1 && sel[0].read && sel[0].write && sel[0].mime.indexOf('image/') !== -1 ? 0 : -1;
\t};
\t
\tthis.resizeRequest = function(data, f, dfrd) {
\t\tvar file = f || fm.file(data.target),
\t\t\ttmb  = file? file.tmb : null,
\t\t\tenabled = fm.isCommandEnabled('resize', data.target);
\t\t
\t\tif (enabled && (! file || (file && file.read && file.write && file.mime.indexOf('image/') !== -1 ))) {
\t\t\treturn fm.request({
\t\t\t\tdata : Object.assign(data, {
\t\t\t\t\tcmd : 'resize'
\t\t\t\t}),
\t\t\t\tnotify : {type : 'resize', cnt : 1}
\t\t\t})
\t\t\t.fail(function(error) {
\t\t\t\tif (dfrd) {
\t\t\t\t\tdfrd.reject(error);
\t\t\t\t}
\t\t\t})
\t\t\t.done(function() {
\t\t\t\tif (data.quality) {
\t\t\t\t\tfm.storage('jpgQuality', data.quality === fm.option('jpgQuality')? null : data.quality);
\t\t\t\t}
\t\t\t\tdfrd && dfrd.resolve();
\t\t\t});
\t\t} else {
\t\t\tvar error;
\t\t\t
\t\t\tif (file) {
\t\t\t\tif (file.mime.indexOf('image/') === -1) {
\t\t\t\t\terror = ['errResize', file.name, 'errUsupportType'];
\t\t\t\t} else {
\t\t\t\t\terror = ['errResize', file.name, 'errPerm'];
\t\t\t\t}
\t\t\t} else {
\t\t\t\terror = ['errResize', data.target, 'errPerm'];
\t\t\t}
\t\t\t
\t\t\tif (dfrd) {
\t\t\t\tdfrd.reject(error);
\t\t\t} else {
\t\t\t\tfm.error(error);
\t\t\t}
\t\t\treturn \$.Deferred().reject(error);
\t\t}
\t};
\t
\tthis.exec = function(hashes) {
\t\tvar self  = this,
\t\t\tfiles = this.files(hashes),
\t\t\tdfrd  = \$.Deferred(),
\t\t\tapi2  = (fm.api > 1),
\t\t\toptions = this.options,
\t\t\tdialogWidth = 650,
\t\t\tfmnode = fm.getUI(),
\t\t\tctrgrup = \$().controlgroup? 'controlgroup' : 'buttonset',
\t\t\tgrid8Def = typeof options.grid8px === 'undefined' || options.grid8px !== 'disable'? true : false,
\t\t\tpresetSize = Array.isArray(options.presetSize)? options.presetSize : [],
\t\t\tclactive = 'elfinder-dialog-active',
\t\t\tclsediting = fm.res('class', 'editing'),
\t\t\topen = function(file, id, src) {
\t\t\t\tvar isJpeg   = (file.mime === 'image/jpeg'),
\t\t\t\t\tdialog   = \$('<div class=\"elfinder-resize-container\"></div>'),
\t\t\t\t\tinput    = '<input type=\"number\" class=\"ui-corner-all\"/>',
\t\t\t\t\trow      = '<div class=\"elfinder-resize-row\"></div>',
\t\t\t\t\tlabel    = '<div class=\"elfinder-resize-label\"></div>',
\t\t\t\t\tchangeTm = null,
\t\t\t\t\toperate  = false,
\t\t\t\t\topStart  = function() { operate = true; },
\t\t\t\t\topStop   = function() {
\t\t\t\t\t\tif (operate) {
\t\t\t\t\t\t\toperate = false;
\t\t\t\t\t\t\tcontrol.trigger('change');
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tcontrol  = \$('<div class=\"elfinder-resize-control\"></div>')
\t\t\t\t\t\t.on('focus', 'input[type=text],input[type=number]', function() {
\t\t\t\t\t\t\t\$(this).trigger('select');
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\t\tchangeTm && cancelAnimationFrame(changeTm);
\t\t\t\t\t\t\tchangeTm = requestAnimationFrame(function() {
\t\t\t\t\t\t\t\tvar panel, quty, canvas, ctx, img, sx, sy, sw, sh, deg, theta, bb;
\t\t\t\t\t\t\t\tif (sizeImg && ! operate && (canvas = sizeImg.data('canvas'))) {
\t\t\t\t\t\t\t\t\tpanel = control.children('div.elfinder-resize-control-panel:visible');
\t\t\t\t\t\t\t\t\tquty = panel.find('input.elfinder-resize-quality');
\t\t\t\t\t\t\t\t\tif (quty.is(':visible')) {
\t\t\t\t\t\t\t\t\t\tctx = sizeImg.data('ctx');
\t\t\t\t\t\t\t\t\t\timg = sizeImg.get(0);
\t\t\t\t\t\t\t\t\t\tif (panel.hasClass('elfinder-resize-uiresize')) {
\t\t\t\t\t\t\t\t\t\t\t// resize
\t\t\t\t\t\t\t\t\t\t\tsw = canvas.width = width.val();
\t\t\t\t\t\t\t\t\t\t\tsh = canvas.height = height.val();
\t\t\t\t\t\t\t\t\t\t\tctx.drawImage(img, 0, 0, sw, sh);
\t\t\t\t\t\t\t\t\t\t} else if (panel.hasClass('elfinder-resize-uicrop')) {
\t\t\t\t\t\t\t\t\t\t\t// crop
\t\t\t\t\t\t\t\t\t\t\tsx = pointX.val();
\t\t\t\t\t\t\t\t\t\t\tsy = pointY.val();
\t\t\t\t\t\t\t\t\t\t\tsw = offsetX.val();
\t\t\t\t\t\t\t\t\t\t\tsh = offsetY.val();
\t\t\t\t\t\t\t\t\t\t\tcanvas.width = sw;
\t\t\t\t\t\t\t\t\t\t\tcanvas.height = sh;
\t\t\t\t\t\t\t\t\t\t\tctx.drawImage(img, sx, sy, sw, sh, 0, 0, sw, sh);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t// rotate
\t\t\t\t\t\t\t\t\t\t\tdeg = degree.val();
\t\t\t\t\t\t\t\t\t\t\ttheta = (degree.val() * Math.PI) / 180;
\t\t\t\t\t\t\t\t\t\t\tbb = getBounceBox(owidth, oheight, theta);
\t\t\t\t\t\t\t\t\t\t\tsw = canvas.width = bb.width;
\t\t\t\t\t\t\t\t\t\t\tsh = canvas.height = bb.height;
\t\t\t\t\t\t\t\t\t\t\tctx.save();
\t\t\t\t\t\t\t\t\t\t\tif (deg % 90 !== 0) {
\t\t\t\t\t\t\t\t\t\t\t\tctx.fillStyle = bg.val() || '#FFF';
\t\t\t\t\t\t\t\t\t\t\t\tctx.fillRect(0, 0, sw, sh);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\tctx.translate(sw / 2, sh / 2);
\t\t\t\t\t\t\t\t\t\t\tctx.rotate(theta);
\t\t\t\t\t\t\t\t\t\t\tctx.drawImage(img, -img.width/2, -img.height/2, owidth, oheight);
\t\t\t\t\t\t\t\t\t\t\tctx.restore();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tcanvas.toBlob(function(blob) {
\t\t\t\t\t\t\t\t\t\t\tif (blob) {
\t\t\t\t\t\t\t\t\t\t\t\tsize1 = blob.size;
\t\t\t\t\t\t\t\t\t\t\t\tquty.next('span').text(' (' + fm.formatSize(blob.size) + ')');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}, 'image/jpeg', Math.max(Math.min(quty.val(), 100), 1) / 100);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('mouseup', 'input', function(e) {
\t\t\t\t\t\t\t\$(e.target).trigger('change');
\t\t\t\t\t\t}),
\t\t\t\t\tpreview  = \$('<div class=\"elfinder-resize-preview\"></div>')
\t\t\t\t\t\t.on('touchmove', function(e) {
\t\t\t\t\t\t\tif (\$(e.target).hasClass('touch-punch')) {
\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}),
\t\t\t\t\tspinner  = \$('<div class=\"elfinder-resize-loading\">'+fm.i18n('ntfloadimg')+'</div>'),
\t\t\t\t\trhandle  = \$('<div class=\"elfinder-resize-handle touch-punch\"></div>'),
\t\t\t\t\trhandlec = \$('<div class=\"elfinder-resize-handle touch-punch\"></div>'),
\t\t\t\t\tuiresize = \$('<div class=\"elfinder-resize-uiresize elfinder-resize-control-panel\"></div>'),
\t\t\t\t\tuicrop   = \$('<div class=\"elfinder-resize-uicrop elfinder-resize-control-panel\"></div>'),
\t\t\t\t\tuirotate = \$('<div class=\"elfinder-resize-rotate elfinder-resize-control-panel\"></div>'),
\t\t\t\t\tuideg270 = \$('<button></button>').attr('title',fm.i18n('rotate-cw')).append(\$('<span class=\"elfinder-button-icon elfinder-button-icon-rotate-l\"></span>')),
\t\t\t\t\tuideg90  = \$('<button></button>').attr('title',fm.i18n('rotate-ccw')).append(\$('<span class=\"elfinder-button-icon elfinder-button-icon-rotate-r\"></span>')),
\t\t\t\t\tuiprop   = \$('<span ></span>'),
\t\t\t\t\treset    = \$('<button class=\"elfinder-resize-reset\">').text(fm.i18n('reset'))
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tresetView();
\t\t\t\t\t\t})
\t\t\t\t\t\t.button({
\t\t\t\t\t\t\ticons: {
\t\t\t\t\t\t\t\tprimary: 'ui-icon-arrowrefresh-1-n'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttext: false
\t\t\t\t\t\t}),
\t\t\t\t\tuitype   = \$('<div class=\"elfinder-resize-type\"></div>')
\t\t\t\t\t\t.append('<input type=\"radio\" name=\"type\" id=\"'+id+'-resize\" value=\"resize\" checked=\"checked\" /><label for=\"'+id+'-resize\">'+fm.i18n('resize')+'</label>',
\t\t\t\t\t\t'<input class=\"api2\" type=\"radio\" name=\"type\" id=\"'+id+'-crop\" value=\"crop\" /><label class=\"api2\" for=\"'+id+'-crop\">'+fm.i18n('crop')+'</label>',
\t\t\t\t\t\t'<input class=\"api2\" type=\"radio\" name=\"type\" id=\"'+id+'-rotate\" value=\"rotate\" /><label class=\"api2\" for=\"'+id+'-rotate\">'+fm.i18n('rotate')+'</label>'),
\t\t\t\t\tmode     = 'resize',
\t\t\t\t\ttype     = uitype[ctrgrup]()[ctrgrup]('disable').find('input')
\t\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\t\tmode = \$(this).val();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tresetView();
\t\t\t\t\t\t\tresizable(true);
\t\t\t\t\t\t\tcroppable(true);
\t\t\t\t\t\t\trotateable(true);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (mode == 'resize') {
\t\t\t\t\t\t\t\tuiresize.show();
\t\t\t\t\t\t\t\tuirotate.hide();
\t\t\t\t\t\t\t\tuicrop.hide();
\t\t\t\t\t\t\t\tresizable();
\t\t\t\t\t\t\t\tisJpeg && grid8px.insertAfter(uiresize.find('.elfinder-resize-grid8'));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\telse if (mode == 'crop') {
\t\t\t\t\t\t\t\tuirotate.hide();
\t\t\t\t\t\t\t\tuiresize.hide();
\t\t\t\t\t\t\t\tuicrop.show();
\t\t\t\t\t\t\t\tcroppable();
\t\t\t\t\t\t\t\tisJpeg && grid8px.insertAfter(uicrop.find('.elfinder-resize-grid8'));
\t\t\t\t\t\t\t} else if (mode == 'rotate') {
\t\t\t\t\t\t\t\tuiresize.hide();
\t\t\t\t\t\t\t\tuicrop.hide();
\t\t\t\t\t\t\t\tuirotate.show();
\t\t\t\t\t\t\t\trotateable();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}),
\t\t\t\t\twidth   = \$(input)
\t\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\t\tvar w = round(parseInt(width.val())),
\t\t\t\t\t\t\t\th = round(cratio ? w/ratio : parseInt(height.val()));

\t\t\t\t\t\t\tif (w > 0 && h > 0) {
\t\t\t\t\t\t\t\tresize.updateView(w, h);
\t\t\t\t\t\t\t\twidth.val(w);
\t\t\t\t\t\t\t\theight.val(h);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}).addClass('elfinder-focus'),
\t\t\t\t\theight  = \$(input)
\t\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\t\tvar h = round(parseInt(height.val())),
\t\t\t\t\t\t\t\tw = round(cratio ? h*ratio : parseInt(width.val()));

\t\t\t\t\t\t\tif (w > 0 && h > 0) {
\t\t\t\t\t\t\t\tresize.updateView(w, h);
\t\t\t\t\t\t\t\twidth.val(w);
\t\t\t\t\t\t\t\theight.val(h);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}),
\t\t\t\t\tpointX  = \$(input).on('change', function(){crop.updateView();}),
\t\t\t\t\tpointY  = \$(input).on('change', function(){crop.updateView();}),
\t\t\t\t\toffsetX = \$(input).on('change', function(){crop.updateView('w');}),
\t\t\t\t\toffsetY = \$(input).on('change', function(){crop.updateView('h');}),
\t\t\t\t\tquality = isJpeg && api2?
\t\t\t\t\t\t\$(input).val(fm.storage('jpgQuality') > 0? fm.storage('jpgQuality') : fm.option('jpgQuality'))
\t\t\t\t\t\t\t.addClass('elfinder-resize-quality')
\t\t\t\t\t\t\t.attr('min', '1').attr('max', '100').attr('title', '1 - 100')
\t\t\t\t\t\t\t.on('blur', function(){
\t\t\t\t\t\t\t\tvar q = Math.min(100, Math.max(1, parseInt(this.value)));
\t\t\t\t\t\t\t\tcontrol.find('input.elfinder-resize-quality').val(q);
\t\t\t\t\t\t\t})
\t\t\t\t\t\t: null,
\t\t\t\t\tdegree = \$('<input type=\"number\" class=\"ui-corner-all\" maxlength=\"3\" value=\"0\" />')
\t\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\t\trotate.update();
\t\t\t\t\t\t}),
\t\t\t\t\tuidegslider = \$('<div class=\"elfinder-resize-rotate-slider touch-punch\"></div>')
\t\t\t\t\t\t.slider({
\t\t\t\t\t\t\tmin: 0,
\t\t\t\t\t\t\tmax: 360,
\t\t\t\t\t\t\tvalue: degree.val(),
\t\t\t\t\t\t\tanimate: true,
\t\t\t\t\t\t\tstart: opStart,
\t\t\t\t\t\t\tstop: opStop,
\t\t\t\t\t\t\tchange: function(event, ui) {
\t\t\t\t\t\t\t\tif (ui.value != uidegslider.slider('value')) {
\t\t\t\t\t\t\t\t\trotate.update(ui.value);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tslide: function(event, ui) {
\t\t\t\t\t\t\t\trotate.update(ui.value, false);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}).find('.ui-slider-handle')
\t\t\t\t\t\t\t.addClass('elfinder-tabstop')
\t\t\t\t\t\t\t.off('keydown')
\t\t\t\t\t\t\t.on('keydown', function(e) {
\t\t\t\t\t\t\t\tif (e.keyCode == \$.ui.keyCode.LEFT || e.keyCode == \$.ui.keyCode.RIGHT) {
\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\trotate.update(Number(degree.val()) + (e.keyCode == \$.ui.keyCode.RIGHT? 1 : -1), false);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t.end(),
\t\t\t\t\tpickimg,
\t\t\t\t\tpickcanv,
\t\t\t\t\tpickctx,
\t\t\t\t\tpickc = {},
\t\t\t\t\tpick = function(e) {
\t\t\t\t\t\tvar color, r, g, b, h, s, l;

\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tcolor = pickc[Math.round(e.offsetX)][Math.round(e.offsetY)];
\t\t\t\t\t\t} catch(e) {}
\t\t\t\t\t\tif (!color) return;

\t\t\t\t\t\tr = color[0]; g = color[1]; b = color[2];
\t\t\t\t\t\th = color[3]; s = color[4]; l = color[5];

\t\t\t\t\t\tsetbg(r, g, b, (e.type === 'click'));
\t\t\t\t\t},
\t\t\t\t\tpalpick = function(e) {
\t\t\t\t\t\tsetbg(\$(this).css('backgroundColor'), '', '', (e.type === 'click'));
\t\t\t\t\t},
\t\t\t\t\tsetbg = function(r, g, b, off) {
\t\t\t\t\t\tvar s, m, cc;
\t\t\t\t\t\tif (typeof r === 'string') {
\t\t\t\t\t\t\tg = '';
\t\t\t\t\t\t\tif (r && (s = \$('<span>').css('backgroundColor', r).css('backgroundColor')) && (m = s.match(/rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)/i))) {
\t\t\t\t\t\t\t\tr = Number(m[1]);
\t\t\t\t\t\t\t\tg = Number(m[2]);
\t\t\t\t\t\t\t\tb = Number(m[3]);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tcc = (g === '')? r : '#' + getColorCode(r, g, b);
\t\t\t\t\t\tbg.val(cc).css({ backgroundColor: cc, backgroundImage: 'none', color: (r+g+b < 384? '#fff' : '#000') });
\t\t\t\t\t\tpreview.css('backgroundColor', cc);
\t\t\t\t\t\tif (off) {
\t\t\t\t\t\t\timgr.off('.picker').removeClass('elfinder-resize-picking');
\t\t\t\t\t\t\tpallet.off('.picker').removeClass('elfinder-resize-picking');
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tgetColorCode = function(r, g, b) {
\t\t\t\t\t\treturn \$.map([r,g,b], function(c){return ('0'+parseInt(c).toString(16)).slice(-2);}).join('');
\t\t\t\t\t},
\t\t\t\t\tpicker = \$('<button>').text(fm.i18n('colorPicker'))
\t\t\t\t\t.on('click', function() { 
\t\t\t\t\t\timgr.on('mousemove.picker click.picker', pick).addClass('elfinder-resize-picking');
\t\t\t\t\t\tpallet.on('mousemove.picker click.picker', 'span', palpick).addClass('elfinder-resize-picking');
\t\t\t\t\t})
\t\t\t\t\t.button({
\t\t\t\t\t\ticons: {
\t\t\t\t\t\t\tprimary: 'ui-icon-pin-s'
\t\t\t\t\t\t},
\t\t\t\t\t\ttext: false
\t\t\t\t\t}),
\t\t\t\t\treseter = \$('<button>').text(fm.i18n('reset'))
\t\t\t\t\t\t.on('click', function() { 
\t\t\t\t\t\t\tsetbg('', '', '', true);
\t\t\t\t\t\t})
\t\t\t\t\t\t.button({
\t\t\t\t\t\t\ticons: {
\t\t\t\t\t\t\t\tprimary: 'ui-icon-arrowrefresh-1-n'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttext: false
\t\t\t\t\t\t}),
\t\t\t\t\tbg = \$('<input class=\"ui-corner-all elfinder-resize-bg\" type=\"text\">')
\t\t\t\t\t\t.on('focus', function() {
\t\t\t\t\t\t\t\$(this).attr('style', '');
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('blur', function() {
\t\t\t\t\t\t\tsetbg(\$(this).val());
\t\t\t\t\t\t}),
\t\t\t\t\tpallet  = \$('<div class=\"elfinder-resize-pallet\">').on('click', 'span', function() {
\t\t\t\t\t\tsetbg(\$(this).css('backgroundColor'));
\t\t\t\t\t}),
\t\t\t\t\tratio   = 1,
\t\t\t\t\tprop    = 1,
\t\t\t\t\towidth  = 0,
\t\t\t\t\toheight = 0,
\t\t\t\t\tcratio  = true,
\t\t\t\t\tcratioc = false,
\t\t\t\t\tpwidth  = 0,
\t\t\t\t\tpheight = 0,
\t\t\t\t\trwidth  = 0,
\t\t\t\t\trheight = 0,
\t\t\t\t\trdegree = 0,
\t\t\t\t\tgrid8   = isJpeg? grid8Def : false,
\t\t\t\t\tconstr  = \$('<button>').html(fm.i18n('aspectRatio'))
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tcratio = ! cratio;
\t\t\t\t\t\t\tconstr.button('option', {
\t\t\t\t\t\t\t\ticons : { primary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tresize.fixHeight();
\t\t\t\t\t\t\trhandle.resizable('option', 'aspectRatio', cratio).data('uiResizable')._aspectRatio = cratio;
\t\t\t\t\t\t})
\t\t\t\t\t\t.button({
\t\t\t\t\t\t\ticons : {
\t\t\t\t\t\t\t\tprimary: cratio? 'ui-icon-locked' : 'ui-icon-unlocked'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttext: false
\t\t\t\t\t\t}),
\t\t\t\t\tconstrc = \$('<button>').html(fm.i18n('aspectRatio'))
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tcratioc = ! cratioc;
\t\t\t\t\t\t\tconstrc.button('option', {
\t\t\t\t\t\t\t\ticons : { primary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\trhandlec.resizable('option', 'aspectRatio', cratioc).data('uiResizable')._aspectRatio = cratioc;
\t\t\t\t\t\t})
\t\t\t\t\t\t.button({
\t\t\t\t\t\t\ticons : {
\t\t\t\t\t\t\t\tprimary: cratioc? 'ui-icon-locked' : 'ui-icon-unlocked'
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\ttext: false
\t\t\t\t\t\t}),
\t\t\t\t\tgrid8px = \$('<button>').html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8)
\t\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t\tgrid8 = ! grid8;
\t\t\t\t\t\t\tgrid8px.html(fm.i18n(grid8? 'enabled' : 'disabled')).toggleClass('ui-state-active', grid8);
\t\t\t\t\t\t\tsetStep8();
\t\t\t\t\t\t})
\t\t\t\t\t\t.button(),
\t\t\t\t\tsetStep8 = function() {
\t\t\t\t\t\tvar step = grid8? 8 : 1;
\t\t\t\t\t\t\$.each([width, height, offsetX, offsetY, pointX, pointY], function() {
\t\t\t\t\t\t\tthis.attr('step', step);
\t\t\t\t\t\t});
\t\t\t\t\t\tif (grid8) {
\t\t\t\t\t\t\twidth.val(round(width.val()));
\t\t\t\t\t\t\theight.val(round(height.val()));
\t\t\t\t\t\t\toffsetX.val(round(offsetX.val()));
\t\t\t\t\t\t\toffsetY.val(round(offsetY.val()));
\t\t\t\t\t\t\tpointX.val(round(pointX.val()));
\t\t\t\t\t\t\tpointY.val(round(pointY.val()));
\t\t\t\t\t\t\tif (uiresize.is(':visible')) {
\t\t\t\t\t\t\t\tresize.updateView(width.val(), height.val());
\t\t\t\t\t\t\t} else if (uicrop.is(':visible')) {
\t\t\t\t\t\t\t\tcrop.updateView();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetuprimg = function() {
\t\t\t\t\t\tvar r_scale,
\t\t\t\t\t\t\tfail = function() {
\t\t\t\t\t\t\t\tbg.parent().hide();
\t\t\t\t\t\t\t\tpallet.hide();
\t\t\t\t\t\t\t};
\t\t\t\t\t\tr_scale = Math.min(pwidth, pheight) / Math.sqrt(Math.pow(owidth, 2) + Math.pow(oheight, 2));
\t\t\t\t\t\trwidth = Math.ceil(owidth * r_scale);
\t\t\t\t\t\trheight = Math.ceil(oheight * r_scale);
\t\t\t\t\t\timgr.width(rwidth)
\t\t\t\t\t\t\t.height(rheight)
\t\t\t\t\t\t\t.css('margin-top', (pheight-rheight)/2 + 'px')
\t\t\t\t\t\t\t.css('margin-left', (pwidth-rwidth)/2 + 'px');
\t\t\t\t\t\tif (imgr.is(':visible') && bg.is(':visible')) {
\t\t\t\t\t\t\tif (file.mime !== 'image/png') {
\t\t\t\t\t\t\t\tpreview.css('backgroundColor', bg.val());
\t\t\t\t\t\t\t\tpickimg = \$('<img>');
\t\t\t\t\t\t\t\tif (fm.isCORS) {
\t\t\t\t\t\t\t\t\tpickimg.attr('crossorigin', 'use-credentials');
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tpickimg.on('load', function() {
\t\t\t\t\t\t\t\t\tif (pickcanv && pickcanv.width !== rwidth) {
\t\t\t\t\t\t\t\t\t\tsetColorData();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.on('error', fail)
\t\t\t\t\t\t\t\t.attr('src', canvSrc);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tfail();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetupimg = function() {
\t\t\t\t\t\tresize.updateView(owidth, oheight);
\t\t\t\t\t\tsetuprimg();
\t\t\t\t\t\tbasec
\t\t\t\t\t\t\t.width(img.width())
\t\t\t\t\t\t\t.height(img.height());
\t\t\t\t\t\timgc
\t\t\t\t\t\t\t.width(img.width())
\t\t\t\t\t\t\t.height(img.height());
\t\t\t\t\t\tcrop.updateView();
\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t},
\t\t\t\t\tsetColorData = function() {
\t\t\t\t\t\tif (pickctx) {
\t\t\t\t\t\t\tvar n, w, h, r, g, b, a, s, l, hsl, hue,
\t\t\t\t\t\t\t\tdata, scale, tx1, tx2, ty1, ty2, rgb,
\t\t\t\t\t\t\t\tdomi = {},
\t\t\t\t\t\t\t\tdomic = [],
\t\t\t\t\t\t\t\tdomiv, palc,
\t\t\t\t\t\t\t\trgbToHsl = function (r, g, b) {
\t\t\t\t\t\t\t\t\tvar h, s, l,
\t\t\t\t\t\t\t\t\t\tmax = Math.max(Math.max(r, g), b),
\t\t\t\t\t\t\t\t\t\tmin = Math.min(Math.min(r, g), b);
\t\t
\t\t\t\t\t\t\t\t\t// Hue, 0 ~ 359
\t\t\t\t\t\t\t\t\tif (max === min) {
\t\t\t\t\t\t\t\t\t\th = 0;
\t\t\t\t\t\t\t\t\t} else if (r === max) {
\t\t\t\t\t\t\t\t\t\th = ((g - b) / (max - min) * 60 + 360) % 360;
\t\t\t\t\t\t\t\t\t} else if (g === max) {
\t\t\t\t\t\t\t\t\t\th = (b - r) / (max - min) * 60 + 120;
\t\t\t\t\t\t\t\t\t} else if (b === max) {
\t\t\t\t\t\t\t\t\t\th = (r - g) / (max - min) * 60 + 240;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t// Saturation, 0 ~ 1
\t\t\t\t\t\t\t\t\ts = (max - min) / max;
\t\t\t\t\t\t\t\t\t// Lightness, 0 ~ 1
\t\t\t\t\t\t\t\t\tl = (r *  0.3 + g * 0.59 + b * 0.11) / 255;
\t\t
\t\t\t\t\t\t\t\t\treturn [h, s, l, 'hsl'];
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\trgbRound = function(c) {
\t\t\t\t\t\t\t\t\treturn Math.round(c / 8) * 8;
\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tcalc:
\t\t\t\t\t\t\ttry {
\t\t\t\t\t\t\t\tw = pickcanv.width = imgr.width();
\t\t\t\t\t\t\t\th = pickcanv.height = imgr.height();
\t\t\t\t\t\t\t\tscale = w / owidth;
\t\t\t\t\t\t\t\tpickctx.scale(scale, scale);
\t\t\t\t\t\t\t\tpickctx.drawImage(pickimg.get(0), 0, 0);
\t\t\t
\t\t\t\t\t\t\t\tdata = pickctx.getImageData(0, 0, w, h).data;
\t\t\t
\t\t\t\t\t\t\t\t// Range to detect the dominant color
\t\t\t\t\t\t\t\ttx1 = w * 0.1;
\t\t\t\t\t\t\t\ttx2 = w * 0.9;
\t\t\t\t\t\t\t\tty1 = h * 0.1;
\t\t\t\t\t\t\t\tty2 = h * 0.9;
\t\t\t
\t\t\t\t\t\t\t\tfor (var y = 0; y < h - 1; y++) {
\t\t\t\t\t\t\t\t\tfor (var x = 0; x < w - 1; x++) {
\t\t\t\t\t\t\t\t\t\tn = x * 4 + y * w * 4;
\t\t\t\t\t\t\t\t\t\t// RGB
\t\t\t\t\t\t\t\t\t\tr = data[n]; g = data[n + 1]; b = data[n + 2]; a = data[n + 3];
\t\t\t\t\t\t\t\t\t\t// check alpha ch
\t\t\t\t\t\t\t\t\t\tif (a !== 255) {
\t\t\t\t\t\t\t\t\t\t\tbg.parent().hide();
\t\t\t\t\t\t\t\t\t\t\tpallet.hide();
\t\t\t\t\t\t\t\t\t\t\tbreak calc;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t// HSL
\t\t\t\t\t\t\t\t\t\thsl = rgbToHsl(r, g, b);
\t\t\t\t\t\t\t\t\t\thue = Math.round(hsl[0]); s = Math.round(hsl[1] * 100); l = Math.round(hsl[2] * 100);
\t\t\t\t\t\t\t\t\t\tif (! pickc[x]) {
\t\t\t\t\t\t\t\t\t\t\tpickc[x] = {};
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t// set pickc
\t\t\t\t\t\t\t\t\t\tpickc[x][y] = [r, g, b, hue, s, l];
\t\t\t\t\t\t\t\t\t\t// detect the dominant color
\t\t\t\t\t\t\t\t\t\tif ((x < tx1 || x > tx2) && (y < ty1 || y > ty2)) {
\t\t\t\t\t\t\t\t\t\t\trgb = rgbRound(r) + ',' + rgbRound(g) + ',' + rgbRound(b);
\t\t\t\t\t\t\t\t\t\t\tif (! domi[rgb]) {
\t\t\t\t\t\t\t\t\t\t\t\tdomi[rgb] = 1;
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t++domi[rgb];
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (! pallet.children(':first').length) {
\t\t\t\t\t\t\t\t\tpalc = 1;
\t\t\t\t\t\t\t\t\t\$.each(domi, function(c, v) {
\t\t\t\t\t\t\t\t\t\tdomic.push({c: c, v: v});
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\$.each(domic.sort(function(a, b) {
\t\t\t\t\t\t\t\t\t\treturn (a.v > b.v)? -1 : 1;
\t\t\t\t\t\t\t\t\t}), function() {
\t\t\t\t\t\t\t\t\t\tif (this.v < 2 || palc > 10) {
\t\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tpallet.append(\$('<span style=\"width:20px;height:20px;display:inline-block;background-color:rgb('+this.c+');\">'));
\t\t\t\t\t\t\t\t\t\t++palc;
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\t\tpicker.hide();
\t\t\t\t\t\t\t\tpallet.hide();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetupPicker = function() {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tpickcanv = document.createElement('canvas');
\t\t\t\t\t\t\tpickctx = pickcanv.getContext('2d');
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tpicker.hide();
\t\t\t\t\t\t\tpallet.hide();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsetupPreset = function() {
\t\t\t\t\t\tpreset.on('click', 'span.elfinder-resize-preset', function() {
\t\t\t\t\t\t\tvar btn = \$(this),
\t\t\t\t\t\t\t\tw = btn.data('s')[0],
\t\t\t\t\t\t\t\th = btn.data('s')[1],
\t\t\t\t\t\t\t\tr = owidth / oheight;
\t\t\t\t\t\t\tbtn.data('s', [h, w]).text(h + 'x' + w);
\t\t\t\t\t\t\tif (owidth > w || oheight > h) {
\t\t\t\t\t\t\t\tif (owidth <= w) {
\t\t\t\t\t\t\t\t\tw = round(h * r);
\t\t\t\t\t\t\t\t} else if (oheight <= h) {
\t\t\t\t\t\t\t\t\th = round(w / r);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tif (owidth - w > oheight - h) {
\t\t\t\t\t\t\t\t\t\th = round(w / r);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tw = round(h * r);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tw = owidth;
\t\t\t\t\t\t\t\th = oheight;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\twidth.val(w);
\t\t\t\t\t\t\theight.val(h);
\t\t\t\t\t\t\tresize.updateView(w, h);
\t\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t\t});
\t\t\t\t\t\tpresetc.on('click', 'span.elfinder-resize-preset', function() {
\t\t\t\t\t\t\tvar btn = \$(this),
\t\t\t\t\t\t\t\tw = btn.data('s')[0],
\t\t\t\t\t\t\t\th = btn.data('s')[1],
\t\t\t\t\t\t\t\tx = pointX.val(),
\t\t\t\t\t\t\t\ty = pointY.val();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tbtn.data('s', [h, w]).text(h + 'x' + w);
\t\t\t\t\t\t\tif (owidth >= w && oheight >= h) {
\t\t\t\t\t\t\t\tif (owidth - w - x < 0) {
\t\t\t\t\t\t\t\t\tx = owidth - w;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (oheight - h - y < 0) {
\t\t\t\t\t\t\t\t\ty = oheight - h;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tpointX.val(x);
\t\t\t\t\t\t\t\tpointY.val(y);
\t\t\t\t\t\t\t\toffsetX.val(w);
\t\t\t\t\t\t\t\toffsetY.val(h);
\t\t\t\t\t\t\t\tcrop.updateView();
\t\t\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tpresetc.children('span.elfinder-resize-preset').each(function() {
\t\t\t\t\t\t\tvar btn = \$(this),
\t\t\t\t\t\t\t\tw = btn.data('s')[0],
\t\t\t\t\t\t\t\th = btn.data('s')[1];
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tbtn[(owidth >= w && oheight >= h)? 'show' : 'hide']();
\t\t\t\t\t\t});
\t\t\t\t\t},
\t\t\t\t\tdimreq  = null,
\t\t\t\t\tinited  = false,
\t\t\t\t\tsetdim  = function(dim) {
\t\t\t\t\t\tvar rfile = fm.file(file.hash);
\t\t\t\t\t\trfile.width = dim[0];
\t\t\t\t\t\trfile.height = dim[1];
\t\t\t\t\t},
\t\t\t\t\tinit    = function() {
\t\t\t\t\t\tvar elm, memSize, r_scale, imgRatio;
\t\t\t\t\t\t
\t\t\t\t\t\tif (inited) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\tinited = true;
\t\t\t\t\t\tdimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject();
\t\t\t\t\t\t
\t\t\t\t\t\t// check lossless rotete
\t\t\t\t\t\tif (fm.api >= 2.1030) {
\t\t\t\t\t\t\tif (losslessRotate === 0) {
\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\tdata: {
\t\t\t\t\t\t\t\t\t\tcmd    : 'resize',
\t\t\t\t\t\t\t\t\t\ttarget : file.hash,
\t\t\t\t\t\t\t\t\t\tdegree : 0,
\t\t\t\t\t\t\t\t\t\tmode   : 'rotate'
\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\t\t\t\tlosslessRotate = data.losslessRotate? 1 : -1;
\t\t\t\t\t\t\t\t\tif (losslessRotate === 1 && (degree.val() % 90 === 0)) {
\t\t\t\t\t\t\t\t\t\tuirotate.children('div.elfinder-resize-quality').hide();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}).fail(function() {
\t\t\t\t\t\t\t\t\tlosslessRotate = -1;
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tlosslessRotate = -1;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\telm = img.get(0);
\t\t\t\t\t\tmemSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()});
\t\t\t\t\t
\t\t\t\t\t\tmemSize && img.removeAttr('width').removeAttr('height');
\t\t\t\t\t\t
\t\t\t\t\t\towidth  = file.width || elm.naturalWidth || elm.width || img.width();
\t\t\t\t\t\toheight = file.height || elm.naturalHeight || elm.height || img.height();
\t\t\t\t\t\tif (!file.width || !file.height) {
\t\t\t\t\t\t\tsetdim([owidth, oheight]);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tmemSize && img.width(memSize.w).height(memSize.h);
\t\t\t\t\t\t
\t\t\t\t\t\tdMinBtn.show();
\t
\t\t\t\t\t\timgRatio = oheight / owidth;
\t\t\t\t\t\t
\t\t\t\t\t\tif (imgRatio < 1 && preview.height() > preview.width() * imgRatio) {
\t\t\t\t\t\t\tpreview.height(preview.width() * imgRatio);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tif (preview.height() > img.height() + 20) {
\t\t\t\t\t\t\tpreview.height(img.height() + 20);
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tpheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
\t\t\t\t\t\t
\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t\t
\t\t\t\t\t\tratio = owidth/oheight;
\t
\t\t\t\t\t\trhandle.append(img.show()).show();
\t\t\t\t\t\twidth.val(owidth);
\t\t\t\t\t\theight.val(oheight);
\t
\t\t\t\t\t\tsetupPicker();
\t\t\t\t\t\tsetupPreset();
\t\t\t\t\t\tsetupimg();
\t\t\t\t\t\t
\t\t\t\t\t\tuitype[ctrgrup]('enable');
\t\t\t\t\t\tcontrol.find('input,select').prop('disabled', false)
\t\t\t\t\t\t\t.filter(':text').on('keydown', function(e) {
\t\t\t\t\t\t\t\tvar cOpts;
\t\t\t\t\t\t\t\tif (e.keyCode == \$.ui.keyCode.ENTER) {
\t\t\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\t\t\tcOpts = {
\t\t\t\t\t\t\t\t\t\ttitle  : \$('input:checked', uitype).val(),
\t\t\t\t\t\t\t\t\t\ttext   : 'confirmReq',
\t\t\t\t\t\t\t\t\t\taccept : {
\t\t\t\t\t\t\t\t\t\t\tlabel    : 'btnApply',
\t\t\t\t\t\t\t\t\t\t\tcallback : function() {  
\t\t\t\t\t\t\t\t\t\t\t\tsave();
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\tcancel : {
\t\t\t\t\t\t\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\t\t\t\t\t\t\tcallback : function(){
\t\t\t\t\t\t\t\t\t\t\t\t\$(this).trigger('focus');
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\t\tif (useSaveAs) {
\t\t\t\t\t\t\t\t\t\tcOpts['buttons'] = [{
\t\t\t\t\t\t\t\t\t\t\tlabel    : 'btnSaveAs',
\t\t\t\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\t\t\t\trequestAnimationFrame(saveAs);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}];
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tfm.confirm(cOpts);
\t\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.on('keyup', function() {
\t\t\t\t\t\t\t\tvar \$this = \$(this);
\t\t\t\t\t\t\t\tif (! \$this.hasClass('elfinder-resize-bg')) {
\t\t\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\t\t\t\$this.val(\$this.val().replace(/[^0-9]/g, ''));
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t.filter(':first');
\t\t\t\t\t\t
\t\t\t\t\t\tsetStep8();
\t\t\t\t\t\t!fm.UA.Mobile && width.trigger('focus');
\t\t\t\t\t\tresizable();
\t\t\t\t\t},
\t\t\t\t\timg     = \$('<img/>')
\t\t\t\t\t\t.on('load', init)
\t\t\t\t\t\t.on('error', function() {
\t\t\t\t\t\t\tspinner.html(fm.i18n('ntfsmth')).css('background', 'transparent');
\t\t\t\t\t\t}),
\t\t\t\t\tbasec = \$('<div></div>'),
\t\t\t\t\timgc = \$('<img/>'),
\t\t\t\t\tcoverc = \$('<div></div>'),
\t\t\t\t\timgr = \$('<img class=\"elfinder-resize-imgrotate\" />'),
\t\t\t\t\tround = function(v, max) {
\t\t\t\t\t\tv = grid8? Math.round(v/8)*8 : Math.round(v);
\t\t\t\t\t\tv = Math.max(0, v);
\t\t\t\t\t\tif (max && v > max) {
\t\t\t\t\t\t\tv = grid8? Math.floor(max/8)*8 : max;
\t\t\t\t\t\t}
\t\t\t\t\t\treturn v;
\t\t\t\t\t},
\t\t\t\t\tresetView = function() {
\t\t\t\t\t\twidth.val(owidth);
\t\t\t\t\t\theight.val(oheight);
\t\t\t\t\t\tresize.updateView(owidth, oheight);
\t\t\t\t\t\tpointX.val(0);
\t\t\t\t\t\tpointY.val(0);
\t\t\t\t\t\toffsetX.val(owidth);
\t\t\t\t\t\toffsetY.val(oheight);
\t\t\t\t\t\tcrop.updateView();
\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t},
\t\t\t\t\tresize = {
\t\t\t\t\t\tupdate : function() {
\t\t\t\t\t\t\twidth.val(round(img.width()/prop));
\t\t\t\t\t\t\theight.val(round(img.height()/prop));
\t\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\tupdateView : function(w, h) {
\t\t\t\t\t\t\tif (w > pwidth || h > pheight) {
\t\t\t\t\t\t\t\tif (w / pwidth > h / pheight) {
\t\t\t\t\t\t\t\t\tprop = pwidth / w;
\t\t\t\t\t\t\t\t\timg.width(pwidth).height(round(h*prop));
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tprop = pheight / h;
\t\t\t\t\t\t\t\t\timg.height(pheight).width(round(w*prop));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\timg.width(round(w)).height(round(h));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tprop = img.width()/w;
\t\t\t\t\t\t\tuiprop.text('1 : '+(1/prop).toFixed(2));
\t\t\t\t\t\t\tresize.updateHandle();
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\tupdateHandle : function() {
\t\t\t\t\t\t\trhandle.width(img.width()).height(img.height());
\t\t\t\t\t\t},
\t\t\t\t\t\tfixHeight : function() {
\t\t\t\t\t\t\tvar w, h;
\t\t\t\t\t\t\tif (cratio) {
\t\t\t\t\t\t\t\tw = width.val();
\t\t\t\t\t\t\t\th = round(w/ratio);
\t\t\t\t\t\t\t\tresize.updateView(w, h);
\t\t\t\t\t\t\t\theight.val(h);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tcrop = {
\t\t\t\t\t\tupdate : function(change) {
\t\t\t\t\t\t\tpointX.val(round(((rhandlec.data('x')||rhandlec.position().left))/prop, owidth));
\t\t\t\t\t\t\tpointY.val(round(((rhandlec.data('y')||rhandlec.position().top))/prop, oheight));
\t\t\t\t\t\t\tif (change !== 'xy') {
\t\t\t\t\t\t\t\toffsetX.val(round((rhandlec.data('w')||rhandlec.width())/prop, owidth - pointX.val()));
\t\t\t\t\t\t\t\toffsetY.val(round((rhandlec.data('h')||rhandlec.height())/prop, oheight - pointY.val()));
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t\t},
\t\t\t\t\t\tupdateView : function(change) {
\t\t\t\t\t\t\tvar r, x, y, w, h;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tpointX.val(round(pointX.val(), owidth - (grid8? 8 : 1)));
\t\t\t\t\t\t\tpointY.val(round(pointY.val(), oheight - (grid8? 8 : 1)));
\t\t\t\t\t\t\toffsetX.val(round(offsetX.val(), owidth - pointX.val()));
\t\t\t\t\t\t\toffsetY.val(round(offsetY.val(), oheight - pointY.val()));
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (cratioc) {
\t\t\t\t\t\t\t\tr = coverc.width() / coverc.height();
\t\t\t\t\t\t\t\tif (change === 'w') {
\t\t\t\t\t\t\t\t\toffsetY.val(round(parseInt(offsetX.val()) / r));
\t\t\t\t\t\t\t\t} else if (change === 'h') {
\t\t\t\t\t\t\t\t\toffsetX.val(round(parseInt(offsetY.val()) * r));
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tx = Math.round(parseInt(pointX.val()) * prop);
\t\t\t\t\t\t\ty = Math.round(parseInt(pointY.val()) * prop);
\t\t\t\t\t\t\tif (change !== 'xy') {
\t\t\t\t\t\t\t\tw = Math.round(parseInt(offsetX.val()) * prop);
\t\t\t\t\t\t\t\th = Math.round(parseInt(offsetY.val()) * prop);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tw = rhandlec.data('w');
\t\t\t\t\t\t\t\th = rhandlec.data('h');
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\trhandlec.data({x: x, y: y, w: w, h: h})
\t\t\t\t\t\t\t\t.width(w)
\t\t\t\t\t\t\t\t.height(h)
\t\t\t\t\t\t\t\t.css({left: x, top: y});
\t\t\t\t\t\t\tcoverc.width(w)
\t\t\t\t\t\t\t\t.height(h);
\t\t\t\t\t\t},
\t\t\t\t\t\tresize_update : function(e, ui) {
\t\t\t\t\t\t\trhandlec.data({x: ui.position.left, y: ui.position.top, w: ui.size.width, h: ui.size.height});
\t\t\t\t\t\t\tcrop.update();
\t\t\t\t\t\t\tcrop.updateView();
\t\t\t\t\t\t},
\t\t\t\t\t\tdrag_update : function(e, ui) {
\t\t\t\t\t\t\trhandlec.data({x: ui.position.left, y: ui.position.top});
\t\t\t\t\t\t\tcrop.update('xy');
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\trotate = {
\t\t\t\t\t\tmouseStartAngle : 0,
\t\t\t\t\t\timageStartAngle : 0,
\t\t\t\t\t\timageBeingRotated : false,
\t\t\t\t\t\t
\t\t\t\t\t\tsetQuality : function() {
\t\t\t\t\t\t\tuirotate.children('div.elfinder-resize-quality')[(losslessRotate > 0 && (degree.val() % 90) === 0)? 'hide' : 'show']();
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\tupdate : function(value, animate) {
\t\t\t\t\t\t\tif (typeof value == 'undefined') {
\t\t\t\t\t\t\t\trdegree = value = parseInt(degree.val());
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (typeof animate == 'undefined') {
\t\t\t\t\t\t\t\tanimate = true;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (! animate || fm.UA.Opera || fm.UA.ltIE8) {
\t\t\t\t\t\t\t\timgr.rotate(value);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\timgr.animate({rotate: value + 'deg'});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tvalue = value % 360;
\t\t\t\t\t\t\tif (value < 0) {
\t\t\t\t\t\t\t\tvalue += 360;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdegree.val(parseInt(value));

\t\t\t\t\t\t\tuidegslider.slider('value', degree.val());
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trotate.setQuality();
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\texecute : function ( e ) {
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif ( !rotate.imageBeingRotated ) return;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar imageCentre = rotate.getCenter( imgr );
\t\t\t\t\t\t\tvar ev = e.originalEvent.touches? e.originalEvent.touches[0] : e;
\t\t\t\t\t\t\tvar mouseXFromCentre = ev.pageX - imageCentre[0];
\t\t\t\t\t\t\tvar mouseYFromCentre = ev.pageY - imageCentre[1];
\t\t\t\t\t\t\tvar mouseAngle = Math.atan2( mouseYFromCentre, mouseXFromCentre );
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar rotateAngle = mouseAngle - rotate.mouseStartAngle + rotate.imageStartAngle;
\t\t\t\t\t\t\trotateAngle = Math.round(parseFloat(rotateAngle) * 180 / Math.PI);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif ( e.shiftKey ) {
\t\t\t\t\t\t\t\trotateAngle = Math.round((rotateAngle + 6)/15) * 15;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\timgr.rotate(rotateAngle);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trotateAngle = rotateAngle % 360;
\t\t\t\t\t\t\tif (rotateAngle < 0) {
\t\t\t\t\t\t\t\trotateAngle += 360;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tdegree.val(rotateAngle);

\t\t\t\t\t\t\tuidegslider.slider('value', degree.val());
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trotate.setQuality();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\tstart : function ( e ) {
\t\t\t\t\t\t\tif (imgr.hasClass('elfinder-resize-picking')) {
\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\topStart();
\t\t\t\t\t\t\trotate.imageBeingRotated = true;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar imageCentre = rotate.getCenter( imgr );
\t\t\t\t\t\t\tvar ev = e.originalEvent.touches? e.originalEvent.touches[0] : e;
\t\t\t\t\t\t\tvar mouseStartXFromCentre = ev.pageX - imageCentre[0];
\t\t\t\t\t\t\tvar mouseStartYFromCentre = ev.pageY - imageCentre[1];
\t\t\t\t\t\t\trotate.mouseStartAngle = Math.atan2( mouseStartYFromCentre, mouseStartXFromCentre );
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trotate.imageStartAngle = parseFloat(imgr.rotate()) * Math.PI / 180.0;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\$(document).on('mousemove', rotate.execute);
\t\t\t\t\t\t\timgr.on('touchmove', rotate.execute);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t},
\t\t\t\t\t\t\t
\t\t\t\t\t\tstop : function ( e ) {
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif ( !rotate.imageBeingRotated ) return;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\$(document).off('mousemove', rotate.execute);
\t\t\t\t\t\t\timgr.off('touchmove', rotate.execute);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trequestAnimationFrame(function() { rotate.imageBeingRotated = false; });
\t\t\t\t\t\t\topStop();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t},
\t\t\t\t\t\t
\t\t\t\t\t\tgetCenter : function ( image ) {
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar currentRotation = imgr.rotate();
\t\t\t\t\t\t\timgr.rotate(0);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tvar imageOffset = imgr.offset();
\t\t\t\t\t\t\tvar imageCentreX = imageOffset.left + imgr.width() / 2;
\t\t\t\t\t\t\tvar imageCentreY = imageOffset.top + imgr.height() / 2;
\t\t\t\t\t\t\t
\t\t\t\t\t\t\timgr.rotate(currentRotation);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\treturn Array( imageCentreX, imageCentreY );
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tresizable = function(destroy) {
\t\t\t\t\t\tif (destroy) {
\t\t\t\t\t\t\trhandle.filter(':ui-resizable').resizable('destroy');
\t\t\t\t\t\t\trhandle.hide();
\t\t\t\t\t\t}
\t\t\t\t\t\telse {
\t\t\t\t\t\t\trhandle.show();
\t\t\t\t\t\t\trhandle.resizable({
\t\t\t\t\t\t\t\talsoResize  : img,
\t\t\t\t\t\t\t\taspectRatio : cratio,
\t\t\t\t\t\t\t\tresize      : resize.update,
\t\t\t\t\t\t\t\tstart       : opStart,
\t\t\t\t\t\t\t\tstop        : function(e) {
\t\t\t\t\t\t\t\t\tresize.fixHeight;
\t\t\t\t\t\t\t\t\tresize.updateView(width.val(), height.val());
\t\t\t\t\t\t\t\t\topStop();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t\tdinit();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tcroppable = function(destroy) {
\t\t\t\t\t\tif (destroy) {
\t\t\t\t\t\t\trhandlec.filter(':ui-resizable').resizable('destroy')
\t\t\t\t\t\t\t\t.filter(':ui-draggable').draggable('destroy');
\t\t\t\t\t\t\tbasec.hide();
\t\t\t\t\t\t}
\t\t\t\t\t\telse {
\t\t\t\t\t\t\tbasec.show();
\t\t\t\t\t\t\t
\t\t\t\t\t\t\trhandlec
\t\t\t\t\t\t\t\t.resizable({
\t\t\t\t\t\t\t\t\tcontainment : basec,
\t\t\t\t\t\t\t\t\taspectRatio : cratioc,
\t\t\t\t\t\t\t\t\tresize      : crop.resize_update,
\t\t\t\t\t\t\t\t\tstart       : opStart,
\t\t\t\t\t\t\t\t\tstop        : opStop,
\t\t\t\t\t\t\t\t\thandles     : 'all'
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.draggable({
\t\t\t\t\t\t\t\t\thandle      : coverc,
\t\t\t\t\t\t\t\t\tcontainment : imgc,
\t\t\t\t\t\t\t\t\tdrag        : crop.drag_update,
\t\t\t\t\t\t\t\t\tstart       : opStart,
\t\t\t\t\t\t\t\t\tstop        : function() {
\t\t\t\t\t\t\t\t\t\tcrop.updateView('xy');
\t\t\t\t\t\t\t\t\t\topStop();
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tdinit();
\t\t\t\t\t\t\tcrop.update();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\trotateable = function(destroy) {
\t\t\t\t\t\tif (destroy) {
\t\t\t\t\t\t\timgr.hide();
\t\t\t\t\t\t}
\t\t\t\t\t\telse {
\t\t\t\t\t\t\timgr.show();
\t\t\t\t\t\t\tdinit();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tcheckVals = function() {
\t\t\t\t\t\tvar w, h, x, y, d, q, b = '';
\t\t\t\t\t\t
\t\t\t\t\t\tif (mode == 'resize') {
\t\t\t\t\t\t\tw = parseInt(width.val()) || 0;
\t\t\t\t\t\t\th = parseInt(height.val()) || 0;
\t\t\t\t\t\t} else if (mode == 'crop') {
\t\t\t\t\t\t\tw = parseInt(offsetX.val()) || 0;
\t\t\t\t\t\t\th = parseInt(offsetY.val()) || 0;
\t\t\t\t\t\t\tx = parseInt(pointX.val()) || 0;
\t\t\t\t\t\t\ty = parseInt(pointY.val()) || 0;
\t\t\t\t\t\t} else if (mode == 'rotate') {
\t\t\t\t\t\t\tw = owidth;
\t\t\t\t\t\t\th = oheight;
\t\t\t\t\t\t\td = parseInt(degree.val()) || 0;
\t\t\t\t\t\t\tif (d < 0 || d > 360) {
\t\t\t\t\t\t\t\tfm.error('Invalid rotate degree');
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (d == 0 || d == 360) {
\t\t\t\t\t\t\t\tfm.error('errResizeNoChange');
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tb = bg.val();
\t\t\t\t\t\t}
\t\t\t\t\t\tq = quality? parseInt(quality.val()) : 0;
\t\t\t\t\t\t
\t\t\t\t\t\tif (mode != 'rotate') {
\t\t\t\t\t\t\tif (w <= 0 || h <= 0) {
\t\t\t\t\t\t\t\tfm.error('Invalid image size');
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\tif (w == owidth && h == oheight && parseInt(size0 / 1000) === parseInt(size1/1000)) {
\t\t\t\t\t\t\t\tfm.error('errResizeNoChange');
\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\treturn {w: w, h: h, x: x, y: y, d: d, q: q, b: b};
\t\t\t\t\t},
\t\t\t\t\tsave = function() {
\t\t\t\t\t\tvar vals;
\t\t\t\t\t\t
\t\t\t\t\t\tif (vals = checkVals()) {
\t\t\t\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\t\t\t\tself.resizeRequest({
\t\t\t\t\t\t\t\ttarget : file.hash,
\t\t\t\t\t\t\t\twidth  : vals.w,
\t\t\t\t\t\t\t\theight : vals.h,
\t\t\t\t\t\t\t\tx      : vals.x,
\t\t\t\t\t\t\t\ty      : vals.y,
\t\t\t\t\t\t\t\tdegree : vals.d,
\t\t\t\t\t\t\t\tquality: vals.q,
\t\t\t\t\t\t\t\tbg     : vals.b,
\t\t\t\t\t\t\t\tmode   : mode
\t\t\t\t\t\t\t}, file, dfrd);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tsaveAs = function() {
\t\t\t\t\t\tvar fail = function() {
\t\t\t\t\t\t\t\tdialogs.addClass(clsediting).fadeIn(function() {
\t\t\t\t\t\t\t\t\tbase.addClass(clactive);
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tfm.disable();
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tmake = function() {
\t\t\t\t\t\t\t\tself.mime = file.mime;
\t\t\t\t\t\t\t\tself.prefix = file.name.replace(/ \\d+(\\.[^.]+)?\$/, '\$1');
\t\t\t\t\t\t\t\tself.requestCmd = 'mkfile';
\t\t\t\t\t\t\t\tself.nextAction = {};
\t\t\t\t\t\t\t\tself.data = {target : file.phash};
\t\t\t\t\t\t\t\t\$.proxy(fm.res('mixin', 'make'), self)()
\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\tvar hash, dfd;
\t\t\t\t\t\t\t\t\t\tif (data.added && data.added.length) {
\t\t\t\t\t\t\t\t\t\t\thash = data.added[0].hash;
\t\t\t\t\t\t\t\t\t\t\tdfd = fm.api < 2.1032? fm.url(file.hash, { async: true, temporary: true }) : null;
\t\t\t\t\t\t\t\t\t\t\t\$.when(dfd).done(function(url) {
\t\t\t\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\t\t\t\toptions : {type : 'post'},
\t\t\t\t\t\t\t\t\t\t\t\t\tdata : {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcmd     : 'put',
\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget  : hash,
\t\t\t\t\t\t\t\t\t\t\t\t\t\tencoding: dfd? 'scheme' : 'hash', 
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcontent : dfd? fm.convAbsUrl(url) : file.hash
\t\t\t\t\t\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'copy', cnt : 1},
\t\t\t\t\t\t\t\t\t\t\t\t\tsyncOnFail : true
\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t.fail(fail)
\t\t\t\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\t\t\t\tdata = fm.normalize(data);
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.updateCache(data);
\t\t\t\t\t\t\t\t\t\t\t\t\tfile = fm.file(hash);
\t\t\t\t\t\t\t\t\t\t\t\t\tdata.changed && data.changed.length && fm.change(data);
\t\t\t\t\t\t\t\t\t\t\t\t\tbase.show().find('.elfinder-dialog-title').html(fm.escape(file.name));
\t\t\t\t\t\t\t\t\t\t\t\t\tsave();
\t\t\t\t\t\t\t\t\t\t\t\t\tdialogs.fadeIn();
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t}).fail(fail);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tfail();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.fail(fail)
\t\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\t\tdelete self.mime;
\t\t\t\t\t\t\t\t\t\tdelete self.prefix;
\t\t\t\t\t\t\t\t\t\tdelete self.nextAction;
\t\t\t\t\t\t\t\t\t\tdelete self.data;
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tfm.trigger('unselectfiles', { files: [ file.hash ] });
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\treqOpen = null,
\t\t\t\t\t\t\tdialogs;
\t\t\t\t\t\t
\t\t\t\t\t\tif (checkVals()) {
\t\t\t\t\t\t\tdialogs = fmnode.children('.' + self.dialogClass + ':visible').removeClass(clsediting).fadeOut();
\t\t\t\t\t\t\tbase.removeClass(clactive);
\t\t\t\t\t\t\tfm.enable();
\t\t\t\t\t\t\tif (fm.searchStatus.state < 2 && file.phash !== fm.cwd().hash) {
\t\t\t\t\t\t\t\treqOpen = fm.exec('open', [file.phash], {thash: file.phash});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\$.when([reqOpen]).done(function() {
\t\t\t\t\t\t\t\treqOpen? fm.one('cwdrender', make) : make();
\t\t\t\t\t\t\t}).fail(fail);
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tbuttons = {},
\t\t\t\t\thline   = 'elfinder-resize-handle-hline',
\t\t\t\t\tvline   = 'elfinder-resize-handle-vline',
\t\t\t\t\trpoint  = 'elfinder-resize-handle-point',
\t\t\t\t\tcanvSrc = src,
\t\t\t\t\tsizeImg = quality? \$('<img>').attr('crossorigin', fm.isCORS? 'use-credentials' : '').attr('src', canvSrc).on('load', function() {
\t\t\t\t\t\ttry {
\t\t\t\t\t\t\tvar canv = document.createElement('canvas');
\t\t\t\t\t\t\tsizeImg.data('canvas', canv).data('ctx', canv.getContext('2d'));
\t\t\t\t\t\t\tjpgCalc();
\t\t\t\t\t\t} catch(e) {
\t\t\t\t\t\t\tsizeImg.removeData('canvas').removeData('ctx');
\t\t\t\t\t\t}
\t\t\t\t\t}) : null,
\t\t\t\t\tjpgCalc = function() {
\t\t\t\t\t\tcontrol.find('input.elfinder-resize-quality:visible').trigger('change');
\t\t\t\t\t},
\t\t\t\t\tdinit   = function(e) {
\t\t\t\t\t\tif (base.hasClass('elfinder-dialog-minimized') || base.is(':hidden')) {
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tpreset.hide();
\t\t\t\t\t\tpresetc.hide();
\t\t\t\t\t\t
\t\t\t\t\t\tvar win   = fm.options.dialogContained? fmnode : \$(window),
\t\t\t\t\t\t\twinH  = win.height(),
\t\t\t\t\t\t\twinW  = win.width(),
\t\t\t\t\t\t\tpresW = 'auto',
\t\t\t\t\t\t\tpresIn = true,
\t\t\t\t\t\t\tdw, ctrW, prvW;
\t\t\t\t\t\t
\t\t\t\t\t\tbase.width(Math.min(dialogWidth, winW - 30));
\t\t\t\t\t\tpreview.attr('style', '');
\t\t\t\t\t\tif (owidth && oheight) {
\t\t\t\t\t\t\tpwidth  = preview.width()  - (rhandle.outerWidth()  - rhandle.width());
\t\t\t\t\t\t\tpheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
\t\t\t\t\t\t\tresize.updateView(owidth, oheight);
\t\t\t\t\t\t}
\t\t\t\t\t\tctrW  = dialog.find('div.elfinder-resize-control').width();
\t\t\t\t\t\tprvW  = preview.width();
\t\t\t\t\t\t
\t\t\t\t\t\tdw = dialog.width() - 20;
\t\t\t\t\t\tif (prvW > dw) {
\t\t\t\t\t\t\tpreview.width(dw);
\t\t\t\t\t\t\tpresIn = false;
\t\t\t\t\t\t} else if ((dw - prvW) < ctrW) {
\t\t\t\t\t\t\tif (winW > winH) {
\t\t\t\t\t\t\t\tpreview.width(dw - ctrW - 20);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tpreview.css({ float: 'none', marginLeft: 'auto', marginRight: 'auto'});
\t\t\t\t\t\t\t\tpresIn = false;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t\tif (presIn) {
\t\t\t\t\t\t\tpresW = ctrW;
\t\t\t\t\t\t}
\t\t\t\t\t\tpwidth  = preview.width()  - (rhandle.outerWidth()  - rhandle.width());
\t\t\t\t\t\tif (fmnode.hasClass('elfinder-fullscreen')) {
\t\t\t\t\t\t\tif (base.height() > winH) {
\t\t\t\t\t\t\t\twinH -= 2;
\t\t\t\t\t\t\t\tpreview.height(winH - base.height() + preview.height());
\t\t\t\t\t\t\t\tbase.css('top', 0 - fmnode.offset().top);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\twinH -= 30;
\t\t\t\t\t\t\t(preview.height() > winH) && preview.height(winH);
\t\t\t\t\t\t}
\t\t\t\t\t\tpheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
\t\t\t\t\t\tif (owidth && oheight) {
\t\t\t\t\t\t\tsetupimg();
\t\t\t\t\t\t}
\t\t\t\t\t\tif (img.height() && preview.height() > img.height() + 20) {
\t\t\t\t\t\t\tpreview.height(img.height() + 20);
\t\t\t\t\t\t\tpheight = preview.height() - (rhandle.outerHeight() - rhandle.height());
\t\t\t\t\t\t\tsetuprimg();
\t\t\t\t\t\t}
\t\t\t\t\t\t
\t\t\t\t\t\tpreset.css('width', presW).show();
\t\t\t\t\t\tpresetc.css('width', presW).show();
\t\t\t\t\t\tif (!presetc.children('span.elfinder-resize-preset:visible').length) {
\t\t\t\t\t\t\tpresetc.hide();
\t\t\t\t\t\t}
\t\t\t\t\t\tdialog.elfinderdialog('posInit');
\t\t\t\t\t},
\t\t\t\t\tpreset = (function() {
\t\t\t\t\t\tvar sets = \$('<fieldset class=\"elfinder-resize-preset-container\">').append(\$('<legend>').html(fm.i18n('presets'))).css('box-sizing', 'border-box').hide(),
\t\t\t\t\t\t\thasC;
\t\t\t\t\t\t\$.each(presetSize, function(i, s) {
\t\t\t\t\t\t\tif (s.length === 2) {
\t\t\t\t\t\t\t\thasC = true;
\t\t\t\t\t\t\t\tsets.append(\$('<span class=\"elfinder-resize-preset\"></span>')
\t\t\t\t\t\t\t\t\t.data('s', s)
\t\t\t\t\t\t\t\t\t.text(s[0]+'x'+s[1])
\t\t\t\t\t\t\t\t\t.button()
\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t\tif (!hasC) {
\t\t\t\t\t\t\treturn \$();
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\treturn sets;
\t\t\t\t\t\t}
\t\t\t\t\t})(),
\t\t\t\t\tpresetc = preset.clone(true),
\t\t\t\t\tuseSaveAs = fm.uploadMimeCheck(file.mime, file.phash),
\t\t\t\t\tdMinBtn, base;
\t\t\t\t
\t\t\t\tsize0 = size1 = file.size;
\t\t\t\tuiresize.append(
\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('width')), width),
\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('height')), height, \$('<div class=\"elfinder-resize-whctrls\">').append(constr, reset)),
\t\t\t\t\t(quality? \$(row).append(\$(label).text(fm.i18n('quality')), quality, \$('<span></span>')) : \$()),
\t\t\t\t\t(isJpeg? \$(row).append(\$(label).text(fm.i18n('8pxgrid')).addClass('elfinder-resize-grid8'), grid8px) : \$()),
\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('scale')), uiprop),
\t\t\t\t\t\$(row).append(preset)
\t\t\t\t);

\t\t\t\tif (api2) {
\t\t\t\t\tuicrop.append(
\t\t\t\t\t\t\$(row).append(\$(label).text('X'), pointX),
\t\t\t\t\t\t\$(row).append(\$(label).text('Y')).append(pointY),
\t\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('width')), offsetX),
\t\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('height')), offsetY, \$('<div class=\"elfinder-resize-whctrls\">').append(constrc, reset.clone(true))),
\t\t\t\t\t\t(quality? \$(row).append(\$(label).text(fm.i18n('quality')), quality.clone(true), \$('<span></span>')) : \$()),
\t\t\t\t\t\t(isJpeg? \$(row).append(\$(label).text(fm.i18n('8pxgrid')).addClass('elfinder-resize-grid8')) : \$()),
\t\t\t\t\t\t\$(row).append(presetc)
\t\t\t\t\t);
\t\t\t\t\t
\t\t\t\t\tuirotate.append(
\t\t\t\t\t\t\$(row).addClass('elfinder-resize-degree').append(
\t\t\t\t\t\t\t\$(label).text(fm.i18n('rotate')),
\t\t\t\t\t\t\tdegree,
\t\t\t\t\t\t\t\$('<span></span>').text(fm.i18n('degree')),
\t\t\t\t\t\t\t\$('<div></div>').append(uideg270, uideg90)[ctrgrup]()
\t\t\t\t\t\t),
\t\t\t\t\t\t\$(row).css('height', '20px').append(uidegslider),
\t\t\t\t\t\t((quality)? \$(row)[losslessRotate < 1? 'show' : 'hide']().addClass('elfinder-resize-quality').append(
\t\t\t\t\t\t\t\$(label).text(fm.i18n('quality')),
\t\t\t\t\t\t\tquality.clone(true),
\t\t\t\t\t\t\t\$('<span></span>')) : \$()
\t\t\t\t\t\t),
\t\t\t\t\t\t\$(row).append(\$(label).text(fm.i18n('bgcolor')), bg, picker, reseter),
\t\t\t\t\t\t\$(row).css('height', '20px').append(pallet)
\t\t\t\t\t);
\t\t\t\t\tuideg270.on('click', function() {
\t\t\t\t\t\trdegree = rdegree - 90;
\t\t\t\t\t\trotate.update(rdegree);
\t\t\t\t\t});
\t\t\t\t\tuideg90.on('click', function(){
\t\t\t\t\t\trdegree = rdegree + 90;
\t\t\t\t\t\trotate.update(rdegree);
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t\tdialog.append(uitype).on('resize', function(e){
\t\t\t\t\te.stopPropagation();
\t\t\t\t});

\t\t\t\tif (api2) {
\t\t\t\t\tcontrol.append(/*\$(row), */uiresize, uicrop.hide(), uirotate.hide());
\t\t\t\t} else {
\t\t\t\t\tcontrol.append(/*\$(row), */uiresize);
\t\t\t\t}
\t\t\t\t
\t\t\t\trhandle.append('<div class=\"'+hline+' '+hline+'-top\"></div>',
\t\t\t\t\t'<div class=\"'+hline+' '+hline+'-bottom\"></div>',
\t\t\t\t\t'<div class=\"'+vline+' '+vline+'-left\"></div>',
\t\t\t\t\t'<div class=\"'+vline+' '+vline+'-right\"></div>',
\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-e\"></div>',
\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-se\"></div>',
\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-s\"></div>');
\t\t\t\t\t
\t\t\t\tpreview.append(spinner).append(rhandle.hide()).append(img.hide());

\t\t\t\tif (api2) {
\t\t\t\t\trhandlec.css('position', 'absolute')
\t\t\t\t\t\t.append('<div class=\"'+hline+' '+hline+'-top\"></div>',
\t\t\t\t\t\t'<div class=\"'+hline+' '+hline+'-bottom\"></div>',
\t\t\t\t\t\t'<div class=\"'+vline+' '+vline+'-left\"></div>',
\t\t\t\t\t\t'<div class=\"'+vline+' '+vline+'-right\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-n\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-e\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-s\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-w\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-ne\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-se\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-sw\"></div>',
\t\t\t\t\t\t'<div class=\"'+rpoint+' '+rpoint+'-nw\"></div>');

\t\t\t\t\tpreview.append(basec.css('position', 'absolute').hide().append(imgc, rhandlec.append(coverc)));
\t\t\t\t\t
\t\t\t\t\tpreview.append(imgr.hide());
\t\t\t\t}
\t\t\t\t
\t\t\t\tpreview.css('overflow', 'hidden');
\t\t\t\t
\t\t\t\tdialog.append(preview, control);
\t\t\t\t
\t\t\t\tbuttons[fm.i18n('btnApply')] = save;
\t\t\t\tif (useSaveAs) {
\t\t\t\t\tbuttons[fm.i18n('btnSaveAs')] = function() { requestAnimationFrame(saveAs); };
\t\t\t\t}
\t\t\t\tbuttons[fm.i18n('btnCancel')] = function() { dialog.elfinderdialog('close'); };
\t\t\t\t
\t\t\t\tdialog.find('input,button').addClass('elfinder-tabstop');
\t\t\t\t
\t\t\t\tbase = self.fmDialog(dialog, {
\t\t\t\t\ttitle          : fm.escape(file.name),
\t\t\t\t\twidth          : dialogWidth,
\t\t\t\t\tresizable      : false,
\t\t\t\t\tbuttons        : buttons,
\t\t\t\t\topen           : function() {
\t\t\t\t\t\tvar doDimReq = function(force) {
\t\t\t\t\t\t\t\tdimreq = fm.request({
\t\t\t\t\t\t\t\t\tdata : {cmd : 'dim', target : file.hash, substitute : substituteImg? 400 : ''},
\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\tif (!data.url && needPng) {
\t\t\t\t\t\t\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\t\t\t\t\t\t\tfm.error(['errOpen', file.name]);
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tif (data.dim) {
\t\t\t\t\t\t\t\t\t\t\tvar dim = data.dim.split('x');
\t\t\t\t\t\t\t\t\t\t\tfile.width = dim[0];
\t\t\t\t\t\t\t\t\t\t\tfile.height = dim[1];
\t\t\t\t\t\t\t\t\t\t\tsetdim(dim);
\t\t\t\t\t\t\t\t\t\t\tif (data.url) {
\t\t\t\t\t\t\t\t\t\t\t\timg.attr('src', data.url);
\t\t\t\t\t\t\t\t\t\t\t\timgc.attr('src', data.url);
\t\t\t\t\t\t\t\t\t\t\t\timgr.attr('src', data.url);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\treturn init();
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\tneedPng = !{'image/jpeg':true,'image/png':true,'image/gif':true,}[file.mime],
\t\t\t\t\t\t\tsubstituteImg = fm.option('substituteImg', file.hash) && (needPng || file.size > options.dimSubImgSize)? true : false,
\t\t\t\t\t\t\thasSize = (file.width && file.height)? true : false;
\t\t\t\t\t\tdMinBtn = base.find('.ui-dialog-titlebar .elfinder-titlebar-minimize').hide();
\t\t\t\t\t\tfm.bind('resize', dinit);
\t\t\t\t\t\timg.attr('src', src).one('error.dimreq', function() {
\t\t\t\t\t\t\tdoDimReq(true);
\t\t\t\t\t\t});
\t\t\t\t\t\timgc.attr('src', src);
\t\t\t\t\t\timgr.attr('src', src);
\t\t\t\t\t\tif (api2) {
\t\t\t\t\t\t\timgr.on('mousedown touchstart', rotate.start)
\t\t\t\t\t\t\t\t.on('touchend', rotate.stop);
\t\t\t\t\t\t\tbase.on('mouseup', rotate.stop);
\t\t\t\t\t\t}
\t\t\t\t\t\tif (hasSize && !substituteImg) {
\t\t\t\t\t\t\treturn init();
\t\t\t\t\t\t}
\t\t\t\t\t\tif (file.size > (options.getDimThreshold || 0)) {
\t\t\t\t\t\t\timg.off('error.dimreq');
\t\t\t\t\t\t\tdoDimReq();
\t\t\t\t\t\t} else if (hasSize) {
\t\t\t\t\t\t\treturn init();
\t\t\t\t\t\t}
\t\t\t\t\t},
\t\t\t\t\tclose          : function() {
\t\t\t\t\t\tif (api2) {
\t\t\t\t\t\t\timgr.off('mousedown touchstart', rotate.start)
\t\t\t\t\t\t\t\t.off('touchend', rotate.stop);
\t\t\t\t\t\t\t\$(document).off('mouseup', rotate.stop);
\t\t\t\t\t\t}
\t\t\t\t\t\tfm.unbind('resize', dinit);
\t\t\t\t\t\t\$(this).elfinderdialog('destroy');
\t\t\t\t\t},
\t\t\t\t\tresize         : function(e, data) {
\t\t\t\t\t\tif (data && data.minimize === 'off') {
\t\t\t\t\t\t\tdinit();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}).attr('id', id).closest('.ui-dialog').addClass(clsediting);
\t\t\t\t
\t\t\t\t// for IE < 9 dialog mising at open second+ time.
\t\t\t\tif (fm.UA.ltIE8) {
\t\t\t\t\t\$('.elfinder-dialog').css('filter', '');
\t\t\t\t}
\t\t\t\t
\t\t\t\tcoverc.css({ 'opacity': 0.2, 'background-color': '#fff', 'position': 'absolute'}),
\t\t\t\trhandlec.css('cursor', 'move');
\t\t\t\trhandlec.find('.elfinder-resize-handle-point').css({
\t\t\t\t\t'background-color' : '#fff',
\t\t\t\t\t'opacity': 0.5,
\t\t\t\t\t'border-color':'#000'
\t\t\t\t});

\t\t\t\tif (! api2) {
\t\t\t\t\tuitype.find('.api2').remove();
\t\t\t\t}
\t\t\t\t
\t\t\t\tcontrol.find('input,select').prop('disabled', true);
\t\t\t\tcontrol.find('input.elfinder-resize-quality')
\t\t\t\t\t.next('span').addClass('elfinder-resize-jpgsize').attr('title', fm.i18n('roughFileSize'));

\t\t\t},
\t\t\t
\t\t\tid, dialog, size0, size1
\t\t\t;
\t\t\t

\t\tif (!files.length || files[0].mime.indexOf('image/') === -1) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\tid = 'resize-'+fm.namespace+'-'+files[0].hash;
\t\tdialog = fmnode.find('#'+id);
\t\t
\t\tif (dialog.length) {
\t\t\tdialog.elfinderdialog('toTop');
\t\t\treturn dfrd.resolve();
\t\t}
\t\t
\t\t
\t\tfm.openUrl(files[0].hash, 'sameorigin', function(src) {
\t\t\topen(files[0], id, src);
\t\t});
\t\t\t
\t\treturn dfrd;
\t};

};

(function (\$) {
\t
\tvar findProperty = function (styleObject, styleArgs) {
\t\tvar i = 0 ;
\t\tfor( i in styleArgs) {
\t        if (typeof styleObject[styleArgs[i]] != 'undefined') 
\t        \treturn styleArgs[i];
\t\t}
\t\tstyleObject[styleArgs[i]] = '';
\t    return styleArgs[i];
\t};
\t
\t\$.cssHooks.rotate = {
\t\tget: function(elem, computed, extra) {
\t\t\treturn \$(elem).rotate();
\t\t},
\t\tset: function(elem, value) {
\t\t\t\$(elem).rotate(value);
\t\t\treturn value;
\t\t}
\t};
\t\$.cssHooks.transform = {
\t\tget: function(elem, computed, extra) {
\t\t\tvar name = findProperty( elem.style , 
\t\t\t\t['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
\t\t\treturn elem.style[name];
\t\t},
\t\tset: function(elem, value) {
\t\t\tvar name = findProperty( elem.style , 
\t\t\t\t['WebkitTransform', 'MozTransform', 'OTransform' , 'msTransform' , 'transform'] );
\t\t\telem.style[name] = value;
\t\t\treturn value;
\t\t}
\t};
\t
\t\$.fn.rotate = function(val) {
\t\tvar r;
\t\tif (typeof val == 'undefined') {
\t\t\tif (!!window.opera) {
\t\t\t\tr = this.css('transform').match(/rotate\\((.*?)\\)/);
\t\t\t\treturn  ( r && r[1])?
\t\t\t\t\tMath.round(parseFloat(r[1]) * 180 / Math.PI) : 0;
\t\t\t} else {
\t\t\t\tr = this.css('transform').match(/rotate\\((.*?)\\)/);
\t\t\t\treturn  ( r && r[1])? parseInt(r[1]) : 0;
\t\t\t}
\t\t}
\t\tthis.css('transform', 
\t\t\tthis.css('transform').replace(/none|rotate\\(.*?\\)/, '') + 'rotate(' + parseInt(val) + 'deg)');
\t\treturn this;
\t};

\t\$.fx.step.rotate  = function(fx) {
\t\tif ( fx.state == 0 ) {
\t\t\tfx.start = \$(fx.elem).rotate();
\t\t\tfx.now = fx.start;
\t\t}
\t\t\$(fx.elem).rotate(fx.now);
\t};

\tif (typeof window.addEventListener == \"undefined\" && typeof document.getElementsByClassName == \"undefined\") { // IE & IE<9
\t\tvar GetAbsoluteXY = function(element) {
\t\t\tvar pnode = element;
\t\t\tvar x = pnode.offsetLeft;
\t\t\tvar y = pnode.offsetTop;
\t\t\t
\t\t\twhile ( pnode.offsetParent ) {
\t\t\t\tpnode = pnode.offsetParent;
\t\t\t\tif (pnode != document.body && pnode.currentStyle['position'] != 'static') {
\t\t\t\t\tbreak;
\t\t\t\t}
\t\t\t\tif (pnode != document.body && pnode != document.documentElement) {
\t\t\t\t\tx -= pnode.scrollLeft;
\t\t\t\t\ty -= pnode.scrollTop;
\t\t\t\t}
\t\t\t\tx += pnode.offsetLeft;
\t\t\t\ty += pnode.offsetTop;
\t\t\t}
\t\t\t
\t\t\treturn { x: x, y: y };
\t\t};
\t\t
\t\tvar StaticToAbsolute = function (element) {
\t\t\tif ( element.currentStyle['position'] != 'static') {
\t\t\t\treturn ;
\t\t\t}

\t\t\tvar xy = GetAbsoluteXY(element);
\t\t\telement.style.position = 'absolute' ;
\t\t\telement.style.left = xy.x + 'px';
\t\t\telement.style.top = xy.y + 'px';
\t\t};

\t\tvar IETransform = function(element,transform){

\t\t\tvar r;
\t\t\tvar m11 = 1;
\t\t\tvar m12 = 1;
\t\t\tvar m21 = 1;
\t\t\tvar m22 = 1;

\t\t\tif (typeof element.style['msTransform'] != 'undefined'){
\t\t\t\treturn true;
\t\t\t}

\t\t\tStaticToAbsolute(element);

\t\t\tr = transform.match(/rotate\\((.*?)\\)/);
\t\t\tvar rotate =  ( r && r[1])\t?\tparseInt(r[1])\t:\t0;

\t\t\trotate = rotate % 360;
\t\t\tif (rotate < 0) rotate = 360 + rotate;

\t\t\tvar radian= rotate * Math.PI / 180;
\t\t\tvar cosX =Math.cos(radian);
\t\t\tvar sinY =Math.sin(radian);

\t\t\tm11 *= cosX;
\t\t\tm12 *= -sinY;
\t\t\tm21 *= sinY;
\t\t\tm22 *= cosX;

\t\t\telement.style.filter =  (element.style.filter || '').replace(/progid:DXImageTransform\\.Microsoft\\.Matrix\\([^)]*\\)/, \"\" ) +
\t\t\t\t(\"progid:DXImageTransform.Microsoft.Matrix(\" + 
\t\t\t\t\t \"M11=\" + m11 + 
\t\t\t\t\t\",M12=\" + m12 + 
\t\t\t\t\t\",M21=\" + m21 + 
\t\t\t\t\t\",M22=\" + m22 + 
\t\t\t\t\t\",FilterType='bilinear',sizingMethod='auto expand')\") 
\t\t\t\t;

\t  \t\tvar ow = parseInt(element.style.width || element.width || 0 );
\t  \t\tvar oh = parseInt(element.style.height || element.height || 0 );

\t\t\tradian = rotate * Math.PI / 180;
\t\t\tvar absCosX =Math.abs(Math.cos(radian));
\t\t\tvar absSinY =Math.abs(Math.sin(radian));

\t\t\tvar dx = (ow - (ow * absCosX + oh * absSinY)) / 2;
\t\t\tvar dy = (oh - (ow * absSinY + oh * absCosX)) / 2;

\t\t\telement.style.marginLeft = Math.floor(dx) + \"px\";
\t\t\telement.style.marginTop  = Math.floor(dy) + \"px\";

\t\t\treturn(true);
\t\t};
\t\t
\t\tvar transform_set = \$.cssHooks.transform.set;
\t\t\$.cssHooks.transform.set = function(elem, value) {
\t\t\ttransform_set.apply(this, [elem, value] );
\t\t\tIETransform(elem,value);
\t\t\treturn value;
\t\t};
\t}

})(jQuery);


/*
 * File: /js/commands/restore.js
 */

/**
 * @class  elFinder command \"restore\"
 * Restore items from the trash
 *
 * @author Naoki Sawada
 **/
(elFinder.prototype.commands.restore = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm = this.fm,
\t\tfakeCnt = 0,
\t\tgetFilesRecursively = function(files) {
\t\t\tvar dfd = \$.Deferred(),
\t\t\t\tdirs = [],
\t\t\t\tresults = [],
\t\t\t\treqs = [],
\t\t\t\tphashes = [],
\t\t\t\tgetFile;
\t\t\t
\t\t\tdfd._xhrReject = function() {
\t\t\t\t\$.each(reqs, function() {
\t\t\t\t\tthis && this.reject && this.reject();
\t\t\t\t});
\t\t\t\tgetFile && getFile._xhrReject();
\t\t\t};
\t\t\t
\t\t\t\$.each(files, function(i, f) {
\t\t\t\tf.mime === 'directory'? dirs.push(f) : results.push(f);
\t\t\t});
\t\t\t
\t\t\tif (dirs.length) {
\t\t\t\t\$.each(dirs, function(i, d) {
\t\t\t\t\treqs.push(fm.request({
\t\t\t\t\t\tdata : {cmd  : 'open', target : d.hash},
\t\t\t\t\t\tpreventDefault : true,
\t\t\t\t\t\tasNotOpen : true
\t\t\t\t\t}));
\t\t\t\t\tphashes[i] = d.hash;
\t\t\t\t});
\t\t\t\t\$.when.apply(\$, reqs).fail(function() {
\t\t\t\t\tdfd.reject();
\t\t\t\t}).done(function() {
\t\t\t\t\tvar items = [];
\t\t\t\t\t\$.each(arguments, function(i, r) {
\t\t\t\t\t\tvar files;
\t\t\t\t\t\tif (r.files) {
\t\t\t\t\t\t\tif (r.files.length) {
\t\t\t\t\t\t\t\titems = items.concat(r.files);
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\titems.push({
\t\t\t\t\t\t\t\t\thash: 'fakefile_' + (fakeCnt++),
\t\t\t\t\t\t\t\t\tphash: phashes[i],
\t\t\t\t\t\t\t\t\tmime: 'fakefile',
\t\t\t\t\t\t\t\t\tname: 'fakefile',
\t\t\t\t\t\t\t\t\tts: 0
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tfm.cache(items);
\t\t\t\t\tgetFile = getFilesRecursively(items).done(function(res) {
\t\t\t\t\t\tresults = results.concat(res);
\t\t\t\t\t\tdfd.resolve(results);
\t\t\t\t\t});
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfd.resolve(results);
\t\t\t}
\t\t\t
\t\t\treturn dfd;
\t\t},
\t\trestore = function(dfrd, files, targets, ops) {
\t\t\tvar rHashes = {},
\t\t\t\tothers = [],
\t\t\t\tfound = false,
\t\t\t\tdirs = [],
\t\t\t\topts = ops || {},
\t\t\t\tid = +new Date(),
\t\t\t\ttm, getFile;
\t\t\t
\t\t\tfm.lockfiles({files : targets});
\t\t\t
\t\t\tdirs = \$.map(files, function(f) {
\t\t\t\treturn f.mime === 'directory'? f.hash : null;
\t\t\t});
\t\t\t
\t\t\tdfrd.done(function() {
\t\t\t\tdirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
\t\t\t}).always(function() {
\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t});
\t\t\t
\t\t\ttm = setTimeout(function() {
\t\t\t\tfm.notify({type : 'search', id : id, cnt : 1, hideCnt : true, cancel : function() {
\t\t\t\t\tgetFile && getFile._xhrReject();
\t\t\t\t\tdfrd.reject();
\t\t\t\t}});
\t\t\t}, fm.notifyDelay);

\t\t\tfakeCnt = 0;
\t\t\tgetFile = getFilesRecursively(files).always(function() {
\t\t\t\ttm && clearTimeout(tm);
\t\t\t\tfm.notify({type : 'search', id: id, cnt : -1, hideCnt : true});
\t\t\t}).fail(function() {
\t\t\t\tdfrd.reject('errRestore', 'errFileNotFound');
\t\t\t}).done(function(res) {
\t\t\t\tvar errFolderNotfound = ['errRestore', 'errFolderNotFound'],
\t\t\t\t\tdirTop = '';
\t\t\t\t
\t\t\t\tif (res.length) {
\t\t\t\t\t\$.each(res, function(i, f) {
\t\t\t\t\t\tvar phash = f.phash,
\t\t\t\t\t\t\tpfile,
\t\t\t\t\t\t\tsrcRoot, tPath;
\t\t\t\t\t\twhile(phash) {
\t\t\t\t\t\t\tif (srcRoot = fm.trashes[phash]) {
\t\t\t\t\t\t\t\tif (! rHashes[srcRoot]) {
\t\t\t\t\t\t\t\t\tif (found) {
\t\t\t\t\t\t\t\t\t\t// Keep items of other trash
\t\t\t\t\t\t\t\t\t\tothers.push(f.hash);
\t\t\t\t\t\t\t\t\t\treturn null; // continue \$.each
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\trHashes[srcRoot] = {};
\t\t\t\t\t\t\t\t\tfound = true;
\t\t\t\t\t\t\t\t}
\t\t
\t\t\t\t\t\t\t\ttPath = fm.path(f.hash).substr(fm.path(phash).length).replace(/\\\\/g, '/');
\t\t\t\t\t\t\t\ttPath = tPath.replace(/\\/[^\\/]+?\$/, '');
\t\t\t\t\t\t\t\tif (tPath === '') {
\t\t\t\t\t\t\t\t\ttPath = '/';
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (!rHashes[srcRoot][tPath]) {
\t\t\t\t\t\t\t\t\trHashes[srcRoot][tPath] = [];
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (f.mime === 'fakefile') {
\t\t\t\t\t\t\t\t\tfm.updateCache({removed:[f.hash]});
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\trHashes[srcRoot][tPath].push(f.hash);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (!dirTop || dirTop.length > tPath.length) {
\t\t\t\t\t\t\t\t\tdirTop = tPath;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tbreak;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t
\t\t\t\t\t\t\t// Go up one level for next check
\t\t\t\t\t\t\tpfile = fm.file(phash);
\t\t\t\t\t\t\t
\t\t\t\t\t\t\tif (!pfile) {
\t\t\t\t\t\t\t\tphash = false;
\t\t\t\t\t\t\t\t// Detection method for search results
\t\t\t\t\t\t\t\t\$.each(fm.trashes, function(ph) {
\t\t\t\t\t\t\t\t\tvar file = fm.file(ph),
\t\t\t\t\t\t\t\t\t\tfilePath = fm.path(ph);
\t\t\t\t\t\t\t\t\tif ((!file.volumeid || f.hash.indexOf(file.volumeid) === 0) && fm.path(f.hash).indexOf(filePath) === 0) {
\t\t\t\t\t\t\t\t\t\tphash = ph;
\t\t\t\t\t\t\t\t\t\treturn false;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tphash = pfile.phash;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\tif (found) {
\t\t\t\t\t\t\$.each(rHashes, function(src, dsts) {
\t\t\t\t\t\t\tvar dirs = Object.keys(dsts),
\t\t\t\t\t\t\t\tcnt = dirs.length;
\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\tdata   : {cmd  : 'mkdir', target : src, dirs : dirs}, 
\t\t\t\t\t\t\t\tnotify : {type : 'chkdir', cnt : cnt},
\t\t\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t\t\t}).fail(function(error) {
\t\t\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t\t\t\t}).done(function(data) {
\t\t\t\t\t\t\t\tvar cmdPaste, hashes;
\t\t\t\t\t\t\t\t
\t\t\t\t\t\t\t\tif (hashes = data.hashes) {
\t\t\t\t\t\t\t\t\tcmdPaste = fm.getCommand('paste');
\t\t\t\t\t\t\t\t\tif (cmdPaste) {
\t\t\t\t\t\t\t\t\t\t// wait until file cache made
\t\t\t\t\t\t\t\t\t\tfm.one('mkdirdone', function() {
\t\t\t\t\t\t\t\t\t\t\tvar hasErr = false;
\t\t\t\t\t\t\t\t\t\t\t\$.each(dsts, function(dir, files) {
\t\t\t\t\t\t\t\t\t\t\t\tif (hashes[dir]) {
\t\t\t\t\t\t\t\t\t\t\t\t\tif (files.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (fm.file(hashes[dir])) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.clipboard(files, true);
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('paste', [ hashes[dir] ], {_cmd : 'restore', noToast : (opts.noToast || dir !== dirTop)})
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (data && (data.error || data.warning)) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thasErr = true;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.fail(function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\thasErr = true;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (--cnt < 1) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd[hasErr? 'reject' : 'resolve']();
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (others.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Restore items of other trash
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('restore', others);
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject(errFolderNotfound);
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (--cnt < 1) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.resolve();
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (others.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Restore items of other trash
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('restore', others);
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tdfrd.reject(['errRestore', 'errCmdNoSupport', '(paste)']);
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tdfrd.reject(errFolderNotfound);
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t});
\t\t\t\t\t} else {
\t\t\t\t\t\tdfrd.reject(errFolderNotfound);
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tdfrd.reject('errFileNotFound');
\t\t\t\t\tdirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
\t\t\t\t}
\t\t\t});
\t\t};
\t
\t// for to be able to overwrite
\tthis.restore = restore;

\tthis.linkedCmds = ['copy', 'paste', 'mkdir', 'rm'];
\tthis.updateOnSelect = false;
\t
\tthis.init = function() {
\t\t// re-assign for extended command
\t\tself = this;
\t\tfm = this.fm;
\t};

\tthis.getstate = function(sel, e) {
\t\tsel = sel || fm.selected();
\t\treturn sel.length && \$.grep(sel, function(h) {var f = fm.file(h); return f && ! f.locked && ! fm.isRoot(f)? true : false; }).length == sel.length
\t\t\t? 0 : -1;
\t};
\t
\tthis.exec = function(hashes, opts) {
\t\tvar dfrd   = \$.Deferred()
\t\t\t\t.fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t}),
\t\t\tfiles  = self.files(hashes);

\t\tif (! files.length) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\t\$.each(files, function(i, file) {
\t\t\tif (fm.isRoot(file)) {
\t\t\t\treturn !dfrd.reject(['errRestore', file.name]);
\t\t\t}
\t\t\tif (file.locked) {
\t\t\t\treturn !dfrd.reject(['errLocked', file.name]);
\t\t\t}
\t\t});

\t\tif (dfrd.state() === 'pending') {
\t\t\tthis.restore(dfrd, files, hashes, opts);
\t\t}
\t\t\t
\t\treturn dfrd;
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/rm.js
 */

/**
 * @class  elFinder command \"rm\"
 * Delete files
 *
 * @author Dmitry (dio) Levashov
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.rm = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm = this.fm,
\t\ttpl = '<div class=\"ui-helper-clearfix elfinder-rm-title\"><span class=\"elfinder-cwd-icon {class} ui-corner-all\"></span>{title}<div class=\"elfinder-rm-desc\">{desc}</div></div>',
\t\tconfirm = function(dfrd, targets, files, tHash, addTexts) {
\t\t\tvar cnt = targets.length,
\t\t\t\tcwd = fm.cwd().hash,
\t\t\t\tdescs = [],
\t\t\t\tspinner = fm.i18n('calc') + '<span class=\"elfinder-spinner\"></span>',
\t\t\t\tdialog, text, tmb, size, f, fname;
\t\t\t
\t\t\tif (cnt > 1) {
\t\t\t\tsize = 0;
\t\t\t\t\$.each(files, function(h, f) { 
\t\t\t\t\tif (f.size && f.size != 'unknown' && f.mime !== 'directory') {
\t\t\t\t\t\tvar s = parseInt(f.size);
\t\t\t\t\t\tif (s >= 0 && size >= 0) {
\t\t\t\t\t\t\tsize += s;
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tsize = 'unknown';
\t\t\t\t\t\treturn false;
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\tgetSize = (size === 'unknown');
\t\t\t\tdescs.push(fm.i18n('size')+': '+(getSize? spinner : fm.formatSize(size)));
\t\t\t\ttext = [\$(tpl.replace('{class}', 'elfinder-cwd-icon-group').replace('{title}', '<strong>' + fm.i18n('items')+ ': ' + cnt + '</strong>').replace('{desc}', descs.join('<br>')))];
\t\t\t} else {
\t\t\t\tf = files[0];
\t\t\t\ttmb = fm.tmb(f);
\t\t\t\tgetSize = (f.mime === 'directory');
\t\t\t\tdescs.push(fm.i18n('size')+': '+(getSize? spinner : fm.formatSize(f.size)));
\t\t\t\tdescs.push(fm.i18n('modify')+': '+fm.formatDate(f));
\t\t\t\tfname = fm.escape(f.i18 || f.name).replace(/([_.])/g, '&#8203;\$1');
\t\t\t\ttext = [\$(tpl.replace('{class}', fm.mime2class(f.mime)).replace('{title}', '<strong>' + fname + '</strong>').replace('{desc}', descs.join('<br>')))];
\t\t\t}
\t\t\t
\t\t\tif (addTexts) {
\t\t\t\ttext = text.concat(addTexts);
\t\t\t}
\t\t\t
\t\t\ttext.push(tHash? 'confirmTrash' : 'confirmRm');
\t\t\t
\t\t\tdialog = fm.confirm({
\t\t\t\ttitle  : self.title,
\t\t\t\ttext   : text,
\t\t\t\taccept : {
\t\t\t\t\tlabel    : 'btnRm',
\t\t\t\t\tcallback : function() {  
\t\t\t\t\t\tif (tHash) {
\t\t\t\t\t\t\tself.toTrash(dfrd, targets, tHash);
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tremove(dfrd, targets);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t},
\t\t\t\tcancel : {
\t\t\t\t\tlabel    : 'btnCancel',
\t\t\t\t\tcallback : function() {
\t\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t\t\tif (targets.length === 1 && fm.file(targets[0]).phash !== cwd) {
\t\t\t\t\t\t\tfm.select({selected : targets});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tfm.selectfiles({files : targets});
\t\t\t\t\t\t}
\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\t// load thumbnail
\t\t\tif (tmb) {
\t\t\t\t\$('<img/>')
\t\t\t\t\t.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', \"url('\"+tmb.url+\"')\"); })
\t\t\t\t\t.attr('src', tmb.url);
\t\t\t}
\t\t\t
\t\t\tif (getSize) {
\t\t\t\tgetSize = fm.getSize(\$.map(files, function(f) { return f.mime === 'directory'? f.hash : null; })).done(function(data) {
\t\t\t\t\tdialog.find('span.elfinder-spinner').parent().html(fm.i18n('size')+': '+data.formated);
\t\t\t\t}).fail(function() {
\t\t\t\t\tdialog.find('span.elfinder-spinner').parent().html(fm.i18n('size')+': '+fm.i18n('unknown'));
\t\t\t\t}).always(function() {
\t\t\t\t\tgetSize = false;
\t\t\t\t});
\t\t\t}
\t\t},
\t\ttoTrash = function(dfrd, targets, tHash) {
\t\t\tvar dsts = {},
\t\t\t\titemCnt = targets.length,
\t\t\t\tmaxCnt = self.options.toTrashMaxItems,
\t\t\t\tcheckDirs = [],
\t\t\t\treqDfd = \$.Deferred(),
\t\t\t\treq, dirs, cnt;
\t\t\t
\t\t\tif (itemCnt > maxCnt) {
\t\t\t\tself.confirm(dfrd, targets, self.files(targets), null, [fm.i18n('tooManyToTrash')]);
\t\t\t\treturn;
\t\t\t}
\t\t\t
\t\t\t// Directory preparation preparation and directory enumeration
\t\t\t\$.each(targets, function(i, h) {
\t\t\t\tvar file = fm.file(h),
\t\t\t\t\tpath = fm.path(h).replace(/\\\\/g, '/'),
\t\t\t\t\tm = path.match(/^[^\\/]+?(\\/(?:[^\\/]+?\\/)*)[^\\/]+?\$/);
\t\t\t\t
\t\t\t\tif (file) {
\t\t\t\t\tif (m) {
\t\t\t\t\t\tm[1] = m[1].replace(/(^\\/.*?)\\/?\$/, '\$1');
\t\t\t\t\t\tif (! dsts[m[1]]) {
\t\t\t\t\t\t\tdsts[m[1]] = [];
\t\t\t\t\t\t}
\t\t\t\t\t\tdsts[m[1]].push(h);
\t\t\t\t\t}
\t\t\t\t\tif (file.mime === 'directory') {
\t\t\t\t\t\tcheckDirs.push(h);
\t\t\t\t\t}
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\t// Check directory information
\t\t\tif (checkDirs.length) {
\t\t\t\treq = fm.request({
\t\t\t\t\tdata : {cmd : 'size', targets : checkDirs},
\t\t\t\t\tnotify : {type: 'readdir', cnt: 1, hideCnt: true},
\t\t\t\t\tpreventDefault : true
\t\t\t\t}).done(function(data) {
\t\t\t\t\tvar cnt = 0;
\t\t\t\t\tdata.fileCnt && (cnt += parseInt(data.fileCnt));
\t\t\t\t\tdata.dirCnt && (cnt += parseInt(data.dirCnt));
\t\t\t\t\treqDfd[cnt > maxCnt ? 'reject' : 'resolve']();
\t\t\t\t}).fail(function() {
\t\t\t\t\treqDfd.reject();
\t\t\t\t});
\t\t\t\tsetTimeout(function() {
\t\t\t\t\tvar xhr = (req && req.xhr)? req.xhr : null;
\t\t\t\t\tif (xhr && xhr.state() == 'pending') {
\t\t\t\t\t\treq.syncOnFail(false);
\t\t\t\t\t\treq.reject();
\t\t\t\t\t\treqDfd.reject();
\t\t\t\t\t}
\t\t\t\t}, self.options.infoCheckWait * 1000);
\t\t\t} else {
\t\t\t\treqDfd.resolve();
\t\t\t}
\t\t\t
\t\t\t// Directory creation and paste command execution
\t\t\treqDfd.done(function() {
\t\t\t\tdirs = Object.keys(dsts);
\t\t\t\tcnt = dirs.length;
\t\t\t\tif (cnt) {
\t\t\t\t\tfm.request({
\t\t\t\t\t\tdata   : {cmd  : 'mkdir', target : tHash, dirs : dirs}, 
\t\t\t\t\t\tnotify : {type : 'chkdir', cnt : cnt},
\t\t\t\t\t\tpreventFail : true
\t\t\t\t\t})
\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tvar margeRes = function(data, phash, reqData) {
\t\t\t\t\t\t\t\tvar undo, prevUndo, redo, prevRedo;
\t\t\t\t\t\t\t\t\$.each(data, function(k, v) {
\t\t\t\t\t\t\t\t\tif (Array.isArray(v)) {
\t\t\t\t\t\t\t\t\t\tif (res[k]) {
\t\t\t\t\t\t\t\t\t\t\tres[k] = res[k].concat(v);
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tres[k] = v;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\tif (data.sync) {
\t\t\t\t\t\t\t\t\tres.sync = 1;
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tif (data.added && data.added.length) {
\t\t\t\t\t\t\t\t\tundo = function() {
\t\t\t\t\t\t\t\t\t\tvar targets = [],
\t\t\t\t\t\t\t\t\t\t\tdirs    = \$.map(data.added, function(f) { return f.mime === 'directory'? f.hash : null; });
\t\t\t\t\t\t\t\t\t\t\$.each(data.added, function(i, f) {
\t\t\t\t\t\t\t\t\t\t\tif (\$.inArray(f.phash, dirs) === -1) {
\t\t\t\t\t\t\t\t\t\t\t\ttargets.push(f.hash);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\treturn fm.exec('restore', targets, {noToast: true});
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\tredo = function() {
\t\t\t\t\t\t\t\t\t\treturn fm.request({
\t\t\t\t\t\t\t\t\t\t\tdata   : reqData,
\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'redo', cnt : targets.length}
\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\tif (res.undo) {
\t\t\t\t\t\t\t\t\t\tprevUndo = res.undo;
\t\t\t\t\t\t\t\t\t\tres.undo = function() {
\t\t\t\t\t\t\t\t\t\t\tundo();
\t\t\t\t\t\t\t\t\t\t\tprevUndo();
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tres.undo = undo;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\tif (res.redo) {
\t\t\t\t\t\t\t\t\t\tprevRedo = res.redo;
\t\t\t\t\t\t\t\t\t\tres.redo = function() {
\t\t\t\t\t\t\t\t\t\t\tredo();
\t\t\t\t\t\t\t\t\t\t\tprevRedo();
\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\tres.redo = redo;
\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\terr = ['errTrash'],
\t\t\t\t\t\t\tres = {},
\t\t\t\t\t\t\thasNtf = function() {
\t\t\t\t\t\t\t\treturn fm.ui.notify.children('.elfinder-notify-trash').length;
\t\t\t\t\t\t\t},
\t\t\t\t\t\t\thashes, tm, prg, prgSt;
\t\t\t\t\t\t
\t\t\t\t\t\tif (hashes = data.hashes) {
\t\t\t\t\t\t\tprg = 1 / cnt * 100;
\t\t\t\t\t\t\tprgSt = cnt === 1? 100 : 5;
\t\t\t\t\t\t\ttm = setTimeout(function() {
\t\t\t\t\t\t\t\tfm.notify({type : 'trash', cnt : 1, hideCnt : true, progress : prgSt});
\t\t\t\t\t\t\t}, fm.notifyDelay);
\t\t\t\t\t\t\t\$.each(dsts, function(dir, files) {
\t\t\t\t\t\t\t\tvar phash = fm.file(files[0]).phash,
\t\t\t\t\t\t\t\t\treqData;
\t\t\t\t\t\t\t\tif (hashes[dir]) {
\t\t\t\t\t\t\t\t\treqData = {cmd : 'paste', dst : hashes[dir], targets : files, cut : 1};
\t\t\t\t\t\t\t\t\tfm.request({
\t\t\t\t\t\t\t\t\t\tdata : reqData,
\t\t\t\t\t\t\t\t\t\tpreventDefault : true
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\t\t\t\t\tif (error) {
\t\t\t\t\t\t\t\t\t\t\terr = err.concat(error);
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\t\t\t\t\tdata = fm.normalize(data);
\t\t\t\t\t\t\t\t\t\tfm.updateCache(data);
\t\t\t\t\t\t\t\t\t\tmargeRes(data, phash, reqData);
\t\t\t\t\t\t\t\t\t\tif (data.warning) {
\t\t\t\t\t\t\t\t\t\t\terr = err.concat(data.warning);
\t\t\t\t\t\t\t\t\t\t\tdelete data.warning;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t// fire some event to update cache/ui
\t\t\t\t\t\t\t\t\t\tdata.removed && data.removed.length && fm.remove(data);
\t\t\t\t\t\t\t\t\t\tdata.added   && data.added.length   && fm.add(data);
\t\t\t\t\t\t\t\t\t\tdata.changed && data.changed.length && fm.change(data);
\t\t\t\t\t\t\t\t\t\t// fire event with command name
\t\t\t\t\t\t\t\t\t\tfm.trigger('paste', data);
\t\t\t\t\t\t\t\t\t\t// fire event with command name + 'done'
\t\t\t\t\t\t\t\t\t\tfm.trigger('pastedone');
\t\t\t\t\t\t\t\t\t\t// force update content
\t\t\t\t\t\t\t\t\t\tdata.sync && fm.sync();
\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t.always(function() {
\t\t\t\t\t\t\t\t\t\tvar hashes = [], addTexts, end = 2;
\t\t\t\t\t\t\t\t\t\tif (hasNtf()) {
\t\t\t\t\t\t\t\t\t\t\tfm.notify({type : 'trash', cnt : 0, hideCnt : true, progress : prg});
\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\tprgSt+= prg;
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\tif (--cnt < 1) {
\t\t\t\t\t\t\t\t\t\t\ttm && clearTimeout(tm);
\t\t\t\t\t\t\t\t\t\t\thasNtf() && fm.notify({type : 'trash', cnt  : -1});
\t\t\t\t\t\t\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t\t\t\t\t\t\t\tif (Object.keys(res).length) {
\t\t\t\t\t\t\t\t\t\t\t\tif (err.length > 1) {
\t\t\t\t\t\t\t\t\t\t\t\t\tif (res.removed || res.removed.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\thashes = \$.grep(targets, function(h) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn \$.inArray(h, res.removed) === -1? true : false;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\tif (hashes.length) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (err.length > end) {
\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tend = (fm.messages[err[end-1]] || '').indexOf('\$') === -1? end : end + 1;
\t\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.exec('rm', hashes, { addTexts: err.slice(0, end), forceRm: true });
\t\t\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tfm.error(err);
\t\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\tres._noSound = true;
\t\t\t\t\t\t\t\t\t\t\t\tif (res.undo && res.redo) {
\t\t\t\t\t\t\t\t\t\t\t\t\tres.undo = {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcmd : 'trash',
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcallback : res.undo,
\t\t\t\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\t\t\t\tres.redo = {
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcmd : 'trash',
\t\t\t\t\t\t\t\t\t\t\t\t\t\tcallback : res.redo
\t\t\t\t\t\t\t\t\t\t\t\t\t};
\t\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t\t\tdfrd.resolve(res);
\t\t\t\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\t\t\t\tdfrd.reject(err);
\t\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t});
\t\t\t\t\t\t} else {
\t\t\t\t\t\t\tdfrd.reject('errFolderNotFound');
\t\t\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\tdfrd.reject(['error', 'The folder hierarchy to be deleting can not be determined.']);
\t\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t\t}
\t\t\t}).fail(function() {
\t\t\t\tself.confirm(dfrd, targets, self.files(targets), null, [fm.i18n('tooManyToTrash')]);
\t\t\t});
\t\t},
\t\tremove = function(dfrd, targets, quiet) {
\t\t\tvar notify = quiet? {} : {type : 'rm', cnt : targets.length};
\t\t\tfm.request({
\t\t\t\tdata   : {cmd  : 'rm', targets : targets}, 
\t\t\t\tnotify : notify,
\t\t\t\tpreventFail : true
\t\t\t})
\t\t\t.fail(function(error) {
\t\t\t\tdfrd.reject(error);
\t\t\t})
\t\t\t.done(function(data) {
\t\t\t\tif (data.error || data.warning) {
\t\t\t\t\tdata.sync = true;
\t\t\t\t}
\t\t\t\tdfrd.resolve(data);
\t\t\t})
\t\t\t.always(function() {
\t\t\t\tfm.unlockfiles({files : targets});
\t\t\t});
\t\t},
\t\tgetTHash = function(targets) {
\t\t\tvar thash = null,
\t\t\t\troot1st;
\t\t\t
\t\t\tif (targets && targets.length) {
\t\t\t\tif (targets.length > 1 && fm.searchStatus.state === 2) {
\t\t\t\t\troot1st = fm.file(fm.root(targets[0])).volumeid;
\t\t\t\t\tif (!\$.grep(targets, function(h) { return h.indexOf(root1st) !== 0? true : false ; }).length) {
\t\t\t\t\t\tthash = fm.option('trashHash', targets[0]);
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tthash = fm.option('trashHash', targets[0]);
\t\t\t\t}
\t\t\t}
\t\t\treturn thash;
\t\t},
\t\tgetSize = false;
\t
\t// for to be able to overwrite
\tthis.confirm = confirm;
\tthis.toTrash = toTrash;
\tthis.remove = remove;

\tthis.syncTitleOnChange = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts = [{
\t\tpattern     : 'delete ctrl+backspace shift+delete'
\t}];
\tthis.value = 'rm';
\t
\tthis.init = function() {
\t\t// re-assign for extended command
\t\tself = this;
\t\tfm = this.fm;
\t\t// bind function of change
\t\tself.change(function() {
\t\t\tvar targets;
\t\t\tdelete self.extra;
\t\t\tself.title = fm.i18n('cmd' + self.value);
\t\t\tself.className = self.value;
\t\t\tself.button && self.button.children('span.elfinder-button-icon')[self.value === 'trash'? 'addClass' : 'removeClass']('elfinder-button-icon-trash');
\t\t\tif (self.value === 'trash') {
\t\t\t\tself.extra = {
\t\t\t\t\ticon: 'rm',
\t\t\t\t\tnode: \$('<span></span>')
\t\t\t\t\t\t.attr({title: fm.i18n('cmdrm')})
\t\t\t\t\t\t.on('ready', function(e, data) {
\t\t\t\t\t\t\ttargets = data.targets;
\t\t\t\t\t\t})
\t\t\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\t\tfm.getUI().trigger('click'); // to close the context menu immediately
\t\t\t\t\t\t\tfm.exec('rm', targets, {_userAction: true, forceRm : true});
\t\t\t\t\t\t})
\t\t\t\t};
\t\t\t}
\t\t});
\t};
\t
\tthis.getstate = function(select) {
\t\tvar sel   = this.hashes(select);
\t\t
\t\treturn sel.length && \$.grep(sel, function(h) { var f = fm.file(h); return f && ! f.locked && ! fm.isRoot(f)? true : false; }).length == sel.length
\t\t\t? 0 : -1;
\t};
\t
\tthis.exec = function(hashes, cOpts) {
\t\tvar opts   = cOpts || {},
\t\t\tdfrd   = \$.Deferred()
\t\t\t\t.always(function() {
\t\t\t\t\tif (getSize && getSize.state && getSize.state() === 'pending') {
\t\t\t\t\t\tgetSize.reject();
\t\t\t\t\t}
\t\t\t\t})
\t\t\t\t.fail(function(error) {
\t\t\t\t\terror && fm.error(error);
\t\t\t\t}).done(function(data) {
\t\t\t\t\t!opts.quiet && !data._noSound && data.removed && data.removed.length && fm.trigger('playsound', {soundFile : 'rm.wav'});
\t\t\t\t}),
\t\t\tfiles  = self.files(hashes),
\t\t\tcnt    = files.length,
\t\t\ttHash  = null,
\t\t\taddTexts = opts.addTexts? opts.addTexts : null,
\t\t\tforceRm = opts.forceRm,
\t\t\tquiet = opts.quiet,
\t\t\ttargets;

\t\tif (! cnt) {
\t\t\treturn dfrd.reject();
\t\t}
\t\t
\t\t\$.each(files, function(i, file) {
\t\t\tif (fm.isRoot(file)) {
\t\t\t\treturn !dfrd.reject(['errRm', file.name, 'errPerm']);
\t\t\t}
\t\t\tif (file.locked) {
\t\t\t\treturn !dfrd.reject(['errLocked', file.name]);
\t\t\t}
\t\t});

\t\tif (dfrd.state() === 'pending') {
\t\t\ttargets = self.hashes(hashes);
\t\t\tcnt     = files.length;
\t\t\t
\t\t\tif (forceRm || (self.event && self.event.originalEvent && self.event.originalEvent.shiftKey)) {
\t\t\t\ttHash = '';
\t\t\t\tself.title = fm.i18n('cmdrm');
\t\t\t}
\t\t\t
\t\t\tif (tHash === null) {
\t\t\t\ttHash = getTHash(targets);
\t\t\t}
\t\t\t
\t\t\tfm.lockfiles({files : targets});
\t\t\t
\t\t\tif (tHash && self.options.quickTrash) {
\t\t\t\tself.toTrash(dfrd, targets, tHash);
\t\t\t} else {
\t\t\t\tif (quiet) {
\t\t\t\t\tremove(dfrd, targets, quiet);
\t\t\t\t} else {
\t\t\t\t\tself.confirm(dfrd, targets, files, tHash, addTexts);
\t\t\t\t}
\t\t\t}
\t\t}
\t\t\t
\t\treturn dfrd;
\t};

\tfm.bind('select contextmenucreate closecontextmenu', function(e) {
\t\tvar targets = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
\t\tif (targets && targets.length) {
\t\t\tself.update(void(0), (targets? getTHash(targets) : fm.option('trashHash'))? 'trash' : 'rm');
\t\t}
\t});

};


/*
 * File: /js/commands/search.js
 */

/**
 * @class  elFinder command \"search\"
 * Find files
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.search = function() {
\t\"use strict\";
\tthis.title          = 'Find files';
\tthis.options        = {ui : 'searchbutton'};
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\t
\t/**
\t * Return command status.
\t * Search does not support old api.
\t *
\t * @return Number
\t **/
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\t/**
\t * Send search request to backend.
\t *
\t * @param  String  search string
\t * @return \$.Deferred
\t **/
\tthis.exec = function(q, target, mime, type) {
\t\tvar fm = this.fm,
\t\t\treqDef = [],
\t\t\tsType = type || '',
\t\t\tonlyMimes = fm.options.onlyMimes,
\t\t\tphash, targetVolids = [],
\t\t\tsetType = function(data) {
\t\t\t\tif (sType && sType !== 'SearchName' && sType !== 'SearchMime') {
\t\t\t\t\tdata.type = sType;
\t\t\t\t}
\t\t\t\treturn data;
\t\t\t},
\t\t\trootCnt;
\t\t
\t\tif (typeof q == 'string' && q) {
\t\t\tif (typeof target == 'object') {
\t\t\t\tmime = target.mime || '';
\t\t\t\ttarget = target.target || '';
\t\t\t}
\t\t\ttarget = target? target : '';
\t\t\tif (mime) {
\t\t\t\tmime = \$.trim(mime).replace(',', ' ').split(' ');
\t\t\t\tif (onlyMimes.length) {
\t\t\t\t\tmime = \$.map(mime, function(m){ 
\t\t\t\t\t\tm = \$.trim(m);
\t\t\t\t\t\treturn m && (\$.inArray(m, onlyMimes) !== -1
\t\t\t\t\t\t\t\t\t|| \$.grep(onlyMimes, function(om) { return m.indexOf(om) === 0? true : false; }).length
\t\t\t\t\t\t\t\t\t)? m : null;
\t\t\t\t\t});
\t\t\t\t}
\t\t\t} else {
\t\t\t\tmime = [].concat(onlyMimes);
\t\t\t}

\t\t\tfm.trigger('searchstart', setType({query : q, target : target, mimes : mime}));
\t\t\t
\t\t\tif (! onlyMimes.length || mime.length) {
\t\t\t\tif (target === '' && fm.api >= 2.1) {
\t\t\t\t\trootCnt = Object.keys(fm.roots).length;
\t\t\t\t\t\$.each(fm.roots, function(id, hash) {
\t\t\t\t\t\treqDef.push(fm.request({
\t\t\t\t\t\t\tdata   : setType({cmd : 'search', q : q, target : hash, mimes : mime}),
\t\t\t\t\t\t\tnotify : {type : 'search', cnt : 1, hideCnt : (rootCnt > 1? false : true)},
\t\t\t\t\t\t\tcancel : true,
\t\t\t\t\t\t\tpreventDone : true
\t\t\t\t\t\t}));
\t\t\t\t\t});
\t\t\t\t} else {
\t\t\t\t\treqDef.push(fm.request({
\t\t\t\t\t\tdata   : setType({cmd : 'search', q : q, target : target, mimes : mime}),
\t\t\t\t\t\tnotify : {type : 'search', cnt : 1, hideCnt : true},
\t\t\t\t\t\tcancel : true,
\t\t\t\t\t\tpreventDone : true
\t\t\t\t\t}));
\t\t\t\t\tif (target !== '' && fm.api >= 2.1 && Object.keys(fm.leafRoots).length) {
\t\t\t\t\t\t\$.each(fm.leafRoots, function(hash, roots) {
\t\t\t\t\t\t\tphash = hash;
\t\t\t\t\t\t\twhile(phash) {
\t\t\t\t\t\t\t\tif (target === phash) {
\t\t\t\t\t\t\t\t\t\$.each(roots, function() {
\t\t\t\t\t\t\t\t\t\tvar f = fm.file(this);
\t\t\t\t\t\t\t\t\t\tf && f.volumeid && targetVolids.push(f.volumeid);
\t\t\t\t\t\t\t\t\t\treqDef.push(fm.request({
\t\t\t\t\t\t\t\t\t\t\tdata   : setType({cmd : 'search', q : q, target : this, mimes : mime}),
\t\t\t\t\t\t\t\t\t\t\tnotify : {type : 'search', cnt : 1, hideCnt : false},
\t\t\t\t\t\t\t\t\t\t\tcancel : true,
\t\t\t\t\t\t\t\t\t\t\tpreventDone : true
\t\t\t\t\t\t\t\t\t\t}));
\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tphash = (fm.file(phash) || {}).phash;
\t\t\t\t\t\t\t}
\t\t\t\t\t\t});
\t\t\t\t\t}
\t\t\t\t}
\t\t\t} else {
\t\t\t\treqDef = [\$.Deferred().resolve({files: []})];
\t\t\t}
\t\t\t
\t\t\tfm.searchStatus.mixed = (reqDef.length > 1)? targetVolids : false;
\t\t\t
\t\t\treturn \$.when.apply(\$, reqDef).done(function(data) {
\t\t\t\tvar argLen = arguments.length,
\t\t\t\t\ti;
\t\t\t\t
\t\t\t\tdata.warning && fm.error(data.warning);
\t\t\t\t
\t\t\t\tif (argLen > 1) {
\t\t\t\t\tdata.files = (data.files || []);
\t\t\t\t\tfor(i = 1; i < argLen; i++) {
\t\t\t\t\t\targuments[i].warning && fm.error(arguments[i].warning);
\t\t\t\t\t\t
\t\t\t\t\t\tif (arguments[i].files) {
\t\t\t\t\t\t\tdata.files.push.apply(data.files, arguments[i].files);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\t
\t\t\t\t// because \"preventDone : true\" so update files cache
\t\t\t\tdata.files && data.files.length && fm.cache(data.files);
\t\t\t\t
\t\t\t\tfm.lazy(function() {
\t\t\t\t\tfm.trigger('search', data);
\t\t\t\t}).then(function() {
\t\t\t\t\t// fire event with command name + 'done'
\t\t\t\t\treturn fm.lazy(function() {
\t\t\t\t\t\tfm.trigger('searchdone');
\t\t\t\t\t});
\t\t\t\t}).then(function() {
\t\t\t\t\t// force update content
\t\t\t\t\tdata.sync && fm.sync();
\t\t\t\t});
\t\t\t});
\t\t}
\t\tfm.getUI('toolbar').find('.'+fm.res('class', 'searchbtn')+' :text').trigger('focus');
\t\treturn \$.Deferred().reject();
\t};

};


/*
 * File: /js/commands/selectall.js
 */

/**
 * @class  elFinder command \"selectall\"
 * Select ALL of cwd items
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.selectall = function() {
\t\"use strict\";
\tvar self = this,
\t\tstate = 0;
\t
\tthis.fm.bind('select', function(e) {
\t\tstate = (e.data && e.data.selectall)? -1 : 0;
\t});
\t
\tthis.state = 0;
\tthis.updateOnSelect = false;
\t
\tthis.getstate = function() {
\t\treturn state;
\t};
\t
\tthis.exec = function() {
\t\t\$(document).trigger(\$.Event('keydown', { keyCode: 65, ctrlKey : true, shiftKey : false, altKey : false, metaKey : false }));
\t\treturn \$.Deferred().resolve();
\t};
};


/*
 * File: /js/commands/selectinvert.js
 */

/**
 * @class  elFinder command \"selectinvert\"
 * Invert Selection of cwd items
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.selectinvert = function() {
\t\"use strict\";
\tthis.updateOnSelect = false;
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function() {
\t\t\$(document).trigger(\$.Event('keydown', { keyCode: 73, ctrlKey : true, shiftKey : true, altKey : false, metaKey : false }));
\t\treturn \$.Deferred().resolve();
\t};

};


/*
 * File: /js/commands/selectnone.js
 */

/**
 * @class  elFinder command \"selectnone\"
 * Unselect ALL of cwd items
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.selectnone = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm = this.fm,
\t\tstate = -1;
\t
\tfm.bind('select', function(e) {
\t\tstate = (e.data && e.data.unselectall)? -1 : 0;
\t});
\t
\tthis.state = -1;
\tthis.updateOnSelect = false;
\t
\tthis.getstate = function() {
\t\treturn state;
\t};
\t
\tthis.exec = function() {
\t\tfm.getUI('cwd').trigger('unselectall');
\t\treturn \$.Deferred().resolve();
\t};
};


/*
 * File: /js/commands/sort.js
 */

/**
 * @class  elFinder command \"sort\"
 * Change sort files rule
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.sort = function() {
\t\"use strict\";
\tvar self  = this,
\t\tfm    = self.fm,
\t\tsetVar = function() {
\t\t\tself.variants = [];
\t\t\t\$.each(fm.sortRules, function(name, value) {
\t\t\t\tif (fm.sorters[name]) {
\t\t\t\t\tvar arr = (name === fm.sortType)? (fm.sortOrder === 'asc'? 'n' : 's') : '';
\t\t\t\t\tself.variants.push([name, (arr? '<span class=\"ui-icon ui-icon-arrowthick-1-'+arr+'\"></span>' : '') + '&nbsp;' + fm.i18n('sort'+name)]);
\t\t\t\t}
\t\t\t});
\t\t\tself.variants.push('|');
\t\t\tself.variants.push([
\t\t\t\t'stick',
\t\t\t\t(fm.sortStickFolders? '<span class=\"ui-icon ui-icon-check\"></span>' : '') + '&nbsp;' + fm.i18n('sortFoldersFirst')
\t\t\t]);
\t\t\tif (fm.ui.tree && fm.options.sortAlsoTreeview !== null) {
\t\t\t\tself.variants.push('|');
\t\t\t\tself.variants.push([
\t\t\t\t\t'tree',
\t\t\t\t\t(fm.sortAlsoTreeview? '<span class=\"ui-icon ui-icon-check\"></span>' : '') + '&nbsp;' + fm.i18n('sortAlsoTreeview')
\t\t\t\t]);
\t\t\t}
\t\t\tupdateContextmenu();
\t\t},
\t\tupdateContextmenu = function() {
\t\t\tvar cm = fm.getUI('contextmenu'),
\t\t\t\ticon, sub;
\t\t\tif (cm.is(':visible')) {
\t\t\t\ticon = cm.find('span.elfinder-button-icon-sort');
\t\t\t\tsub = icon.siblings('div.elfinder-contextmenu-sub');
\t\t\t\tsub.find('span.ui-icon').remove();
\t\t\t\tsub.children('div.elfinder-contextsubmenu-item').each(function() {
\t\t\t\t\tvar tgt = \$(this).children('span'),
\t\t\t\t\t\tname = tgt.text().trim(),
\t\t\t\t\t\tarr;
\t\t\t\t\tif (name === (i18Name.stick || (i18Name.stick = fm.i18n('sortFoldersFirst')))) {
\t\t\t\t\t\tif (fm.sortStickFolders) {
\t\t\t\t\t\t\ttgt.prepend('<span class=\"ui-icon ui-icon-check\"></span>');
\t\t\t\t\t\t}
\t\t\t\t\t} else if (name === (i18Name.tree || (i18Name.tree = fm.i18n('sortAlsoTreeview')))) {
\t\t\t\t\t\tif (fm.sortAlsoTreeview) {
\t\t\t\t\t\t\ttgt.prepend('<span class=\"ui-icon ui-icon-check\"></span>');
\t\t\t\t\t\t}
\t\t\t\t\t} else if (name === (i18Name[fm.sortType] || (i18Name[fm.sortType] = fm.i18n('sort' + fm.sortType)))) {
\t\t\t\t\t\tarr = fm.sortOrder === 'asc'? 'n' : 's';
\t\t\t\t\t\ttgt.prepend('<span class=\"ui-icon ui-icon-arrowthick-1-'+arr+'\"></span>');
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t},
\t\ti18Name = {};
\t
\t/**
\t * Command options
\t *
\t * @type  Object
\t */
\tthis.options = {ui : 'sortbutton'};
\t
\tthis.keepContextmenu = true;

\tfm.bind('sortchange', setVar)
\t.bind('sorterupdate', function() {
\t\tsetVar();
\t\tfm.getUI().children('.elfinder-button-sort-menu').children('.elfinder-button-menu-item').each(function() {
\t\t\tvar tgt = \$(this),
\t\t\t\trel = tgt.attr('rel');
\t\t\ttgt.toggle(!!(! rel || fm.sorters[rel]));
\t\t});
\t})
\t.bind('cwdrender', function() {
\t\tvar cols = \$(fm.cwd).find('div.elfinder-cwd-wrapper-list table');
\t\tif (cols.length) {
\t\t\t\$.each(fm.sortRules, function(name, value) {
\t\t\t\tvar td = cols.find('thead tr td.elfinder-cwd-view-th-'+name);
\t\t\t\tif (td.length) {
\t\t\t\t\tvar current = ( name == fm.sortType),
\t\t\t\t\tsort = {
\t\t\t\t\t\ttype  : name,
\t\t\t\t\t\torder : current ? fm.sortOrder == 'asc' ? 'desc' : 'asc' : fm.sortOrder
\t\t\t\t\t},arr;
\t\t\t\t\tif (current) {
\t\t\t\t\t\ttd.addClass('ui-state-active');
\t\t\t\t\t\tarr = fm.sortOrder == 'asc' ? 'n' : 's';
\t\t\t\t\t\t\$('<span class=\"ui-icon ui-icon-triangle-1-'+arr+'\"></span>').appendTo(td);
\t\t\t\t\t}
\t\t\t\t\t\$(td).on('click', function(e){
\t\t\t\t\t\tif (! \$(this).data('dragging')) {
\t\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\t\tif (! fm.getUI('cwd').data('longtap')) {
\t\t\t\t\t\t\t\tfm.exec('sort', [], sort);
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('mouseenter mouseleave', function(e) {
\t\t\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
\t\t\t\t\t});
\t\t\t\t}
\t\t\t\t
\t\t\t});
\t\t}
\t});
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.exec = function(hashes, cOpt) {
\t\tvar fm = this.fm,
\t\t\tsortopt = \$.isPlainObject(cOpt)? cOpt : (function() {
\t\t\t\tcOpt += '';
\t\t\t\tvar sOpts = {};
\t\t\t\tif (cOpt === 'stick') {
\t\t\t\t\tsOpts.stick = !fm.sortStickFolders;
\t\t\t\t} else if (cOpt === 'tree') {
\t\t\t\t\tsOpts.tree = !fm.sortAlsoTreeview;
\t\t\t\t} else if (fm.sorters[cOpt]) {
\t\t\t\t\tif (fm.sortType === cOpt) {
\t\t\t\t\t\tsOpts.order = fm.sortOrder === 'asc'? 'desc' : 'asc';
\t\t\t\t\t} else {
\t\t\t\t\t\tsOpts.type = cOpt;
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn sOpts;
\t\t\t})(),
\t\t\tsort = Object.assign({
\t\t\t\ttype  : fm.sortType,
\t\t\t\torder : fm.sortOrder,
\t\t\t\tstick : fm.sortStickFolders,
\t\t\t\ttree  : fm.sortAlsoTreeview
\t\t\t}, sortopt);

\t\treturn fm.lazy(function() {
\t\t\tfm.setSort(sort.type, sort.order, sort.stick, sort.tree);
\t\t\tthis.resolve();
\t\t});
\t};

};


/*
 * File: /js/commands/undo.js
 */

/**
 * @class  elFinder command \"undo\"
 * Undo previous commands
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.undo = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm = this.fm,
\t\tsetTitle = function(undo) {
\t\t\tif (undo) {
\t\t\t\tself.title = fm.i18n('cmdundo') + ' ' + fm.i18n('cmd'+undo.cmd);
\t\t\t\tself.state = 0;
\t\t\t} else {
\t\t\t\tself.title = fm.i18n('cmdundo');
\t\t\t\tself.state = -1;
\t\t\t}
\t\t\tself.change();
\t\t},
\t\tcmds = [];
\t
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts      = [{
\t\tpattern     : 'ctrl+z'
\t}];
\tthis.syncTitleOnChange = true;
\t
\tthis.getstate = function() {
\t\treturn cmds.length? 0 : -1;
\t};
\t
\tthis.setUndo = function(undo, redo) {
\t\tvar _undo = {};
\t\tif (undo) {
\t\t\tif (\$.isPlainObject(undo) && undo.cmd && undo.callback) {
\t\t\t\tObject.assign(_undo, undo);
\t\t\t\tif (redo) {
\t\t\t\t\tdelete redo.undo;
\t\t\t\t\t_undo.redo = redo;
\t\t\t\t} else {
\t\t\t\t\tfm.getCommand('redo').setRedo(null);
\t\t\t\t}
\t\t\t\tcmds.push(_undo);
\t\t\t\tsetTitle(_undo);
\t\t\t}
\t\t}
\t};
\t
\tthis.exec = function() {
\t\tvar redo = fm.getCommand('redo'),
\t\t\tdfd = \$.Deferred(),
\t\t\tundo, res, _redo = {};
\t\tif (cmds.length) {
\t\t\tundo = cmds.pop();
\t\t\tif (undo.redo) {
\t\t\t\tObject.assign(_redo, undo.redo);
\t\t\t\tdelete undo.redo;
\t\t\t} else {
\t\t\t\t_redo = null;
\t\t\t} 
\t\t\tdfd.done(function() {
\t\t\t\tif (_redo) {
\t\t\t\t\tredo.setRedo(_redo, undo);
\t\t\t\t}
\t\t\t});
\t\t\t
\t\t\tsetTitle(cmds.length? cmds[cmds.length-1] : void(0));
\t\t\t
\t\t\tres = undo.callback();
\t\t\t
\t\t\tif (res && res.done) {
\t\t\t\tres.done(function() {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}).fail(function() {
\t\t\t\t\tdfd.reject();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfd.resolve();
\t\t\t}
\t\t\tif (cmds.length) {
\t\t\t\tthis.update(0, cmds[cmds.length - 1].name);
\t\t\t} else {
\t\t\t\tthis.update(-1, '');
\t\t\t}
\t\t} else {
\t\t\tdfd.reject();
\t\t}
\t\treturn dfd;
\t};
\t
\tfm.bind('exec', function(e) {
\t\tvar data = e.data || {};
\t\tif (data.opts && data.opts._userAction) {
\t\t\tif (data.dfrd && data.dfrd.done) {
\t\t\t\tdata.dfrd.done(function(res) {
\t\t\t\t\tif (res && res.undo && res.redo) {
\t\t\t\t\t\tres.undo.redo = res.redo;
\t\t\t\t\t\tself.setUndo(res.undo);
\t\t\t\t\t}
\t\t\t\t});
\t\t\t}
\t\t}
\t});
};

/**
 * @class  elFinder command \"redo\"
 * Redo previous commands
 *
 * @author Naoki Sawada
 **/
elFinder.prototype.commands.redo = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm   = this.fm,
\t\tsetTitle = function(redo) {
\t\t\tif (redo && redo.callback) {
\t\t\t\tself.title = fm.i18n('cmdredo') + ' ' + fm.i18n('cmd'+redo.cmd);
\t\t\t\tself.state = 0;
\t\t\t} else {
\t\t\t\tself.title = fm.i18n('cmdredo');
\t\t\t\tself.state = -1;
\t\t\t}
\t\t\tself.change();
\t\t},
\t\tcmds = [];
\t
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;
\tthis.shortcuts      = [{
\t\tpattern     : 'shift+ctrl+z ctrl+y'
\t}];
\tthis.syncTitleOnChange = true;
\t
\tthis.getstate = function() {
\t\treturn cmds.length? 0 : -1;
\t};
\t
\tthis.setRedo = function(redo, undo) {
\t\tif (redo === null) {
\t\t\tcmds = [];
\t\t\tsetTitle();
\t\t} else {
\t\t\tif (redo && redo.cmd && redo.callback) {
\t\t\t\tif (undo) {
\t\t\t\t\tredo.undo = undo;
\t\t\t\t}
\t\t\t\tcmds.push(redo);
\t\t\t\tsetTitle(redo);
\t\t\t}
\t\t}
\t};
\t
\tthis.exec = function() {
\t\tvar undo = fm.getCommand('undo'),
\t\t\tdfd = \$.Deferred(),
\t\t\tredo, res, _undo = {}, _redo = {};
\t\tif (cmds.length) {
\t\t\tredo = cmds.pop();
\t\t\tif (redo.undo) {
\t\t\t\tObject.assign(_undo, redo.undo);
\t\t\t\tObject.assign(_redo, redo);
\t\t\t\tdelete _redo.undo;
\t\t\t\tdfd.done(function() {
\t\t\t\t\tundo.setUndo(_undo, _redo);
\t\t\t\t});
\t\t\t}
\t\t\t
\t\t\tsetTitle(cmds.length? cmds[cmds.length-1] : void(0));
\t\t\t
\t\t\tres = redo.callback();
\t\t\t
\t\t\tif (res && res.done) {
\t\t\t\tres.done(function() {
\t\t\t\t\tdfd.resolve();
\t\t\t\t}).fail(function() {
\t\t\t\t\tdfd.reject();
\t\t\t\t});
\t\t\t} else {
\t\t\t\tdfd.resolve();
\t\t\t}
\t\t\treturn dfd;
\t\t} else {
\t\t\treturn dfd.reject();
\t\t}
\t};
};


/*
 * File: /js/commands/up.js
 */

/**
 * @class  elFinder command \"up\"
 * Go into parent directory
 *
 * @author Dmitry (dio) Levashov
 **/
(elFinder.prototype.commands.up = function() {
\t\"use strict\";
\tthis.alwaysEnabled = true;
\tthis.updateOnSelect = false;
\t
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+up'
\t}];
\t
\tthis.getstate = function() {
\t\treturn this.fm.cwd().phash ? 0 : -1;
\t};
\t
\tthis.exec = function() {
\t\tvar fm = this.fm,
\t\t\tcwdhash = fm.cwd().hash;
\t\treturn this.fm.cwd().phash ? this.fm.exec('open', this.fm.cwd().phash).done(function() {
\t\t\tfm.one('opendone', function() {
\t\t\t\tfm.selectfiles({files : [cwdhash]});
\t\t\t});
\t\t}) : \$.Deferred().reject();
\t};

}).prototype = { forceLoad : true }; // this is required command


/*
 * File: /js/commands/upload.js
 */

/**
 * @class elFinder command \"upload\"
 * Upload files using iframe or XMLHttpRequest & FormData.
 * Dialog allow to send files using drag and drop
 *
 * @type  elFinder.command
 * @author  Dmitry (dio) Levashov
 */
elFinder.prototype.commands.upload = function() {
\t\"use strict\";
\tvar hover = this.fm.res('class', 'hover');
\t
\tthis.disableOnSearch = true;
\tthis.updateOnSelect  = false;
\t
\t// Shortcut opens dialog
\tthis.shortcuts = [{
\t\tpattern     : 'ctrl+u'
\t}];
\t
\t/**
\t * Return command state
\t *
\t * @return Number
\t **/
\tthis.getstate = function(select) {
\t\tvar fm = this.fm, f,
\t\tsel = (select || [fm.cwd().hash]);
\t\tif (!this._disabled && sel.length == 1) {
\t\t\tf = fm.file(sel[0]);
\t\t}
\t\treturn (f && f.mime == 'directory' && f.write)? 0 : -1;
\t};
\t
\t
\tthis.exec = function(data) {
\t\tvar fm = this.fm,
\t\t\tcwdHash = fm.cwd().hash,
\t\t\tgetTargets = function() {
\t\t\t\tvar tgts = data && (data instanceof Array)? data : null,
\t\t\t\t\tsel;
\t\t\t\tif (! data || data instanceof Array) {
\t\t\t\t\tif (! tgts && (sel = fm.selected()).length === 1 && fm.file(sel[0]).mime === 'directory') {
\t\t\t\t\t\ttgts = sel;
\t\t\t\t\t} else if (!tgts || tgts.length !== 1 || fm.file(tgts[0]).mime !== 'directory') {
\t\t\t\t\t\ttgts = [ cwdHash ];
\t\t\t\t\t}
\t\t\t\t}
\t\t\t\treturn tgts;
\t\t\t},
\t\t\ttargets = getTargets(),
\t\t\tcheck = targets? targets[0] : (data && data.target? data.target : null),
\t\t\ttargetDir = check? fm.file(check) : fm.cwd(),
\t\t\tfmUpload = function(data) {
\t\t\t\tfm.upload(data)
\t\t\t\t\t.fail(function(error) {
\t\t\t\t\t\tdfrd.reject(error);
\t\t\t\t\t})
\t\t\t\t\t.done(function(data) {
\t\t\t\t\t\tvar cwd = fm.getUI('cwd'),
\t\t\t\t\t\t\tnode;
\t\t\t\t\t\tdfrd.resolve(data);
\t\t\t\t\t\tif (data && data.added && data.added[0] && ! fm.ui.notify.children('.elfinder-notify-upload').length) {
\t\t\t\t\t\t\tvar newItem = fm.findCwdNodes(data.added);
\t\t\t\t\t\t\tif (newItem.length) {
\t\t\t\t\t\t\t\tnewItem.trigger('scrolltoview');
\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\tif (targetDir.hash !== cwdHash) {
\t\t\t\t\t\t\t\t\tnode = \$('<div></div>').append(
\t\t\t\t\t\t\t\t\t\t\$('<button type=\"button\" class=\"ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop\"><span class=\"ui-button-text\">'+fm.i18n('cmdopendir')+'</span></button>')
\t\t\t\t\t\t\t\t\t\t.on('mouseenter mouseleave', function(e) { 
\t\t\t\t\t\t\t\t\t\t\t\$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
\t\t\t\t\t\t\t\t\t\t}).on('click', function() {
\t\t\t\t\t\t\t\t\t\t\tfm.exec('open', check).done(function() {
\t\t\t\t\t\t\t\t\t\t\t\tfm.one('opendone', function() {
\t\t\t\t\t\t\t\t\t\t\t\t\tfm.trigger('selectfiles', {files : \$.map(data.added, function(f) {return f.hash;})});
\t\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t\t\t\t})
\t\t\t\t\t\t\t\t\t);
\t\t\t\t\t\t\t\t} else {
\t\t\t\t\t\t\t\t\tfm.trigger('selectfiles', {files : \$.map(data.added, function(f) {return f.hash;})});
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t\tfm.toast({msg: fm.i18n(['complete', fm.i18n('cmdupload')]), extNode: node});
\t\t\t\t\t\t\t}
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.progress(function() {
\t\t\t\t\t\tdfrd.notifyWith(this, Array.from(arguments));
\t\t\t\t\t});
\t\t\t},
\t\t\tupload = function(data) {
\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\tif (targets) {
\t\t\t\t\tdata.target = targets[0];
\t\t\t\t}
\t\t\t\tfmUpload(data);
\t\t\t},
\t\t\tgetSelector = function() {
\t\t\t\tvar hash = targetDir.hash,
\t\t\t\t\tdirs = \$.map(fm.files(hash), function(f) {
\t\t\t\t\t\treturn (f.mime === 'directory' && f.write)? f : null; 
\t\t\t\t\t});
\t\t\t\t
\t\t\t\tif (! dirs.length) {
\t\t\t\t\treturn \$();
\t\t\t\t}
\t\t\t\t
\t\t\t\treturn \$('<div class=\"elfinder-upload-dirselect elfinder-tabstop\" title=\"' + fm.i18n('folders') + '\"></div>')
\t\t\t\t.on('click', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.preventDefault();
\t\t\t\t\tdirs = fm.sortFiles(dirs);
\t\t\t\t\tvar \$this  = \$(this),
\t\t\t\t\t\tcwd    = fm.cwd(),
\t\t\t\t\t\tbase   = dialog.closest('div.ui-dialog'),
\t\t\t\t\t\tgetRaw = function(f, icon) {
\t\t\t\t\t\t\treturn {
\t\t\t\t\t\t\t\tlabel    : fm.escape(f.i18 || f.name),
\t\t\t\t\t\t\t\ticon     : icon,
\t\t\t\t\t\t\t\tremain   : false,
\t\t\t\t\t\t\t\tcallback : function() {
\t\t\t\t\t\t\t\t\tvar title = base.children('.ui-dialog-titlebar:first').find('span.elfinder-upload-target');
\t\t\t\t\t\t\t\t\ttargets = [ f.hash ];
\t\t\t\t\t\t\t\t\ttitle.html(' - ' + fm.escape(f.i18 || f.name));
\t\t\t\t\t\t\t\t\t\$this.trigger('focus');
\t\t\t\t\t\t\t\t},
\t\t\t\t\t\t\t\toptions  : {
\t\t\t\t\t\t\t\t\tclassName : (targets && targets.length && f.hash === targets[0])? 'ui-state-active' : '',
\t\t\t\t\t\t\t\t\ticonClass : f.csscls || '',
\t\t\t\t\t\t\t\t\ticonImg   : f.icon   || ''
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\t},
\t\t\t\t\t\traw = [ getRaw(targetDir, 'opendir'), '|' ];
\t\t\t\t\t\$.each(dirs, function(i, f) {
\t\t\t\t\t\traw.push(getRaw(f, 'dir'));
\t\t\t\t\t});
\t\t\t\t\t\$this.trigger('blur');
\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\traw: raw,
\t\t\t\t\t\tx: e.pageX || \$(this).offset().left,
\t\t\t\t\t\ty: e.pageY || \$(this).offset().top,
\t\t\t\t\t\tprevNode: base,
\t\t\t\t\t\tfitHeight: true
\t\t\t\t\t});
\t\t\t\t}).append('<span class=\"elfinder-button-icon elfinder-button-icon-dir\" ></span>');
\t\t\t},
\t\t\tinputButton = function(type, caption) {
\t\t\t\tvar button,
\t\t\t\t\tinput = \$('<input type=\"file\" ' + type + '/>')
\t\t\t\t\t.on('click', function() {
\t\t\t\t\t\t// for IE's bug
\t\t\t\t\t\tif (fm.UA.IE) {
\t\t\t\t\t\t\tsetTimeout(function() {
\t\t\t\t\t\t\t\tform.css('display', 'none').css('position', 'relative');
\t\t\t\t\t\t\t\trequestAnimationFrame(function() {
\t\t\t\t\t\t\t\t\tform.css('display', '').css('position', '');
\t\t\t\t\t\t\t\t});
\t\t\t\t\t\t\t}, 100);
\t\t\t\t\t\t}
\t\t\t\t\t})
\t\t\t\t\t.on('change', function() {
\t\t\t\t\t\tupload({input : input.get(0), type : 'files'});
\t\t\t\t\t})
\t\t\t\t\t.on('dragover', function(e) {
\t\t\t\t\t\te.originalEvent.dataTransfer.dropEffect = 'copy';
\t\t\t\t\t}),
\t\t\t\t\tform = \$('<form></form>').append(input).on('click', function(e) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t});

\t\t\t\treturn \$('<div class=\"ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only elfinder-tabstop elfinder-focus\"><span class=\"ui-button-text\">'+fm.i18n(caption)+'</span></div>')
\t\t\t\t\t.append(form)
\t\t\t\t\t.on('click', function(e) {
\t\t\t\t\t\te.stopPropagation();
\t\t\t\t\t\te.preventDefault();
\t\t\t\t\t\tinput.trigger('click');
\t\t\t\t\t})
\t\t\t\t\t.on('mouseenter mouseleave', function(e) {
\t\t\t\t\t\t\$(this).toggleClass(hover, e.type === 'mouseenter');
\t\t\t\t\t});
\t\t\t},
\t\t\tdfrd = \$.Deferred(),
\t\t\tdialog, dropbox, pastebox, dropUpload, paste, dirs, spinner, uidialog;
\t\t
\t\tdropUpload = function(e) {
\t\t\te.stopPropagation();
\t\t\te.preventDefault();
\t\t\tvar file = false,
\t\t\t\ttype = '',
\t\t\t\telfFrom = null,
\t\t\t\tmycwd = '',
\t\t\t\tdata = null,
\t\t\t\ttarget = e._target || null,
\t\t\t\ttrf = e.dataTransfer || null,
\t\t\t\tkind = (trf.items && trf.items.length && trf.items[0].kind)? trf.items[0].kind : '',
\t\t\t\terrors;
\t\t\t
\t\t\tif (trf) {
\t\t\t\ttry {
\t\t\t\t\telfFrom = trf.getData('elfinderfrom');
\t\t\t\t\tif (elfFrom) {
\t\t\t\t\t\tmycwd = window.location.href + fm.cwd().hash;
\t\t\t\t\t\tif ((!target && elfFrom === mycwd) || target === mycwd) {
\t\t\t\t\t\t\tdfrd.reject();
\t\t\t\t\t\t\treturn;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} catch(e) {}
\t\t\t\t
\t\t\t\tif (kind === 'file' && (trf.items[0].getAsEntry || trf.items[0].webkitGetAsEntry)) {
\t\t\t\t\tfile = trf;
\t\t\t\t\ttype = 'data';
\t\t\t\t} else if (kind !== 'string' && trf.files && trf.files.length && \$.inArray('Text', trf.types) === -1) {
\t\t\t\t\tfile = trf.files;
\t\t\t\t\ttype = 'files';
\t\t\t\t} else {
\t\t\t\t\ttry {
\t\t\t\t\t\tif ((data = trf.getData('text/html')) && data.match(/<(?:img|a)/i)) {
\t\t\t\t\t\t\tfile = [ data ];
\t\t\t\t\t\t\ttype = 'html';
\t\t\t\t\t\t}
\t\t\t\t\t} catch(e) {}
\t\t\t\t\tif (! file) {
\t\t\t\t\t\tif (data = trf.getData('text')) {
\t\t\t\t\t\t\tfile = [ data ];
\t\t\t\t\t\t\ttype = 'text';
\t\t\t\t\t\t} else if (trf && trf.files) {
\t\t\t\t\t\t\t// maybe folder uploading but this UA dose not support it
\t\t\t\t\t\t\tkind = 'file';
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}
\t\t\t}
\t\t\tif (file) {
\t\t\t\tfmUpload({files : file, type : type, target : target, dropEvt : e});
\t\t\t} else {
\t\t\t\terrors = ['errUploadNoFiles'];
\t\t\t\tif (kind === 'file') {
\t\t\t\t\terrors.push('errFolderUpload');
\t\t\t\t}
\t\t\t\tfm.error(errors);
\t\t\t\tdfrd.reject();
\t\t\t}
\t\t};
\t\t
\t\tif (!targets && data) {
\t\t\tif (data.input || data.files) {
\t\t\t\tdata.type = 'files';
\t\t\t\tfmUpload(data);
\t\t\t} else if (data.dropEvt) {
\t\t\t\tdropUpload(data.dropEvt);
\t\t\t}
\t\t\treturn dfrd;
\t\t}
\t\t
\t\tpaste = function(ev) {
\t\t\tvar e = ev.originalEvent || ev;
\t\t\tvar files = [], items = [];
\t\t\tvar file;
\t\t\tif (e.clipboardData) {
\t\t\t\tif (e.clipboardData.items && e.clipboardData.items.length){
\t\t\t\t\titems = e.clipboardData.items;
\t\t\t\t\tfor (var i=0; i < items.length; i++) {
\t\t\t\t\t\tif (e.clipboardData.items[i].kind == 'file') {
\t\t\t\t\t\t\tfile = e.clipboardData.items[i].getAsFile();
\t\t\t\t\t\t\tfiles.push(file);
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t} else if (e.clipboardData.files && e.clipboardData.files.length) {
\t\t\t\t\tfiles = e.clipboardData.files;
\t\t\t\t}
\t\t\t\tif (files.length) {
\t\t\t\t\tupload({files : files, type : 'files', clipdata : true});
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t}
\t\t\tvar my = e.target || e.srcElement;
\t\t\trequestAnimationFrame(function() {
\t\t\t\tvar type = 'text',
\t\t\t\t\tsrc;
\t\t\t\tif (my.innerHTML) {
\t\t\t\t\t\$(my).find('img').each(function(i, v){
\t\t\t\t\t\tif (v.src.match(/^webkit-fake-url:\\/\\//)) {
\t\t\t\t\t\t\t// For Safari's bug.
\t\t\t\t\t\t\t// ref. https://bugs.webkit.org/show_bug.cgi?id=49141
\t\t\t\t\t\t\t//      https://dev.ckeditor.com/ticket/13029
\t\t\t\t\t\t\t\$(v).remove();
\t\t\t\t\t\t}
\t\t\t\t\t});
\t\t\t\t\t
\t\t\t\t\tif (\$(my).find('a,img').length) {
\t\t\t\t\t\ttype = 'html';
\t\t\t\t\t}
\t\t\t\t\tsrc = my.innerHTML;
\t\t\t\t\tmy.innerHTML = '';
\t\t\t\t\tupload({files : [ src ], type : type});
\t\t\t\t}
\t\t\t});
\t\t};
\t\t
\t\tdialog = \$('<div class=\"elfinder-upload-dialog-wrapper\"></div>')
\t\t\t.append(inputButton('multiple', 'selectForUpload'));
\t\t
\t\tif (! fm.UA.Mobile && (function(input) {
\t\t\treturn (typeof input.webkitdirectory !== 'undefined' || typeof input.directory !== 'undefined');})(document.createElement('input'))) {
\t\t\tdialog.append(inputButton('multiple webkitdirectory directory', 'selectFolder'));
\t\t}
\t\t
\t\tif (targetDir.dirs) {
\t\t\t
\t\t\tif (targetDir.hash === cwdHash || fm.navHash2Elm(targetDir.hash).hasClass('elfinder-subtree-loaded')) {
\t\t\t\tgetSelector().appendTo(dialog);
\t\t\t} else {
\t\t\t\tspinner = \$('<div class=\"elfinder-upload-dirselect\" title=\"' + fm.i18n('nowLoading') + '\"></div>')
\t\t\t\t\t.append('<span class=\"elfinder-button-icon elfinder-button-icon-spinner\" ></span>')
\t\t\t\t\t.appendTo(dialog);
\t\t\t\tfm.request({cmd : 'tree', target : targetDir.hash})
\t\t\t\t\t.done(function() { 
\t\t\t\t\t\tfm.one('treedone', function() {
\t\t\t\t\t\t\tspinner.replaceWith(getSelector());
\t\t\t\t\t\t\tuidialog.elfinderdialog('tabstopsInit');
\t\t\t\t\t\t});
\t\t\t\t\t})
\t\t\t\t\t.fail(function() {
\t\t\t\t\t\tspinner.remove();
\t\t\t\t\t});
\t\t\t}
\t\t}
\t\t
\t\tif (fm.dragUpload) {
\t\t\tdropbox = \$('<div class=\"ui-corner-all elfinder-upload-dropbox elfinder-tabstop\" contenteditable=\"true\" data-ph=\"'+fm.i18n('dropPasteFiles')+'\"></div>')
\t\t\t\t.on('paste', function(e){
\t\t\t\t\tpaste(e);
\t\t\t\t})
\t\t\t\t.on('mousedown click', function(){
\t\t\t\t\t\$(this).trigger('focus');
\t\t\t\t})
\t\t\t\t.on('focus', function(){
\t\t\t\t\tthis.innerHTML = '';
\t\t\t\t})
\t\t\t\t.on('mouseover', function(){
\t\t\t\t\t\$(this).addClass(hover);
\t\t\t\t})
\t\t\t\t.on('mouseout', function(){
\t\t\t\t\t\$(this).removeClass(hover);
\t\t\t\t})
\t\t\t\t.on('dragenter', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t  \te.preventDefault();
\t\t\t\t  \t\$(this).addClass(hover);
\t\t\t\t})
\t\t\t\t.on('dragleave', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t  \te.preventDefault();
\t\t\t\t  \t\$(this).removeClass(hover);
\t\t\t\t})
\t\t\t\t.on('dragover', function(e) {
\t\t\t\t\te.stopPropagation();
\t\t\t\t  \te.preventDefault();
\t\t\t\t\te.originalEvent.dataTransfer.dropEffect = 'copy';
\t\t\t\t\t\$(this).addClass(hover);
\t\t\t\t})
\t\t\t\t.on('drop', function(e) {
\t\t\t\t\tdialog.elfinderdialog('close');
\t\t\t\t\ttargets && (e.originalEvent._target = targets[0]);
\t\t\t\t\tdropUpload(e.originalEvent);
\t\t\t\t})
\t\t\t\t.prependTo(dialog)
\t\t\t\t.after('<div class=\"elfinder-upload-dialog-or\">'+fm.i18n('or')+'</div>')[0];
\t\t\t
\t\t} else {
\t\t\tpastebox = \$('<div class=\"ui-corner-all elfinder-upload-dropbox\" contenteditable=\"true\">'+fm.i18n('dropFilesBrowser')+'</div>')
\t\t\t\t.on('paste drop', function(e){
\t\t\t\t\tpaste(e);
\t\t\t\t})
\t\t\t\t.on('mousedown click', function(){
\t\t\t\t\t\$(this).trigger('focus');
\t\t\t\t})
\t\t\t\t.on('focus', function(){
\t\t\t\t\tthis.innerHTML = '';
\t\t\t\t})
\t\t\t\t.on('dragenter mouseover', function(){
\t\t\t\t\t\$(this).addClass(hover);
\t\t\t\t})
\t\t\t\t.on('dragleave mouseout', function(){
\t\t\t\t\t\$(this).removeClass(hover);
\t\t\t\t})
\t\t\t\t.prependTo(dialog)
\t\t\t\t.after('<div class=\"elfinder-upload-dialog-or\">'+fm.i18n('or')+'</div>')[0];
\t\t\t
\t\t}
\t\t
\t\tuidialog = this.fmDialog(dialog, {
\t\t\ttitle          : this.title + '<span class=\"elfinder-upload-target\">' + (targetDir? ' - ' + fm.escape(targetDir.i18 || targetDir.name) : '') + '</span>',
\t\t\tmodal          : true,
\t\t\tresizable      : false,
\t\t\tdestroyOnClose : true,
\t\t\tpropagationEvents : ['mousemove', 'mouseup', 'click'],
\t\t\tclose          : function() {
\t\t\t\tvar cm = fm.getUI('contextmenu');
\t\t\t\tif (cm.is(':visible')) {
\t\t\t\t\tcm.click();
\t\t\t\t}
\t\t\t}
\t\t});
\t\t
\t\treturn dfrd;
\t};

};


/*
 * File: /js/commands/view.js
 */

/**
 * @class  elFinder command \"view\"
 * Change current directory view (icons/list)
 *
 * @author Dmitry (dio) Levashov
 **/
elFinder.prototype.commands.view = function() {
\t\"use strict\";
\tvar self = this,
\t\tfm = this.fm,
\t\tsubMenuRaw;
\tthis.value          = fm.viewType;
\tthis.alwaysEnabled  = true;
\tthis.updateOnSelect = false;

\tthis.options = { ui : 'viewbutton'};
\t
\tthis.getstate = function() {
\t\treturn 0;
\t};
\t
\tthis.extra = {
\t\ticon: 'menu',
\t\tnode: \$('<span></span>')
\t\t\t.attr({title: fm.i18n('viewtype')})
\t\t\t.on('click touchstart', function(e){
\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\tvar node = \$(this);
\t\t\t\te.stopPropagation();
\t\t\t\te.preventDefault();
\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\traw: getSubMenuRaw(),
\t\t\t\t\tx: node.offset().left,
\t\t\t\t\ty: node.offset().top
\t\t\t\t});
\t\t\t})
\t};

\tthis.exec = function() {
\t\tvar self  = this,
\t\t\tvalue = this.value == 'list' ? 'icons' : 'list';
\t\t\t
\t\tfm.storage('view', value);
\t\treturn fm.lazy(function() {
\t\t\tfm.viewchange();
\t\t\tself.update(void(0), value);
\t\t\tthis.resolve();
\t\t});
\t};

\tfm.bind('init', function() {
\t\tsubMenuRaw = (function() {
\t\t\tvar cwd = fm.getUI('cwd'),
\t\t\t\traws = [],
\t\t\t\tsizeNames = fm.options.uiOptions.cwd.iconsView.sizeNames,
\t\t\t\tmax = fm.options.uiOptions.cwd.iconsView.sizeMax,
\t\t\t\ti, size;
\t\t\tfor (i = 0; i <= max; i++) {
\t\t\t\traws.push(
\t\t\t\t\t{
\t\t\t\t\t\tlabel    : fm.i18n(sizeNames[i] || ('Size-' + i + ' icons')),
\t\t\t\t\t\ticon     : 'view',
\t\t\t\t\t\tcallback : (function(s) {
\t\t\t\t\t\t\treturn function() {
\t\t\t\t\t\t\t\tcwd.trigger('iconpref', {size: s});
\t\t\t\t\t\t\t\tfm.storage('iconsize', s);
\t\t\t\t\t\t\t\tif (self.value === 'list') {
\t\t\t\t\t\t\t\t\tself.exec();
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t};
\t\t\t\t\t\t})(i)
\t\t\t\t\t}
\t\t\t\t);
\t\t\t}
\t\t\traws.push('|');
\t\t\traws.push(
\t\t\t\t{
\t\t\t\t\tlabel    : fm.i18n('viewlist'),
\t\t\t\t\ticon     : 'view-list',
\t\t\t\t\tcallback : function() {
\t\t\t\t\t\tif (self.value !== 'list') {
\t\t\t\t\t\t\tself.exec();
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t}\t\t
\t\t\t);
\t\t\treturn raws;
\t\t})();
\t}).bind('contextmenucreate', function() {
\t\tself.extra = {
\t\t\ticon: 'menu',
\t\t\tnode: \$('<span></span>')
\t\t\t\t.attr({title: fm.i18n('cmdview')})
\t\t\t\t.on('click touchstart', function(e){
\t\t\t\t\tif (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
\t\t\t\t\t\treturn;
\t\t\t\t\t}
\t\t\t\t\tvar node = \$(this),
\t\t\t\t\t\traw = subMenuRaw.concat(),
\t\t\t\t\t\tidx, i;
\t\t\t\t\tif (self.value === 'list') {
\t\t\t\t\t\tidx = subMenuRaw.length - 1;
\t\t\t\t\t} else {
\t\t\t\t\t\tidx = parseInt(fm.storage('iconsize') || 0);
\t\t\t\t\t}
\t\t\t\t\tfor (i = 0; i < subMenuRaw.length; i++) {
\t\t\t\t\t\tif (subMenuRaw[i] !== '|') {
\t\t\t\t\t\t\tsubMenuRaw[i].options = (i === idx? {'className': 'ui-state-active'} : void(0))
\t\t\t\t\t\t\t;
\t\t\t\t\t\t}
\t\t\t\t\t}
\t\t\t\t\te.stopPropagation();
\t\t\t\t\te.preventDefault();
\t\t\t\t\tfm.trigger('contextmenu', {
\t\t\t\t\t\traw: subMenuRaw,
\t\t\t\t\t\tx: node.offset().left,
\t\t\t\t\t\ty: node.offset().top
\t\t\t\t\t});
\t\t\t\t})
\t\t};
\t});

};

return elFinder;
}));";
    }

    public function getTemplateName()
    {
        return "@bundles/CoreBundle/Assets/js/libraries/filemanager/elfinder/dist/js/elfinder.full.js";
    }

    public function getDebugInfo()
    {
        return array (  37 => 1,);
    }

    public function getSourceContext()
    {
        return new Source("", "@bundles/CoreBundle/Assets/js/libraries/filemanager/elfinder/dist/js/elfinder.full.js", "/var/www/mautic/app/bundles/CoreBundle/Assets/js/libraries/filemanager/elfinder/dist/js/elfinder.full.js");
    }
}
