cloudcmd/client/dom/current-file.js
2024-03-21 08:46:31 +02:00

314 lines
7.2 KiB
JavaScript

'use strict';
/* global DOM */
/* global CloudCmd */
const {atob, btoa} = require('../../common/base64');
const createElement = require('@cloudcmd/create-element');
const {encode, decode} = require('../../common/entity');
const {getTitle, FS} = require('../../common/cloudfunc');
let Title;
const CURRENT_FILE = 'current-file';
const encodeNBSP = (a) => a?.replace('\xa0', ' ');
const decodeNBSP = (a) => a?.replace(' ', '\xa0');
module.exports._CURRENT_FILE = CURRENT_FILE;
/**
* set name from current (or param) file
*
* @param name
* @param current
*/
module.exports.setCurrentName = (name, current) => {
const Info = DOM.CurrentInfo;
const {link} = Info;
const {prefix} = CloudCmd;
const dir = prefix + FS + Info.dirPath;
const encoded = encode(name);
link.title = encoded;
link.href = dir + encoded;
link.innerHTML = encoded;
current.setAttribute('data-name', createNameAttribute(name));
CloudCmd.emit('current-file', current);
return link;
};
/**
* get name from current (or param) file
*
* @param currentFile
*/
module.exports.getCurrentName = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
if (!current)
return '';
return parseNameAttribute(current.getAttribute('data-name'));
};
/**
* Generate a `data-name` attribute for the given filename
* @param name The string name to encode
*/
const createNameAttribute = (name) => {
const encoded = btoa(encodeURI(name));
return `js-file-${encoded}`;
};
/**
* Parse a `data-name` attribute string back into the original filename
* @param attribute The string we wish to decode
*/
const parseNameAttribute = (attribute) => {
attribute = attribute.replace('js-file-', '');
return decodeNBSP(decodeURI(atob(attribute)));
};
module.exports._parseNameAttribute = parseNameAttribute;
const parseHrefAttribute = (prefix, attribute) => {
attribute = attribute.replace(RegExp('^' + prefix + FS), '');
return decode(decodeNBSP(attribute));
};
module.exports._parseHrefAttribute = parseHrefAttribute;
/**
* get current direcotory path
*/
module.exports.getCurrentDirPath = (panel = DOM.getPanel()) => {
const path = DOM.getByDataName('js-path', panel);
return path.textContent;
};
/**
* get link from current (or param) file
*
* @param currentFile - current file by default
*/
module.exports.getCurrentPath = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const [element] = DOM.getByTag('a', current);
const {prefix} = CloudCmd;
return parseHrefAttribute(prefix, element.getAttribute('href'));
};
/**
* get current direcotory name
*/
module.exports.getCurrentDirName = () => {
const href = DOM
.getCurrentDirPath()
.replace(/\/$/, '');
const substr = href.substr(href, href.lastIndexOf('/'));
return href.replace(`${substr}/`, '') || '/';
};
/**
* get current direcotory path
*/
module.exports.getParentDirPath = (panel) => {
const path = DOM.getCurrentDirPath(panel);
const dirName = DOM.getCurrentDirName() + '/';
const index = path.lastIndexOf(dirName);
if (path === '/')
return path;
return path.slice(0, index);
};
/**
* get not current direcotory path
*/
module.exports.getNotCurrentDirPath = () => {
const panel = DOM.getPanel({
active: false,
});
return DOM.getCurrentDirPath(panel);
};
/**
* unified way to get current file
*
* @currentFile
*/
module.exports.getCurrentFile = () => {
return DOM.getByClass(CURRENT_FILE);
};
/**
* get current file by name
*/
module.exports.getCurrentByName = (name, panel = DOM.CurrentInfo.panel) => {
const dataName = 'js-file-' + btoa(encodeURI(encodeNBSP(name)));
return DOM.getByDataName(dataName, panel);
};
/**
* private function thet unset currentfile
*
* @currentFile
*/
function unsetCurrentFile(currentFile) {
const is = DOM.isCurrentFile(currentFile);
if (!is)
return;
currentFile.classList.remove(CURRENT_FILE);
}
/**
* unified way to set current file
*/
module.exports.setCurrentFile = (currentFile, options) => {
const o = options;
const currentFileWas = DOM.getCurrentFile();
if (!currentFile)
return DOM;
let pathWas = '';
if (currentFileWas) {
pathWas = DOM.getCurrentDirPath();
unsetCurrentFile(currentFileWas);
}
currentFile.classList.add(CURRENT_FILE);
const path = DOM.getCurrentDirPath();
const name = CloudCmd.config('name');
if (path !== pathWas) {
DOM.setTitle(getTitle({
name,
path,
}));
/* history could be present
* but it should be false
* to prevent default behavior
*/
if (!o || o.history) {
const historyPath = path === '/' ? path : FS + path;
DOM.setHistory(historyPath, null, historyPath);
}
}
/* scrolling to current file */
const CENTER = true;
DOM.scrollIntoViewIfNeeded(currentFile, CENTER);
CloudCmd.emit('current-file', currentFile);
CloudCmd.emit('current-path', path);
CloudCmd.emit('current-name', DOM.getCurrentName(currentFile));
return DOM;
};
this.setCurrentByName = (name) => {
const current = DOM.getCurrentByName(name);
return DOM.setCurrentFile(current);
};
/*
* set current file by position
*
* @param layer - element
* @param - position {x, y}
*/
module.exports.getCurrentByPosition = ({x, y}) => {
const element = document.elementFromPoint(x, y);
const getEl = (el) => {
const {tagName} = el;
const isChild = /A|SPAN|LI/.test(tagName);
if (!isChild)
return null;
if (tagName === 'A')
return el.parentElement.parentElement;
if (tagName === 'SPAN')
return el.parentElement;
return el;
};
const el = getEl(element);
if (el && el.tagName !== 'LI')
return null;
return el;
};
/**
* current file check
*
* @param currentFile
*/
module.exports.isCurrentFile = (currentFile) => {
if (!currentFile)
return false;
return DOM.isContainClass(currentFile, CURRENT_FILE);
};
/**
* set title or create title element
*
* @param name
*/
module.exports.setTitle = (name) => {
if (!Title)
Title = DOM.getByTag('title')[0] || createElement('title', {
innerHTML: name,
parent: document.head,
});
Title.textContent = name;
return DOM;
};
/**
* check is current file is a directory
*
* @param currentFile
*/
module.exports.isCurrentIsDir = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const path = DOM.getCurrentPath(current);
const fileType = DOM.getCurrentType(current);
const isZip = /\.zip$/.test(path);
const isDir = /^directory(-link)?/.test(fileType);
return isDir || isZip;
};
module.exports.getCurrentType = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const el = DOM.getByDataName('js-type', current);
const type = el
.className
.split(' ')
.pop();
return type;
};