/*global imce:true*/ (function ($, Drupal, imce) { 'use strict'; /** * @file * Defines imce Folder object. */ /** * Folder. */ imce.Folder = function (name, conf) { this.construct(name, conf); }; /** * Item prototype */ var ItemProto = imce.Item.prototype; /** * Folder prototype extends Item prototype. */ var Folder = $.extend(imce.Folder.prototype, ItemProto); /** * Constructs the Folder. */ Folder.construct = function (name, conf) { var Folder = this; Folder.isFolder = true; Folder.type = 'folder'; Folder.items = []; Folder.files = {}; Folder.subfolders = {}; ItemProto.construct.apply(Folder, arguments); Folder.setConf(conf); }; /** * Creates folder elements. */ Folder.createEl = function () { var nameEl; var toggleEl; var branchEl; var Folder = this; if (!Folder.el) { // Item elements. ItemProto.createEl.apply(Folder, arguments); Folder.el.className += ' folder'; // Folder elements Folder.contentEl = imce.createEl('
'); Folder.subtreeEl = imce.createEl('
'); branchEl = Folder.branchEl = imce.createEl('
'); toggleEl = Folder.branchToggleEl = branchEl.firstChild; toggleEl.onclick = imce.eBranchToggleClick; nameEl = Folder.branchNameEl = branchEl.children[1]; nameEl.onclick = imce.eBranchNameClick; branchEl.Folder = nameEl.Folder = toggleEl.Folder = Folder; } }; /** * Sets the folder content. */ Folder.setContent = function (content) { var i; var Item; var list; var Folder = this; var items = Folder.getItems(); // Remove the items that no longer exist. for (i in items) { if (!imce.owns(items, i)) { continue; } Item = items[i]; list = Item.isFolder ? content.subfolders : content.files; // Existing item is not in the list if (!list || !imce.owns(list, Item.name)) { // Make sure it's not (parent of) a predefined folder if (!Item.isFolder || !Item.hasPredefinedPath()) { Folder.removeItem(Item); } } } Folder.extend(content.props); Folder.addContent(content); Folder.content = content; Folder.updateSubtree(); }; /** * Adds new files and subfolders. */ Folder.addContent = function (content, selectNew) { var Folder = this; var files = content.files; var subfolders = content.subfolders; if (!files && !subfolders) { return; } // Add items Folder.addItems(files, 'file'); Folder.addItems(subfolders, 'folder'); // Update sort if (Folder.active) { Folder.sortItems(); } else { Folder.needSort = 1; } Folder.sortTree(); // Select new items. if (selectNew && Folder.active) { var name; var fname; var sname; imce.deselectAll(); if (files) { for (fname in files) { if (!imce.owns(files, fname)) { continue; } Folder.getItem(fname).select(); } } if (subfolders) { for (sname in subfolders) { if (!imce.owns(subfolders, sname)) { continue; } Folder.getItem(sname).select(); } } // Scroll the last item into view if (name = (fname || sname)) { Folder.getItem(name).scrollIntoView(); } } }; /** * Add a list of items of a specific type. */ Folder.addItems = function (items, type) { var Item; var name; var Type = type === 'folder' ? imce.Folder : imce.File; if (items) { for (name in items) { // Update if (Item = this.getItem(name)) { Item.extend(items[name]); this.updateStatus(); } // Insert else { Item = new Type(name); Item.extend(items[name]); this.appendItem(Item); } } } }; /** * Returns a copy of items array. */ Folder.getItems = function () { return this.items.slice(0); }; /** * Append an item to the folder. */ Folder.appendItem = function (Item) { var Folder = this; var name = Item.name; var existing; if (!Folder.validateAppend(Item)) { return; } // Remove the item from old parent Item.remove(true); // Remove existing item with the same name if (existing = Folder.getItem(name)) { existing.remove(); } // Append item. Folder.items.push(Item); Item.parent = Folder; Folder.contentEl.appendChild(Item.el); // Append subfolder if (Item.isFolder) { Folder.prepareSubtree(); Folder.subtreeEl.appendChild(Item.branchEl); Folder.subfolders[name] = Item; Item.setPath((Folder.parent ? Folder.path + '/' : '') + Item.name); } // Append file else { Folder.files[name] = Item; } // Update status. Folder.updateStatus(); }; /** * Remove an item from the folder. */ Folder.removeItem = function (Item, shallow) { var name = Item.name; var Folder = this; // Check if the item is a child if (Item.parent !== Folder) { return; } // Deep removal if (!shallow) { // Remove all descendants of the subfolder. if (Item.isFolder) { for (var i in Item.items) { if (!imce.owns(Item.items, i)) { continue; } Item.removeItem(Item.items[i]); } } } // Set item free. Item.deselect(); Item.setBusy(false); // Remove subfolder if (Item.isFolder) { if (Item.active) { Folder.activate(); } Item.setPath(null); delete Folder.subfolders[name]; imce.removeEl(Item.branchEl); Folder.updateSubtree(); } // Remove file else { delete Folder.files[name]; } // Remove item Folder.items.splice(Folder.indexOf(Item), 1); delete Item.parent; imce.removeEl(Item.el); Folder.updateStatus(); }; /** * Set folder path. * Register the folder to the tree. */ Folder.setPath = function (newpath) { var i; var Folder = this; var oldpath = Folder.path; var subfolders = Folder.subfolders; if (oldpath !== newpath) { // Remove if (newpath == null) { for (i in subfolders) { if (!imce.owns(subfolders, i)) { continue; } subfolders[i].setPath(null); } delete imce.tree[oldpath]; delete Folder.path; } // Add else { Folder.path = newpath; imce.tree[newpath] = Folder; Folder.setDisabled(!Folder.getConf()); for (i in subfolders) { if (!imce.owns(subfolders, i)) { continue; } subfolders[i].setPath(newpath + '/' + subfolders[i].name); } Folder.updateStatus(); } } }; /** * Returns a permission value. */ Folder.getPermission = function (name) { return imce.permissionInFolderConf(name, this.getConf()); }; /** * Returns folder configuration. */ Folder.getConf = function () { var conf = this.conf; var parent; if (conf) { return conf; } if (parent = this.parent) { if (conf = parent.getConf()) { if (imce.permissionInFolderConf('browse_subfolders', conf)) { return $.extend({inherited: true}, conf); } } } }; /** * Sets folder configuration. */ Folder.setConf = function (conf) { if (this.conf !== conf) { this.conf = conf; this.setDisabled(!this.getConf()); } }; /** * Open folder. */ Folder.open = function (refresh) { if (refresh || !this.content) { this.load(); } this.activate(); }; /** * Dynamically load folder contents. */ Folder.load = function () { if (this.isReady()) { this.setLoading(true); imce.ajax('browse', { activeFolder: this, customComplete: imce.xFolderLoadComplete }); } }; /** * Activate folder. */ Folder.activate = function () { var Folder = this; var oldFolder = imce.activeFolder; var parent = Folder.parent; if (!Folder.active) { // Deactivate the old dir. if (oldFolder) { oldFolder.deactivate(); } // Check sort if (Folder.needSort) { Folder.sortItems(); } imce.activeFolder = Folder; Folder.active = true; $(Folder.branchEl).addClass('active'); // Add the content to the dom if it is fully loaded. if (!Folder.loading) { Folder.addContentToDom(); } Folder.setContentVisibility(true); // Expand parents if collapsed. while (parent) { parent.expand(); parent = parent.parent; } // Update status and header Folder.updateHeader(); Folder.updateStatus(); // Trigger activateFolder handlers. imce.trigger('activateFolder', Folder, oldFolder); } }; /** * Deactivate folder. */ Folder.deactivate = function () { var Folder = this; if (Folder.active) { Folder.setContentVisibility(false); imce.deselectAll(); imce.activeFolder = null; Folder.active = false; $(Folder.branchEl).removeClass('active'); } }; /** * Set loading state. */ Folder.setLoading = function (state) { var Folder = this; if (state) { if (!Folder.loading) { Folder.setBusy(true); Folder.setState('loading'); if (Folder.active) { imce.deselectAll(); } } } else if (Folder.loading) { Folder.setBusy(false); Folder.unsetState('loading'); if (Folder.active) { Folder.addContentToDom(); } } }; /** * Returns an item by name. */ Folder.getItem = function (name) { var Folder = this; if (imce.owns(Folder.files, name)) { return Folder.files[name]; } if (imce.owns(Folder.subfolders, name)) { return Folder.subfolders[name]; } }; /** * Returns an item by index. */ Folder.getItemAt = function (i) { return this.items[i]; }; /** * Returns the index of an item. */ Folder.indexOf = function (Item) { return $.inArray(Item, this.items); }; /** * Selects all items. */ Folder.selectAll = function () { for (var i in this.items) { if (!imce.owns(this.items, i)) { continue; } this.items[i].select(); } }; /** * Returns the number of items. */ Folder.countItems = function () { return this.items.length; }; /** * Returns the number of subfolders. */ Folder.countSubfolders = function () { var i; var count = 0; for (i in this.subfolders) { if (!imce.owns(this.subfolders, i)) { continue; } count++; } return count; }; /** * Name change handler. */ Folder.onNameChange = function (oldval) { ItemProto.onNameChange.apply(this, arguments); this.branchNameEl.innerHTML = Drupal.checkPlain(this.name); this.branchNameEl.title = this.name; }; /** * Item name change handler. * Triggered by imce.Item.onNameChange() */ Folder.onItemNameChange = function (Item, oldname) { var Folder = this; var name = Item.name; var group = Item.isFolder ? Folder.subfolders : Folder.files; delete group[oldname]; group[name] = Item; // Set folder path if (Item.isFolder) { Item.setPath((Folder.parent ? Folder.path + '/' : '') + name); } }; /** * Double-click handler. */ Folder.dblClick = function () { this.open(); }; /** * Inserts the content element into the main content area. */ Folder.addContentToDom = function () { var el = this.contentEl; var parentEl = imce.contentEl; if (el.parentNode !== parentEl) { parentEl.appendChild(el); } }; /** * Sets visibility of the content element. */ Folder.setContentVisibility = function (show) { var el = this.contentEl; el.style.display = show ? '' : 'none'; if (el.scrollTop) { el.scrollTop = 0; } }; /** * Prepares for subfolder appending. */ Folder.prepareSubtree = function () { var Folder = this; if (Folder.subtreeEl.parentNode !== Folder.branchEl) { Folder.branchEl.appendChild(Folder.subtreeEl); $(Folder.branchEl).removeClass('leaf'); // Prevent expanding of inactive dirs except the first activated dir on init if (!Folder.active && imce.activeFolder) { Folder.expanded = true; Folder.shrink(); } else { Folder.expand(); } } }; /** * Check and remove subtree element if it's empty. */ Folder.updateSubtree = function () { if (!this.countSubfolders()) { this.shrink(); imce.removeEl(this.subtreeEl); $(this.branchEl).addClass('leaf'); } }; /** * Expands the subtree. */ Folder.expand = function () { if (!this.expanded) { this.expanded = true; $(this.branchEl).addClass('expanded'); $(this.subtreeEl).show(); } }; /** * Shrinks the subtree. */ Folder.shrink = function () { if (this.expanded) { this.expanded = false; $(this.branchEl).removeClass('expanded'); $(this.subtreeEl).hide(); } }; /** * Update folder status. */ Folder.updateStatus = function () { if (this.active) { imce.updateStatus(); } }; /** * Update header sort. */ Folder.updateHeader = function () { if (this.active) { imce.updateHeader(); } }; /** * Sort folder items by an item property. */ Folder.sortItems = function (key, desc) { var i; var sorter; var Folder = this; var items = Folder.items; var active = Folder.activeSort || imce.activeSort || imce.local.activeSort || {}; if (key == null) { key = active.key || 'name'; } if (desc == null) { desc = !!active.desc; } // Remove lazy sort flag. Folder.needSort = 0; // Check sorter if (sorter = imce.sorters[key]) { items.sort(sorter); if (desc) { items.reverse(); } for (i in items) { if (!imce.owns(items, i)) { continue; } this.contentEl.appendChild(items[i].el); } Folder.activeSort = {key: key, desc: desc}; Folder.updateHeader(); } }; /** * Sorts folder tree elements by name. */ Folder.sortTree = function () { var i; var Folder = this; var subfolders = Folder.subfolders; var arr = []; for (i in subfolders) { if (!imce.owns(subfolders, i)) { continue; } arr.push(subfolders[i]); } if (arr.length > 1) { arr.sort(imce.sortBranchName); for (i in arr) { if (!imce.owns(arr, i)) { continue; } Folder.subtreeEl.appendChild(arr[i].branchEl); } } }; /** * Check if the item can be appended to the folder. */ Folder.validateAppend = function (Item, copy) { // Disallow self appending if (Item === this) { return false; } var parent = Item.parent; // Allow orphan appending if (!parent) { return true; } // Disallow re-appending children if (!copy && parent === this) { return false; } // Disallow (grand)parents appending if (Item.isFolder) { for (parent = this.parent; parent; parent = parent.parent) { if (parent === Item) { return false; } } } return true; }; /** * Checks if the folder is predefined. */ Folder.isPredefined = function () { return !!this.conf; }; /** * Returns the first predefined descendent including itself. */ Folder.hasPredefinedPath = function () { if (this.isPredefined()) { return this; } var i; var Folder; var subfolders = this.subfolders; for (i in subfolders) { if (Folder = subfolders[i].hasPredefinedPath()) { return Folder; } } return false; }; /** * Returns status text. */ Folder.formatStatus = function () { return '
' + imce.formatItemsStatus(this.countItems(), this.getSize()) + '
'; }; /** * Returns the size of the folder. */ Folder.getSize = function () { var i; var size = 0; var files = this.files; for (i in files) { if (!imce.owns(files, i)) { continue; } size += files[i].size || 0; } return size; }; /** * Click event for branch name. */ imce.eBranchNameClick = function (event) { this.Folder.open(); return false; }; /** * Click event for branch toggle. */ imce.eBranchToggleClick = function (event) { var Folder = this.Folder; if (Folder.countSubfolders()) { if (Folder.expanded) { Folder.shrink(); } else { Folder.expand(); } } else { Folder.open(); } return false; }; /** * Ajax complete handler for folder loading. */ imce.xFolderLoadComplete = function (xhr, status) { var content; var opt = this; var Folder = opt.activeFolder; var response = opt.response; if (response && (content = response.content)) { Folder.setContent(content); } Folder.setLoading(false); if (Folder.countSubfolders()) { Folder.expand(); } }; })(jQuery, Drupal, imce);