(function($) { //Global container. window.imce = {tree: {}, findex: [], fids: {}, selected: {}, selcount: 0, ops: {}, cache: {}, urlId: {}, vars: {previewImages: 1, cache: 1}, hooks: {load: [], list: [], navigate: [], cache: []}, //initiate imce. initiate: function() { imce.conf = Drupal.settings.imce || {}; if (imce.conf.error != false) return; imce.ie = (navigator.userAgent.match(/msie (\d+)/i) || ['', 0])[1] * 1; imce.FLW = imce.el('file-list-wrapper'), imce.SBW = imce.el('sub-browse-wrapper'); imce.NW = imce.el('navigation-wrapper'), imce.BW = imce.el('browse-wrapper'); imce.PW = imce.el('preview-wrapper'), imce.FW = imce.el('forms-wrapper'); imce.updateUI(); imce.prepareMsgs();//process initial status messages imce.initiateTree();//build directory tree imce.hooks.list.unshift(imce.processRow);//set the default list-hook. imce.initiateList();//process file list imce.initiateOps();//prepare operation tabs imce.refreshOps(); // Bind global error handler $(document).ajaxError(imce.ajaxError); imce.invoke('load', window);//run functions set by external applications. }, //process navigation tree initiateTree: function() { $('#navigation-tree li').each(function(i) { var a = this.firstChild, txt = a.firstChild; txt && (txt.data = imce.decode(txt.data)); var branch = imce.tree[a.title] = {'a': a, li: this, ul: this.lastChild.tagName == 'UL' ? this.lastChild : null}; if (a.href) imce.dirClickable(branch); imce.dirCollapsible(branch); }); }, //Add a dir to the tree under parent dirAdd: function(dir, parent, clickable) { if (imce.tree[dir]) return clickable ? imce.dirClickable(imce.tree[dir]) : imce.tree[dir]; var parent = parent || imce.tree['.']; parent.ul = parent.ul ? parent.ul : parent.li.appendChild(imce.newEl('ul')); var branch = imce.dirCreate(dir, imce.decode(dir.substr(dir.lastIndexOf('/')+1)), clickable); parent.ul.appendChild(branch.li); return branch; }, //create list item for navigation tree dirCreate: function(dir, text, clickable) { if (imce.tree[dir]) return imce.tree[dir]; var branch = imce.tree[dir] = {li: imce.newEl('li'), a: imce.newEl('a')}; $(branch.a).addClass('folder').text(text).attr('title', dir).appendTo(branch.li); imce.dirCollapsible(branch); return clickable ? imce.dirClickable(branch) : branch; }, //change currently active directory dirActivate: function(dir) { if (dir != imce.conf.dir) { if (imce.tree[imce.conf.dir]){ $(imce.tree[imce.conf.dir].a).removeClass('active'); } $(imce.tree[dir].a).addClass('active'); imce.conf.dir = dir; } return imce.tree[imce.conf.dir]; }, //make a dir accessible dirClickable: function(branch) { if (branch.clkbl) return branch; $(branch.a).attr('href', '#').removeClass('disabled').click(function() {imce.navigate(this.title); return false;}); branch.clkbl = true; return branch; }, //sub-directories expand-collapse ability dirCollapsible: function (branch) { if (branch.clpsbl) return branch; $(imce.newEl('span')).addClass('expander').html(' ').click(function() { if (branch.ul) { $(branch.ul).toggle(); $(branch.li).toggleClass('expanded'); imce.ie && $('#navigation-header').css('top', imce.NW.scrollTop); } else if (branch.clkbl){ $(branch.a).click(); } }).prependTo(branch.li); branch.clpsbl = true; return branch; }, //update navigation tree after getting subdirectories. dirSubdirs: function(dir, subdirs) { var branch = imce.tree[dir]; if (subdirs && subdirs.length) { var prefix = dir == '.' ? '' : dir +'/'; for (var i in subdirs) {//add subdirectories imce.dirAdd(prefix + subdirs[i], branch, true); } $(branch.li).removeClass('leaf').addClass('expanded'); $(branch.ul).show(); } else if (!branch.ul){//no subdirs->leaf $(branch.li).removeClass('expanded').addClass('leaf'); } }, //process file list initiateList: function(cached) { var L = imce.hooks.list, dir = imce.conf.dir, token = {'%dir': dir == '.' ? $(imce.tree['.'].a).text() : imce.decode(dir)} imce.findex = [], imce.fids = {}, imce.selected = {}, imce.selcount = 0, imce.vars.lastfid = null; imce.tbody = imce.el('file-list').tBodies[0]; if (imce.tbody.rows.length) { for (var row, i = 0; row = imce.tbody.rows[i]; i++) { var fid = row.id; imce.findex[i] = imce.fids[fid] = row; if (cached) { if (imce.hasC(row, 'selected')) { imce.selected[imce.vars.lastfid = fid] = row; imce.selcount++; } } else { for (var func, j = 0; func = L[j]; j++) func(row);//invoke list-hook } } } if (!imce.conf.perm.browse) { imce.setMessage(Drupal.t('File browsing is disabled in directory %dir.', token), 'error'); } }, //add a file to the list. (having properties name,size,formatted size,width,height,date,formatted date) fileAdd: function(file) { var row, fid = file.name, i = imce.findex.length, attr = ['name', 'size', 'width', 'height', 'date']; if (!(row = imce.fids[fid])) { row = imce.findex[i] = imce.fids[fid] = imce.tbody.insertRow(i); for (var i in attr) row.insertCell(i).className = attr[i]; } row.cells[0].innerHTML = row.id = fid; row.cells[1].innerHTML = file.fsize; row.cells[1].id = file.size; row.cells[2].innerHTML = file.width; row.cells[3].innerHTML = file.height; row.cells[4].innerHTML = file.fdate; row.cells[4].id = file.date; imce.invoke('list', row); if (imce.vars.prvfid == fid) imce.setPreview(fid); if (file.id) imce.urlId[imce.getURL(fid)] = file.id; }, //remove a file from the list fileRemove: function(fid) { if (!(row = imce.fids[fid])) return; imce.fileDeSelect(fid); imce.findex.splice(row.rowIndex, 1); $(row).remove(); delete imce.fids[fid]; if (imce.vars.prvfid == fid) imce.setPreview(); }, //return a file object containing all properties. fileGet: function (fid) { var file = imce.fileProps(fid); if (file) { file.name = imce.decode(fid); file.url = imce.getURL(fid); file.relpath = imce.getRelpath(fid); file.id = imce.urlId[file.url] || 0; //file id for newly uploaded files } return file; }, //return file properties embedded in html. fileProps: function (fid) { var row = imce.fids[fid]; return row ? { size: row.cells[1].innerHTML, bytes: row.cells[1].id * 1, width: row.cells[2].innerHTML * 1, height: row.cells[3].innerHTML * 1, date: row.cells[4].innerHTML, time: row.cells[4].id * 1 } : null; }, //simulate row click. selection-highlighting fileClick: function(row, ctrl, shft) { if (!row) return; var fid = typeof(row) == 'string' ? row : row.id; if (ctrl || fid == imce.vars.prvfid) { imce.fileToggleSelect(fid); } else if (shft) { var last = imce.lastFid(); var start = last ? imce.fids[last].rowIndex : -1; var end = imce.fids[fid].rowIndex; var step = start > end ? -1 : 1; while (start != end) { start += step; imce.fileSelect(imce.findex[start].id); } } else { for (var fname in imce.selected) { imce.fileDeSelect(fname); } imce.fileSelect(fid); } //set preview imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); }, //file select/deselect functions fileSelect: function (fid) { if (imce.selected[fid] || !imce.fids[fid]) return; imce.selected[fid] = imce.fids[imce.vars.lastfid=fid]; $(imce.selected[fid]).addClass('selected'); imce.selcount++; }, fileDeSelect: function (fid) { if (!imce.selected[fid] || !imce.fids[fid]) return; if (imce.vars.lastfid == fid) imce.vars.lastfid = null; $(imce.selected[fid]).removeClass('selected'); delete imce.selected[fid]; imce.selcount--; }, fileToggleSelect: function (fid) { imce['file'+ (imce.selected[fid] ? 'De' : '') +'Select'](fid); }, //process file operation form and create operation tabs. initiateOps: function() { imce.setHtmlOps(); imce.setUploadOp();//upload imce.setFileOps();//thumb, delete, resize }, //process existing html ops. setHtmlOps: function () { $(imce.el('ops-list')).children('li').each(function() { if (!this.firstChild) return $(this).remove(); var name = this.id.substr(8); var Op = imce.ops[name] = {div: imce.el('op-content-'+ name), li: imce.el('op-item-'+ name)}; Op.a = Op.li.firstChild; Op.title = Op.a.innerHTML; $(Op.a).click(function() {imce.opClick(name); return false;}); }); }, //convert upload form to an op. setUploadOp: function () { var el, form = imce.el('imce-upload-form'); if (!form) return; $(form).ajaxForm(imce.uploadSettings()).find('fieldset').each(function() {//clean up fieldsets this.removeChild(this.firstChild); $(this).after(this.childNodes); }).remove(); // Set html response flag el = form.elements['files[imce]']; if (el && el.files && window.FormData) { if (el = form.elements.html_response) { el.value = 0; } } imce.opAdd({name: 'upload', title: Drupal.t('Upload'), content: form});//add op }, //convert fileop form submit buttons to ops. setFileOps: function () { var form = imce.el('imce-fileop-form'); if (!form) return; $(form.elements.filenames).parent().remove(); $(form).find('fieldset').each(function() {//remove fieldsets var $sbmt = $('input:submit', this); if (!$sbmt.length) return; var Op = {name: $sbmt.attr('id').substr(5)}; var func = function() {imce.fopSubmit(Op.name); return false;}; $sbmt.click(func); Op.title = $(this).children('legend').remove().text() || $sbmt.val(); Op.name == 'delete' ? (Op.func = func) : (Op.content = this.childNodes); imce.opAdd(Op); }).remove(); imce.vars.opform = $(form).serialize();//serialize remaining parts. }, //refresh ops states. enable/disable refreshOps: function() { for (var p in imce.conf.perm) { if (imce.conf.perm[p]) imce.opEnable(p); else imce.opDisable(p); } }, //add a new file operation opAdd: function (op) { var oplist = imce.el('ops-list'), opcons = imce.el('op-contents'); var name = op.name || ('op-'+ $(oplist).children('li').length); var title = op.title || 'Untitled'; var Op = imce.ops[name] = {title: title}; if (op.content) { Op.div = imce.newEl('div'); $(Op.div).attr({id: 'op-content-'+ name, 'class': 'op-content'}).appendTo(opcons).append(op.content); } Op.a = imce.newEl('a'); Op.li = imce.newEl('li'); $(Op.a).attr({href: '#', name: name, title: title}).html('' + title +'').click(imce.opClickEvent); $(Op.li).attr('id', 'op-item-'+ name).append(Op.a).appendTo(oplist); Op.func = op.func || imce.opVoid; return Op; }, //click event for file operations opClickEvent: function(e) { imce.opClick(this.name); return false; }, //void operation function opVoid: function() {}, //perform op click opClick: function(name) { var Op = imce.ops[name], oldop = imce.vars.op; if (!Op || Op.disabled) { return imce.setMessage(Drupal.t('You can not perform this operation.'), 'error'); } if (Op.div) { if (oldop) { var toggle = oldop == name; imce.opShrink(oldop, toggle ? 'fadeOut' : 'hide'); if (toggle) return false; } var left = Op.li.offsetLeft; var $opcon = $('#op-contents').css({left: 0}); $(Op.div).fadeIn('normal', function() { setTimeout(function() { if (imce.vars.op) { var $inputs = $('input', imce.ops[imce.vars.op].div); $inputs.eq(0).focus(); //form inputs become invisible in IE. Solution is as stupid as the behavior. $('html').hasClass('ie') && $inputs.addClass('dummyie').removeClass('dummyie'); } }); }); var diff = left + $opcon.width() - $('#imce-content').width(); $opcon.css({left: diff > 0 ? left - diff - 1 : left}); $(Op.li).addClass('active'); $(imce.opCloseLink).fadeIn(300); imce.vars.op = name; } Op.func(true); return true; }, //enable a file operation opEnable: function(name) { var Op = imce.ops[name]; if (Op && Op.disabled) { Op.disabled = false; $(Op.li).show(); } }, //disable a file operation opDisable: function(name) { var Op = imce.ops[name]; if (Op && !Op.disabled) { Op.div && imce.opShrink(name); $(Op.li).hide(); Op.disabled = true; } }, //hide contents of a file operation opShrink: function(name, effect) { if (imce.vars.op != name) return; var Op = imce.ops[name]; $(Op.div).stop(true, true)[effect || 'hide'](); $(Op.li).removeClass('active'); $(imce.opCloseLink).hide(); Op.func(false); imce.vars.op = null; }, //navigate to dir navigate: function(dir) { if (imce.vars.navbusy || (dir == imce.conf.dir && !confirm(Drupal.t('Do you want to refresh the current directory?')))) return; var cache = imce.vars.cache && dir != imce.conf.dir; var set = imce.navSet(dir, cache); if (cache && imce.cache[dir]) {//load from the cache set.success({data: imce.cache[dir]}); set.complete(); } else $.ajax(set);//live load }, //ajax navigation settings navSet: function (dir, cache) { $(imce.tree[dir].li).addClass('loading'); imce.vars.navbusy = dir; return {url: imce.ajaxURL('navigate', dir), type: 'GET', dataType: 'json', success: function(response) { if (response.data && !response.data.error) { if (cache) imce.navCache(imce.conf.dir, dir);//cache the current dir imce.navUpdate(response.data, dir); } imce.processResponse(response); }, complete: function () { $(imce.tree[dir].li).removeClass('loading'); imce.vars.navbusy = null; } }; }, //update directory using the given data navUpdate: function(data, dir) { var cached = data == imce.cache[dir], olddir = imce.conf.dir; if (cached) data.files.id = 'file-list'; $(imce.FLW).html(data.files); imce.dirActivate(dir); imce.dirSubdirs(dir, data.subdirectories); $.extend(imce.conf.perm, data.perm); imce.refreshOps(); imce.initiateList(cached); imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); imce.SBW.scrollTop = 0; imce.invoke('navigate', data, olddir, cached); }, //set cache navCache: function (dir, newdir) { var C = imce.cache[dir] = {'dir': dir, files: imce.el('file-list'), dirsize: imce.el('dir-size').innerHTML, perm: $.extend({}, imce.conf.perm)}; C.files.id = 'cached-list-'+ dir; imce.FW.appendChild(C.files); imce.invoke('cache', C, newdir); }, //validate upload form uploadValidate: function (data, form, options) { var path = $('#edit-imce').val(); if (!path) return false; if (imce.conf.extensions != '*') { var ext = path.substr(path.lastIndexOf('.') + 1); if ((' '+ imce.conf.extensions +' ').indexOf(' '+ ext.toLowerCase() +' ') == -1) { return imce.setMessage(Drupal.t('Only files with the following extensions are allowed: %files-allowed.', {'%files-allowed': imce.conf.extensions}), 'error'); } } options.url = imce.ajaxURL('upload');//make url contain current dir. imce.fopLoading('upload', true); return true; }, //settings for upload uploadSettings: function () { return { beforeSubmit: imce.uploadValidate, success: function (response) { try{ imce.processResponse($.parseJSON(response)); } catch(e) {} }, complete: function () { imce.fopLoading('upload', false); }, resetForm: true, dataType: 'text' }; }, //validate default ops(delete, thumb, resize) fopValidate: function(fop) { if (!imce.validateSelCount(1, imce.conf.filenum)) return false; switch (fop) { case 'delete': return confirm(Drupal.t('Delete selected files?')); case 'thumb': if (!$('input:checked', imce.ops['thumb'].div).length) { return imce.setMessage(Drupal.t('Please select a thumbnail.'), 'error'); } return imce.validateImage(); case 'resize': var w = imce.el('edit-width').value, h = imce.el('edit-height').value; var maxDim = imce.conf.dimensions.split('x'); var maxW = maxDim[0]*1, maxH = maxW ? maxDim[1]*1 : 0; if (!(/^[1-9][0-9]*$/).test(w) || !(/^[1-9][0-9]*$/).test(h) || (maxW && (maxW < w*1 || maxH < h*1))) { return imce.setMessage(Drupal.t('Please specify dimensions within the allowed range that is from 1x1 to @dimensions.', {'@dimensions': maxW ? imce.conf.dimensions : Drupal.t('unlimited')}), 'error'); } return imce.validateImage(); } var func = fop +'OpValidate'; if (imce[func]) return imce[func](fop); return true; }, //submit wrapper for default ops fopSubmit: function(fop) { switch (fop) { case 'thumb': case 'delete': case 'resize': return imce.commonSubmit(fop); } var func = fop +'OpSubmit'; if (imce[func]) return imce[func](fop); }, //common submit function shared by default ops commonSubmit: function(fop) { if (!imce.fopValidate(fop)) return false; imce.fopLoading(fop, true); $.ajax(imce.fopSettings(fop)); }, //settings for default file operations fopSettings: function (fop) { return {url: imce.ajaxURL(fop), type: 'POST', dataType: 'json', success: imce.processResponse, complete: function (response) {imce.fopLoading(fop, false);}, data: imce.vars.opform +'&filenames='+ encodeURIComponent(imce.serialNames()) +'&jsop='+ fop + (imce.ops[fop].div ? '&'+ $('input, select, textarea', imce.ops[fop].div).serialize() : '')}; }, //toggle loading state fopLoading: function(fop, state) { var el = imce.el('edit-'+ fop), func = state ? 'addClass' : 'removeClass'; if (el) { $(el)[func]('loading'); el.disabled = state; } else { $(imce.ops[fop].li)[func]('loading'); imce.ops[fop].disabled = state; } }, //preview a file. setPreview: function (fid) { var row, html = ''; imce.vars.prvfid = fid; if (fid && (row = imce.fids[fid])) { var width = row.cells[2].innerHTML * 1; html = imce.vars.previewImages && width ? imce.imgHtml(fid, width, row.cells[3].innerHTML) : imce.decodePlain(fid); html = ''+ html +''; } imce.el('file-preview').innerHTML = html; }, //default file send function. sends the file to the new window. send: function (fid) { fid && window.open(imce.getURL(fid)); }, //add an operation for an external application to which the files are send. setSendTo: function (title, func) { imce.send = function (fid) { fid && func(imce.fileGet(fid), window);}; var opFunc = function () { if (imce.selcount != 1) return imce.setMessage(Drupal.t('Please select a file.'), 'error'); imce.send(imce.vars.prvfid); }; imce.vars.prvtitle = title; return imce.opAdd({name: 'sendto', title: title, func: opFunc}); }, //move initial page messages into log prepareMsgs: function () { var msgs; if (msgs = imce.el('imce-messages')) { $('>div', msgs).each(function (){ var type = this.className.split(' ')[1]; var li = $('>ul li', this); if (li.length) li.each(function () {imce.setMessage(this.innerHTML, type);}); else imce.setMessage(this.innerHTML, type); }); $(msgs).remove(); } }, //insert log message setMessage: function (msg, type) { var $box = $(imce.msgBox); var logs = imce.el('log-messages') || $(imce.newEl('div')).appendTo('#help-box-content').before('