feature(cloudcmd) add ability to use not only alphabet and number symbols (#167)

This commit is contained in:
coderaiser 2018-04-25 16:11:54 +03:00
parent 48c36eb5d3
commit 5479dce7da
8 changed files with 199 additions and 117 deletions

View file

@ -0,0 +1,87 @@
'use strict';
/* global DOM */
/* global CloudCmd */
const {
encode,
decode,
} = require('../../common/entity');
const {
FS,
} = require('../../common/cloudfunc');
const NBSP_REG = RegExp(String.fromCharCode(160), 'g');
const SPACE = ' ';
/**
* 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', 'js-file-' + btoa(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 '';
const link = DOM.getCurrentLink(current);
if (!link)
return '';
return decode(link.title)
.replace(NBSP_REG, SPACE);
};
/**
* get current direcotory path
*/
module.exports.getCurrentDirPath = (panel = DOM.getPanel()) => {
const path = DOM.getByDataName('js-path', panel);
return path.textContent
.replace(NBSP_REG, SPACE);
};
/**
* 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)[0];
const prefix = CloudCmd.PREFIX;
const path = element
.getAttribute('href')
.replace(RegExp('^' + prefix + FS), '')
.replace(NBSP_REG, SPACE);
return decode(path);
};

View file

@ -12,26 +12,29 @@ const {
FS,
} = require('../../common/cloudfunc');
const {encode} = require('../../common/entity');
const DOMTree = require('./dom-tree');
const DOM = Object.assign({}, DOMTree, new CmdProto());
module.exports = DOM;
const Images = require('./images');
const load = require('./load');
const Files = require('./files');
const RESTful = require('./rest');
const Storage = require('./storage');
const currentFile = require('./current-file');
const DOMTree = require('./dom-tree');
const DOM = {
...DOMTree,
...currentFile,
...new CmdProto(),
};
DOM.Images = Images;
DOM.load = load;
DOM.Files = Files;
DOM.RESTful = RESTful;
DOM.Storage = Storage;
module.exports = DOM;
DOM.uploadDirectory = require('./directory');
DOM.Buffer = require('./buffer');
DOM.Events = require('./events');
@ -103,10 +106,10 @@ function CmdProto() {
function promptNew(typeName, type) {
const {Dialog} = DOM;
const dir = Cmd.getCurrentDirPath();
const dir = DOM.getCurrentDirPath();
const msg = 'New ' + typeName || 'File';
const getName = () => {
const name = Cmd.getCurrentName();
const name = DOM.getCurrentName();
if (name === '..')
return '';
@ -156,16 +159,6 @@ function CmdProto() {
return ret;
};
/**
* get current direcotory path
*/
this.getCurrentDirPath = (panel = DOM.getPanel()) => {
const path = DOM.getByDataName('js-path', panel);
const ret = path && path.textContent;
return ret;
};
/**
* get current direcotory path
*/
@ -202,7 +195,7 @@ function CmdProto() {
* get current file by name
*/
this.getCurrentByName = (name, panel = CurrentInfo.panel) => {
const dataName = 'js-file-' + name;
const dataName = 'js-file-' + btoa(name);
const element = DOM.getByDataName(dataName, panel);
return element;
@ -246,7 +239,7 @@ function CmdProto() {
};
this.getCurrentDate = (currentFile) => {
const current = currentFile || Cmd.getCurrentFile();
const current = currentFile || DOM.getCurrentFile();
const date = DOM
.getByDataName('js-date', current)
.textContent;
@ -259,7 +252,7 @@ function CmdProto() {
* @currentFile
*/
this.getCurrentSize = (currentFile) => {
const current = currentFile || Cmd.getCurrentFile();
const current = currentFile || DOM.getCurrentFile();
/* если это папка - возвращаем слово dir вместо размера*/
const size = DOM.getByDataName('js-size', current)
.textContent
@ -460,9 +453,9 @@ function CmdProto() {
currentFile.classList.add(CURRENT_FILE);
let path = DOM.getCurrentDirPath();
const path = DOM.getCurrentDirPath();
const name = CloudCmd.config('name');
if (path !== pathWas) {
DOM.setTitle(getTitle({
name,
@ -680,42 +673,6 @@ function CmdProto() {
return link[0];
};
/**
* get link from current (or param) file
*
* @param currentFile - current file by default
*/
this.getCurrentPath = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const element = DOM.getByTag('a', current)[0];
const prefix = CloudCmd.PREFIX;
const path = element.getAttribute('href')
.replace(RegExp('^' + prefix + FS), '');
return path;
};
/**
* get name from current (or param) file
*
* @param currentFile
*/
this.getCurrentName = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
if (!current)
return '';
const link = DOM.getCurrentLink(current);
if (!link)
return '';
const name = link.title;
return name;
};
this.getFilenames = (files) => {
if (!files)
throw Error('AllFiles could not be empty');
@ -735,27 +692,6 @@ function CmdProto() {
return names;
};
/**
* set name from current (or param) file
*
* @param name
* @param current
*/
this.setCurrentName = (name, current) => {
const Info = CurrentInfo;
const link = Info.link;
const PREFIX = CloudCmd.PREFIX;
const dir = PREFIX + FS + Info.dirPath;
link.title = name;
link.innerHTML = encode(name);
link.href = dir + name;
current.setAttribute('data-name', 'js-file-' + name);
return link;
};
/**
* check storage hash
*/
@ -935,10 +871,10 @@ function CmdProto() {
*/
this.deleteCurrent = (current) => {
if (!current)
Cmd.getCurrentFile();
DOM.getCurrentFile();
const parent = current && current.parentElement;
const name = Cmd.getCurrentName(current);
const name = DOM.getCurrentName(current);
if (current && name !== '..') {
const next = current.nextSibling;
@ -970,10 +906,10 @@ function CmdProto() {
this.renameCurrent = (current) => {
const Dialog = DOM.Dialog;
if (!Cmd.isCurrentFile(current))
current = Cmd.getCurrentFile();
if (!DOM.isCurrentFile(current))
current = DOM.getCurrentFile();
const from = Cmd.getCurrentName(current);
const from = DOM.getCurrentName(current);
if (from === '..')
return Dialog.alert.noFiles(TITLE);
@ -982,7 +918,7 @@ function CmdProto() {
Dialog.prompt(TITLE, 'Rename', from, {cancel}).then((to) => {
const isExist = !!DOM.getCurrentByName(to);
const dirPath = Cmd.getCurrentDirPath();
const dirPath = DOM.getCurrentDirPath();
if (from === to)
return;
@ -1157,38 +1093,38 @@ function CmdProto() {
this.CurrentInfo = CurrentInfo,
this.updateCurrentInfo = (currentFile) => {
const info = Cmd.CurrentInfo;
const current = currentFile || Cmd.getCurrentFile();
const info = DOM.CurrentInfo;
const current = currentFile || DOM.getCurrentFile();
const files = current.parentElement;
const panel = files.parentElement;
const panelPassive = Cmd.getPanel({
const panelPassive = DOM.getPanel({
active: false
});
const filesPassive = DOM.getFiles(panelPassive);
const name = Cmd.getCurrentName(current);
const name = DOM.getCurrentName(current);
info.dir = Cmd.getCurrentDirName();
info.dirPath = Cmd.getCurrentDirPath();
info.parentDirPath = Cmd.getParentDirPath();
info.dir = DOM.getCurrentDirName();
info.dirPath = DOM.getCurrentDirPath();
info.parentDirPath = DOM.getParentDirPath();
info.element = current;
info.ext = Util.getExt(name);
info.files = [...files.children];
info.filesPassive = [...filesPassive];
info.first = files.firstChild;
info.getData = Cmd.getCurrentData;
info.getData = DOM.getCurrentData;
info.last = files.lastChild;
info.link = Cmd.getCurrentLink(current);
info.mode = Cmd.getCurrentMode(current);
info.link = DOM.getCurrentLink(current);
info.mode = DOM.getCurrentMode(current);
info.name = name;
info.path = Cmd.getCurrentPath(current);
info.path = DOM.getCurrentPath(current);
info.panel = panel;
info.panelPassive = panelPassive;
info.size = Cmd.getCurrentSize(current);
info.isDir = Cmd.isCurrentIsDir();
info.isSelected = Cmd.isSelected(current);
info.panelPosition = Cmd.getPanel().dataset.name.replace('js-', '');
info.size = DOM.getCurrentSize(current);
info.isDir = DOM.isCurrentIsDir();
info.isSelected = DOM.isSelected(current);
info.panelPosition = DOM.getPanel().dataset.name.replace('js-', '');
info.isOnePanel =
info.panel.getAttribute('data-name') ===
info.panelPassive.getAttribute('data-name');

View file

@ -5,6 +5,9 @@
const itype = require('itype/legacy');
const {FS} = require('../../common/cloudfunc');
const {
encode,
} = require('../../common/entity');
module.exports = new RESTful();
@ -194,10 +197,12 @@ function RESTful() {
const statusText = jqXHR.statusText;
const status = jqXHR.status;
const text = status === 404 ? response : statusText;
const encoded = encode(text);
Images.show.error(encoded);
Images.show.error(text);
setTimeout(() => {
DOM.Dialog.alert(CloudCmd.TITLE, text);
DOM.Dialog.alert(CloudCmd.TITLE, encoded);
}, 100);
p.callback(Error(text));

View file

@ -11,6 +11,10 @@ const currify = require('currify/legacy');
const wraptile = require('wraptile/legacy');
const exec = require('execon');
const {
encode,
} = require('../../../common/entity');
const RESTful = require('../../dom/rest');
const removeExtension = require('./remove-extension');
const setListeners = require('./set-listeners');
@ -213,7 +217,7 @@ function OperationProto(operation, data) {
if (n >= 5)
name += '\n...';
msg = msgAsk + msgSel + n + ' files/directories?\n' + name ;
msg = msgAsk + msgSel + n + ' files/directories?\n' + encode(name);
} else {
const current = DOM.getCurrentFile();
const isDir = DOM.isCurrentIsDir(current);
@ -312,7 +316,7 @@ function OperationProto(operation, data) {
const operation = isCopy ? copyFn : moveFn;
if (shouldAsk && config(option))
return message(title, to, names)
return message(title, to, names.map(encode))
.then(ask);
ask(to);
@ -331,10 +335,10 @@ function OperationProto(operation, data) {
function go() {
showLoad();
files = {
from : from,
to : to,
names : names
files = {
from,
to,
names,
};
operation(files, (error) => {

13
common/btoa.js Normal file
View file

@ -0,0 +1,13 @@
'use strict';
/* global btoa */
module.exports = (str) => {
if (typeof btoa === 'function')
return btoa(str);
return Buffer
.from(str)
.toString('base64');
};

View file

@ -4,6 +4,7 @@ const rendy = require('rendy');
const currify = require('currify/legacy');
const store = require('fullstore/legacy');
const encode = require('./entity').encode;
const btoa = require('./btoa');
const getHeaderField = currify(_getHeaderField);
@ -12,7 +13,6 @@ const getHeaderField = currify(_getHeaderField);
/* название программы */
const NAME = 'Cloud Commander';
const FS = '/fs';
const Path = store();
Path('/');
@ -96,6 +96,11 @@ function getPathLink(url, prefix, template) {
return pathHTML;
}
const getDataName = (name) => {
const encoded = btoa(name);
return `data-name="js-file-${encoded}" `;
};
/**
* Функция строит таблицу файлв из JSON-информации о файлах
* @param params - информация о файлах
@ -108,7 +113,7 @@ module.exports.buildFromJSON = (params) => {
const templateLink = template.link;
const json = params.data;
const path = json.path;
const path = encode(json.path);
const files = json.files;
const sort = params.sort || 'name';
@ -123,7 +128,7 @@ module.exports.buildFromJSON = (params) => {
let fileTable = rendy(template.path, {
link : prefix + FS + path,
fullPath : path,
path : htmlPath
path : htmlPath,
});
const owner = 'owner';
@ -197,7 +202,7 @@ module.exports.buildFromJSON = (params) => {
attribute: getAttribute(file.size)
});
const dataName = `data-name="js-file-${name}" `;
const dataName = getDataName(file.name);
const attribute = `draggable="true" ${dataName}`;
return rendy(templateFile, {

32
test/common/btoa.js Normal file
View file

@ -0,0 +1,32 @@
'use strict';
const test = require('tape');
const diff = require('sinon-called-with-diff');
const sinon = diff(require('sinon'));
const btoa = require('../../common/btoa');
test('btoa: browser', (t) => {
const btoaOriginal = global.btoa;
const str = 'hello';
global.btoa = sinon.stub();
btoa(str);
t.ok(global.btoa.calledWith(str), 'should call global.btoa');
t.end();
global.btoa = btoaOriginal;
});
test('btoa: node', (t) => {
const str = 'hello';
const expected = 'aGVsbG8=';
const result = btoa(str);
t.equal(result, expected, 'should encode base64');
t.end();
});

View file

@ -12,14 +12,14 @@
<span data-name="js-date" class="date reduce-text">--.--.----</span>
<span data-name="js-owner" class="owner reduce-text">.</span>
<span data-name="js-mode" class="mode reduce-text">--- --- ---</span>
</li><li draggable="true" data-name="js-file-applnk" class="">
</li><li draggable="true" data-name="js-file-YXBwbG5r" class="">
<span data-name="js-type" class="mini-icon directory"></span>
<span data-name="js-name" class="name reduce-text"><a href="/fs/etc/X11/applnk" title="applnk" draggable="true">applnk</a></span>
<span data-name="js-size" class="size reduce-text">&lt;dir&gt;</span>
<span data-name="js-date" class="date reduce-text">21.02.2016</span>
<span data-name="js-owner" class="owner reduce-text">root</span>
<span data-name="js-mode" class="mode reduce-text">rwx r-x r-x</span>
</li><li draggable="true" data-name="js-file-prefdm" class="">
</li><li draggable="true" data-name="js-file-cHJlZmRt" class="">
<span data-name="js-type" class="mini-icon text-file"></span>
<span data-name="js-name" class="name reduce-text"><a href="/fs/etc/X11/prefdm" title="prefdm" target="_blank" draggable="true">prefdm</a></span>
<span data-name="js-size" class="size reduce-text">1.30kb</span>