From 5479dce7dad4dfdedee7dff721cc6f9ccc1fe314 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Wed, 25 Apr 2018 16:11:54 +0300 Subject: [PATCH] feature(cloudcmd) add ability to use not only alphabet and number symbols (#167) --- client/dom/current-file.js | 87 ++++++++++++++++++ client/dom/index.js | 142 ++++++++---------------------- client/dom/rest.js | 9 +- client/modules/operation/index.js | 16 ++-- common/btoa.js | 13 +++ common/cloudfunc.js | 13 ++- test/common/btoa.js | 32 +++++++ test/common/cloudfunc.html | 4 +- 8 files changed, 199 insertions(+), 117 deletions(-) create mode 100644 client/dom/current-file.js create mode 100644 common/btoa.js create mode 100644 test/common/btoa.js diff --git a/client/dom/current-file.js b/client/dom/current-file.js new file mode 100644 index 00000000..8ff1c425 --- /dev/null +++ b/client/dom/current-file.js @@ -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); +}; + diff --git a/client/dom/index.js b/client/dom/index.js index 066c2273..c140985e 100644 --- a/client/dom/index.js +++ b/client/dom/index.js @@ -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'); diff --git a/client/dom/rest.js b/client/dom/rest.js index 83d0617c..6e0faa01 100644 --- a/client/dom/rest.js +++ b/client/dom/rest.js @@ -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)); diff --git a/client/modules/operation/index.js b/client/modules/operation/index.js index 2afc8610..2c8130ac 100644 --- a/client/modules/operation/index.js +++ b/client/modules/operation/index.js @@ -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) => { diff --git a/common/btoa.js b/common/btoa.js new file mode 100644 index 00000000..0293ebbc --- /dev/null +++ b/common/btoa.js @@ -0,0 +1,13 @@ +'use strict'; + +/* global btoa */ + +module.exports = (str) => { + if (typeof btoa === 'function') + return btoa(str); + + return Buffer + .from(str) + .toString('base64'); +}; + diff --git a/common/cloudfunc.js b/common/cloudfunc.js index 0ea96826..6954cbcd 100644 --- a/common/cloudfunc.js +++ b/common/cloudfunc.js @@ -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, { diff --git a/test/common/btoa.js b/test/common/btoa.js new file mode 100644 index 00000000..4d4bbe46 --- /dev/null +++ b/test/common/btoa.js @@ -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(); +}); + diff --git a/test/common/cloudfunc.html b/test/common/cloudfunc.html index 229c69b9..dac3354b 100644 --- a/test/common/cloudfunc.html +++ b/test/common/cloudfunc.html @@ -12,14 +12,14 @@ --.--.---- . --- --- --- -
  • +
  • applnk <dir> 21.02.2016 root rwx r-x r-x -
  • +
  • prefdm 1.30kb