imce.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. (function($) {
  2. //Global container.
  3. window.imce = {tree: {}, findex: [], fids: {}, selected: {}, selcount: 0, ops: {}, cache: {}, urlId: {},
  4. vars: {previewImages: 1, cache: 1},
  5. hooks: {load: [], list: [], navigate: [], cache: []},
  6. //initiate imce.
  7. initiate: function() {
  8. imce.conf = Drupal.settings.imce || {};
  9. if (imce.conf.error != false) return;
  10. imce.ie = (navigator.userAgent.match(/msie (\d+)/i) || ['', 0])[1] * 1;
  11. imce.FLW = imce.el('file-list-wrapper'), imce.SBW = imce.el('sub-browse-wrapper');
  12. imce.NW = imce.el('navigation-wrapper'), imce.BW = imce.el('browse-wrapper');
  13. imce.PW = imce.el('preview-wrapper'), imce.FW = imce.el('forms-wrapper');
  14. imce.updateUI();
  15. imce.prepareMsgs();//process initial status messages
  16. imce.initiateTree();//build directory tree
  17. imce.hooks.list.unshift(imce.processRow);//set the default list-hook.
  18. imce.initiateList();//process file list
  19. imce.initiateOps();//prepare operation tabs
  20. imce.refreshOps();
  21. // Bind global error handler
  22. $(document).ajaxError(imce.ajaxError);
  23. imce.invoke('load', window);//run functions set by external applications.
  24. },
  25. //process navigation tree
  26. initiateTree: function() {
  27. $('#navigation-tree li').each(function(i) {
  28. var a = this.firstChild, txt = a.firstChild;
  29. txt && (txt.data = imce.decode(txt.data));
  30. var branch = imce.tree[a.title] = {'a': a, li: this, ul: this.lastChild.tagName == 'UL' ? this.lastChild : null};
  31. if (a.href) imce.dirClickable(branch);
  32. imce.dirCollapsible(branch);
  33. });
  34. },
  35. //Add a dir to the tree under parent
  36. dirAdd: function(dir, parent, clickable) {
  37. if (imce.tree[dir]) return clickable ? imce.dirClickable(imce.tree[dir]) : imce.tree[dir];
  38. var parent = parent || imce.tree['.'];
  39. parent.ul = parent.ul ? parent.ul : parent.li.appendChild(imce.newEl('ul'));
  40. var branch = imce.dirCreate(dir, imce.decode(dir.substr(dir.lastIndexOf('/')+1)), clickable);
  41. parent.ul.appendChild(branch.li);
  42. return branch;
  43. },
  44. //create list item for navigation tree
  45. dirCreate: function(dir, text, clickable) {
  46. if (imce.tree[dir]) return imce.tree[dir];
  47. var branch = imce.tree[dir] = {li: imce.newEl('li'), a: imce.newEl('a')};
  48. $(branch.a).addClass('folder').text(text).attr('title', dir).appendTo(branch.li);
  49. imce.dirCollapsible(branch);
  50. return clickable ? imce.dirClickable(branch) : branch;
  51. },
  52. //change currently active directory
  53. dirActivate: function(dir) {
  54. if (dir != imce.conf.dir) {
  55. if (imce.tree[imce.conf.dir]){
  56. $(imce.tree[imce.conf.dir].a).removeClass('active');
  57. }
  58. $(imce.tree[dir].a).addClass('active');
  59. imce.conf.dir = dir;
  60. }
  61. return imce.tree[imce.conf.dir];
  62. },
  63. //make a dir accessible
  64. dirClickable: function(branch) {
  65. if (branch.clkbl) return branch;
  66. $(branch.a).attr('href', '#').removeClass('disabled').click(function() {imce.navigate(this.title); return false;});
  67. branch.clkbl = true;
  68. return branch;
  69. },
  70. //sub-directories expand-collapse ability
  71. dirCollapsible: function (branch) {
  72. if (branch.clpsbl) return branch;
  73. $(imce.newEl('span')).addClass('expander').html(' ').click(function() {
  74. if (branch.ul) {
  75. $(branch.ul).toggle();
  76. $(branch.li).toggleClass('expanded');
  77. imce.ie && $('#navigation-header').css('top', imce.NW.scrollTop);
  78. }
  79. else if (branch.clkbl){
  80. $(branch.a).click();
  81. }
  82. }).prependTo(branch.li);
  83. branch.clpsbl = true;
  84. return branch;
  85. },
  86. //update navigation tree after getting subdirectories.
  87. dirSubdirs: function(dir, subdirs) {
  88. var branch = imce.tree[dir];
  89. if (subdirs && subdirs.length) {
  90. var prefix = dir == '.' ? '' : dir +'/';
  91. for (var i in subdirs) {//add subdirectories
  92. imce.dirAdd(prefix + subdirs[i], branch, true);
  93. }
  94. $(branch.li).removeClass('leaf').addClass('expanded');
  95. $(branch.ul).show();
  96. }
  97. else if (!branch.ul){//no subdirs->leaf
  98. $(branch.li).removeClass('expanded').addClass('leaf');
  99. }
  100. },
  101. //process file list
  102. initiateList: function(cached) {
  103. var L = imce.hooks.list, dir = imce.conf.dir, token = {'%dir': dir == '.' ? $(imce.tree['.'].a).text() : imce.decode(dir)}
  104. imce.findex = [], imce.fids = {}, imce.selected = {}, imce.selcount = 0, imce.vars.lastfid = null;
  105. imce.tbody = imce.el('file-list').tBodies[0];
  106. if (imce.tbody.rows.length) {
  107. for (var row, i = 0; row = imce.tbody.rows[i]; i++) {
  108. var fid = row.id;
  109. imce.findex[i] = imce.fids[fid] = row;
  110. if (cached) {
  111. if (imce.hasC(row, 'selected')) {
  112. imce.selected[imce.vars.lastfid = fid] = row;
  113. imce.selcount++;
  114. }
  115. }
  116. else {
  117. for (var func, j = 0; func = L[j]; j++) func(row);//invoke list-hook
  118. }
  119. }
  120. }
  121. if (!imce.conf.perm.browse) {
  122. imce.setMessage(Drupal.t('File browsing is disabled in directory %dir.', token), 'error');
  123. }
  124. },
  125. //add a file to the list. (having properties name,size,formatted size,width,height,date,formatted date)
  126. fileAdd: function(file) {
  127. var row, fid = file.name, i = imce.findex.length, attr = ['name', 'size', 'width', 'height', 'date'];
  128. if (!(row = imce.fids[fid])) {
  129. row = imce.findex[i] = imce.fids[fid] = imce.tbody.insertRow(i);
  130. for (var i in attr) row.insertCell(i).className = attr[i];
  131. }
  132. row.cells[0].innerHTML = row.id = fid;
  133. row.cells[1].innerHTML = file.fsize; row.cells[1].id = file.size;
  134. row.cells[2].innerHTML = file.width;
  135. row.cells[3].innerHTML = file.height;
  136. row.cells[4].innerHTML = file.fdate; row.cells[4].id = file.date;
  137. imce.invoke('list', row);
  138. if (imce.vars.prvfid == fid) imce.setPreview(fid);
  139. if (file.id) imce.urlId[imce.getURL(fid)] = file.id;
  140. },
  141. //remove a file from the list
  142. fileRemove: function(fid) {
  143. if (!(row = imce.fids[fid])) return;
  144. imce.fileDeSelect(fid);
  145. imce.findex.splice(row.rowIndex, 1);
  146. $(row).remove();
  147. delete imce.fids[fid];
  148. if (imce.vars.prvfid == fid) imce.setPreview();
  149. },
  150. //return a file object containing all properties.
  151. fileGet: function (fid) {
  152. var file = imce.fileProps(fid);
  153. if (file) {
  154. file.name = imce.decode(fid);
  155. file.url = imce.getURL(fid);
  156. file.relpath = imce.getRelpath(fid);
  157. file.id = imce.urlId[file.url] || 0; //file id for newly uploaded files
  158. }
  159. return file;
  160. },
  161. //return file properties embedded in html.
  162. fileProps: function (fid) {
  163. var row = imce.fids[fid];
  164. return row ? {
  165. size: row.cells[1].innerHTML,
  166. bytes: row.cells[1].id * 1,
  167. width: row.cells[2].innerHTML * 1,
  168. height: row.cells[3].innerHTML * 1,
  169. date: row.cells[4].innerHTML,
  170. time: row.cells[4].id * 1
  171. } : null;
  172. },
  173. //simulate row click. selection-highlighting
  174. fileClick: function(row, ctrl, shft) {
  175. if (!row) return;
  176. var fid = typeof(row) == 'string' ? row : row.id;
  177. if (ctrl || fid == imce.vars.prvfid) {
  178. imce.fileToggleSelect(fid);
  179. }
  180. else if (shft) {
  181. var last = imce.lastFid();
  182. var start = last ? imce.fids[last].rowIndex : -1;
  183. var end = imce.fids[fid].rowIndex;
  184. var step = start > end ? -1 : 1;
  185. while (start != end) {
  186. start += step;
  187. imce.fileSelect(imce.findex[start].id);
  188. }
  189. }
  190. else {
  191. for (var fname in imce.selected) {
  192. imce.fileDeSelect(fname);
  193. }
  194. imce.fileSelect(fid);
  195. }
  196. //set preview
  197. imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null);
  198. },
  199. //file select/deselect functions
  200. fileSelect: function (fid) {
  201. if (imce.selected[fid] || !imce.fids[fid]) return;
  202. imce.selected[fid] = imce.fids[imce.vars.lastfid=fid];
  203. $(imce.selected[fid]).addClass('selected');
  204. imce.selcount++;
  205. },
  206. fileDeSelect: function (fid) {
  207. if (!imce.selected[fid] || !imce.fids[fid]) return;
  208. if (imce.vars.lastfid == fid) imce.vars.lastfid = null;
  209. $(imce.selected[fid]).removeClass('selected');
  210. delete imce.selected[fid];
  211. imce.selcount--;
  212. },
  213. fileToggleSelect: function (fid) {
  214. imce['file'+ (imce.selected[fid] ? 'De' : '') +'Select'](fid);
  215. },
  216. //process file operation form and create operation tabs.
  217. initiateOps: function() {
  218. imce.setHtmlOps();
  219. imce.setUploadOp();//upload
  220. imce.setFileOps();//thumb, delete, resize
  221. },
  222. //process existing html ops.
  223. setHtmlOps: function () {
  224. $(imce.el('ops-list')).children('li').each(function() {
  225. if (!this.firstChild) return $(this).remove();
  226. var name = this.id.substr(8);
  227. var Op = imce.ops[name] = {div: imce.el('op-content-'+ name), li: imce.el('op-item-'+ name)};
  228. Op.a = Op.li.firstChild;
  229. Op.title = Op.a.innerHTML;
  230. $(Op.a).click(function() {imce.opClick(name); return false;});
  231. });
  232. },
  233. //convert upload form to an op.
  234. setUploadOp: function () {
  235. var el, form = imce.el('imce-upload-form');
  236. if (!form) return;
  237. $(form).ajaxForm(imce.uploadSettings()).find('fieldset').each(function() {//clean up fieldsets
  238. this.removeChild(this.firstChild);
  239. $(this).after(this.childNodes);
  240. }).remove();
  241. // Set html response flag
  242. el = form.elements['files[imce]'];
  243. if (el && el.files && window.FormData) {
  244. if (el = form.elements.html_response) {
  245. el.value = 0;
  246. }
  247. }
  248. imce.opAdd({name: 'upload', title: Drupal.t('Upload'), content: form});//add op
  249. },
  250. //convert fileop form submit buttons to ops.
  251. setFileOps: function () {
  252. var form = imce.el('imce-fileop-form');
  253. if (!form) return;
  254. $(form.elements.filenames).parent().remove();
  255. $(form).find('fieldset').each(function() {//remove fieldsets
  256. var $sbmt = $('input:submit', this);
  257. if (!$sbmt.length) return;
  258. var Op = {name: $sbmt.attr('id').substr(5)};
  259. var func = function() {imce.fopSubmit(Op.name); return false;};
  260. $sbmt.click(func);
  261. Op.title = $(this).children('legend').remove().text() || $sbmt.val();
  262. Op.name == 'delete' ? (Op.func = func) : (Op.content = this.childNodes);
  263. imce.opAdd(Op);
  264. }).remove();
  265. imce.vars.opform = $(form).serialize();//serialize remaining parts.
  266. },
  267. //refresh ops states. enable/disable
  268. refreshOps: function() {
  269. for (var p in imce.conf.perm) {
  270. if (imce.conf.perm[p]) imce.opEnable(p);
  271. else imce.opDisable(p);
  272. }
  273. },
  274. //add a new file operation
  275. opAdd: function (op) {
  276. var oplist = imce.el('ops-list'), opcons = imce.el('op-contents');
  277. var name = op.name || ('op-'+ $(oplist).children('li').length);
  278. var title = op.title || 'Untitled';
  279. var Op = imce.ops[name] = {title: title};
  280. if (op.content) {
  281. Op.div = imce.newEl('div');
  282. $(Op.div).attr({id: 'op-content-'+ name, 'class': 'op-content'}).appendTo(opcons).append(op.content);
  283. }
  284. Op.a = imce.newEl('a');
  285. Op.li = imce.newEl('li');
  286. $(Op.a).attr({href: '#', name: name, title: title}).html('<span>' + title +'</span>').click(imce.opClickEvent);
  287. $(Op.li).attr('id', 'op-item-'+ name).append(Op.a).appendTo(oplist);
  288. Op.func = op.func || imce.opVoid;
  289. return Op;
  290. },
  291. //click event for file operations
  292. opClickEvent: function(e) {
  293. imce.opClick(this.name);
  294. return false;
  295. },
  296. //void operation function
  297. opVoid: function() {},
  298. //perform op click
  299. opClick: function(name) {
  300. var Op = imce.ops[name], oldop = imce.vars.op;
  301. if (!Op || Op.disabled) {
  302. return imce.setMessage(Drupal.t('You can not perform this operation.'), 'error');
  303. }
  304. if (Op.div) {
  305. if (oldop) {
  306. var toggle = oldop == name;
  307. imce.opShrink(oldop, toggle ? 'fadeOut' : 'hide');
  308. if (toggle) return false;
  309. }
  310. var left = Op.li.offsetLeft;
  311. var $opcon = $('#op-contents').css({left: 0});
  312. $(Op.div).fadeIn('normal', function() {
  313. setTimeout(function() {
  314. if (imce.vars.op) {
  315. var $inputs = $('input', imce.ops[imce.vars.op].div);
  316. $inputs.eq(0).focus();
  317. //form inputs become invisible in IE. Solution is as stupid as the behavior.
  318. $('html').hasClass('ie') && $inputs.addClass('dummyie').removeClass('dummyie');
  319. }
  320. });
  321. });
  322. var diff = left + $opcon.width() - $('#imce-content').width();
  323. $opcon.css({left: diff > 0 ? left - diff - 1 : left});
  324. $(Op.li).addClass('active');
  325. $(imce.opCloseLink).fadeIn(300);
  326. imce.vars.op = name;
  327. }
  328. Op.func(true);
  329. return true;
  330. },
  331. //enable a file operation
  332. opEnable: function(name) {
  333. var Op = imce.ops[name];
  334. if (Op && Op.disabled) {
  335. Op.disabled = false;
  336. $(Op.li).show();
  337. }
  338. },
  339. //disable a file operation
  340. opDisable: function(name) {
  341. var Op = imce.ops[name];
  342. if (Op && !Op.disabled) {
  343. Op.div && imce.opShrink(name);
  344. $(Op.li).hide();
  345. Op.disabled = true;
  346. }
  347. },
  348. //hide contents of a file operation
  349. opShrink: function(name, effect) {
  350. if (imce.vars.op != name) return;
  351. var Op = imce.ops[name];
  352. $(Op.div).stop(true, true)[effect || 'hide']();
  353. $(Op.li).removeClass('active');
  354. $(imce.opCloseLink).hide();
  355. Op.func(false);
  356. imce.vars.op = null;
  357. },
  358. //navigate to dir
  359. navigate: function(dir) {
  360. if (imce.vars.navbusy || (dir == imce.conf.dir && !confirm(Drupal.t('Do you want to refresh the current directory?')))) return;
  361. var cache = imce.vars.cache && dir != imce.conf.dir;
  362. var set = imce.navSet(dir, cache);
  363. if (cache && imce.cache[dir]) {//load from the cache
  364. set.success({data: imce.cache[dir]});
  365. set.complete();
  366. }
  367. else $.ajax(set);//live load
  368. },
  369. //ajax navigation settings
  370. navSet: function (dir, cache) {
  371. $(imce.tree[dir].li).addClass('loading');
  372. imce.vars.navbusy = dir;
  373. return {url: imce.ajaxURL('navigate', dir),
  374. type: 'GET',
  375. dataType: 'json',
  376. success: function(response) {
  377. if (response.data && !response.data.error) {
  378. if (cache) imce.navCache(imce.conf.dir, dir);//cache the current dir
  379. imce.navUpdate(response.data, dir);
  380. }
  381. imce.processResponse(response);
  382. },
  383. complete: function () {
  384. $(imce.tree[dir].li).removeClass('loading');
  385. imce.vars.navbusy = null;
  386. }
  387. };
  388. },
  389. //update directory using the given data
  390. navUpdate: function(data, dir) {
  391. var cached = data == imce.cache[dir], olddir = imce.conf.dir;
  392. if (cached) data.files.id = 'file-list';
  393. $(imce.FLW).html(data.files);
  394. imce.dirActivate(dir);
  395. imce.dirSubdirs(dir, data.subdirectories);
  396. $.extend(imce.conf.perm, data.perm);
  397. imce.refreshOps();
  398. imce.initiateList(cached);
  399. imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null);
  400. imce.SBW.scrollTop = 0;
  401. imce.invoke('navigate', data, olddir, cached);
  402. },
  403. //set cache
  404. navCache: function (dir, newdir) {
  405. var C = imce.cache[dir] = {'dir': dir, files: imce.el('file-list'), dirsize: imce.el('dir-size').innerHTML, perm: $.extend({}, imce.conf.perm)};
  406. C.files.id = 'cached-list-'+ dir;
  407. imce.FW.appendChild(C.files);
  408. imce.invoke('cache', C, newdir);
  409. },
  410. //validate upload form
  411. uploadValidate: function (data, form, options) {
  412. var path = $('#edit-imce').val();
  413. if (!path) return false;
  414. if (imce.conf.extensions != '*') {
  415. var ext = path.substr(path.lastIndexOf('.') + 1);
  416. if ((' '+ imce.conf.extensions +' ').indexOf(' '+ ext.toLowerCase() +' ') == -1) {
  417. return imce.setMessage(Drupal.t('Only files with the following extensions are allowed: %files-allowed.', {'%files-allowed': imce.conf.extensions}), 'error');
  418. }
  419. }
  420. options.url = imce.ajaxURL('upload');//make url contain current dir.
  421. imce.fopLoading('upload', true);
  422. return true;
  423. },
  424. //settings for upload
  425. uploadSettings: function () {
  426. return {
  427. beforeSubmit: imce.uploadValidate,
  428. success: function (response) {
  429. try{
  430. imce.processResponse($.parseJSON(response));
  431. } catch(e) {}
  432. },
  433. complete: function () {
  434. imce.fopLoading('upload', false);
  435. },
  436. resetForm: true,
  437. dataType: 'text'
  438. };
  439. },
  440. //validate default ops(delete, thumb, resize)
  441. fopValidate: function(fop) {
  442. if (!imce.validateSelCount(1, imce.conf.filenum)) return false;
  443. switch (fop) {
  444. case 'delete':
  445. return confirm(Drupal.t('Delete selected files?'));
  446. case 'thumb':
  447. if (!$('input:checked', imce.ops['thumb'].div).length) {
  448. return imce.setMessage(Drupal.t('Please select a thumbnail.'), 'error');
  449. }
  450. return imce.validateImage();
  451. case 'resize':
  452. var w = imce.el('edit-width').value, h = imce.el('edit-height').value;
  453. var maxDim = imce.conf.dimensions.split('x');
  454. var maxW = maxDim[0]*1, maxH = maxW ? maxDim[1]*1 : 0;
  455. if (!(/^[1-9][0-9]*$/).test(w) || !(/^[1-9][0-9]*$/).test(h) || (maxW && (maxW < w*1 || maxH < h*1))) {
  456. 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');
  457. }
  458. return imce.validateImage();
  459. }
  460. var func = fop +'OpValidate';
  461. if (imce[func]) return imce[func](fop);
  462. return true;
  463. },
  464. //submit wrapper for default ops
  465. fopSubmit: function(fop) {
  466. switch (fop) {
  467. case 'thumb': case 'delete': case 'resize': return imce.commonSubmit(fop);
  468. }
  469. var func = fop +'OpSubmit';
  470. if (imce[func]) return imce[func](fop);
  471. },
  472. //common submit function shared by default ops
  473. commonSubmit: function(fop) {
  474. if (!imce.fopValidate(fop)) return false;
  475. imce.fopLoading(fop, true);
  476. $.ajax(imce.fopSettings(fop));
  477. },
  478. //settings for default file operations
  479. fopSettings: function (fop) {
  480. 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() : '')};
  481. },
  482. //toggle loading state
  483. fopLoading: function(fop, state) {
  484. var el = imce.el('edit-'+ fop), func = state ? 'addClass' : 'removeClass';
  485. if (el) {
  486. $(el)[func]('loading');
  487. el.disabled = state;
  488. }
  489. else {
  490. $(imce.ops[fop].li)[func]('loading');
  491. imce.ops[fop].disabled = state;
  492. }
  493. },
  494. //preview a file.
  495. setPreview: function (fid) {
  496. var row, html = '';
  497. imce.vars.prvfid = fid;
  498. if (fid && (row = imce.fids[fid])) {
  499. var width = row.cells[2].innerHTML * 1;
  500. html = imce.vars.previewImages && width ? imce.imgHtml(fid, width, row.cells[3].innerHTML) : imce.decodePlain(fid);
  501. html = '<a href="#" onclick="imce.send(\''+ fid +'\'); return false;" title="'+ (imce.vars.prvtitle||'') +'">'+ html +'</a>';
  502. }
  503. imce.el('file-preview').innerHTML = html;
  504. },
  505. //default file send function. sends the file to the new window.
  506. send: function (fid) {
  507. fid && window.open(imce.getURL(fid));
  508. },
  509. //add an operation for an external application to which the files are send.
  510. setSendTo: function (title, func) {
  511. imce.send = function (fid) { fid && func(imce.fileGet(fid), window);};
  512. var opFunc = function () {
  513. if (imce.selcount != 1) return imce.setMessage(Drupal.t('Please select a file.'), 'error');
  514. imce.send(imce.vars.prvfid);
  515. };
  516. imce.vars.prvtitle = title;
  517. return imce.opAdd({name: 'sendto', title: title, func: opFunc});
  518. },
  519. //move initial page messages into log
  520. prepareMsgs: function () {
  521. var msgs;
  522. if (msgs = imce.el('imce-messages')) {
  523. $('>div', msgs).each(function (){
  524. var type = this.className.split(' ')[1];
  525. var li = $('>ul li', this);
  526. if (li.length) li.each(function () {imce.setMessage(this.innerHTML, type);});
  527. else imce.setMessage(this.innerHTML, type);
  528. });
  529. $(msgs).remove();
  530. }
  531. },
  532. //insert log message
  533. setMessage: function (msg, type) {
  534. var $box = $(imce.msgBox);
  535. var logs = imce.el('log-messages') || $(imce.newEl('div')).appendTo('#help-box-content').before('<h4>'+ Drupal.t('Log messages') +':</h4>').attr('id', 'log-messages')[0];
  536. var msg = '<div class="message '+ (type || 'status') +'">'+ msg +'</div>';
  537. $box.queue(function() {
  538. $box.css({opacity: 0, display: 'block'}).html(msg);
  539. $box.dequeue();
  540. });
  541. var q = $box.queue().length, t = imce.vars.msgT || 1000;
  542. q = q < 2 ? 1 : q < 3 ? 0.8 : q < 4 ? 0.7 : 0.4;//adjust speed with respect to queue length
  543. $box.fadeTo(600 * q, 1).fadeTo(t * q, 1).fadeOut(400 * q);
  544. $(logs).append(msg);
  545. return false;
  546. },
  547. //invoke hooks
  548. invoke: function (hook) {
  549. var i, args, func, funcs;
  550. if ((funcs = imce.hooks[hook]) && funcs.length) {
  551. (args = $.makeArray(arguments)).shift();
  552. for (i = 0; func = funcs[i]; i++) func.apply(this, args);
  553. }
  554. },
  555. //process response
  556. processResponse: function (response) {
  557. if (response.data) imce.resData(response.data);
  558. if (response.messages) imce.resMsgs(response.messages);
  559. },
  560. //process response data
  561. resData: function (data) {
  562. var i, added, removed;
  563. if (added = data.added) {
  564. var cnt = imce.findex.length;
  565. for (i in added) {//add new files or update existing
  566. imce.fileAdd(added[i]);
  567. }
  568. if (added.length == 1) {//if it is a single file operation
  569. imce.highlight(added[0].name);//highlight
  570. }
  571. if (imce.findex.length != cnt) {//if new files added, scroll to bottom.
  572. $(imce.SBW).animate({scrollTop: imce.SBW.scrollHeight}).focus();
  573. }
  574. }
  575. if (removed = data.removed) for (i in removed) {
  576. imce.fileRemove(removed[i]);
  577. }
  578. imce.conf.dirsize = data.dirsize;
  579. imce.updateStat();
  580. },
  581. //set response messages
  582. resMsgs: function (msgs) {
  583. for (var type in msgs) for (var i in msgs[type]) {
  584. imce.setMessage(msgs[type][i], type);
  585. }
  586. },
  587. //return img markup
  588. imgHtml: function (fid, width, height) {
  589. return '<img src="'+ imce.getURL(fid, true) +'" width="'+ width +'" height="'+ height +'" alt="'+ imce.decodePlain(fid) +'">';
  590. },
  591. //check if the file is an image
  592. isImage: function (fid) {
  593. return imce.fids[fid].cells[2].innerHTML * 1;
  594. },
  595. //find the first non-image in the selection
  596. getNonImage: function (selected) {
  597. for (var fid in selected) {
  598. if (!imce.isImage(fid)) return fid;
  599. }
  600. return false;
  601. },
  602. //validate current selection for images
  603. validateImage: function () {
  604. var nonImg = imce.getNonImage(imce.selected);
  605. return nonImg ? imce.setMessage(Drupal.t('%filename is not an image.', {'%filename': imce.decode(nonImg)}), 'error') : true;
  606. },
  607. //validate number of selected files
  608. validateSelCount: function (Min, Max) {
  609. if (Min && imce.selcount < Min) {
  610. return imce.setMessage(Min == 1 ? Drupal.t('Please select a file.') : Drupal.t('You must select at least %num files.', {'%num': Min}), 'error');
  611. }
  612. if (Max && Max < imce.selcount) {
  613. return imce.setMessage(Drupal.t('You are not allowed to operate on more than %num files.', {'%num': Max}), 'error');
  614. }
  615. return true;
  616. },
  617. //update file count and dir size
  618. updateStat: function () {
  619. imce.el('file-count').innerHTML = imce.findex.length;
  620. imce.el('dir-size').innerHTML = imce.conf.dirsize;
  621. },
  622. //serialize selected files. return fids with a colon between them
  623. serialNames: function () {
  624. var str = '';
  625. for (var fid in imce.selected) {
  626. str += ':'+ fid;
  627. }
  628. return str.substr(1);
  629. },
  630. //get file url. re-encode & and # for mod rewrite
  631. getURL: function (fid, uncached) {
  632. var url = imce.getRelpath(fid);
  633. if (imce.conf.modfix) {
  634. url = url.replace(/%(23|26)/g, '%25$1');
  635. }
  636. url = imce.conf.furl + url;
  637. if (uncached) {
  638. var file = imce.fileProps(fid);
  639. url += (url.indexOf('?') === -1 ? '?' : '&') + 's' + file.bytes + 'd' + file.time;
  640. }
  641. return url;
  642. },
  643. //get encoded file path relative to root.
  644. getRelpath: function (fid) {
  645. var dir = imce.conf.dir;
  646. return (dir === '.' ? '' : dir + '/') + fid;
  647. },
  648. //el. by id
  649. el: function (id) {
  650. return document.getElementById(id);
  651. },
  652. //find the latest selected fid
  653. lastFid: function () {
  654. if (imce.vars.lastfid) return imce.vars.lastfid;
  655. for (var fid in imce.selected);
  656. return fid;
  657. },
  658. //create ajax url
  659. ajaxURL: function (op, dir) {
  660. return imce.conf.url + (imce.conf.clean ? '?' :'&') +'jsop='+ op +'&dir='+ (dir||imce.conf.dir);
  661. },
  662. //fast class check
  663. hasC: function (el, name) {
  664. return el.className && (' '+ el.className +' ').indexOf(' '+ name +' ') != -1;
  665. },
  666. //highlight a single file
  667. highlight: function (fid) {
  668. if (imce.vars.prvfid) imce.fileClick(imce.vars.prvfid);
  669. imce.fileClick(fid);
  670. },
  671. //process a row
  672. processRow: function (row) {
  673. row.cells[0].innerHTML = '<span>' + imce.decodePlain(row.id) + '</span>';
  674. row.onmousedown = function(e) {
  675. var e = e||window.event;
  676. imce.fileClick(this, e.ctrlKey, e.shiftKey);
  677. return !(e.ctrlKey || e.shiftKey);
  678. };
  679. row.ondblclick = function(e) {
  680. imce.send(this.id);
  681. return false;
  682. };
  683. },
  684. //decode urls. uses unescape. can be overridden to use decodeURIComponent
  685. decode: function (str) {
  686. try {
  687. return decodeURIComponent(str);
  688. } catch(e) {}
  689. return str;
  690. },
  691. //decode and convert to plain text
  692. decodePlain: function (str) {
  693. return Drupal.checkPlain(imce.decode(str));
  694. },
  695. //global ajax error function
  696. ajaxError: function (e, response, settings, thrown) {
  697. imce.setMessage(Drupal.ajaxError(response, settings.url).replace(/\n/g, '<br />'), 'error');
  698. },
  699. //convert button elements to standard input buttons
  700. convertButtons: function(form) {
  701. $('button:submit', form).each(function(){
  702. $(this).replaceWith('<input type="submit" value="'+ $(this).text() +'" name="'+ this.name +'" class="form-submit" id="'+ this.id +'" />');
  703. });
  704. },
  705. //create element
  706. newEl: function(name) {
  707. return document.createElement(name);
  708. },
  709. //scroll syncronization for section headers
  710. syncScroll: function(scrlEl, fixEl, bottom) {
  711. var $fixEl = $(fixEl);
  712. var prop = bottom ? 'bottom' : 'top';
  713. var factor = bottom ? -1 : 1;
  714. var syncScrl = function(el) {
  715. $fixEl.css(prop, factor * el.scrollTop);
  716. }
  717. $(scrlEl).scroll(function() {
  718. var el = this;
  719. syncScrl(el);
  720. setTimeout(function() {
  721. syncScrl(el);
  722. });
  723. });
  724. },
  725. //get UI ready. provide backward compatibility.
  726. updateUI: function() {
  727. //file urls.
  728. var furl = imce.conf.furl, isabs = furl.indexOf('://') > -1;
  729. var absurls = imce.conf.absurls = imce.vars.absurls || imce.conf.absurls;
  730. var host = location.host;
  731. var baseurl = location.protocol + '//' + host;
  732. if (furl.charAt(furl.length - 1) != '/') {
  733. furl = imce.conf.furl = furl + '/';
  734. }
  735. imce.conf.modfix = imce.conf.clean && furl.split('/')[3] === 'system';
  736. if (absurls && !isabs) {
  737. imce.conf.furl = baseurl + furl;
  738. }
  739. else if (!absurls && isabs && furl.indexOf(baseurl) == 0) {
  740. furl = furl.substr(baseurl.length);
  741. // Server base url is defined with a port which is missing in current page url.
  742. if (furl.charAt(0) === ':') {
  743. furl = furl.replace(/^:\d*/, '');
  744. }
  745. imce.conf.furl = furl;
  746. }
  747. //convert button elements to input elements.
  748. imce.convertButtons(imce.FW);
  749. //ops-list
  750. $('#ops-list').removeClass('tabs secondary').addClass('clear-block clearfix');
  751. imce.opCloseLink = $(imce.newEl('a')).attr({id: 'op-close-link', href: '#', title: Drupal.t('Close')}).click(function() {
  752. imce.vars.op && imce.opClick(imce.vars.op);
  753. return false;
  754. }).appendTo('#op-contents')[0];
  755. //navigation-header
  756. if (!$('#navigation-header').length) {
  757. $(imce.NW).children('.navigation-text').attr('id', 'navigation-header').wrapInner('<span></span>');
  758. }
  759. //log
  760. $('#log-prv-wrapper').before($('#log-prv-wrapper > #preview-wrapper')).remove();
  761. $('#log-clearer').remove();
  762. //content resizer
  763. $('#content-resizer').remove();
  764. //message-box
  765. imce.msgBox = imce.el('message-box') || $(imce.newEl('div')).attr('id', 'message-box').prependTo('#imce-content')[0];
  766. //create help tab
  767. var $hbox = $('#help-box');
  768. $hbox.is('a') && $hbox.replaceWith($(imce.newEl('div')).attr('id', 'help-box').append($hbox.children()));
  769. imce.hooks.load.push(function() {
  770. imce.opAdd({name: 'help', title: $('#help-box-title').remove().text(), content: $('#help-box').show()});
  771. });
  772. //add ie classes
  773. imce.ie && $('html').addClass('ie') && imce.ie < 8 && $('html').addClass('ie-7');
  774. // enable box view for file list
  775. imce.vars.boxW && imce.boxView();
  776. //scrolling file list
  777. imce.syncScroll(imce.SBW, '#file-header-wrapper');
  778. imce.syncScroll(imce.SBW, '#dir-stat', true);
  779. //scrolling directory tree
  780. imce.syncScroll(imce.NW, '#navigation-header');
  781. }
  782. };
  783. //initiate
  784. $(document).ready(imce.initiate);
  785. })(jQuery);