')[0].play();
- });
- }
-
- // bind external event handlers
- $.each(this.options.handlers, function(event, callback) {
- self.bind(event, callback);
- });
-
- /**
- * History object. Store visited folders
- *
- * @type Object
- **/
- this.history = new this.history(this);
-
- /**
- * Root hashed
- *
- * @type Object
- */
- this.roots = {};
-
- /**
- * leaf roots
- *
- * @type Object
- */
- this.leafRoots = {};
-
- this.volumeExpires = {};
-
- /**
- * Loaded commands
- *
- * @type Object
- **/
- this._commands = {};
-
- if (!Array.isArray(this.options.commands)) {
- this.options.commands = [];
- }
-
- if ($.inArray('*', this.options.commands) !== -1) {
- this.options.commands = Object.keys(this.commands);
- }
-
- /**
- * UI command map of cwd volume ( That volume driver option `uiCmdMap` )
- *
- * @type Object
- **/
- this.commandMap = {};
-
- /**
- * cwd options of each volume
- * key: volumeid
- * val: options object
- *
- * @type Object
- */
- this.volOptions = {};
-
- /**
- * Has volOptions data
- *
- * @type Boolean
- */
- this.hasVolOptions = false;
-
- /**
- * Hash of trash holders
- * key: trash folder hash
- * val: source volume hash
- *
- * @type Object
- */
- this.trashes = {};
-
- /**
- * cwd options of each folder/file
- * key: hash
- * val: options object
- *
- * @type Object
- */
- this.optionsByHashes = {};
-
- /**
- * UI Auto Hide Functions
- * Each auto hide function mast be call to `fm.trigger('uiautohide')` at end of process
- *
- * @type Array
- **/
- this.uiAutoHide = [];
-
- // trigger `uiautohide`
- this.one('open', function() {
- if (self.uiAutoHide.length) {
- setTimeout(function() {
- self.trigger('uiautohide');
- }, 500);
- }
- });
-
- // Auto Hide Functions sequential processing start
- this.bind('uiautohide', function() {
- if (self.uiAutoHide.length) {
- self.uiAutoHide.shift()();
- }
- });
-
- if (this.options.width) {
- width = this.options.width;
- }
-
- if (this.options.height) {
- height = this.options.height;
- }
-
- if (this.options.heightBase) {
- heightBase = $(this.options.heightBase);
- }
-
- if (this.options.soundPath) {
- soundPath = this.options.soundPath.replace(/\/+$/, '') + '/';
- } else {
- soundPath = this.baseUrl + soundPath;
- }
-
- self.one('opendone', function() {
- var tm;
- // attach events to document
- $(document)
- // disable elfinder on click outside elfinder
- .on('click.'+namespace, function(e) { enabled && ! self.options.enableAlways && !$(e.target).closest(node).length && self.disable(); })
- // exec shortcuts
- .on(keydown+' '+keypress+' '+keyup+' '+mousedown, execShortcut);
-
- // attach events to window
- self.options.useBrowserHistory && $(window)
- .on('popstate.' + namespace, function(ev) {
- var state = ev.originalEvent.state || {},
- hasThash = state.thash? true : false,
- dialog = node.find('.elfinder-frontmost:visible'),
- input = node.find('.elfinder-navbar-dir,.elfinder-cwd-filename').find('input,textarea'),
- onOpen, toast;
- if (!hasThash) {
- state = { thash: self.cwd().hash };
- // scroll to elFinder node
- $('html,body').animate({ scrollTop: node.offset().top });
- }
- if (dialog.length || input.length) {
- history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
- if (dialog.length) {
- if (!dialog.hasClass(self.res('class', 'preventback'))) {
- if (dialog.hasClass('elfinder-contextmenu')) {
- $(document).trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
- } else if (dialog.hasClass('elfinder-dialog')) {
- dialog.elfinderdialog('close');
- } else {
- dialog.trigger('close');
- }
- }
- } else {
- input.trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
- }
- } else {
- if (hasThash) {
- !$.isEmptyObject(self.files()) && self.request({
- data : {cmd : 'open', target : state.thash, onhistory : 1},
- notify : {type : 'open', cnt : 1, hideCnt : true},
- syncOnFail : true
- });
- } else {
- onOpen = function() {
- toast.trigger('click');
- };
- self.one('open', onOpen, true);
- toast = self.toast({
- msg: self.i18n('pressAgainToExit'),
- onHidden: function() {
- self.unbind('open', onOpen);
- history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash);
- }
- });
- }
- }
- });
-
- $(window).on('resize.' + namespace, function(e){
- if (e.target === this) {
- tm && cancelAnimationFrame(tm);
- tm = requestAnimationFrame(function() {
- var prv = node.data('resizeSize') || {w: 0, h: 0},
- size = {w: Math.round(node.width()), h: Math.round(node.height())};
- node.data('resizeSize', size);
- if (size.w !== prv.w || size.h !== prv.h) {
- node.trigger('resize');
- self.trigger('resize', {width : size.w, height : size.h});
- }
- });
- }
- })
- .on('beforeunload.' + namespace,function(e){
- var msg, cnt;
- if (!self.pauseUnloadCheck()) {
- if (node.is(':visible')) {
- if (self.ui.notify.children().length && $.inArray('hasNotifyDialog', self.options.windowCloseConfirm) !== -1) {
- msg = self.i18n('ntfsmth');
- } else if (node.find('.'+self.res('class', 'editing')).length && $.inArray('editingFile', self.options.windowCloseConfirm) !== -1) {
- msg = self.i18n('editingFile');
- } else if ((cnt = Object.keys(self.selected()).length) && $.inArray('hasSelectedItem', self.options.windowCloseConfirm) !== -1) {
- msg = self.i18n('hasSelected', ''+cnt);
- } else if ((cnt = Object.keys(self.clipboard()).length) && $.inArray('hasClipboardData', self.options.windowCloseConfirm) !== -1) {
- msg = self.i18n('hasClipboard', ''+cnt);
- }
- if (msg) {
- e.returnValue = msg;
- return msg;
- }
- }
- self.trigger('unload');
- }
- });
-
- // bind window onmessage for CORS
- $(window).on('message.' + namespace, function(e){
- var res = e.originalEvent || null,
- obj, data;
- if (res && self.uploadURL.indexOf(res.origin) === 0) {
- try {
- obj = JSON.parse(res.data);
- data = obj.data || null;
- if (data) {
- if (data.error) {
- if (obj.bind) {
- self.trigger(obj.bind+'fail', data);
- }
- self.error(data.error);
- } else {
- data.warning && self.error(data.warning);
- self.updateCache(data);
- data.removed && data.removed.length && self.remove(data);
- data.added && data.added.length && self.add(data);
- data.changed && data.changed.length && self.change(data);
- if (obj.bind) {
- self.trigger(obj.bind, data);
- self.trigger(obj.bind+'done');
- }
- data.sync && self.sync();
- }
- }
- } catch (e) {
- self.sync();
- }
- }
- });
-
- // elFinder enable always
- if (self.options.enableAlways) {
- $(window).on('focus.' + namespace, function(e){
- (e.target === this) && self.enable();
- });
- if (inFrame) {
- $(window.top).on('focus.' + namespace, function() {
- if (self.enable() && (! parentIframe || parentIframe.is(':visible'))) {
- requestAnimationFrame(function() {
- $(window).trigger('focus');
- });
- }
- });
- }
- } else if (inFrame) {
- $(window).on('blur.' + namespace, function(e){
- enabled && e.target === this && self.disable();
- });
- }
-
- // return focus to the window on click (elFInder in the frame)
- if (inFrame) {
- node.on('click', function(e) {
- $(window).trigger('focus');
- });
- }
-
- // elFinder to enable by mouse over
- if (self.options.enableByMouseOver) {
- node.on('mouseenter touchstart', function(e) {
- (inFrame) && $(window).trigger('focus');
- ! self.enabled() && self.enable();
- });
- }
-
- // When the browser tab turn to foreground/background
- $(window).on('visibilitychange.' + namespace, function(e) {
- var background = document.hidden || document.webkitHidden || document.msHidden;
- // AutoSync turn On/Off
- if (self.options.syncStart) {
- self.autoSync(background? 'stop' : void(0));
- }
- });
- });
-
- // store instance in node
- node[0].elfinder = this;
-
- // auto load language file
- dfrdsBeforeBootup.push((function() {
- var lang = self.lang,
- langJs = self.i18nBaseUrl + 'elfinder.' + lang + '.js',
- dfd = $.Deferred().done(function() {
- if (self.i18[lang]) {
- self.lang = lang;
- }
- self.trigger('i18load');
- i18n = self.lang === 'en'
- ? self.i18['en']
- : $.extend(true, {}, self.i18['en'], self.i18[self.lang]);
- });
-
- if (!self.i18[lang]) {
- self.lang = 'en';
- if (self.hasRequire) {
- require([langJs], function() {
- dfd.resolve();
- }, function() {
- dfd.resolve();
- });
- } else {
- self.loadScript([langJs], function() {
- dfd.resolve();
- }, {
- loadType: 'tag',
- error : function() {
- dfd.resolve();
- }
- });
- }
- } else {
- dfd.resolve();
- }
- return dfd;
- })());
-
- // elFinder boot up function
- bootUp = function() {
- var columnNames;
-
- /**
- * i18 messages
- *
- * @type Object
- **/
- self.messages = i18n.messages;
-
- // check jquery ui
- if (!($.fn.selectable && $.fn.draggable && $.fn.droppable && $.fn.resizable && $.fn.button && $.fn.slider)) {
- return alert(self.i18n('errJqui'));
- }
-
- // check node
- if (!node.length) {
- return alert(self.i18n('errNode'));
- }
- // check connector url
- if (!self.options.url) {
- return alert(self.i18n('errURL'));
- }
-
- // column key/name map for fm.getColumnName()
- columnNames = Object.assign({
- name : self.i18n('name'),
- perm : self.i18n('perms'),
- date : self.i18n('modify'),
- size : self.i18n('size'),
- kind : self.i18n('kind'),
- modestr : self.i18n('mode'),
- modeoct : self.i18n('mode'),
- modeboth : self.i18n('mode')
- }, self.options.uiOptions.cwd.listView.columnsCustomName);
-
- /**
- * Gets the column name of cwd list view
- *
- * @param String key The key
- * @return String The column name.
- */
- self.getColumnName = function(key) {
- return columnNames[key] || self.i18n(key);
- };
-
- /**
- * Interface direction
- *
- * @type String
- * @default "ltr"
- **/
- self.direction = i18n.direction;
-
- /**
- * Date/time format
- *
- * @type String
- * @default "m.d.Y"
- **/
- self.dateFormat = self.options.dateFormat || i18n.dateFormat;
-
- /**
- * Date format like "Yesterday 10:20:12"
- *
- * @type String
- * @default "{day} {time}"
- **/
- self.fancyFormat = self.options.fancyDateFormat || i18n.fancyDateFormat;
-
- /**
- * Date format for if upload file has not original unique name
- * e.g. Clipboard image data, Image data taken with iOS
- *
- * @type String
- * @default "ymd-His"
- **/
- self.nonameDateFormat = (self.options.nonameDateFormat || i18n.nonameDateFormat).replace(/[\/\\]/g, '_');
-
- /**
- * Css classes
- *
- * @type String
- **/
- self.cssClass = 'ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-'
- +(self.direction == 'rtl' ? 'rtl' : 'ltr')
- +(self.UA.Touch? (' elfinder-touch' + (self.options.resizable ? ' touch-punch' : '')) : '')
- +(self.UA.Mobile? ' elfinder-mobile' : '')
- +(self.UA.iOS? ' elfinder-ios' : '')
- +' '+self.options.cssClass;
-
- // prepare node
- node.addClass(self.cssClass)
- .on(mousedown, function() {
- !enabled && self.enable();
- });
-
- // draggable closure
- (function() {
- var ltr, wzRect, wzBottom, wzBottom2, nodeStyle,
- keyEvt = keydown + 'draggable' + ' keyup.' + namespace + 'draggable';
-
- /**
- * Base draggable options
- *
- * @type Object
- **/
- self.draggable = {
- appendTo : node,
- addClasses : false,
- distance : 4,
- revert : true,
- refreshPositions : false,
- cursor : 'crosshair',
- cursorAt : {left : 50, top : 47},
- scroll : false,
- start : function(e, ui) {
- var helper = ui.helper,
- targets = $.grep(helper.data('files')||[], function(h) {
- if (h) {
- remember[h] = true;
- return true;
- }
- return false;
- }),
- locked = false,
- cnt, h;
-
- // fix node size
- nodeStyle = node.attr('style');
- node.width(node.width()).height(node.height());
-
- // set var for drag()
- ltr = (self.direction === 'ltr');
- wzRect = self.getUI('workzone').data('rectangle');
- wzBottom = wzRect.top + wzRect.height;
- wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true);
-
- self.draggingUiHelper = helper;
- cnt = targets.length;
- while (cnt--) {
- h = targets[cnt];
- if (files[h].locked) {
- locked = true;
- helper.data('locked', true);
- break;
- }
- }
- !locked && self.trigger('lockfiles', {files : targets});
-
- helper.data('autoScrTm', setInterval(function() {
- if (helper.data('autoScr')) {
- self.autoScroll[helper.data('autoScr')](helper.data('autoScrVal'));
- }
- }, 50));
- },
- drag : function(e, ui) {
- var helper = ui.helper,
- autoScr, autoUp, bottom;
-
- if ((autoUp = wzRect.top > e.pageY) || wzBottom2 < e.pageY) {
- if (wzRect.cwdEdge > e.pageX) {
- autoScr = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
- } else {
- autoScr = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
- }
- if (!autoUp) {
- if (autoScr.substr(0, 3) === 'cwd') {
- if (wzBottom < e.pageY) {
- bottom = wzBottom;
- } else {
- autoScr = null;
- }
- } else {
- bottom = wzBottom2;
- }
- }
- if (autoScr) {
- helper.data('autoScr', autoScr);
- helper.data('autoScrVal', Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - bottom), 1.3));
- }
- }
- if (! autoScr) {
- if (helper.data('autoScr')) {
- helper.data('refreshPositions', 1).data('autoScr', null);
- }
- }
- if (helper.data('refreshPositions') && $(this).elfUiWidgetInstance('draggable')) {
- if (helper.data('refreshPositions') > 0) {
- $(this).draggable('option', { refreshPositions : true, elfRefresh : true });
- helper.data('refreshPositions', -1);
- } else {
- $(this).draggable('option', { refreshPositions : false, elfRefresh : false });
- helper.data('refreshPositions', null);
- }
- }
- },
- stop : function(e, ui) {
- var helper = ui.helper,
- files;
-
- $(document).off(keyEvt);
- $(this).elfUiWidgetInstance('draggable') && $(this).draggable('option', { refreshPositions : false });
- self.draggingUiHelper = null;
- self.trigger('focus').trigger('dragstop');
- if (! helper.data('droped')) {
- files = $.grep(helper.data('files')||[], function(h) { return h? true : false ;});
- self.trigger('unlockfiles', {files : files});
- self.trigger('selectfiles', {files : self.selected()});
- }
- self.enable();
-
- // restore node style
- node.attr('style', nodeStyle);
-
- helper.data('autoScrTm') && clearInterval(helper.data('autoScrTm'));
- },
- helper : function(e, ui) {
- var element = this.id ? $(this) : $(this).parents('[id]:first'),
- helper = $('
'),
- icon = function(f) {
- var mime = f.mime, i, tmb = self.tmb(f);
- i = '';
- if (tmb) {
- i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML;
- } else if (f.icon) {
- i = $(i).css(self.getIconStyle(f, true)).get(0).outerHTML;
- }
- if (f.csscls) {
- i = '' + i + '
';
- }
- return i;
- },
- hashes, l, ctr;
-
- self.draggingUiHelper && self.draggingUiHelper.stop(true, true);
-
- self.trigger('dragstart', {target : element[0], originalEvent : e}, true);
-
- hashes = element.hasClass(self.res('class', 'cwdfile'))
- ? self.selected()
- : [self.navId2Hash(element.attr('id'))];
-
- helper.append(icon(files[hashes[0]])).data('files', hashes).data('locked', false).data('droped', false).data('namespace', namespace).data('dropover', 0);
-
- if ((l = hashes.length) > 1) {
- helper.append(icon(files[hashes[l-1]]) + ''+l+'');
- }
-
- $(document).on(keyEvt, function(e){
- var chk = (e.shiftKey||e.ctrlKey||e.metaKey);
- if (ctr !== chk) {
- ctr = chk;
- if (helper.is(':visible') && helper.data('dropover') && ! helper.data('droped')) {
- helper.toggleClass('elfinder-drag-helper-plus', helper.data('locked')? true : ctr);
- self.trigger(ctr? 'unlockfiles' : 'lockfiles', {files : hashes, helper: helper});
- }
- }
- });
-
- return helper;
- }
- };
- })();
-
- // in getFileCallback set - change default actions on double click/enter/ctrl+enter
- if (self.commands.getfile) {
- if (typeof(self.options.getFileCallback) == 'function') {
- self.bind('dblclick', function(e) {
- e.preventDefault();
- self.exec('getfile').fail(function() {
- self.exec('open', e.data && e.data.file? [ e.data.file ]: void(0));
- });
- });
- self.shortcut({
- pattern : 'enter',
- description : self.i18n('cmdgetfile'),
- callback : function() { self.exec('getfile').fail(function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }); }
- })
- .shortcut({
- pattern : 'ctrl+enter',
- description : self.i18n(self.OS == 'mac' ? 'cmdrename' : 'cmdopen'),
- callback : function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }
- });
- } else {
- self.options.getFileCallback = null;
- }
- }
-
- // load commands
- $.each(self.commands, function(name, cmd) {
- var proto = Object.assign({}, cmd.prototype),
- extendsCmd, opts;
- if ($.isFunction(cmd) && !self._commands[name] && (cmd.prototype.forceLoad || $.inArray(name, self.options.commands) !== -1)) {
- extendsCmd = cmd.prototype.extendsCmd || '';
- if (extendsCmd) {
- if ($.isFunction(self.commands[extendsCmd])) {
- cmd.prototype = Object.assign({}, base, new self.commands[extendsCmd](), cmd.prototype);
- } else {
- return true;
- }
- } else {
- cmd.prototype = Object.assign({}, base, cmd.prototype);
- }
- self._commands[name] = new cmd();
- cmd.prototype = proto;
- opts = self.options.commandsOptions[name] || {};
- if (extendsCmd && self.options.commandsOptions[extendsCmd]) {
- opts = $.extend(true, {}, self.options.commandsOptions[extendsCmd], opts);
- }
- self._commands[name].setup(name, opts);
- // setup linked commands
- if (self._commands[name].linkedCmds.length) {
- $.each(self._commands[name].linkedCmds, function(i, n) {
- var lcmd = self.commands[n];
- if ($.isFunction(lcmd) && !self._commands[n]) {
- lcmd.prototype = base;
- self._commands[n] = new lcmd();
- self._commands[n].setup(n, self.options.commandsOptions[n]||{});
- }
- });
- }
- }
- });
-
- /**
- * UI nodes
- *
- * @type Object
- **/
- self.ui = {
- // container for nav panel and current folder container
- workzone : $('').appendTo(node).elfinderworkzone(self),
- // container for folders tree / places
- navbar : $('').appendTo(node).elfindernavbar(self, self.options.uiOptions.navbar || {}),
- // container for for preview etc at below the navbar
- navdock : $('').appendTo(node).elfindernavdock(self, self.options.uiOptions.navdock || {}),
- // contextmenu
- contextmenu : $('').appendTo(node).elfindercontextmenu(self),
- // overlay
- overlay : $('').appendTo(node).elfinderoverlay({
- show : function() { self.disable(); },
- hide : function() { prevEnabled && self.enable(); }
- }),
- // current folder container
- cwd : $('').appendTo(node).elfindercwd(self, self.options.uiOptions.cwd || {}),
- // notification dialog window
- notify : self.dialog('', {
- cssClass : 'elfinder-dialog-notify',
- position : self.options.notifyDialog.position,
- absolute : true,
- resizable : false,
- autoOpen : false,
- closeOnEscape : false,
- title : ' ',
- width : self.options.notifyDialog.width? parseInt(self.options.notifyDialog.width) : null,
- minHeight : null
- }),
- statusbar : $('').hide().appendTo(node),
- toast : $('').appendTo(node),
- bottomtray : $('').appendTo(node)
- };
-
- self.trigger('uiready');
-
- // load required ui
- $.each(self.options.ui || [], function(i, ui) {
- var name = 'elfinder'+ui,
- opts = self.options.uiOptions[ui] || {};
-
- if (!self.ui[ui] && $.fn[name]) {
- // regist to self.ui before make instance
- self.ui[ui] = $('<'+(opts.tag || 'div')+'/>').appendTo(node);
- self.ui[ui][name](self, opts);
- }
- });
-
- // update size
- self.resize(width, height);
-
- // make node resizable
- if (self.options.resizable) {
- node.resizable({
- resize : function(e, ui) {
- self.resize(ui.size.width, ui.size.height);
- },
- handles : 'se',
- minWidth : 300,
- minHeight : 200
- });
- if (self.UA.Touch) {
- node.addClass('touch-punch');
- }
- }
-
- (function() {
- var navbar = self.getUI('navbar'),
- cwd = self.getUI('cwd').parent();
-
- self.autoScroll = {
- navbarUp : function(v) {
- navbar.scrollTop(Math.max(0, navbar.scrollTop() - v));
- },
- navbarDown : function(v) {
- navbar.scrollTop(navbar.scrollTop() + v);
- },
- cwdUp : function(v) {
- cwd.scrollTop(Math.max(0, cwd.scrollTop() - v));
- },
- cwdDown : function(v) {
- cwd.scrollTop(cwd.scrollTop() + v);
- }
- };
- })();
-
- // Swipe on the touch devices to show/hide of toolbar or navbar
- if (self.UA.Touch) {
- (function() {
- var lastX, lastY, nodeOffset, nodeWidth, nodeTop, navbarW, toolbarH,
- navbar = self.getUI('navbar'),
- toolbar = self.getUI('toolbar'),
- moveEv = 'touchmove.stopscroll',
- moveTm,
- moveUpOn = function(e) {
- var touches = e.originalEvent.touches || [{}],
- y = touches[0].pageY || null;
- if (!lastY || y < lastY) {
- e.preventDefault();
- moveTm && clearTimeout(moveTm);
- }
- },
- moveDownOn = function(e) {
- e.preventDefault();
- moveTm && clearTimeout(moveTm);
- },
- moveOff = function() {
- moveTm = setTimeout(function() {
- node.off(moveEv);
- }, 100);
- },
- handleW, handleH = 50;
-
- navbar = navbar.children().length? navbar : null;
- toolbar = toolbar.length? toolbar : null;
- node.on('touchstart touchmove touchend', function(e) {
- if (e.type === 'touchend') {
- lastX = false;
- lastY = false;
- moveOff();
- return;
- }
-
- var touches = e.originalEvent.touches || [{}],
- x = touches[0].pageX || null,
- y = touches[0].pageY || null,
- ltr = (self.direction === 'ltr'),
- navbarMode, treeWidth, swipeX, moveX, toolbarT, mode;
-
- if (x === null || y === null || (e.type === 'touchstart' && touches.length > 1)) {
- return;
- }
-
- if (e.type === 'touchstart') {
- nodeOffset = node.offset();
- nodeWidth = node.width();
- if (navbar) {
- lastX = false;
- if (navbar.is(':hidden')) {
- if (! handleW) {
- handleW = Math.max(50, nodeWidth / 10);
- }
- if ((ltr? (x - nodeOffset.left) : (nodeWidth + nodeOffset.left - x)) < handleW) {
- lastX = x;
- }
- } else if (! e.originalEvent._preventSwipeX) {
- navbarW = navbar.width();
- if (ltr) {
- swipeX = (x < nodeOffset.left + navbarW);
- } else {
- swipeX = (x > nodeOffset.left + nodeWidth - navbarW);
- }
- if (swipeX) {
- handleW = Math.max(50, nodeWidth / 10);
- lastX = x;
- } else {
- lastX = false;
- }
- }
- }
- if (toolbar) {
- lastY = false;
- if (! e.originalEvent._preventSwipeY) {
- toolbarH = toolbar.height();
- nodeTop = nodeOffset.top;
- if (y - nodeTop < (toolbar.is(':hidden')? handleH : (toolbarH + 30))) {
- lastY = y;
- node.on(moveEv, toolbar.is(':hidden')? moveDownOn: moveUpOn);
- }
- }
- }
- } else {
- if (navbar && lastX !== false) {
- navbarMode = (ltr? (lastX > x) : (lastX < x))? 'navhide' : 'navshow';
- moveX = Math.abs(lastX - x);
- if (navbarMode === 'navhide' && moveX > navbarW * 0.6
- || (moveX > (navbarMode === 'navhide'? navbarW / 3 : 45)
- && (navbarMode === 'navshow'
- || (ltr? x < nodeOffset.left + 20 : x > nodeOffset.left + nodeWidth - 20)
- ))
- ) {
- self.getUI('navbar').trigger(navbarMode, {handleW: handleW});
- lastX = false;
- }
- }
- if (toolbar && lastY !== false ) {
- toolbarT = toolbar.offset().top;
- if (Math.abs(lastY - y) > Math.min(45, toolbarH / 3)) {
- mode = (lastY > y)? 'slideUp' : 'slideDown';
- if (mode === 'slideDown' || toolbarT + 20 > y) {
- if (toolbar.is(mode === 'slideDown' ? ':hidden' : ':visible')) {
- toolbar.stop(true, true).trigger('toggle', {duration: 100, handleH: handleH});
- }
- lastY = false;
- }
- }
- }
- }
- });
- })();
- }
-
- if (self.dragUpload) {
- // add event listener for HTML5 DnD upload
- (function() {
- var isin = function(e) {
- return (e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && $(e.target).closest('div.ui-dialog-content').length === 0);
- },
- ent = 'native-drag-enter',
- disable = 'native-drag-disable',
- c = 'class',
- navdir = self.res(c, 'navdir'),
- droppable = self.res(c, 'droppable'),
- dropover = self.res(c, 'adroppable'),
- arrow = self.res(c, 'navarrow'),
- clDropActive = self.res(c, 'adroppable'),
- wz = self.getUI('workzone'),
- ltr = (self.direction === 'ltr'),
- clearTm = function() {
- autoScrTm && cancelAnimationFrame(autoScrTm);
- autoScrTm = null;
- },
- wzRect, autoScrFn, autoScrTm;
-
- node.on('dragenter', function(e) {
- clearTm();
- if (isin(e)) {
- e.preventDefault();
- e.stopPropagation();
- wzRect = wz.data('rectangle');
- }
- })
- .on('dragleave', function(e) {
- clearTm();
- if (isin(e)) {
- e.preventDefault();
- e.stopPropagation();
- }
- })
- .on('dragover', function(e) {
- var autoUp;
- if (isin(e)) {
- e.preventDefault();
- e.stopPropagation();
- e.originalEvent.dataTransfer.dropEffect = 'none';
- if (! autoScrTm) {
- autoScrTm = requestAnimationFrame(function() {
- var wzBottom = wzRect.top + wzRect.height,
- wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true),
- fn;
- if ((autoUp = e.pageY < wzRect.top) || e.pageY > wzBottom2 ) {
- if (wzRect.cwdEdge > e.pageX) {
- fn = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down');
- } else {
- fn = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down');
- }
- if (!autoUp) {
- if (fn.substr(0, 3) === 'cwd') {
- if (wzBottom < e.pageY) {
- wzBottom2 = wzBottom;
- } else {
- fn = '';
- }
- }
- }
- fn && self.autoScroll[fn](Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - wzBottom2), 1.3));
- }
- autoScrTm = null;
- });
- }
- } else {
- clearTm();
- }
- })
- .on('drop', function(e) {
- clearTm();
- if (isin(e)) {
- e.stopPropagation();
- e.preventDefault();
- }
- });
-
- node.on('dragenter', '.native-droppable', function(e){
- if (e.originalEvent.dataTransfer) {
- var $elm = $(e.currentTarget),
- id = e.currentTarget.id || null,
- cwd = null,
- elfFrom;
- if (!id) { // target is cwd
- cwd = self.cwd();
- $elm.data(disable, false);
- try {
- $.each(e.originalEvent.dataTransfer.types, function(i, v){
- if (v.substr(0, 13) === 'elfinderfrom:') {
- elfFrom = v.substr(13).toLowerCase();
- }
- });
- } catch(e) {}
- }
- if (!cwd || (cwd.write && (!elfFrom || elfFrom !== (window.location.href + cwd.hash).toLowerCase()))) {
- e.preventDefault();
- e.stopPropagation();
- $elm.data(ent, true);
- $elm.addClass(clDropActive);
- } else {
- $elm.data(disable, true);
- }
- }
- })
- .on('dragleave', '.native-droppable', function(e){
- if (e.originalEvent.dataTransfer) {
- var $elm = $(e.currentTarget);
- e.preventDefault();
- e.stopPropagation();
- if ($elm.data(ent)) {
- $elm.data(ent, false);
- } else {
- $elm.removeClass(clDropActive);
- }
- }
- })
- .on('dragover', '.native-droppable', function(e){
- if (e.originalEvent.dataTransfer) {
- var $elm = $(e.currentTarget);
- e.preventDefault();
- e.stopPropagation();
- e.originalEvent.dataTransfer.dropEffect = $elm.data(disable)? 'none' : 'copy';
- $elm.data(ent, false);
- }
- })
- .on('drop', '.native-droppable', function(e){
- if (e.originalEvent && e.originalEvent.dataTransfer) {
- var $elm = $(e.currentTarget),
- id;
- e.preventDefault();
- e.stopPropagation();
- $elm.removeClass(clDropActive);
- if (e.currentTarget.id) {
- id = $elm.hasClass(navdir)? self.navId2Hash(e.currentTarget.id) : self.cwdId2Hash(e.currentTarget.id);
- } else {
- id = self.cwd().hash;
- }
- e.originalEvent._target = id;
- self.exec('upload', {dropEvt: e.originalEvent, target: id}, void 0, id);
- }
- });
- })();
- }
-
- // trigger event cssloaded if cssAutoLoad disabled
- if (self.cssloaded === false) {
- self.cssloaded = true;
- self.trigger('cssloaded');
- }
-
- // calculate elFinder node z-index
- self.zIndexCalc();
-
- // send initial request and start to pray >_<
- self.trigger('init')
- .request({
- data : {cmd : 'open', target : self.startDir(), init : 1, tree : 1},
- preventDone : true,
- notify : {type : 'open', cnt : 1, hideCnt : true},
- freeze : true
- })
- .fail(function() {
- self.trigger('fail').disable().lastDir('');
- listeners = {};
- shortcuts = {};
- $(document).add(node).off('.'+namespace);
- self.trigger = function() { };
- })
- .done(function(data) {
- var trashDisable = function(th) {
- var src = self.file(self.trashes[th]),
- d = self.options.debug,
- error;
-
- if (src && src.volumeid) {
- delete self.volOptions[src.volumeid].trashHash;
- }
- self.trashes[th] = false;
- self.debug('backend-error', 'Trash hash "'+th+'" was not found or not writable.');
- },
- toChkTh = {};
-
- // regist rawStringDecoder
- if (self.options.rawStringDecoder) {
- self.registRawStringDecoder(self.options.rawStringDecoder);
- }
-
- // re-calculate elFinder node z-index
- self.zIndexCalc();
-
- self.load().debug('api', self.api);
- // update ui's size after init
- node.trigger('resize');
- // initial open
- open(data);
- self.trigger('open', data, false);
- self.trigger('opendone');
-
- if (inFrame && self.options.enableAlways) {
- $(window).trigger('focus');
- }
-
- // check self.trashes
- $.each(self.trashes, function(th) {
- var dir = self.file(th),
- src;
- if (! dir) {
- toChkTh[th] = true;
- } else if (dir.mime !== 'directory' || ! dir.write) {
- trashDisable(th);
- }
- });
- if (Object.keys(toChkTh).length) {
- self.request({
- data : {cmd : 'info', targets : Object.keys(toChkTh)},
- preventDefault : true
- }).done(function(data) {
- if (data && data.files) {
- $.each(data.files, function(i, dir) {
- if (dir.mime === 'directory' && dir.write) {
- delete toChkTh[dir.hash];
- }
- });
- }
- }).always(function() {
- $.each(toChkTh, trashDisable);
- });
- }
- // to enable / disable
- self[self.options.enableAlways? 'enable' : 'disable']();
- });
-
- // self.timeEnd('load');
- // End of bootUp()
- };
-
- // call bootCallback function with elFinder instance, extraObject - { dfrdsBeforeBootup: dfrdsBeforeBootup }
- if (bootCallback && typeof bootCallback === 'function') {
- self.bootCallback = bootCallback;
- bootCallback.call(node.get(0), self, { dfrdsBeforeBootup: dfrdsBeforeBootup });
- }
-
- // call dfrdsBeforeBootup functions then boot up elFinder
- $.when.apply(null, dfrdsBeforeBootup).done(function() {
- bootUp();
- }).fail(function(error) {
- self.error(error);
- });
-};
-
-//register elFinder to global scope
-if (typeof toGlobal === 'undefined' || toGlobal) {
- window.elFinder = elFinder;
-}
-
-/**
- * Prototype
- *
- * @type Object
- */
-elFinder.prototype = {
-
- uniqueid : 0,
-
- res : function(type, id) {
- return this.resources[type] && this.resources[type][id];
- },
-
- /**
- * User os. Required to bind native shortcuts for open/rename
- *
- * @type String
- **/
- OS : navigator.userAgent.indexOf('Mac') !== -1 ? 'mac' : navigator.userAgent.indexOf('Win') !== -1 ? 'win' : 'other',
-
- /**
- * User browser UA.
- * jQuery.browser: version deprecated: 1.3, removed: 1.9
- *
- * @type Object
- **/
- UA : (function(){
- var self = this,
- webkit = !document.unqueID && !window.opera && !window.sidebar && window.localStorage && 'WebkitAppearance' in document.documentElement.style,
- chrome = webkit && window.chrome,
- /*setRotated = function() {
- var a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0;
- if (a === -90) {
- a = 270;
- }
- UA.Angle = a;
- UA.Rotated = a % 180 === 0? false : true;
- },*/
- UA = {
- // Browser IE <= IE 6
- ltIE6 : typeof window.addEventListener == "undefined" && typeof document.documentElement.style.maxHeight == "undefined",
- // Browser IE <= IE 7
- ltIE7 : typeof window.addEventListener == "undefined" && typeof document.querySelectorAll == "undefined",
- // Browser IE <= IE 8
- ltIE8 : typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined",
- // Browser IE <= IE 9
- ltIE9 : document.uniqueID && document.documentMode <= 9,
- // Browser IE <= IE 10
- ltIE10 : document.uniqueID && document.documentMode <= 10,
- // Browser IE >= IE 11
- gtIE11 : document.uniqueID && document.documentMode >= 11,
- IE : document.uniqueID,
- Firefox : window.sidebar,
- Opera : window.opera,
- Webkit : webkit,
- Chrome : chrome,
- Edge : (chrome && window.msCredentials)? true : false,
- Safari : webkit && !window.chrome,
- Mobile : typeof window.orientation != "undefined",
- Touch : typeof window.ontouchstart != "undefined",
- iOS : navigator.platform.match(/^iP(?:[ao]d|hone)/),
- Fullscreen : (typeof (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen) !== 'undefined'),
- Angle : 0,
- Rotated : false,
- CSS : (function() {
- var aStyle = document.createElement('a').style,
- pStyle = document.createElement('p').style,
- css;
- css = 'position:sticky;position:-webkit-sticky;';
- css += 'width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;';
- aStyle.cssText = css;
- return {
- positionSticky : aStyle.position.indexOf('sticky')!==-1,
- widthMaxContent : aStyle.width.indexOf('max-content')!==-1,
- flex : typeof pStyle.flex !== 'undefined'
- };
- })()
- };
- return UA;
- })(),
-
- /**
- * Has RequireJS?
- *
- * @type Boolean
- */
- hasRequire : (typeof define === 'function' && define.amd),
-
- /**
- * Current request command
- *
- * @type String
- */
- currentReqCmd : '',
-
- /**
- * Current keyboard state
- *
- * @type Object
- */
- keyState : {},
-
- /**
- * Internationalization object
- *
- * @type Object
- */
- i18 : {
- en : {
- translator : '',
- language : 'English',
- direction : 'ltr',
- dateFormat : 'd.m.Y H:i',
- fancyDateFormat : '$1 H:i',
- nonameDateFormat : 'ymd-His',
- messages : {}
- },
- months : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- monthsShort : ['msJan', 'msFeb', 'msMar', 'msApr', 'msMay', 'msJun', 'msJul', 'msAug', 'msSep', 'msOct', 'msNov', 'msDec'],
-
- days : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- daysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
- },
-
- /**
- * File mimetype to kind mapping
- *
- * @type Object
- */
- kinds : {
- 'unknown' : 'Unknown',
- 'directory' : 'Folder',
- 'group' : 'Selects',
- 'symlink' : 'Alias',
- 'symlink-broken' : 'AliasBroken',
- 'application/x-empty' : 'TextPlain',
- 'application/postscript' : 'Postscript',
- 'application/vnd.ms-office' : 'MsOffice',
- 'application/msword' : 'MsWord',
- 'application/vnd.ms-word' : 'MsWord',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'MsWord',
- 'application/vnd.ms-word.document.macroEnabled.12' : 'MsWord',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' : 'MsWord',
- 'application/vnd.ms-word.template.macroEnabled.12' : 'MsWord',
- 'application/vnd.ms-excel' : 'MsExcel',
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'MsExcel',
- 'application/vnd.ms-excel.sheet.macroEnabled.12' : 'MsExcel',
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' : 'MsExcel',
- 'application/vnd.ms-excel.template.macroEnabled.12' : 'MsExcel',
- 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' : 'MsExcel',
- 'application/vnd.ms-excel.addin.macroEnabled.12' : 'MsExcel',
- 'application/vnd.ms-powerpoint' : 'MsPP',
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation' : 'MsPP',
- 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' : 'MsPP',
- 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' : 'MsPP',
- 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' : 'MsPP',
- 'application/vnd.openxmlformats-officedocument.presentationml.template' : 'MsPP',
- 'application/vnd.ms-powerpoint.template.macroEnabled.12' : 'MsPP',
- 'application/vnd.ms-powerpoint.addin.macroEnabled.12' : 'MsPP',
- 'application/vnd.openxmlformats-officedocument.presentationml.slide' : 'MsPP',
- 'application/vnd.ms-powerpoint.slide.macroEnabled.12' : 'MsPP',
- 'application/pdf' : 'PDF',
- 'application/xml' : 'XML',
- 'application/vnd.oasis.opendocument.text' : 'OO',
- 'application/vnd.oasis.opendocument.text-template' : 'OO',
- 'application/vnd.oasis.opendocument.text-web' : 'OO',
- 'application/vnd.oasis.opendocument.text-master' : 'OO',
- 'application/vnd.oasis.opendocument.graphics' : 'OO',
- 'application/vnd.oasis.opendocument.graphics-template' : 'OO',
- 'application/vnd.oasis.opendocument.presentation' : 'OO',
- 'application/vnd.oasis.opendocument.presentation-template' : 'OO',
- 'application/vnd.oasis.opendocument.spreadsheet' : 'OO',
- 'application/vnd.oasis.opendocument.spreadsheet-template' : 'OO',
- 'application/vnd.oasis.opendocument.chart' : 'OO',
- 'application/vnd.oasis.opendocument.formula' : 'OO',
- 'application/vnd.oasis.opendocument.database' : 'OO',
- 'application/vnd.oasis.opendocument.image' : 'OO',
- 'application/vnd.openofficeorg.extension' : 'OO',
- 'application/x-shockwave-flash' : 'AppFlash',
- 'application/flash-video' : 'Flash video',
- 'application/x-bittorrent' : 'Torrent',
- 'application/javascript' : 'JS',
- 'application/rtf' : 'RTF',
- 'application/rtfd' : 'RTF',
- 'application/x-font-ttf' : 'TTF',
- 'application/x-font-otf' : 'OTF',
- 'application/x-rpm' : 'RPM',
- 'application/x-web-config' : 'TextPlain',
- 'application/xhtml+xml' : 'HTML',
- 'application/docbook+xml' : 'DOCBOOK',
- 'application/x-awk' : 'AWK',
- 'application/x-gzip' : 'GZIP',
- 'application/x-bzip2' : 'BZIP',
- 'application/x-xz' : 'XZ',
- 'application/zip' : 'ZIP',
- 'application/x-zip' : 'ZIP',
- 'application/x-rar' : 'RAR',
- 'application/x-tar' : 'TAR',
- 'application/x-7z-compressed' : '7z',
- 'application/x-jar' : 'JAR',
- 'text/plain' : 'TextPlain',
- 'text/x-php' : 'PHP',
- 'text/html' : 'HTML',
- 'text/javascript' : 'JS',
- 'text/css' : 'CSS',
- 'text/rtf' : 'RTF',
- 'text/rtfd' : 'RTF',
- 'text/x-c' : 'C',
- 'text/x-csrc' : 'C',
- 'text/x-chdr' : 'CHeader',
- 'text/x-c++' : 'CPP',
- 'text/x-c++src' : 'CPP',
- 'text/x-c++hdr' : 'CPPHeader',
- 'text/x-shellscript' : 'Shell',
- 'application/x-csh' : 'Shell',
- 'text/x-python' : 'Python',
- 'text/x-java' : 'Java',
- 'text/x-java-source' : 'Java',
- 'text/x-ruby' : 'Ruby',
- 'text/x-perl' : 'Perl',
- 'text/x-sql' : 'SQL',
- 'text/xml' : 'XML',
- 'text/x-comma-separated-values' : 'CSV',
- 'text/x-markdown' : 'Markdown',
- 'image/x-ms-bmp' : 'BMP',
- 'image/jpeg' : 'JPEG',
- 'image/gif' : 'GIF',
- 'image/png' : 'PNG',
- 'image/tiff' : 'TIFF',
- 'image/x-targa' : 'TGA',
- 'image/vnd.adobe.photoshop' : 'PSD',
- 'image/xbm' : 'XBITMAP',
- 'image/pxm' : 'PXM',
- 'audio/mpeg' : 'AudioMPEG',
- 'audio/midi' : 'AudioMIDI',
- 'audio/ogg' : 'AudioOGG',
- 'audio/mp4' : 'AudioMPEG4',
- 'audio/x-m4a' : 'AudioMPEG4',
- 'audio/wav' : 'AudioWAV',
- 'audio/x-mp3-playlist' : 'AudioPlaylist',
- 'video/x-dv' : 'VideoDV',
- 'video/mp4' : 'VideoMPEG4',
- 'video/mpeg' : 'VideoMPEG',
- 'video/x-msvideo' : 'VideoAVI',
- 'video/quicktime' : 'VideoMOV',
- 'video/x-ms-wmv' : 'VideoWM',
- 'video/x-flv' : 'VideoFlash',
- 'video/x-matroska' : 'VideoMKV',
- 'video/ogg' : 'VideoOGG'
- },
-
- /**
- * File mimetype to file extention mapping
- *
- * @type Object
- * @see elFinder.mimetypes.js
- */
- mimeTypes : {},
-
- /**
- * Ajax request data validation rules
- *
- * @type Object
- */
- rules : {
- defaults : function(data) {
- if (!data
- || (data.added && !Array.isArray(data.added))
- || (data.removed && !Array.isArray(data.removed))
- || (data.changed && !Array.isArray(data.changed))) {
- return false;
- }
- return true;
- },
- open : function(data) { return data && data.cwd && data.files && $.isPlainObject(data.cwd) && Array.isArray(data.files); },
- tree : function(data) { return data && data.tree && Array.isArray(data.tree); },
- parents : function(data) { return data && data.tree && Array.isArray(data.tree); },
- tmb : function(data) { return data && data.images && ($.isPlainObject(data.images) || Array.isArray(data.images)); },
- upload : function(data) { return data && ($.isPlainObject(data.added) || Array.isArray(data.added));},
- search : function(data) { return data && data.files && Array.isArray(data.files); }
- },
-
- /**
- * Commands costructors
- *
- * @type Object
- */
- commands : {},
-
- /**
- * Commands to add the item (space delimited)
- *
- * @type String
- */
- cmdsToAdd : 'archive duplicate extract mkdir mkfile paste rm upload',
-
- parseUploadData : function(text) {
- var self = this,
- data;
-
- if (!$.trim(text)) {
- return {error : ['errResponse', 'errDataEmpty']};
- }
-
- try {
- data = JSON.parse(text);
- } catch (e) {
- return {error : ['errResponse', 'errDataNotJSON']};
- }
-
- data = self.normalize(data);
- if (!self.validResponse('upload', data)) {
- return {error : (data.norError || ['errResponse'])};
- }
- data.removed = $.merge((data.removed || []), $.map(data.added || [], function(f) { return self.file(f.hash)? f.hash : null; }));
- return data;
-
- },
-
- iframeCnt : 0,
-
- uploads : {
- // xhr muiti uploading flag
- xhrUploading: false,
-
- // Timer of request fail to sync
- failSyncTm: null,
-
- // current chunkfail requesting chunk
- chunkfailReq: {},
-
- // check file/dir exists
- checkExists: function(files, target, fm, isDir) {
- var dfrd = $.Deferred(),
- names, renames = [], hashes = {}, chkFiles = [],
- cancel = function() {
- var i = files.length;
- while (--i > -1) {
- files[i]._remove = true;
- }
- },
- resolve = function() {
- dfrd.resolve(renames, hashes);
- },
- check = function() {
- var existed = [], exists = [], i, c,
- pathStr = target !== fm.cwd().hash? fm.path(target, true) + fm.option('separator', target) : '',
- confirm = function(ndx) {
- var last = ndx == exists.length-1,
- opts = {
- cssClass : 'elfinder-confirm-upload',
- title : fm.i18n('cmdupload'),
- text : ['errExists', pathStr + exists[ndx].name, 'confirmRepl'],
- all : !last,
- accept : {
- label : 'btnYes',
- callback : function(all) {
- !last && !all
- ? confirm(++ndx)
- : resolve();
- }
- },
- reject : {
- label : 'btnNo',
- callback : function(all) {
- var i;
-
- if (all) {
- i = exists.length;
- while (ndx < i--) {
- files[exists[i].i]._remove = true;
- }
- } else {
- files[exists[ndx].i]._remove = true;
- }
-
- !last && !all
- ? confirm(++ndx)
- : resolve();
- }
- },
- cancel : {
- label : 'btnCancel',
- callback : function() {
- cancel();
- resolve();
- }
- },
- buttons : [
- {
- label : 'btnBackup',
- cssClass : 'elfinder-confirm-btn-backup',
- callback : function(all) {
- var i;
- if (all) {
- i = exists.length;
- while (ndx < i--) {
- renames.push(exists[i].name);
- }
- } else {
- renames.push(exists[ndx].name);
- }
- !last && !all
- ? confirm(++ndx)
- : resolve();
- }
- }
- ]
- };
-
- if (!isDir) {
- opts.buttons.push({
- label : 'btnRename' + (last? '' : 'All'),
- cssClass : 'elfinder-confirm-btn-rename',
- callback : function() {
- renames = null;
- resolve();
- }
- });
- }
- if (fm.iframeCnt > 0) {
- delete opts.reject;
- }
- fm.confirm(opts);
- };
-
- if (! fm.file(target).read) {
- // for dropbox type
- resolve();
- return;
- }
-
- names = $.map(files, function(file, i) { return file.name && (!fm.UA.iOS || file.name !== 'image.jpg')? {i: i, name: file.name} : null ;});
-
- fm.request({
- data : {cmd : 'ls', target : target, intersect : $.map(names, function(item) { return item.name;})},
- notify : {type : 'preupload', cnt : 1, hideCnt : true},
- preventDefault : true
- })
- .done(function(data) {
- var existedArr, cwdItems;
- if (data) {
- if (data.error) {
- cancel();
- } else {
- if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
- if (data.list) {
- if (Array.isArray(data.list)) {
- existed = data.list || [];
- } else {
- existedArr = [];
- existed = $.map(data.list, function(n) {
- if (typeof n === 'string') {
- return n;
- } else {
- // support to >=2.1.11 plugin Normalizer, Sanitizer
- existedArr = existedArr.concat(n);
- return false;
- }
- });
- if (existedArr.length) {
- existed = existed.concat(existedArr);
- }
- hashes = data.list;
- }
- exists = $.grep(names, function(name){
- return $.inArray(name.name, existed) !== -1 ? true : false ;
- });
- if (exists.length && existed.length && target == fm.cwd().hash) {
- cwdItems = $.map(fm.files(target), function(file) { return file.name; } );
- if ($.grep(existed, function(n) {
- return $.inArray(n, cwdItems) === -1? true : false;
- }).length){
- fm.sync();
- }
- }
- }
- }
- }
- }
- if (exists.length > 0) {
- confirm(0);
- } else {
- resolve();
- }
- })
- .fail(function(error) {
- cancel();
- resolve();
- error && fm.error(error);
- });
- };
- if (fm.api >= 2.1 && typeof files[0] == 'object') {
- check();
- } else {
- resolve();
- }
- return dfrd;
- },
-
- // check droped contents
- checkFile : function(data, fm, target) {
- if (!!data.checked || data.type == 'files') {
- return data.files;
- } else if (data.type == 'data') {
- var dfrd = $.Deferred(),
- scanDfd = $.Deferred(),
- files = [],
- paths = [],
- dirctorys = [],
- processing = 0,
- items,
- mkdirs = [],
- cancel = false,
- toArray = function(list) {
- return Array.prototype.slice.call(list || [], 0);
- },
- doScan = function(items) {
- var entry, readEntries,
- excludes = fm.options.folderUploadExclude[fm.OS] || null,
- length = items.length,
- check = function() {
- if (--processing < 1 && scanDfd.state() === 'pending') {
- scanDfd.resolve();
- }
- },
- pushItem = function(file) {
- if (! excludes || ! file.name.match(excludes)) {
- paths.push(entry.fullPath || '');
- files.push(file);
- }
- check();
- },
- readEntries = function(dirReader) {
- var entries = [],
- read = function() {
- dirReader.readEntries(function(results) {
- if (cancel || !results.length) {
- for (var i = 0; i < entries.length; i++) {
- if (cancel) {
- scanDfd.reject();
- break;
- }
- doScan([entries[i]]);
- }
- check();
- } else {
- entries = entries.concat(toArray(results));
- read();
- }
- }, check);
- };
- read();
- };
-
- processing++;
- for (var i = 0; i < length; i++) {
- if (cancel) {
- scanDfd.reject();
- break;
- }
- entry = items[i];
- if (entry) {
- if (entry.isFile) {
- processing++;
- entry.file(pushItem, check);
- } else if (entry.isDirectory) {
- if (fm.api >= 2.1) {
- processing++;
- mkdirs.push(entry.fullPath);
- readEntries(entry.createReader()); // Start reading dirs.
- }
- }
- }
- }
- check();
- return scanDfd;
- }, hasDirs;
-
- items = $.map(data.files.items, function(item){
- return item.getAsEntry? item.getAsEntry() : item.webkitGetAsEntry();
- });
- $.each(items, function(i, item) {
- if (item.isDirectory) {
- hasDirs = true;
- return false;
- }
- });
- if (items.length > 0) {
- fm.uploads.checkExists(items, target, fm, hasDirs).done(function(renames, hashes){
- var dfds = [];
- if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
- if (renames === null) {
- data.overwrite = 0;
- renames = [];
- }
- items = $.grep(items, function(item){
- var i, bak, hash, dfd, hi;
- if (item.isDirectory && renames.length) {
- i = $.inArray(item.name, renames);
- if (i !== -1) {
- renames.splice(i, 1);
- bak = fm.uniqueName(item.name + fm.options.backupSuffix , null, '');
- $.each(hashes, function(h, name) {
- if (item.name == name) {
- hash = h;
- return false;
- }
- });
- if (! hash) {
- hash = fm.fileByName(item.name, target).hash;
- }
- fm.lockfiles({files : [hash]});
- dfd = fm.request({
- data : {cmd : 'rename', target : hash, name : bak},
- notify : {type : 'rename', cnt : 1}
- })
- .fail(function() {
- item._remove = true;
- fm.sync();
- })
- .always(function() {
- fm.unlockfiles({files : [hash]});
- });
- dfds.push(dfd);
- }
- }
- return !item._remove? true : false;
- });
- }
- $.when.apply($, dfds).done(function(){
- var notifyto, msg,
- id = +new Date();
-
- if (items.length > 0) {
- msg = fm.escape(items[0].name);
- if (items.length > 1) {
- msg += ' ... ' + items.length + fm.i18n('items');
- }
- notifyto = setTimeout(function() {
- fm.notify({
- type : 'readdir',
- id : id,
- cnt : 1,
- hideCnt: true,
- msg : fm.i18n('ntfreaddir') + ' (' + msg + ')',
- cancel: function() {
- cancel = true;
- }
- });
- }, fm.options.notifyDelay);
- doScan(items).done(function() {
- notifyto && clearTimeout(notifyto);
- fm.notify({type : 'readdir', id: id, cnt : -1});
- if (cancel) {
- dfrd.reject();
- } else {
- dfrd.resolve([files, paths, renames, hashes, mkdirs]);
- }
- }).fail(function() {
- dfrd.reject();
- });
- } else {
- dfrd.reject();
- }
- });
- });
- return dfrd.promise();
- } else {
- return dfrd.reject();
- }
- } else {
- var ret = [];
- var check = [];
- var str = data.files[0];
- if (data.type == 'html') {
- var tmp = $("
").append($.parseHTML(str.replace(/ src=/ig, ' _elfsrc='))),
- atag;
- $('img[_elfsrc]', tmp).each(function(){
- var url, purl,
- self = $(this),
- pa = self.closest('a');
- if (pa && pa.attr('href') && pa.attr('href').match(/\.(?:jpe?g|gif|bmp|png)/i)) {
- purl = pa.attr('href');
- }
- url = self.attr('_elfsrc');
- if (url) {
- if (purl) {
- $.inArray(purl, ret) == -1 && ret.push(purl);
- $.inArray(url, check) == -1 && check.push(url);
- } else {
- $.inArray(url, ret) == -1 && ret.push(url);
- }
- }
- // Probably it's clipboard data
- if (ret.length === 1 && ret[0].match(/^data:image\/png/)) {
- data.clipdata = true;
- }
- });
- atag = $('a[href]', tmp);
- atag.each(function(){
- var text, loc,
- parseUrl = function(url) {
- var a = document.createElement('a');
- a.href = url;
- return a;
- };
- if (text = $(this).text()) {
- loc = parseUrl($(this).attr('href'));
- if (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))) {
- if ($.inArray(loc.href, ret) == -1 && $.inArray(loc.href, check) == -1) ret.push(loc.href);
- }
- }
- });
- } else {
- var regex, m, url;
- regex = /((?:ht|f)tps?:\/\/[-_.!~*\'()a-z0-9;/?:\@&=+\$,%#\*\[\]]+)/ig;
- while (m = regex.exec(str)) {
- url = m[1].replace(/&/g, '&');
- if ($.inArray(url, ret) == -1) ret.push(url);
- }
- }
- return ret;
- }
- },
-
- // upload transport using XMLHttpRequest
- xhr : function(data, fm) {
- var self = fm ? fm : this,
- node = self.getUI(),
- xhr = new XMLHttpRequest(),
- notifyto = null, notifyto2 = null,
- dataChecked = data.checked,
- isDataType = (data.isDataType || data.type == 'data'),
- target = (data.target || self.cwd().hash),
- dropEvt = (data.dropEvt || null),
- extraData = data.extraData || null,
- chunkEnable = (self.option('uploadMaxConn', target) != -1),
- multiMax = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))),
- retryWait = 10000, // 10 sec
- retryMax = 30, // 10 sec * 30 = 300 secs (Max 5 mins)
- retry = 0,
- getFile = function(files) {
- var dfd = $.Deferred(),
- file;
- if (files.promise) {
- files.always(function(f) {
- dfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {});
- });
- } else {
- dfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {});
- }
- return dfd;
- },
- dfrd = $.Deferred()
- .fail(function(err) {
- var error = self.parseError(err),
- userAbort;
- if (error === 'userabort') {
- userAbort = true;
- error = void 0;
- }
- if (files && (self.uploads.xhrUploading || userAbort)) {
- // send request om fail
- getFile(files).done(function(file) {
- if (!userAbort) {
- triggerError(error, file);
- }
- if (! file._cid) {
- // send sync request
- self.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm);
- self.uploads.failSyncTm = setTimeout(function() {
- self.sync(target);
- }, 1000);
- } else if (! self.uploads.chunkfailReq[file._cid]) {
- // send chunkfail request
- self.uploads.chunkfailReq[file._cid] = true;
- setTimeout(function() {
- fm.request({
- data : {
- cmd: 'upload',
- target: target,
- chunk: file._chunk,
- cid: file._cid,
- upload: ['chunkfail'],
- mimes: 'chunkfail'
- },
- options : {
- type: 'post',
- url: self.uploadURL
- },
- preventDefault: true
- }).always(function() {
- delete self.uploads.chunkfailReq[file._chunk];
- });
- }, 1000);
- }
- });
- } else {
- triggerError(error);
- }
- !userAbort && self.sync();
- self.uploads.xhrUploading = false;
- files = null;
- })
- .done(function(data) {
- self.uploads.xhrUploading = false;
- files = null;
- if (data) {
- self.currentReqCmd = 'upload';
- data.warning && triggerError(data.warning);
- self.updateCache(data);
- data.removed && data.removed.length && self.remove(data);
- data.added && data.added.length && self.add(data);
- data.changed && data.changed.length && self.change(data);
- self.trigger('upload', data, false);
- self.trigger('uploaddone');
- if (data.toasts && Array.isArray(data.toasts)) {
- $.each(data.toasts, function() {
- this.msg && self.toast(this);
- });
- }
- data.sync && self.sync();
- data.debug && fm.debug('backend-debug', data);
- }
- })
- .always(function() {
- self.abortXHR(xhr);
- // unregist fnAbort function
- node.off('uploadabort', fnAbort);
- $(window).off('unload', fnAbort);
- notifyto && clearTimeout(notifyto);
- notifyto2 && clearTimeout(notifyto2);
- dataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
- chunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1});
- }),
- formData = new FormData(),
- files = data.input ? data.input.files : self.uploads.checkFile(data, self, target),
- cnt = data.checked? (isDataType? files[0].length : files.length) : files.length,
- loaded = 0,
- prev = 0,
- filesize = 0,
- notify = false,
- notifyElm = self.ui.notify,
- cancelBtn = true,
- abort = false,
- checkNotify = function() {
- if (!notify && (ntfUpload = notifyElm.children('.elfinder-notify-upload')).length) {
- notify = true;
- }
- return notify;
- },
- fnAbort = function(e, error) {
- abort = true;
- self.abortXHR(xhr, { quiet: true, abort: true });
- dfrd.reject(error);
- if (checkNotify()) {
- self.notify({type : 'upload', cnt : ntfUpload.data('cnt') * -1, progress : 0, size : 0});
- }
- },
- cancelToggle = function(show) {
- ntfUpload.children('.elfinder-notify-cancel')[show? 'show':'hide']();
- },
- startNotify = function(size) {
- if (!size) size = filesize;
- return setTimeout(function() {
- notify = true;
- self.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size,
- cancel: function() {
- node.trigger('uploadabort', 'userabort');
- }
- });
- ntfUpload = notifyElm.children('.elfinder-notify-upload');
- prev = loaded;
- if (data.multiupload) {
- cancelBtn && cancelToggle(true);
- } else {
- cancelToggle(cancelBtn && loaded < size);
- }
- }, self.options.notifyDelay);
- },
- doRetry = function() {
- if (retry++ <= retryMax) {
- if (checkNotify() && prev) {
- self.notify({type : 'upload', cnt : 0, progress : 0, size : prev});
- }
- self.abortXHR(xhr, { quiet: true });
- prev = loaded = 0;
- setTimeout(function() {
- var reqId;
- if (! abort) {
- xhr.open('POST', self.uploadURL, true);
- if (self.api >= 2.1029) {
- reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
- (typeof formData['delete'] === 'function') && formData['delete']('reqid');
- formData.append('reqid', reqId);
- xhr._requestId = reqId;
- }
- xhr.send(formData);
- }
- }, retryWait);
- } else {
- node.trigger('uploadabort', ['errAbort', 'errTimeout']);
- }
- },
- progress = function() {
- var node;
- if (notify) {
- dfrd.notifyWith(ntfUpload, [{
- cnt: ntfUpload.data('cnt'),
- progress: ntfUpload.data('progress'),
- total: ntfUpload.data('total')
- }]);
- }
- },
- triggerError = function(err, file, unite) {
- err && self.trigger('xhruploadfail', { error: err, file: file });
- if (unite) {
- if (err) {
- if (errCnt < self.options.maxErrorDialogs) {
- if (Array.isArray(err)) {
- errors = errors.concat(err);
- } else {
- errors.push(err);
- }
- }
- errCnt++;
- }
- } else {
- if (err) {
- self.error(err);
- } else {
- if (errors.length) {
- if (errCnt >= self.options.maxErrorDialogs) {
- errors = errors.concat('moreErrors', errCnt - self.options.maxErrorDialogs);
- }
- self.error(errors);
- }
- errors = [];
- errCnt = 0;
- }
- }
- },
- errors = [],
- errCnt = 0,
- renames = (data.renames || null),
- hashes = (data.hashes || null),
- chunkMerge = false,
- ntfUpload = $();
-
- // regist fnAbort function
- node.one('uploadabort', fnAbort);
- $(window).one('unload.' + fm.namespace, fnAbort);
-
- !chunkMerge && (prev = loaded);
-
- if (!isDataType && !cnt) {
- return dfrd.reject(['errUploadNoFiles']);
- }
-
- xhr.addEventListener('error', function() {
- if (xhr.status == 0) {
- if (abort) {
- dfrd.reject();
- } else {
- // ff bug while send zero sized file
- // for safari - send directory
- if (!isDataType && data.files && $.grep(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
- dfrd.reject(['errAbort', 'errFolderUpload']);
- } else if (data.input && $.grep(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
- dfrd.reject(['errUploadNoFiles']);
- } else {
- doRetry();
- }
- }
- } else {
- node.trigger('uploadabort', 'errConnect');
- }
- }, false);
-
- xhr.addEventListener('load', function(e) {
- var status = xhr.status, res, curr = 0, error = '', errData, errObj;
-
- if (status >= 400) {
- if (status > 500) {
- error = 'errResponse';
- } else {
- error = ['errResponse', 'errServerError'];
- }
- } else {
- if (!xhr.responseText) {
- error = ['errResponse', 'errDataEmpty'];
- }
- }
-
- if (error) {
- node.trigger('uploadabort');
- getFile(files || {}).done(function(file) {
- return dfrd.reject(file._cid? null : error);
- });
- }
-
- loaded = filesize;
-
- if (checkNotify() && (curr = loaded - prev)) {
- self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
- progress();
- }
-
- res = self.parseUploadData(xhr.responseText);
-
- // chunked upload commit
- if (res._chunkmerged) {
- formData = new FormData();
- var _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}];
- chunkMerge = true;
- node.off('uploadabort', fnAbort);
- notifyto2 = setTimeout(function() {
- self.notify({type : 'chunkmerge', cnt : 1});
- }, self.options.notifyDelay);
- isDataType? send(_file, files[1]) : send(_file);
- return;
- }
-
- res._multiupload = data.multiupload? true : false;
- if (res.error) {
- errData = {
- cmd: 'upload',
- err: res,
- xhr: xhr,
- rc: xhr.status
- };
- self.trigger('uploadfail', res);
- // trigger "requestError" event
- self.trigger('requestError', errData);
- if (errData._getEvent && errData._getEvent().isDefaultPrevented()) {
- res.error = '';
- }
- if (res._chunkfailure || res._multiupload) {
- abort = true;
- self.uploads.xhrUploading = false;
- notifyto && clearTimeout(notifyto);
- if (ntfUpload.length) {
- self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
- dfrd.reject(res);
- } else {
- // for multi connection
- dfrd.reject();
- }
- } else {
- dfrd.reject(res);
- }
- } else {
- dfrd.resolve(res);
- }
- }, false);
-
- xhr.upload.addEventListener('loadstart', function(e) {
- if (!chunkMerge && e.lengthComputable) {
- loaded = e.loaded;
- retry && (loaded = 0);
- filesize = e.total;
- if (!loaded) {
- loaded = parseInt(filesize * 0.05);
- }
- if (checkNotify()) {
- self.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize});
- prev = loaded;
- progress();
- }
- }
- }, false);
-
- xhr.upload.addEventListener('progress', function(e) {
- var curr;
-
- if (e.lengthComputable && !chunkMerge && xhr.readyState < 2) {
-
- loaded = e.loaded;
-
- // to avoid strange bug in safari (not in chrome) with drag&drop.
- // bug: macos finder opened in any folder,
- // reset safari cache (option+command+e), reload elfinder page,
- // drop file from finder
- // on first attempt request starts (progress callback called ones) but never ends.
- // any next drop - successfull.
- if (!data.checked && loaded > 0 && !notifyto) {
- notifyto = startNotify(xhr._totalSize - loaded);
- }
-
- if (!filesize) {
- filesize = e.total;
- if (!loaded) {
- loaded = parseInt(filesize * 0.05);
- }
- }
-
- curr = loaded - prev;
- if (checkNotify() && (curr/e.total) >= 0.05) {
- self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
- prev = loaded;
- progress();
- }
-
- if (! data.multiupload && loaded >= filesize) {
- cancelBtn = false;
- cancelToggle(false);
- }
- }
- }, false);
-
- var send = function(files, paths){
- var size = 0,
- fcnt = 1,
- sfiles = [],
- c = 0,
- total = cnt,
- maxFileSize,
- totalSize = 0,
- chunked = [],
- chunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system
- BYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize
- blobSlice = chunkEnable? false : '',
- blobSize, blobMtime, blobName, i, start, end, chunks, blob, chunk, added, done, last, failChunk,
- multi = function(files, num){
- var sfiles = [], cid, sfilesLen = 0, cancelChk;
- if (!abort) {
- while(files.length && sfiles.length < num) {
- sfiles.push(files.shift());
- }
- sfilesLen = sfiles.length;
- if (sfilesLen) {
- cancelChk = sfilesLen;
- for (var i=0; i < sfilesLen; i++) {
- if (abort) {
- break;
- }
- cid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null);
- if (!!failChunk[cid]) {
- last--;
- continue;
- }
- fm.exec('upload', {
- type: data.type,
- isDataType: isDataType,
- files: sfiles[i],
- checked: true,
- target: target,
- dropEvt: dropEvt,
- renames: renames,
- hashes: hashes,
- multiupload: true,
- overwrite: data.overwrite === 0? 0 : void 0,
- clipdata: data.clipdata
- }, void 0, target)
- .fail(function(error) {
- if (error && error === 'No such command') {
- abort = true;
- fm.error(['errUpload', 'errPerm']);
- }
- if (cid) {
- failChunk[cid] = true;
- }
- })
- .always(function(e) {
- if (e && e.added) added = $.merge(added, e.added);
- if (last <= ++done) {
- fm.trigger('multiupload', {added: added});
- notifyto && clearTimeout(notifyto);
- if (checkNotify()) {
- self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
- }
- }
- if (files.length) {
- multi(files, 1); // Next one
- } else {
- if (--cancelChk <= 1) {
- cancelBtn = false;
- cancelToggle(false);
- }
- }
- });
- }
- }
- }
- if (sfiles.length < 1 || abort) {
- if (abort) {
- notifyto && clearTimeout(notifyto);
- if (cid) {
- failChunk[cid] = true;
- }
- dfrd.reject();
- } else {
- dfrd.resolve();
- self.uploads.xhrUploading = false;
- }
- }
- },
- check = function(){
- if (!self.uploads.xhrUploading) {
- self.uploads.xhrUploading = true;
- multi(sfiles, multiMax); // Max connection: 3
- } else {
- setTimeout(check, 100);
- }
- },
- reqId, err;
-
- if (! dataChecked && (isDataType || data.type == 'files')) {
- if (! (maxFileSize = fm.option('uploadMaxSize', target))) {
- maxFileSize = 0;
- }
- for (i=0; i < files.length; i++) {
- try {
- blob = files[i];
- blobSize = blob.size;
- if (blobSlice === false) {
- blobSlice = '';
- if (self.api >= 2.1) {
- if ('slice' in blob) {
- blobSlice = 'slice';
- } else if ('mozSlice' in blob) {
- blobSlice = 'mozSlice';
- } else if ('webkitSlice' in blob) {
- blobSlice = 'webkitSlice';
- }
- }
- }
- } catch(e) {
- cnt--;
- total--;
- continue;
- }
-
- // file size check
- if ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) {
- triggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true);
- cnt--;
- total--;
- continue;
- }
-
- // file mime check
- if (blob.type && ! self.uploadMimeCheck(blob.type, target)) {
- triggerError(['errUploadFile', blob.name, 'errUploadMime', '(' + blob.type + ')'], blob, true);
- cnt--;
- total--;
- continue;
- }
-
- if (blobSlice && blobSize > BYTES_PER_CHUNK) {
- start = 0;
- end = BYTES_PER_CHUNK;
- chunks = -1;
- total = Math.floor((blobSize - 1) / BYTES_PER_CHUNK);
- blobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0;
- blobName = data.clipdata? fm.date(fm.nonameDateFormat) + '.png' : blob.name;
-
- totalSize += blobSize;
- chunked[chunkID] = 0;
- while(start < blobSize) {
- chunk = blob[blobSlice](start, end);
- chunk._chunk = blobName + '.' + (++chunks) + '_' + total + '.part';
- chunk._cid = chunkID;
- chunk._range = start + ',' + chunk.size + ',' + blobSize;
- chunk._mtime = blobMtime;
- chunked[chunkID]++;
-
- if (size) {
- c++;
- }
- if (typeof sfiles[c] == 'undefined') {
- sfiles[c] = [];
- if (isDataType) {
- sfiles[c][0] = [];
- sfiles[c][1] = [];
- }
- }
- size = BYTES_PER_CHUNK;
- fcnt = 1;
- if (isDataType) {
- sfiles[c][0].push(chunk);
- sfiles[c][1].push(paths[i]);
- } else {
- sfiles[c].push(chunk);
- }
-
- start = end;
- end = start + BYTES_PER_CHUNK;
- }
- if (chunk == null) {
- triggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true);
- cnt--;
- total--;
- } else {
- total += chunks;
- size = 0;
- fcnt = 1;
- c++;
- }
- continue;
- }
- if ((fm.uplMaxSize && size + blobSize > fm.uplMaxSize) || fcnt > fm.uplMaxFile) {
- size = 0;
- fcnt = 1;
- c++;
- }
- if (typeof sfiles[c] == 'undefined') {
- sfiles[c] = [];
- if (isDataType) {
- sfiles[c][0] = [];
- sfiles[c][1] = [];
- }
- }
- if (isDataType) {
- sfiles[c][0].push(blob);
- sfiles[c][1].push(paths[i]);
- } else {
- sfiles[c].push(blob);
- }
- size += blobSize;
- totalSize += blobSize;
- fcnt++;
- }
-
- if (errors.length) {
- triggerError();
- }
-
- if (sfiles.length == 0) {
- // no data
- data.checked = true;
- return false;
- }
-
- if (sfiles.length > 1) {
- // multi upload
- notifyto = startNotify(totalSize);
- added = [];
- done = 0;
- last = sfiles.length;
- failChunk = [];
- check();
- return true;
- }
-
- // single upload
- if (isDataType) {
- files = sfiles[0][0];
- paths = sfiles[0][1];
- } else {
- files = sfiles[0];
- }
- }
-
- if (!dataChecked) {
- if (!fm.UA.Safari || !data.files) {
- notifyto = startNotify(totalSize);
- } else {
- xhr._totalSize = totalSize;
- }
- }
-
- dataChecked = true;
-
- if (! files.length) {
- dfrd.reject(['errUploadNoFiles']);
- }
-
- xhr.open('POST', self.uploadURL, true);
-
- // set request headers
- if (fm.customHeaders) {
- $.each(fm.customHeaders, function(key) {
- xhr.setRequestHeader(key, this);
- });
- }
-
- // set xhrFields
- if (fm.xhrFields) {
- $.each(fm.xhrFields, function(key) {
- if (key in xhr) {
- xhr[key] = this;
- }
- });
- }
-
- if (self.api >= 2.1029) {
- // request ID
- reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
- formData.append('reqid', reqId);
- xhr._requestId = reqId;
- }
- formData.append('cmd', 'upload');
- formData.append(self.newAPI ? 'target' : 'current', target);
- if (renames && renames.length) {
- $.each(renames, function(i, v) {
- formData.append('renames[]', v);
- });
- formData.append('suffix', fm.options.backupSuffix);
- }
- if (hashes) {
- $.each(hashes, function(i, v) {
- formData.append('hashes['+ i +']', v);
- });
- }
- $.each(self.customData, function(key, val) {
- formData.append(key, val);
- });
- $.each(self.options.onlyMimes, function(i, mime) {
- formData.append('mimes[]', mime);
- });
-
- $.each(files, function(i, file) {
- var name;
- if (file._chunkmerged) {
- formData.append('chunk', file._chunkmerged);
- formData.append('upload[]', file._name);
- formData.append('mtime[]', file._mtime);
- data.clipdata && formData.append('overwrite', 0);
- } else {
- if (file._chunkfail) {
- formData.append('upload[]', 'chunkfail');
- formData.append('mimes', 'chunkfail');
- } else {
- if (data.clipdata) {
- if (!file._chunk) {
- data.overwrite = 0;
- name = fm.date(fm.nonameDateFormat) + '.png';
- }
- } else {
- if (file.name) {
- name = file.name;
- if (fm.UA.iOS) {
- if (name.match(/^image\.jpe?g$/i)) {
- data.overwrite = 0;
- name = fm.date(fm.nonameDateFormat) + '.jpg';
- } else if (name.match(/^capturedvideo\.mov$/i)) {
- data.overwrite = 0;
- name = fm.date(fm.nonameDateFormat) + '.mov';
- }
- }
- }
- }
- name? formData.append('upload[]', file, name) : formData.append('upload[]', file);
- }
- if (file._chunk) {
- formData.append('chunk', file._chunk);
- formData.append('cid' , file._cid);
- formData.append('range', file._range);
- formData.append('mtime[]', file._mtime);
- } else {
- formData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0);
- }
- }
- });
-
- if (isDataType) {
- $.each(paths, function(i, path) {
- formData.append('upload_path[]', path);
- });
- }
-
- if (data.overwrite === 0) {
- formData.append('overwrite', 0);
- }
-
- // send int value that which meta key was pressed when dropped as `dropWith`
- if (dropEvt) {
- formData.append('dropWith', parseInt(
- (dropEvt.altKey ? '1' : '0')+
- (dropEvt.ctrlKey ? '1' : '0')+
- (dropEvt.metaKey ? '1' : '0')+
- (dropEvt.shiftKey? '1' : '0'), 2));
- }
-
- // set extraData on current request
- if (extraData) {
- $.each(extraData, function(key, val) {
- formData.append(key, val);
- });
- }
-
- xhr.send(formData);
-
- return true;
- };
-
- if (! isDataType) {
- if (files.length > 0) {
- if (! data.clipdata && renames == null) {
- var mkdirs = [],
- paths = [],
- excludes = fm.options.folderUploadExclude[fm.OS] || null;
- $.each(files, function(i, file) {
- var relPath = file.webkitRelativePath || file.relativePath || '',
- idx, rootDir;
- if (! relPath) {
- return false;
- }
- if (excludes && file.name.match(excludes)) {
- file._remove = true;
- relPath = void(0);
- } else {
- // add '/' as prefix to make same to folder uploading with DnD, see #2607
- relPath = '/' + relPath.replace(/\/[^\/]*$/, '').replace(/^\//, '');
- if (relPath && $.inArray(relPath, mkdirs) === -1) {
- mkdirs.push(relPath);
- // checking the root directory to supports see #2378
- idx = relPath.substr(1).indexOf('/');
- if (idx !== -1 && (rootDir = relPath.substr(0, idx + 1)) && $.inArray(rootDir, mkdirs) === -1) {
- mkdirs.unshift(rootDir);
- }
- }
- }
- paths.push(relPath);
- });
- renames = [];
- hashes = {};
- if (mkdirs.length) {
- (function() {
- var checkDirs = $.map(mkdirs, function(name) { return name.substr(1).indexOf('/') === -1 ? {name: name.substr(1)} : null;}),
- cancelDirs = [];
- fm.uploads.checkExists(checkDirs, target, fm, true).done(
- function(res, res2) {
- var dfds = [], dfd, bak, hash;
- if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
- cancelDirs = $.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} );
- checkDirs = $.grep(checkDirs, function(dir) { return !dir._remove? true : false ;} );
- }
- if (cancelDirs.length) {
- $.each(paths.concat(), function(i, path) {
- if ($.inArray(path, cancelDirs) === 0) {
- files[i]._remove = true;
- paths[i] = void(0);
- }
- });
- }
- files = $.grep(files, function(file) { return file._remove? false : true; });
- paths = $.grep(paths, function(path) { return path === void 0 ? false : true; });
- if (checkDirs.length) {
- dfd = $.Deferred();
- if (res.length) {
- $.each(res, function(i, existName) {
- // backup
- bak = fm.uniqueName(existName + fm.options.backupSuffix , null, '');
- $.each(res2, function(h, name) {
- if (res[0] == name) {
- hash = h;
- return false;
- }
- });
- if (! hash) {
- hash = fm.fileByName(res[0], target).hash;
- }
- fm.lockfiles({files : [hash]});
- dfds.push(
- fm.request({
- data : {cmd : 'rename', target : hash, name : bak},
- notify : {type : 'rename', cnt : 1}
- })
- .fail(function(error) {
- dfrd.reject(error);
- fm.sync();
- })
- .always(function() {
- fm.unlockfiles({files : [hash]});
- })
- );
- });
- } else {
- dfds.push(null);
- }
-
- $.when.apply($, dfds).done(function() {
- // ensure directories
- fm.request({
- data : {cmd : 'mkdir', target : target, dirs : mkdirs},
- notify : {type : 'mkdir', cnt : mkdirs.length},
- preventFail: true
- })
- .fail(function(error) {
- error = error || ['errUnknown'];
- if (error[0] === 'errCmdParams') {
- multiMax = 1;
- } else {
- multiMax = 0;
- dfrd.reject(error);
- }
- })
- .done(function(data) {
- var rm = false;
- if (!data.hashes) {
- data.hashes = {};
- }
- paths = $.map(paths.concat(), function(p, i) {
- if (p === '/') {
- return target;
- } else {
- if (data.hashes[p]) {
- return data.hashes[p];
- } else {
- rm = true;
- files[i]._remove = true;
- return null;
- }
- }
- });
- if (rm) {
- files = $.grep(files, function(file) { return file._remove? false : true; });
- }
- })
- .always(function(data) {
- if (multiMax) {
- isDataType = true;
- if (! send(files, paths)) {
- dfrd.reject();
- }
- }
- });
- });
- } else {
- dfrd.reject();
- }
- }
- );
- })();
- } else {
- fm.uploads.checkExists(files, target, fm).done(
- function(res, res2){
- if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
- hashes = res2;
- if (res === null) {
- data.overwrite = 0;
- } else {
- renames = res;
- }
- files = $.grep(files, function(file){return !file._remove? true : false ;});
- }
- cnt = files.length;
- if (cnt > 0) {
- if (! send(files)) {
- dfrd.reject();
- }
- } else {
- dfrd.reject();
- }
- }
- );
- }
- } else {
- if (! send(files)) {
- dfrd.reject();
- }
- }
- } else {
- dfrd.reject();
- }
- } else {
- if (dataChecked) {
- send(files[0], files[1]);
- } else {
- files.done(function(result) { // result: [files, paths, renames, hashes, mkdirs]
- renames = [];
- cnt = result[0].length;
- if (cnt) {
- if (result[4] && result[4].length) {
- // ensure directories
- fm.request({
- data : {cmd : 'mkdir', target : target, dirs : result[4]},
- notify : {type : 'mkdir', cnt : result[4].length},
- preventFail: true
- })
- .fail(function(error) {
- error = error || ['errUnknown'];
- if (error[0] === 'errCmdParams') {
- multiMax = 1;
- } else {
- multiMax = 0;
- dfrd.reject(error);
- }
- })
- .done(function(data) {
- var rm = false;
- if (!data.hashes) {
- data.hashes = {};
- }
- result[1] = $.map(result[1], function(p, i) {
- p = p.replace(/\/[^\/]*$/, '');
- if (p === '') {
- return target;
- } else {
- if (data.hashes[p]) {
- return data.hashes[p];
- } else {
- rm = true;
- result[0][i]._remove = true;
- return null;
- }
- }
- });
- if (rm) {
- result[0] = $.grep(result[0], function(file) { return file._remove? false : true; });
- }
- })
- .always(function(data) {
- if (multiMax) {
- renames = result[2];
- hashes = result[3];
- send(result[0], result[1]);
- }
- });
- return;
- } else {
- result[1] = $.map(result[1], function() { return target; });
- }
- renames = result[2];
- hashes = result[3];
- send(result[0], result[1]);
- } else {
- dfrd.reject(['errUploadNoFiles']);
- }
- }).fail(function(){
- dfrd.reject();
- });
- }
- }
-
- return dfrd;
- },
-
- // upload transport using iframe
- iframe : function(data, fm) {
- var self = fm ? fm : this,
- input = data.input? data.input : false,
- files = !input ? self.uploads.checkFile(data, self) : false,
- dfrd = $.Deferred()
- .fail(function(error) {
- error && self.error(error);
- }),
- name = 'iframe-'+fm.namespace+(++self.iframeCnt),
- form = $(''),
- msie = this.UA.IE,
- // clear timeouts, close notification dialog, remove form/iframe
- onload = function() {
- abortto && clearTimeout(abortto);
- notifyto && clearTimeout(notifyto);
- notify && self.notify({type : 'upload', cnt : -cnt});
-
- setTimeout(function() {
- msie && $('').appendTo(form);
- form.remove();
- iframe.remove();
- }, 100);
- },
- iframe = $('')
- .on('load', function() {
- iframe.off('load')
- .on('load', function() {
- onload();
- // data will be processed in callback response or window onmessage
- dfrd.resolve();
- });
-
- // notify dialog
- notifyto = setTimeout(function() {
- notify = true;
- self.notify({type : 'upload', cnt : cnt});
- }, self.options.notifyDelay);
-
- // emulate abort on timeout
- if (self.options.iframeTimeout > 0) {
- abortto = setTimeout(function() {
- onload();
- dfrd.reject(['errConnect', 'errTimeout']);
- }, self.options.iframeTimeout);
- }
-
- form.submit();
- }),
- target = (data.target || self.cwd().hash),
- names = [],
- dfds = [],
- renames = [],
- hashes = {},
- cnt, notify, notifyto, abortto;
-
- if (files && files.length) {
- $.each(files, function(i, val) {
- form.append('');
- });
- cnt = 1;
- } else if (input && $(input).is(':file') && $(input).val()) {
- if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
- names = input.files? input.files : [{ name: $(input).val().replace(/^(?:.+[\\\/])?([^\\\/]+)$/, '$1') }];
- //names = $.map(names, function(file){return file.name? { name: file.name } : null ;});
- dfds.push(self.uploads.checkExists(names, target, self).done(
- function(res, res2){
- hashes = res2;
- if (res === null) {
- data.overwrite = 0;
- } else{
- renames = res;
- cnt = $.grep(names, function(file){return !file._remove? true : false ;}).length;
- if (cnt != names.length) {
- cnt = 0;
- }
- }
- }
- ));
- }
- cnt = input.files ? input.files.length : 1;
- form.append(input);
- } else {
- return dfrd.reject();
- }
-
- $.when.apply($, dfds).done(function() {
- if (cnt < 1) {
- return dfrd.reject();
- }
- form.append('')
- .append('')
- .append('')
- .append($(input).attr('name', 'upload[]'));
-
- if (renames.length > 0) {
- $.each(renames, function(i, rename) {
- form.append('');
- });
- form.append('');
- }
- if (hashes) {
- $.each(renames, function(i, v) {
- form.append('');
- });
- }
-
- if (data.overwrite === 0) {
- form.append('');
- }
-
- $.each(self.options.onlyMimes||[], function(i, mime) {
- form.append('');
- });
-
- $.each(self.customData, function(key, val) {
- form.append('');
- });
-
- form.appendTo('body');
- iframe.appendTo('body');
- });
-
- return dfrd;
- }
- },
-
-
- /**
- * Bind callback to event(s) The callback is executed at most once per event.
- * To bind to multiply events at once, separate events names by space
- *
- * @param String event name
- * @param Function callback
- * @param Boolan priority first
- * @return elFinder
- */
- one : function(ev, callback, priorityFirst) {
- var self = this,
- event = ev.toLowerCase(),
- h = function(e, f) {
- if (!self.toUnbindEvents[event]) {
- self.toUnbindEvents[event] = [];
- }
- self.toUnbindEvents[event].push({
- type: event,
- callback: h
- });
- return (callback.done? callback.done : callback).apply(this, arguments);
- };
- if (callback.done) {
- h = {done: h};
- }
- return this.bind(event, h, priorityFirst);
- },
-
- /**
- * Set/get data into/from localStorage
- *
- * @param String key
- * @param String|void value
- * @return String|null
- */
- localStorage : function(key, val) {
- var self = this,
- s = window.localStorage,
- oldkey = 'elfinder-'+(key || '')+this.id, // old key of elFinder < 2.1.6
- prefix = window.location.pathname+'-elfinder-',
- suffix = this.id,
- clrs = [],
- retval, oldval, t, precnt, sufcnt;
-
- // reset this node data
- if (typeof(key) === 'undefined') {
- precnt = prefix.length;
- sufcnt = suffix.length * -1;
- $.each(s, function(key) {
- if (key.substr(0, precnt) === prefix && key.substr(sufcnt) === suffix) {
- clrs.push(key);
- }
- });
- $.each(clrs, function(i, key) {
- s.removeItem(key);
- });
- return true;
- }
-
- // new key of elFinder >= 2.1.6
- key = prefix+key+suffix;
-
- if (val === null) {
- return s.removeItem(key);
- }
-
- if (val === void(0) && !(retval = s.getItem(key)) && (oldval = s.getItem(oldkey))) {
- val = oldval;
- s.removeItem(oldkey);
- }
-
- if (val !== void(0)) {
- t = typeof val;
- if (t !== 'string' && t !== 'number') {
- val = JSON.stringify(val);
- }
- try {
- s.setItem(key, val);
- } catch (e) {
- try {
- s.clear();
- s.setItem(key, val);
- } catch (e) {
- self.debug('error', e.toString());
- }
- }
- retval = s.getItem(key);
- }
-
- if (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) {
- try {
- return JSON.parse(retval);
- } catch(e) {}
- }
- return retval;
- },
-
- /**
- * Get/set cookie
- *
- * @param String cookie name
- * @param String|void cookie value
- * @return String|null
- */
- cookie : function(name, value) {
- var d, o, c, i, retval, t;
-
- name = 'elfinder-'+name+this.id;
-
- if (value === void(0)) {
- if (document.cookie && document.cookie != '') {
- c = document.cookie.split(';');
- name += '=';
- for (i=0; i'),
-
- /**
- * Replace not html-safe symbols to html entities
- *
- * @param String text to escape
- * @return String
- */
- escape : function(name) {
- return this._node.text(name).html().replace(/"/g, '"').replace(/'/g, ''');
- },
-
- /**
- * Cleanup ajax data.
- * For old api convert data into new api format
- *
- * @param String command name
- * @param Object data from backend
- * @return Object
- */
- normalize : function(data) {
- var self = this,
- fileFilter = (function() {
- var func, filter;
- if (filter = self.options.fileFilter) {
- if (typeof filter === 'function') {
- func = function(file) {
- return filter.call(self, file);
- };
- } else if (filter instanceof RegExp) {
- func = function(file) {
- return filter.test(file.name);
- };
- }
- }
- return func? func : null;
- })(),
- chkCmdMap = function(opts) {
- // Disable command to replace with other command
- var disabled;
- if (opts.uiCmdMap) {
- if ($.isPlainObject(opts.uiCmdMap) && Object.keys(opts.uiCmdMap).length) {
- if (!opts.disabledFlip) {
- opts.disabledFlip = {};
- }
- disabled = opts.disabledFlip;
- $.each(opts.uiCmdMap, function(f, t) {
- if (t === 'hidden' && !disabled[f]) {
- opts.disabled.push(f);
- opts.disabledFlip[f] = true;
- }
- });
- } else {
- delete opts.uiCmdMap;
- }
- }
- },
- normalizeOptions = function(opts) {
- var getType = function(v) {
- var type = typeof v;
- if (type === 'object' && Array.isArray(v)) {
- type = 'array';
- }
- return type;
- };
- $.each(self.optionProperties, function(k, empty) {
- if (empty !== void(0)) {
- if (opts[k] && getType(opts[k]) !== getType(empty)) {
- opts[k] = empty;
- }
- }
- });
- if (opts['disabled']) {
- opts['disabledFlip'] = self.arrayFlip(opts['disabled'], true);
- } else {
- opts['disabledFlip'] = {};
- }
- return opts;
- },
- filter = function(file, asMap, type) {
- var res = asMap? file : true,
- ign = asMap? null : false,
- vid, targetOptions, isRoot, rootNames;
-
- if (file && file.hash && file.name && file.mime) {
- if (file.mime === 'application/x-empty') {
- file.mime = 'text/plain';
- }
-
- isRoot = self.isRoot(file);
- if (isRoot && ! file.volumeid) {
- self.debug('warning', 'The volume root statuses requires `volumeid` property.');
- }
- if (isRoot || file.mime === 'directory') {
- // Prevention of circular reference
- if (file.phash) {
- if (file.phash === file.hash) {
- error = error.concat(['Parent folder of "$1" is itself.', file.name]);
- return ign;
- }
- if (isRoot && file.volumeid && file.phash.indexOf(file.volumeid) === 0) {
- error = error.concat(['Parent folder of "$1" is inner itself.', file.name]);
- return ign;
- }
- }
-
- // set options, tmbUrls for each volume
- if (file.volumeid) {
- vid = file.volumeid;
-
- if (isRoot) {
- // make or update of leaf roots cache
- if (file.phash) {
- if (! self.leafRoots[file.phash]) {
- self.leafRoots[file.phash] = [ file.hash ];
- } else {
- if ($.inArray(file.hash, self.leafRoots[file.phash]) === -1) {
- self.leafRoots[file.phash].push(file.hash);
- }
- }
- }
-
- self.hasVolOptions = true;
- if (! self.volOptions[vid]) {
- self.volOptions[vid] = {
- // set dispInlineRegex
- dispInlineRegex: self.options.dispInlineRegex
- };
- }
-
- targetOptions = self.volOptions[vid];
-
- if (file.options) {
- // >= v.2.1.14 has file.options
- Object.assign(targetOptions, file.options);
- }
-
- // for compat <= v2.1.13
- if (file.disabled) {
- targetOptions.disabled = file.disabled;
- targetOptions.disabledFlip = self.arrayFlip(file.disabled, true);
- }
- if (file.tmbUrl) {
- targetOptions.tmbUrl = file.tmbUrl;
- }
-
- // '/' required at the end of url
- if (targetOptions.url && targetOptions.url.substr(-1) !== '/') {
- targetOptions.url += '/';
- }
-
- // check uiCmdMap
- chkCmdMap(targetOptions);
-
- // check trash bin hash
- if (targetOptions.trashHash) {
- if (self.trashes[targetOptions.trashHash] === false) {
- delete targetOptions.trashHash;
- } else {
- self.trashes[targetOptions.trashHash] = file.hash;
- }
- }
-
- // set immediate properties
- $.each(self.optionProperties, function(k) {
- if (targetOptions[k]) {
- file[k] = targetOptions[k];
- }
- });
-
- // regist fm.roots
- if (type !== 'cwd') {
- self.roots[vid] = file.hash;
- }
-
- // regist fm.volumeExpires
- if (file.expires) {
- self.volumeExpires[vid] = file.expires;
- }
- }
-
- if (prevId !== vid) {
- prevId = vid;
- i18nFolderName = self.option('i18nFolderName', vid);
- }
- }
-
- // volume root i18n name
- if (isRoot && ! file.i18) {
- name = 'volume_' + file.name,
- i18 = self.i18n(false, name);
-
- if (name !== i18) {
- file.i18 = i18;
- }
- }
-
- // i18nFolderName
- if (i18nFolderName && ! file.i18) {
- name = 'folder_' + file.name,
- i18 = self.i18n(false, name);
-
- if (name !== i18) {
- file.i18 = i18;
- }
- }
-
- if (isRoot) {
- if (rootNames = self.storage('rootNames')) {
- if (rootNames[file.hash]) {
- file._name = file.name;
- file._i18 = file.i18;
- file.name = rootNames[file.hash] = rootNames[file.hash];
- delete file.i18;
- }
- self.storage('rootNames', rootNames);
- }
- }
-
- // lock trash bins holder
- if (self.trashes[file.hash]) {
- file.locked = true;
- }
- } else {
- if (fileFilter) {
- try {
- if (! fileFilter(file)) {
- return ign;
- }
- } catch(e) {
- self.debug(e);
- }
- }
- if (file.size == 0) {
- file.mime = self.getMimetype(file.name, file.mime);
- }
- }
-
- if (file.options) {
- self.optionsByHashes[file.hash] = normalizeOptions(file.options);
- }
-
- delete file.options;
-
- return res;
- }
- return ign;
- },
- getDescendants = function(hashes) {
- var res = [];
- $.each(self.files(), function(h, f) {
- $.each(self.parents(h), function(i, ph) {
- if ($.inArray(ph, hashes) !== -1 && $.inArray(h, hashes) === -1) {
- res.push(h);
- return false;
- }
- });
- });
- return res;
- },
- applyLeafRootStats = function(dataArr, type) {
- $.each(dataArr, function(i, f) {
- var pfile, done;
- if (self.leafRoots[f.hash]) {
- self.applyLeafRootStats(f);
- }
- // update leaf root parent stat
- if (type !== 'change' && f.phash && self.isRoot(f) && (pfile = self.file(f.phash))) {
- self.applyLeafRootStats(pfile);
- // add to data.changed
- if (!data.changed) {
- data.changed = [pfile];
- } else {
- $.each(data.changed, function(i, f) {
- if (f.hash === pfile.hash) {
- data.changed[i] = pfile;
- done = true;
- return false;
- }
- });
- if (!done) {
- data.changed.push(pfile);
- }
- }
- }
- });
- },
- error = [],
- name, i18, i18nFolderName, prevId, cData;
-
- // set cunstom data
- if (data.customData && data.customData !== self.prevCustomData) {
- self.prevCustomData = data.customData;
- try {
- cData = JSON.parse(data.customData);
- if ($.isPlainObject(cData)) {
- self.prevCustomData = cData;
- $.each(Object.keys(cData), function(i, key) {
- if (cData[key] === null) {
- delete cData[key];
- delete self.optsCustomData[key];
- }
- });
- self.customData = Object.assign({}, self.optsCustomData, cData);
- }
- } catch(e) {}
- }
-
- if (data.options) {
- normalizeOptions(data.options);
- }
-
- if (data.cwd) {
- if (data.cwd.volumeid && data.options && Object.keys(data.options).length && self.isRoot(data.cwd)) {
- self.hasVolOptions = true;
- self.volOptions[data.cwd.volumeid] = data.options;
- }
- data.cwd = filter(data.cwd, true, 'cwd');
- }
- if (data.files) {
- data.files = $.grep(data.files, filter);
- }
- if (data.tree) {
- data.tree = $.grep(data.tree, filter);
- }
- if (data.added) {
- data.added = $.grep(data.added, filter);
- }
- if (data.changed) {
- data.changed = $.grep(data.changed, filter);
- }
- if (data.removed && data.removed.length && self.searchStatus.state === 2) {
- data.removed = data.removed.concat(getDescendants(data.removed));
- }
- if (data.api) {
- data.init = true;
- }
-
- if (Object.keys(self.leafRoots).length) {
- data.files && applyLeafRootStats(data.files);
- data.tree && applyLeafRootStats(data.tree);
- data.added && applyLeafRootStats(data.added);
- data.changed && applyLeafRootStats(data.changed, 'change');
- }
-
- // merge options that apply only to cwd
- if (data.cwd && data.cwd.options && data.options) {
- Object.assign(data.options, normalizeOptions(data.cwd.options));
- }
-
- // '/' required at the end of url
- if (data.options && data.options.url && data.options.url.substr(-1) !== '/') {
- data.options.url += '/';
- }
-
- // check error
- if (error.length) {
- data.norError = ['errResponse'].concat(error);
- }
-
- return data;
- },
-
- /**
- * Update sort options
- *
- * @param {String} sort type
- * @param {String} sort order
- * @param {Boolean} show folder first
- */
- setSort : function(type, order, stickFolders, alsoTreeview) {
- this.storage('sortType', (this.sortType = this.sortRules[type] ? type : 'name'));
- this.storage('sortOrder', (this.sortOrder = /asc|desc/.test(order) ? order : 'asc'));
- this.storage('sortStickFolders', (this.sortStickFolders = !!stickFolders) ? 1 : '');
- this.storage('sortAlsoTreeview', (this.sortAlsoTreeview = !!alsoTreeview) ? 1 : '');
- this.trigger('sortchange');
- },
-
- _sortRules : {
- name : function(file1, file2) {
- return elFinder.prototype.naturalCompare(file1.i18 || file1.name, file2.i18 || file2.name);
- },
- size : function(file1, file2) {
- var size1 = parseInt(file1.size) || 0,
- size2 = parseInt(file2.size) || 0;
-
- return size1 === size2 ? 0 : size1 > size2 ? 1 : -1;
- },
- kind : function(file1, file2) {
- return elFinder.prototype.naturalCompare(file1.mime, file2.mime);
- },
- date : function(file1, file2) {
- var date1 = file1.ts || file1.date || 0,
- date2 = file2.ts || file2.date || 0;
-
- return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
- },
- perm : function(file1, file2) {
- var val = function(file) { return (file.write? 2 : 0) + (file.read? 1 : 0); },
- v1 = val(file1),
- v2 = val(file2);
- return v1 === v2 ? 0 : v1 > v2 ? 1 : -1;
- },
- mode : function(file1, file2) {
- var v1 = file1.mode || (file1.perm || ''),
- v2 = file2.mode || (file2.perm || '');
- return elFinder.prototype.naturalCompare(v1, v2);
- },
- owner : function(file1, file2) {
- var v1 = file1.owner || '',
- v2 = file2.owner || '';
- return elFinder.prototype.naturalCompare(v1, v2);
- },
- group : function(file1, file2) {
- var v1 = file1.group || '',
- v2 = file2.group || '';
- return elFinder.prototype.naturalCompare(v1, v2);
- }
- },
-
- /**
- * Valid sort rule names
- *
- * @type Object
- */
- sorters : {},
-
- /**
- * Compare strings for natural sort
- *
- * @param String
- * @param String
- * @return Number
- */
- naturalCompare : function(a, b) {
- var self = elFinder.prototype.naturalCompare;
- if (typeof self.loc == 'undefined') {
- self.loc = (navigator.userLanguage || navigator.browserLanguage || navigator.language || 'en-US');
- }
- if (typeof self.sort == 'undefined') {
- if ('11'.localeCompare('2', self.loc, {numeric: true}) > 0) {
- // Native support
- if (window.Intl && window.Intl.Collator) {
- self.sort = new Intl.Collator(self.loc, {numeric: true}).compare;
- } else {
- self.sort = function(a, b) {
- return a.localeCompare(b, self.loc, {numeric: true});
- };
- }
- } else {
- /*
- * Edited for elFinder (emulates localeCompare() by numeric) by Naoki Sawada aka nao-pon
- */
- /*
- * Huddle/javascript-natural-sort (https://github.com/Huddle/javascript-natural-sort)
- */
- /*
- * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
- * Author: Jim Palmer (based on chunking idea from Dave Koelle)
- * http://opensource.org/licenses/mit-license.php
- */
- self.sort = function(a, b) {
- var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
- sre = /(^[ ]*|[ ]*$)/g,
- dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
- hre = /^0x[0-9a-f]+$/i,
- ore = /^0/,
- syre = /^[\x01\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/, // symbol first - (Naoki Sawada)
- i = function(s) { return self.sort.insensitive && (''+s).toLowerCase() || ''+s; },
- // convert all to strings strip whitespace
- // first character is "_", it's smallest - (Naoki Sawada)
- x = i(a).replace(sre, '').replace(/^_/, "\x01") || '',
- y = i(b).replace(sre, '').replace(/^_/, "\x01") || '',
- // chunk/tokenize
- xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
- yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
- // numeric, hex or date detection
- xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
- yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
- oFxNcL, oFyNcL,
- locRes = 0;
-
- // first try and sort Hex codes or Dates
- if (yD) {
- if ( xD < yD ) return -1;
- else if ( xD > yD ) return 1;
- }
- // natural sorting through split numeric strings and default strings
- for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
-
- // find floats not starting with '0', string or 0 if not defined (Clint Priest)
- oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
- oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
-
- // handle numeric vs string comparison - number < string - (Kyle Adams)
- // but symbol first < number - (Naoki Sawada)
- if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
- if (isNaN(oFxNcL) && (typeof oFxNcL !== 'string' || ! oFxNcL.match(syre))) {
- return 1;
- } else if (typeof oFyNcL !== 'string' || ! oFyNcL.match(syre)) {
- return -1;
- }
- }
-
- // use decimal number comparison if either value is string zero
- if (parseInt(oFxNcL, 10) === 0) oFxNcL = 0;
- if (parseInt(oFyNcL, 10) === 0) oFyNcL = 0;
-
- // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
- if (typeof oFxNcL !== typeof oFyNcL) {
- oFxNcL += '';
- oFyNcL += '';
- }
-
- // use locale sensitive sort for strings when case insensitive
- // note: localeCompare interleaves uppercase with lowercase (e.g. A,a,B,b)
- if (self.sort.insensitive && typeof oFxNcL === 'string' && typeof oFyNcL === 'string') {
- locRes = oFxNcL.localeCompare(oFyNcL, self.loc);
- if (locRes !== 0) return locRes;
- }
-
- if (oFxNcL < oFyNcL) return -1;
- if (oFxNcL > oFyNcL) return 1;
- }
- return 0;
- };
- self.sort.insensitive = true;
- }
- }
- return self.sort(a, b);
- },
-
- /**
- * Compare files based on elFinder.sort
- *
- * @param Object file
- * @param Object file
- * @return Number
- */
- compare : function(file1, file2) {
- var self = this,
- type = self.sortType,
- asc = self.sortOrder == 'asc',
- stick = self.sortStickFolders,
- rules = self.sortRules,
- sort = rules[type],
- d1 = file1.mime == 'directory',
- d2 = file2.mime == 'directory',
- res;
-
- if (stick) {
- if (d1 && !d2) {
- return -1;
- } else if (!d1 && d2) {
- return 1;
- }
- }
-
- res = asc ? sort(file1, file2) : sort(file2, file1);
-
- return type !== 'name' && res === 0
- ? res = asc ? rules.name(file1, file2) : rules.name(file2, file1)
- : res;
- },
-
- /**
- * Sort files based on config
- *
- * @param Array files
- * @return Array
- */
- sortFiles : function(files) {
- return files.sort(this.compare);
- },
-
- /**
- * Open notification dialog
- * and append/update message for required notification type.
- *
- * @param Object options
- * @example
- * this.notify({
- * type : 'copy',
- * msg : 'Copy files', // not required for known types @see this.notifyType
- * cnt : 3,
- * hideCnt : false, // true for not show count
- * progress : 10, // progress bar percents (use cnt : 0 to update progress bar)
- * cancel : callback // callback function for cancel button
- * })
- * @return elFinder
- */
- notify : function(opts) {
- var type = opts.type,
- id = opts.id? 'elfinder-notify-'+opts.id : '',
- msg = this.i18n((typeof opts.msg !== 'undefined')? opts.msg : (this.messages['ntf'+type] ? 'ntf'+type : 'ntfsmth')),
- ndialog = this.ui.notify,
- notify = ndialog.children('.elfinder-notify-'+type+(id? ('.'+id) : '')),
- button = notify.children('div.elfinder-notify-cancel').children('button'),
- ntpl = '',
- delta = opts.cnt,
- size = (typeof opts.size != 'undefined')? parseInt(opts.size) : null,
- progress = (typeof opts.progress != 'undefined' && opts.progress >= 0) ? opts.progress : null,
- cancel = opts.cancel,
- clhover = 'ui-state-hover',
- close = function() {
- notify._esc && $(document).off('keydown', notify._esc);
- notify.remove();
- !ndialog.children().length && ndialog.elfinderdialog('close');
- },
- cnt, total, prc;
-
- if (!type) {
- return this;
- }
-
- if (!notify.length) {
- notify = $(ntpl.replace(/\{type\}/g, type).replace(/\{msg\}/g, msg))
- .appendTo(ndialog)
- .data('cnt', 0);
-
- if (progress != null) {
- notify.data({progress : 0, total : 0});
- }
-
- if (cancel) {
- button = $('')
- .on('mouseenter mouseleave', function(e) {
- $(this).toggleClass(clhover, e.type === 'mouseenter');
- });
- notify.children('div.elfinder-notify-cancel').append(button);
- }
- } else if (typeof opts.msg !== 'undefined') {
- notify.children('span.elfinder-notify-msg').html(msg);
- }
-
- cnt = delta + parseInt(notify.data('cnt'));
-
- if (cnt > 0) {
- if (cancel && button.length) {
- if ($.isFunction(cancel) || (typeof cancel === 'object' && cancel.promise)) {
- notify._esc = function(e) {
- if (e.type == 'keydown' && e.keyCode != $.ui.keyCode.ESCAPE) {
- return;
- }
- e.preventDefault();
- e.stopPropagation();
- close();
- if (cancel.promise) {
- cancel.reject(0); // 0 is canceling flag
- } else {
- cancel(e);
- }
- };
- button.on('click', function(e) {
- notify._esc(e);
- });
- $(document).on('keydown.' + this.namespace, notify._esc);
- }
- }
-
- !opts.hideCnt && notify.children('.elfinder-notify-cnt').text('('+cnt+')');
- ndialog.is(':hidden') && ndialog.elfinderdialog('open', this).height('auto');
- notify.data('cnt', cnt);
-
- if ((progress != null)
- && (total = notify.data('total')) >= 0
- && (prc = notify.data('progress')) >= 0) {
-
- total += size != null? size : delta;
- prc += progress;
- (size == null && delta < 0) && (prc += delta * 100);
- notify.data({progress : prc, total : total});
- if (size != null) {
- prc *= 100;
- total = Math.max(1, total);
- }
- progress = parseInt(prc/total);
-
- notify.find('.elfinder-notify-progress')
- .animate({
- width : (progress < 100 ? progress : 100)+'%'
- }, 20);
- }
-
- } else {
- close();
- }
-
- return this;
- },
-
- /**
- * Open confirmation dialog
- *
- * @param Object options
- * @example
- * this.confirm({
- * cssClass : 'elfinder-confirm-mydialog',
- * title : 'Remove files',
- * text : 'Here is question text',
- * accept : { // accept callback - required
- * label : 'Continue',
- * callback : function(applyToAll) { fm.log('Ok') }
- * },
- * cancel : { // cancel callback - required
- * label : 'Cancel',
- * callback : function() { fm.log('Cancel')}
- * },
- * reject : { // reject callback - optionally
- * label : 'No',
- * callback : function(applyToAll) { fm.log('No')}
- * },
- * buttons : [ // additional buttons callback - optionally
- * {
- * label : 'Btn1',
- * callback : function(applyToAll) { fm.log('Btn1')}
- * }
- * ],
- * all : true // display checkbox "Apply to all"
- * })
- * @return elFinder
- */
- confirm : function(opts) {
- var self = this,
- complete = false,
- options = {
- cssClass : 'elfinder-dialog-confirm',
- modal : true,
- resizable : false,
- title : this.i18n(opts.title || 'confirmReq'),
- buttons : {},
- close : function() {
- !complete && opts.cancel.callback();
- $(this).elfinderdialog('destroy');
- }
- },
- apply = this.i18n('apllyAll'),
- label, checkbox, btnNum;
-
- if (opts.cssClass) {
- options.cssClass += ' ' + opts.cssClass;
- }
- options.buttons[this.i18n(opts.accept.label)] = function() {
- opts.accept.callback(!!(checkbox && checkbox.prop('checked')));
- complete = true;
- $(this).elfinderdialog('close');
- };
- options.buttons[this.i18n(opts.accept.label)]._cssClass = 'elfinder-confirm-accept';
-
- if (opts.reject) {
- options.buttons[this.i18n(opts.reject.label)] = function() {
- opts.reject.callback(!!(checkbox && checkbox.prop('checked')));
- complete = true;
- $(this).elfinderdialog('close');
- };
- options.buttons[this.i18n(opts.reject.label)]._cssClass = 'elfinder-confirm-reject';
- }
-
- if (opts.buttons && opts.buttons.length > 0) {
- btnNum = 1;
- $.each(opts.buttons, function(i, v){
- options.buttons[self.i18n(v.label)] = function() {
- v.callback(!!(checkbox && checkbox.prop('checked')));
- complete = true;
- $(this).elfinderdialog('close');
- };
- options.buttons[self.i18n(v.label)]._cssClass = 'elfinder-confirm-extbtn' + (btnNum++);
- if (v.cssClass) {
- options.buttons[self.i18n(v.label)]._cssClass += ' ' + v.cssClass;
- }
- });
- }
-
- options.buttons[this.i18n(opts.cancel.label)] = function() {
- $(this).elfinderdialog('close');
- };
- options.buttons[this.i18n(opts.cancel.label)]._cssClass = 'elfinder-confirm-cancel';
-
- if (opts.all) {
- options.create = function() {
- var base = $('');
- checkbox = $('');
- $(this).next().find('.ui-dialog-buttonset')
- .prepend(base.append($('').prepend(checkbox)));
- };
- }
-
- if (opts.optionsCallback && $.isFunction(opts.optionsCallback)) {
- opts.optionsCallback(options);
- }
-
- return this.dialog('' + this.i18n(opts.text), options);
- },
-
- /**
- * Create unique file name in required dir
- *
- * @param String file name
- * @param String parent dir hash
- * @param String glue
- * @return String
- */
- uniqueName : function(prefix, phash, glue) {
- var i = 0, ext = '', p, name;
-
- prefix = this.i18n(false, prefix);
- phash = phash || this.cwd().hash;
- glue = (typeof glue === 'undefined')? ' ' : glue;
-
- if (p = prefix.match(/^(.+)(\.[^.]+)$/)) {
- ext = p[2];
- prefix = p[1];
- }
-
- name = prefix+ext;
-
- if (!this.fileByName(name, phash)) {
- return name;
- }
- while (i < 10000) {
- name = prefix + glue + (++i) + ext;
- if (!this.fileByName(name, phash)) {
- return name;
- }
- }
- return prefix + Math.random() + ext;
- },
-
- /**
- * Return message translated onto current language
- * Allowed accept HTML element that was wrapped in jQuery object
- * To be careful to XSS vulnerability of HTML element Ex. You should use `fm.escape(file.name)`
- *
- * @param String|Array message[s]|Object jQuery
- * @return String
- **/
- i18n : function() {
- var self = this,
- messages = this.messages,
- input = [],
- ignore = [],
- message = function(m) {
- var file;
- if (m.indexOf('#') === 0) {
- if ((file = self.file(m.substr(1)))) {
- return file.name;
- }
- }
- return m;
- },
- i, j, m, escFunc, start = 0, isErr;
-
- if (arguments.length && arguments[0] === false) {
- escFunc = function(m){ return m; };
- start = 1;
- }
- for (i = start; i< arguments.length; i++) {
- m = arguments[i];
-
- if (Array.isArray(m)) {
- for (j = 0; j < m.length; j++) {
- if (m[j] instanceof jQuery) {
- // jQuery object is HTML element
- input.push(m[j]);
- } else if (typeof m[j] !== 'undefined'){
- input.push(message('' + m[j]));
- }
- }
- } else if (m instanceof jQuery) {
- // jQuery object is HTML element
- input.push(m[j]);
- } else if (typeof m !== 'undefined'){
- input.push(message('' + m));
- }
- }
-
- for (i = 0; i < input.length; i++) {
- // dont translate placeholders
- if ($.inArray(i, ignore) !== -1) {
- continue;
- }
- m = input[i];
- if (typeof m == 'string') {
- isErr = !!(messages[m] && m.match(/^err/));
- // translate message
- m = messages[m] || (escFunc? escFunc(m) : self.escape(m));
- // replace placeholders in message
- m = m.replace(/\$(\d+)/g, function(match, placeholder) {
- var res;
- placeholder = i + parseInt(placeholder);
- if (placeholder > 0 && input[placeholder]) {
- ignore.push(placeholder);
- }
- res = escFunc? escFunc(input[placeholder]) : self.escape(input[placeholder]);
- if (isErr) {
- res = '' + res + '';
- }
- return res;
- });
- } else {
- // get HTML from jQuery object
- m = m.get(0).outerHTML;
- }
-
- input[i] = m;
- }
-
- return $.grep(input, function(m, i) { return $.inArray(i, ignore) === -1 ? true : false; }).join('
');
- },
-
- /**
- * Get icon style from file.icon
- *
- * @param Object elFinder file object
- * @return String|Object
- */
- getIconStyle : function(file, asObject) {
- var self = this,
- template = {
- 'background' : 'url(\'{url}\') 0 0 no-repeat',
- 'background-size' : 'contain'
- },
- style = '',
- cssObj = {},
- i = 0;
- if (file.icon) {
- style = 'style="';
- $.each(template, function(k, v) {
- if (i++ === 0) {
- v = v.replace('{url}', self.escape(file.icon));
- }
- if (asObject) {
- cssObj[k] = v;
- } else {
- style += k+':'+v+';';
- }
- });
- style += '"';
- }
- return asObject? cssObj : style;
- },
-
- /**
- * Convert mimetype into css classes
- *
- * @param String file mimetype
- * @return String
- */
- mime2class : function(mimeType) {
- var prefix = 'elfinder-cwd-icon-',
- mime = mimeType.toLowerCase(),
- isText = this.textMimes[mime];
-
- mime = mime.split('/');
- if (isText) {
- mime[0] += ' ' + prefix + 'text';
- } else if (mime[1] && mime[1].match(/\+xml$/)) {
- mime[0] += ' ' + prefix + 'xml';
- }
-
- return prefix + mime[0] + (mime[1] ? ' ' + prefix + mime[1].replace(/(\.|\+)/g, '-') : '');
- },
-
- /**
- * Return localized kind of file
- *
- * @param Object|String file or file mimetype
- * @return String
- */
- mime2kind : function(f) {
- var isObj = typeof(f) == 'object' ? true : false,
- mime = isObj ? f.mime : f,
- kind;
-
-
- if (isObj && f.alias && mime != 'symlink-broken') {
- kind = 'Alias';
- } else if (this.kinds[mime]) {
- if (isObj && mime === 'directory' && (! f.phash || f.isroot)) {
- kind = 'Root';
- } else {
- kind = this.kinds[mime];
- }
- }
- if (! kind) {
- if (mime.indexOf('text') === 0) {
- kind = 'Text';
- } else if (mime.indexOf('image') === 0) {
- kind = 'Image';
- } else if (mime.indexOf('audio') === 0) {
- kind = 'Audio';
- } else if (mime.indexOf('video') === 0) {
- kind = 'Video';
- } else if (mime.indexOf('application') === 0) {
- kind = 'App';
- } else {
- kind = mime;
- }
- }
-
- return this.messages['kind'+kind] ? this.i18n('kind'+kind) : mime;
- },
-
- /**
- * Return boolean Is mime-type text file
- *
- * @param String mime-type
- * @return Boolean
- */
- mimeIsText : function(mime) {
- return (this.textMimes[mime.toLowerCase()] || (mime.indexOf('text/') === 0 && mime.substr(5, 3) !== 'rtf') || mime.match(/^application\/.+\+xml$/))? true : false;
- },
-
- /**
- * Returns a date string formatted according to the given format string
- *
- * @param String format string
- * @param Object Date object
- * @return String
- */
- date : function(format, date) {
- var self = this,
- output, d, dw, m, y, h, g, i, s;
-
- if (! date) {
- date = new Date();
- }
-
- h = date[self.getHours]();
- g = h > 12 ? h - 12 : h;
- i = date[self.getMinutes]();
- s = date[self.getSeconds]();
- d = date[self.getDate]();
- dw = date[self.getDay]();
- m = date[self.getMonth]() + 1;
- y = date[self.getFullYear]();
-
- output = format.replace(/[a-z]/gi, function(val) {
- switch (val) {
- case 'd': return d > 9 ? d : '0'+d;
- case 'j': return d;
- case 'D': return self.i18n(self.i18.daysShort[dw]);
- case 'l': return self.i18n(self.i18.days[dw]);
- case 'm': return m > 9 ? m : '0'+m;
- case 'n': return m;
- case 'M': return self.i18n(self.i18.monthsShort[m-1]);
- case 'F': return self.i18n(self.i18.months[m-1]);
- case 'Y': return y;
- case 'y': return (''+y).substr(2);
- case 'H': return h > 9 ? h : '0'+h;
- case 'G': return h;
- case 'g': return g;
- case 'h': return g > 9 ? g : '0'+g;
- case 'a': return h >= 12 ? 'pm' : 'am';
- case 'A': return h >= 12 ? 'PM' : 'AM';
- case 'i': return i > 9 ? i : '0'+i;
- case 's': return s > 9 ? s : '0'+s;
- }
- return val;
- });
-
- return output;
- },
-
- /**
- * Return localized date
- *
- * @param Object file object
- * @return String
- */
- formatDate : function(file, t) {
- var self = this,
- ts = t || file.ts,
- i18 = self.i18,
- date, format, output, d, dw, m, y, h, g, i, s;
-
- if (self.options.clientFormatDate && ts > 0) {
-
- date = new Date(ts*1000);
- format = ts >= this.yesterday
- ? this.fancyFormat
- : this.dateFormat;
-
- output = self.date(format, date);
-
- return ts >= this.yesterday
- ? output.replace('$1', this.i18n(ts >= this.today ? 'Today' : 'Yesterday'))
- : output;
- } else if (file.date) {
- return file.date.replace(/([a-z]+)\s/i, function(a1, a2) { return self.i18n(a2)+' '; });
- }
-
- return self.i18n('dateUnknown');
- },
-
- /**
- * Return localized number string
- *
- * @param Number
- * @return String
- */
- toLocaleString : function(num) {
- var v = new Number(num);
- if (v) {
- if (v.toLocaleString) {
- return v.toLocaleString();
- } else {
- return String(num).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
- }
- }
- return num;
- },
-
- /**
- * Return css class marks file permissions
- *
- * @param Object file
- * @return String
- */
- perms2class : function(o) {
- var c = '';
-
- if (!o.read && !o.write) {
- c = 'elfinder-na';
- } else if (!o.read) {
- c = 'elfinder-wo';
- } else if (!o.write) {
- c = 'elfinder-ro';
- }
-
- if (o.type) {
- c += ' elfinder-' + this.escape(o.type);
- }
-
- return c;
- },
-
- /**
- * Return localized string with file permissions
- *
- * @param Object file
- * @return String
- */
- formatPermissions : function(f) {
- var p = [];
-
- f.read && p.push(this.i18n('read'));
- f.write && p.push(this.i18n('write'));
-
- return p.length ? p.join(' '+this.i18n('and')+' ') : this.i18n('noaccess');
- },
-
- /**
- * Return formated file size
- *
- * @param Number file size
- * @return String
- */
- formatSize : function(s) {
- var n = 1, u = 'b';
-
- if (s == 'unknown') {
- return this.i18n('unknown');
- }
-
- if (s > 1073741824) {
- n = 1073741824;
- u = 'GB';
- } else if (s > 1048576) {
- n = 1048576;
- u = 'MB';
- } else if (s > 1024) {
- n = 1024;
- u = 'KB';
- }
- s = s/n;
- return (s > 0 ? n >= 1048576 ? s.toFixed(2) : Math.round(s) : 0) +' '+u;
- },
-
- /**
- * Return formated file mode by options.fileModeStyle
- *
- * @param String file mode
- * @param String format style
- * @return String
- */
- formatFileMode : function(p, style) {
- var i, o, s, b, sticy, suid, sgid, str, oct;
-
- if (!style) {
- style = this.options.fileModeStyle.toLowerCase();
- }
- p = $.trim(p);
- if (p.match(/[rwxs-]{9}$/i)) {
- str = p = p.substr(-9);
- if (style == 'string') {
- return str;
- }
- oct = '';
- s = 0;
- for (i=0; i<7; i=i+3) {
- o = p.substr(i, 3);
- b = 0;
- if (o.match(/[r]/i)) {
- b += 4;
- }
- if (o.match(/[w]/i)) {
- b += 2;
- }
- if (o.match(/[xs]/i)) {
- if (o.match(/[xs]/)) {
- b += 1;
- }
- if (o.match(/[s]/i)) {
- if (i == 0) {
- s += 4;
- } else if (i == 3) {
- s += 2;
- }
- }
- }
- oct += b.toString(8);
- }
- if (s) {
- oct = s.toString(8) + oct;
- }
- } else {
- p = parseInt(p, 8);
- oct = p? p.toString(8) : '';
- if (!p || style == 'octal') {
- return oct;
- }
- o = p.toString(8);
- s = 0;
- if (o.length > 3) {
- o = o.substr(-4);
- s = parseInt(o.substr(0, 1), 8);
- o = o.substr(1);
- }
- sticy = ((s & 1) == 1); // not support
- sgid = ((s & 2) == 2);
- suid = ((s & 4) == 4);
- str = '';
- for(i=0; i<3; i++) {
- if ((parseInt(o.substr(i, 1), 8) & 4) == 4) {
- str += 'r';
- } else {
- str += '-';
- }
- if ((parseInt(o.substr(i, 1), 8) & 2) == 2) {
- str += 'w';
- } else {
- str += '-';
- }
- if ((parseInt(o.substr(i, 1), 8) & 1) == 1) {
- str += ((i==0 && suid)||(i==1 && sgid))? 's' : 'x';
- } else {
- str += '-';
- }
- }
- }
- if (style == 'both') {
- return str + ' (' + oct + ')';
- } else if (style == 'string') {
- return str;
- } else {
- return oct;
- }
- },
-
- /**
- * Regist this.decodeRawString function
- *
- * @return void
- */
- registRawStringDecoder : function(rawStringDecoder) {
- if ($.isFunction(rawStringDecoder)) {
- this.decodeRawString = this.options.rawStringDecoder = rawStringDecoder;
- }
- },
-
- /**
- * Return boolean that uploadable MIME type into target folder
- *
- * @param String mime MIME type
- * @param String target target folder hash
- * @return Bool
- */
- uploadMimeCheck : function(mime, target) {
- target = target || this.cwd().hash;
- var res = true, // default is allow
- mimeChecker = this.option('uploadMime', target),
- allow,
- deny,
- check = function(checker) {
- var ret = false;
- if (typeof checker === 'string' && checker.toLowerCase() === 'all') {
- ret = true;
- } else if (Array.isArray(checker) && checker.length) {
- $.each(checker, function(i, v) {
- v = v.toLowerCase();
- if (v === 'all' || mime.indexOf(v) === 0) {
- ret = true;
- return false;
- }
- });
- }
- return ret;
- };
- if (mime && $.isPlainObject(mimeChecker)) {
- mime = mime.toLowerCase();
- allow = check(mimeChecker.allow);
- deny = check(mimeChecker.deny);
- if (mimeChecker.firstOrder === 'allow') {
- res = false; // default is deny
- if (! deny && allow === true) { // match only allow
- res = true;
- }
- } else {
- res = true; // default is allow
- if (deny === true && ! allow) { // match only deny
- res = false;
- }
- }
- }
- return res;
- },
-
- /**
- * call chained sequence of async deferred functions
- *
- * @param Array tasks async functions
- * @return Object jQuery.Deferred
- */
- sequence : function(tasks) {
- var l = tasks.length,
- chain = function(task, idx) {
- ++idx;
- if (tasks[idx]) {
- return chain(task.then(tasks[idx]), idx);
- } else {
- return task;
- }
- };
- if (l > 1) {
- return chain(tasks[0](), 0);
- } else {
- return tasks[0]();
- }
- },
-
- /**
- * Reload contents of target URL for clear browser cache
- *
- * @param String url target URL
- * @return Object jQuery.Deferred
- */
- reloadContents : function(url) {
- var dfd = $.Deferred(),
- ifm;
- try {
- ifm = $('