2022-10-07 15:20:07 +02:00

793 lines
17 KiB
JavaScript

/*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('<div class="imce-folder-content clearfix"></div>');
Folder.subtreeEl = imce.createEl('<div class="imce-subtree"></div>');
branchEl = Folder.branchEl = imce.createEl('<div class="imce-branch"><span class="imce-branch-toggle"></span><span class="imce-branch-name imce-ficon"></span></div>');
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 '<div class="items">' + imce.formatItemsStatus(this.countItems(), this.getSize()) + '</div>';
};
/**
* 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);