2016-06-24 21:26:59 +02:00

237 lines
5.1 KiB
JavaScript

const {keys, each, filter, sortBy, isFn, isStr, isNum} = require('../lo');
const server = require('../server');
const location = require('../core/location');
const settings = require('../core/settings');
const types = require('../core/types');
const reEndsWithSlash = /\/$/;
const reSplitPath = /^(.*\/)([^\/]+\/?)$/;
const cache = {};
const startsWith = (sequence, part) => {
if (!sequence || !sequence.indexOf) {
return false;
}
return sequence.indexOf(part) === 0;
};
const createLabel = sequence => {
sequence = sequence.replace(reEndsWithSlash, '');
try {
sequence = decodeURIComponent(sequence);
} catch (e) {/* skip */}
return sequence;
};
const splitPath = sequence => { // eslint-disable-line consistent-return
if (sequence === '/') {
return {
parent: null,
name: '/'
};
}
const match = reSplitPath.exec(sequence);
if (match) {
const split = {
parent: match[1],
name: match[2]
};
if (split.parent && !startsWith(split.parent, settings.rootHref)) {
split.parent = null;
}
return split;
}
};
const getItem = options => {
if (isStr(options)) {
options = {href: options};
} else if (!options || !isStr(options.href)) {
return null;
}
const href = location.forceEncoding(options.href);
if (!startsWith(href, settings.rootHref)) {
return null;
}
const item = cache[href] || Item(href); // eslint-disable-line no-use-before-define
if (isNum(options.time)) {
item.time = options.time;
}
if (isNum(options.size)) {
item.size = options.size;
}
if (options.managed) {
item.isManaged = true;
}
if (options.fetched) {
item.isContentFetched = true;
}
return item;
};
const removeItem = absHref => {
absHref = location.forceEncoding(absHref);
const item = cache[absHref];
if (item) {
delete cache[absHref];
if (item.parent) {
delete item.parent.content[item.absHref];
}
each(item.content, child => {
removeItem(child.absHref);
});
}
};
const fetchContent = (absHref, callback) => {
const item = getItem(absHref);
if (!isFn(callback)) {
callback = () => undefined;
}
if (item.isContentFetched) {
callback(item);
} else {
server.request({action: 'get', items: {href: item.absHref, what: 1}}).then(response => {
if (response.items) {
each(response.items, jsonItem => {
getItem(jsonItem);
});
}
callback(item);
});
}
};
const Item = absHref => {
const split = splitPath(absHref);
const inst = Object.assign(Object.create(Item.prototype), {
absHref,
type: types.getType(absHref),
label: createLabel(absHref === '/' ? location.getDomain() : split.name),
time: null,
size: null,
parent: null,
isManaged: null,
content: {}
});
cache[absHref] = inst;
if (split.parent) {
inst.parent = getItem(split.parent);
inst.parent.content[inst.absHref] = inst;
if (keys(inst.parent.content).length > 1) {
inst.parent.isContentFetched = true;
}
}
return inst;
};
Item.prototype = {
constructor: Item,
isFolder() {
return reEndsWithSlash.test(this.absHref);
},
isCurrentFolder() {
return this.absHref === location.getAbsHref();
},
isInCurrentFolder() {
return !!this.parent && this.parent.isCurrentFolder();
},
isCurrentParentFolder() {
const item = getItem(location.getAbsHref());
return !!item && this === item.parent;
},
isDomain() {
return this.absHref === '/';
},
isRoot() {
return this.absHref === settings.rootHref;
},
isEmpty() {
return keys(this.content).length === 0;
},
fetchContent(callback) {
return fetchContent(this.absHref, callback);
},
getCrumb() {
let item = this; // eslint-disable-line consistent-this
const crumb = [item];
while (item.parent) {
item = item.parent;
crumb.unshift(item);
}
return crumb;
},
getSubfolders() {
return sortBy(filter(this.content, item => {
return item.isFolder();
}), item => {
return item.label.toLowerCase();
});
},
getStats() {
let folders = 0;
let files = 0;
each(this.content, item => {
if (item.isFolder()) {
folders += 1;
} else {
files += 1;
}
});
let depth = 0;
let item = this; // eslint-disable-line consistent-this
while (item.parent) {
depth += 1;
item = item.parent;
}
return {
folders,
files,
depth
};
}
};
module.exports = {
get: getItem,
remove: removeItem
};