: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @class elFinder command "quicklook"
* Fast preview for some files types
* @author Dmitry (dio) Levashov
(elFinder.prototype.commands.quicklook = function() {
* window docked and hidden state
* for fix conflicts with Prototype.JS
* `@see https://github.com/Studio-42/elFinder/pull/2346
evUpdate = Element.update? 'quicklookupdate' : 'update',
navicon = 'elfinder-quicklook-navbar-icon',
* navbar "fullscreen" icon class
fullscreen = 'elfinder-quicklook-fullscreen',
infocls = 'elfinder-quicklook-info-wrapper',
* Triger keydown/keypress event with left/right arrow key code
* @param Number left/right arrow key code
navtrigger = function(code) {
jQuery(document).trigger(jQuery.Event('keydown', { keyCode: code, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
* Return css for closed window
* @param jQuery file node in cwd
closedCss = function(node) {
var elf = fm.getUI().offset(),
var target = node.find('.elfinder-cwd-file-wrapper');
return target.length? target : node;
baseOffset = base.offset() || { top: 0, left: 0 };
height : base.height() - 30,
top : baseOffset.top - elf.top,
left : baseOffset.left - elf.left
* Return css for opened window
var contain = self.options.contain || fm.options.dialogContained,
win = contain? fm.getUI() : jQuery(window),
elf = fm.getUI().offset(),
w = Math.min(width, win.width()-10),
h = Math.min(height, win.height()-80);
top : parseInt((win.height() - h - 60) / 2 + (contain? 0 : win.scrollTop() - elf.top)),
left : parseInt((win.width() - w) / 2 + (contain? 0 : win.scrollLeft() - elf.left))
support = function(codec, name) {
var node = name || codec.substr(0, codec.indexOf('/')),
media = mediaNode[node]? mediaNode[node] : (mediaNode[node] = document.createElement(node)),
value = media.canPlayType && media.canPlayType(codec);
return (value && value !== '' && value != 'no')? true : false;
platformWin = (window.navigator.platform.indexOf('Win') != -1),
* Opened window width (from config)
* Opened window height (from config)
* Previous style before docked
* elFinder current directory node
leftKey = jQuery.ui.keyCode.LEFT,
rightKey = jQuery.ui.keyCode.RIGHT,
coverEv = 'mousemove touchstart ' + ('onwheel' in document? 'wheel' : 'onmousewheel' in document? 'mousewheel' : 'DOMMouseScroll'),
title = jQuery('<span class="elfinder-dialog-title elfinder-quicklook-title"></span>'),
icon = jQuery('<div></div>'),
info = jQuery('<div class="elfinder-quicklook-info"></div>'),//.hide(),
cover = jQuery('<div class="ui-front elfinder-quicklook-cover"></div>'),
fsicon = jQuery('<div class="'+navicon+' '+navicon+'-fullscreen"></div>')
.on('click touchstart', function(e) {
full = win.hasClass(fullscreen),
$window = jQuery(window),
resize = function() { self.preview.trigger('changesize'); };
win.toggleClass(fullscreen)
.css(win.data('position'));
$window.trigger(self.resize).off(self.resize, resize);
navbar.off('mouseenter mouseleave');
win.toggleClass(fullscreen)
jQuery(window).on(self.resize, resize)
cover.on(coverEv, function(e) {
if (e.type === 'mousemove' || e.type === 'touchstart') {
navtm = setTimeout(function() {
if (fm.UA.Mobile || navbar.parent().find('.elfinder-quicklook-navbar:hover').length < 1) {
navbar.fadeOut('slow', function() {
if (cover.is(':visible')) {
cover.data('tm', setTimeout(function() {
}).show().trigger('mousemove');
navbar.on('mouseenter mouseleave', function(e) {
if (e.type === 'mouseenter') {
cover.trigger('mousemove');
win.css('z-index', fm.zIndex + 1);
navbar.attr('style', navStyle);
navbar.attr('style', navStyle).draggable(full ? 'destroy' : {
navStyle = self.navbar.attr('style');
requestAnimationFrame(function() {
jQuery(this).toggleClass(navicon+'-fullscreen-off');
if (parent.is('.ui-resizable')) {
collection = collection.add(parent);
collection.resizable(full ? 'enable' : 'disable').removeClass('ui-state-disabled');
win.trigger('viewchange');
updateOnSel = function() {
self.update(void(0), (function() {
files = fm.selectedFiles(),
jQuery.each(files, function(i, f) {
hash : files[0].hash + '/' + (+new Date()),
name : fm.i18n('items') + ': ' + cnt,
files : jQuery.map(files, function(f) { return f.hash; }),
return (cnt === 1)? files[0] : getInfo();
if (self.window.hasClass(fullscreen)) {
navtm && clearTimeout(navtm);
// if use `show()` it make infinite loop with old jQuery (jQuery/jQuery UI: 1.8.0/1.9.0)
// see #1478 https://github.com/Studio-42/elFinder/issues/1478
navbar.stop(true, true).css('display', 'block');
cover.data('tm') && clearTimeout(cover.data('tm'));
prev = jQuery('<div class="'+navicon+' '+navicon+'-prev"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(leftKey); return false; }),
next = jQuery('<div class="'+navicon+' '+navicon+'-next"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(rightKey); return false; }),
navbar = jQuery('<div class="elfinder-quicklook-navbar"></div>')
.append('<div class="elfinder-quicklook-navbar-separator"></div>')
.append(jQuery('<div class="'+navicon+' '+navicon+'-close"></div>').on('click touchstart', function(e) { ! navmove && self.window.trigger('close'); return false; }))
titleClose = jQuery('<span class="ui-front ui-icon elfinder-icon-close ui-icon-closethick"></span>').on('mousedown', function(e) {
self.window.trigger('close');
titleDock = jQuery('<span class="ui-front ui-icon elfinder-icon-minimize ui-icon-minusthick"></span>').on('mousedown', function(e) {
self.window.trigger('navdockin');
self.window.trigger('navdockout');
spinner = '<span class="elfinder-spinner-text">' + fm.i18n('calc') + '</span>' + '<span class="elfinder-spinner"></span>',
dockHeight, getSize, tm4cwd, dockedNode, selectTm;
* Any flags for each plugin
this.evUpdate = evUpdate;
(this.navbar = navbar)._show = navShow;
this.resize = 'resize.'+fm.namespace;
this.info = jQuery('<div></div>').addClass(infocls)
this.autoPlay = function() {
return !! self.options[self.docked()? 'dockAutoplay' : 'autoplay'];
this.preview = jQuery('<div class="elfinder-quicklook-preview ui-helper-clearfix"></div>')
.on('change', function() {
navbar.attr('style', navStyle);
self.docked() && navbar.hide();
self.preview.attr('style', '').removeClass('elfinder-overflow-auto');
self.info.attr('style', '').hide();
self.cover.removeClass('elfinder-quicklook-coverbg');
icon.removeAttr('class').attr('style', '');
.on(evUpdate, function(e) {
var preview = self.preview,
tpl = '<div class="elfinder-quicklook-info-data">{value}</div>',
var win = self.window.css('overflow', 'hidden');
name = fm.escape(file.i18 || file.name);
!file.read && e.stopImmediatePropagation();
self.window.data('hash', file.hash);
self.preview.off('changesize').trigger('change').children().remove();
prev.css('visibility', '');
next.css('visibility', '');
if (file.hash === fm.cwdId2Hash(cwd.find('[id]:not(.elfinder-cwd-parent):first').attr('id'))) {
prev.css('visibility', 'hidden');
if (file.hash === fm.cwdId2Hash(cwd.find('[id]:last').attr('id'))) {
next.css('visibility', 'hidden');
if (file.mime === 'directory') {
getSizeHashes = [ file.hash ];
} else if (file.mime === 'group' && file.getSize) {
getSizeHashes = file.files;
tpl.replace(/\{value\}/, name)
+ tpl.replace(/\{value\}/, fm.mime2kind(file))
+ tpl.replace(/\{value\}/, getSizeHashes.length ? spinner : fm.formatSize(file.size))
+ tpl.replace(/\{value\}/, fm.i18n('modify')+': '+ fm.formatDate(file))
if (getSizeHashes.length) {
getSize = fm.getSize(getSizeHashes).done(function(data) {
info.find('span.elfinder-spinner').parent().html(data.formated);
info.find('span.elfinder-spinner').parent().html(fm.i18n('unknown'));
getSize._hash = file.hash;
icon.addClass('elfinder-cwd-icon ui-corner-all '+fm.mime2class(file.mime));
icon.css(fm.getIconStyle(file, true));
self.info.attr('class', infocls);
self.info.addClass(file.csscls);
if (file.read && (tmb = fm.tmb(file))) {
icon.addClass(tmb.className).css('background-image', "url('"+tmb.url+"')");
self.info.delay(100).fadeIn(10);
if (self.window.hasClass(fullscreen)) {
cover.trigger('mousemove');
tmb, name, getSizeHashes = [];
if (file && ! Object.keys(file).length) {
if (file && getSize && getSize.state() === 'pending' && getSize._hash !== file.hash) {
if (file && (e.forceUpdate || self.window.data('hash') !== file.hash)) {
e.stopImmediatePropagation();
this.window = jQuery('<div class="ui-front ui-helper-reset ui-widget elfinder-quicklook touch-punch" style="position:absolute"></div>')
.addClass(fm.UA.Touch? 'elfinder-touch' : '')
.on('click', function(e) {
requestAnimationFrame(function() {
state === opened && fm.toFront(win);
jQuery('<div class="ui-dialog-titlebar ui-widget-header ui-corner-top ui-helper-clearfix elfinder-quicklook-titlebar"></div>')
jQuery('<span class="ui-widget-header ui-dialog-titlebar-close ui-corner-all elfinder-titlebar-button elfinder-quicklook-titlebar-icon'+(platformWin? ' elfinder-titlebar-button-right' : '')+'"></span>').append(