elFinder.prototype.commands.quicklook.plugins = [
* @param elFinder.commands.quicklook
var mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'],
getDimSize = ql.fm.returnBytes((ql.options.getDimThreshold || 0)),
WebP.onload = WebP.onerror = function() {
mimes.push('image/webp');
WebP.src='data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
// what kind of images we can display
$.each(navigator.mimeTypes, function(i, o) {
if (mime.indexOf('image/') === 0 && $.inArray(mime, mimes)) {
preview.on(ql.evUpdate, function(e) {
var rfile = fm.file(file.hash);
var elm, varelm, memSize, width, height, prop;
dimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject();
memSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()});
memSize && img.removeAttr('width').removeAttr('height');
width = file.width || elm.naturalWidth || elm.width || img.width();
height = file.height || elm.naturalHeight || elm.height || img.height();
if (!file.width || !file.height) {
memSize && img.width(memSize.w).height(memSize.h);
prop = (width/height).toFixed(2);
preview.on('changesize', function() {
var pw = parseInt(preview.width()),
ph = parseInt(preview.height()),
if (prop < (pw/ph).toFixed(2)) {
w = Math.floor(h * prop);
img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
url, img, loading, prog, m, opDfd;
flipMime = fm.arrayFlip(mimes);
if (flipMime[file.mime] && ql.dispInlineRegex.test(file.mime)) {
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
.on('error', function() {
opDfd = fm.openUrl(file.hash, false, function(url) {
}, { progressBar: prog });
// stop loading on change file if not loaded yet
preview.one('change', function() {
opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
if (file.width && file.height) {
} else if (file.size > getDimSize) {
data : {cmd : 'dim', target : file.hash},
var dim = data.dim.split('x');
* @param object ql elFinder.commands.quicklook
if (window.Worker && window.Uint8Array) {
preview.on(ql.evUpdate, function(e) {
var rfile = fm.file(file.hash);
loading, prog, url, base, wk, opDfd;
if (file.mime === mime) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
// stop loading on change file if not loaded yet
preview.one('change', function() {
opDfd = fm.getContents(file.hash, 'arraybuffer', { progressBar: prog }).done(function(data) {
base = $('<div></div>').css({width:'100%',height:'100%'}).hide().appendTo(preview);
wk.onmessage = function(res) {
cv = document.createElement('canvas');
co = cv.getContext('2d');
id = co.createImageData(data.width, data.height);
(id).data.set(new Uint8Array(data.image));
co.putImageData(id, 0, 0);
prop = (data.width/data.height).toFixed(2);
preview.on('changesize', function() {
var pw = parseInt(preview.width()),
ph = parseInt(preview.height()),
if (prop < (pw/ph).toFixed(2)) {
w = Math.floor(h * prop);
$(cv).width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
}).trigger('changesize');
if (!file.width || !file.height) {
setdim([data.width, data.height]);
scripts: [fm.options.cdns.tiff, fm.getWorkerUrl('quicklook.tiff.js')],
// stop loading on change file if not loaded yet
preview.one('change', function() {
opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
* PSD(Adobe Photoshop data) preview plugin
* @param elFinder.commands.quicklook
mimes = fm.arrayFlip(['image/vnd.adobe.photoshop', 'image/x-photoshop']),
load = function(url, img, loading) {
PSD.fromURL(url).then(function(psd) {
img.attr('src', psd.image.toBase64());
requestAnimationFrame(function() {
prop = (img.width()/img.height()).toFixed(2);
preview.on('changesize', function() {
var pw = parseInt(preview.width()),
ph = parseInt(preview.height()),
if (prop < (pw/ph).toFixed(2)) {
w = Math.floor(h * prop);
img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0);
}).trigger('changesize');
preview.on(ql.evUpdate, function(e) {
url, img, loading, prog, m,
_define, _require, opDfd;
if (mimes[file.mime] && fm.options.cdns.psd && ! fm.UA.ltIE10 && ql.dispInlineRegex.test(file.mime)) {
// this is our file - stop event propagation
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
opDfd = fm.openUrl(file.hash, 'sameorigin', function(url) {
img = $('<img/>').hide().appendTo(preview);
_require = window.require;
_define? (window.define = _define) : (delete window.define);
_require? (window.require = _require) : (delete window.require);
}, { progressBar: prog });
// stop loading on change file if not loaded yet
preview.one('change', function() {
opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject();
* @param elFinder.commands.quicklook
mimes = fm.arrayFlip(['text/html', 'application/xhtml+xml']),
preview.on(ql.evUpdate, function(e) {
var file = e.file, jqxhr, loading, prog;
if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
// stop loading on change file if not loaded yet
preview.one('change', function() {
jqxhr.state() == 'pending' && jqxhr.reject();
}).addClass('elfinder-overflow-auto');
data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
options : {type: 'get', cache : true},
var doc = $('<iframe class="elfinder-quicklook-preview-html"></iframe>').appendTo(preview)[0].contentWindow.document;
* MarkDown preview plugin
* @param elFinder.commands.quicklook
mimes = fm.arrayFlip(['text/x-markdown']),
show = function(data, loading) {
var doc = $('<iframe class="elfinder-quicklook-preview-html"></iframe>').appendTo(preview)[0].contentWindow.document;
doc.write((marked.parse || marked)(data.content));
error = function(loading) {
preview.on(ql.evUpdate, function(e) {
var file = e.file, jqxhr, loading, prog;
if (mimes[file.mime] && fm.options.cdns.marked && marked !== false && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
// stop loading on change file if not loaded yet
preview.one('change', function() {
jqxhr.state() == 'pending' && jqxhr.reject();
}).addClass('elfinder-overflow-auto');
data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts},
options : {type: 'get', cache : true},
if (marked || window.marked) {
fm.loadScript([fm.options.cdns.marked],
marked = res || window.marked || false;
* PDF/ODT/ODS/ODP preview with ViewerJS
* @param elFinder.commands.quicklook
if (ql.options.viewerjs) {
opts = ql.options.viewerjs,
mimes = opts.url? fm.arrayFlip(opts.mimes || []) : [],
navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '30px' : '');
preview.on('update', function(e) {
var file = e.file, node, loading, prog, opDfd;
if (mimes[file.mime] && (file.mime !== 'application/pdf' || !opts.pdfNative || !ql.flags.pdfNative)) {
e.stopImmediatePropagation();
loading = $('<div class="elfinder-quicklook-info-data"><span class="elfinder-spinner-text">'+fm.i18n('nowLoading')+'</span><span class="elfinder-spinner"></span></div>').appendTo(ql.info.find('.elfinder-quicklook-info'));
prog = $('<div class="elfinder-quicklook-info-progress"></div>').appendTo(loading);
opDfd = fm.openUrl(file.hash, 'sameorigin', function(url) {
node = $('<iframe class="elfinder-quicklook-preview-iframe"></iframe>')
.css('background-color', 'transparent')
node.css('background-color', '#fff');
.on('error', function() {
.attr('src', opts.url + '#' + url);
win.on('viewchange.viewerjs', setNavi);
preview.one('change', function() {
win.off('viewchange.viewerjs');
node.off('load').remove();