feature(user-menu) add default user menu

This commit is contained in:
coderaiser 2019-05-23 18:16:49 +03:00
parent 7b6e767ccb
commit 76184c0251
11 changed files with 325 additions and 272 deletions

View file

@ -17,7 +17,7 @@ module.exports.alert = (...a) => alert(title, ...a, {
module.exports.prompt = (...a) => tryToCatch(prompt, title, ...a);
module.exports.confirm = (...a) => tryToCatch(confirm, title, ...a);
module.exports.progress = (...a) => tryToCatch(progress, title, ...a);
module.exports.progress = (...a) => progress(title, ...a);
module.exports.alert.noFiles = () => {
return alert(title, 'No files selected!', {

View file

@ -13,11 +13,10 @@ const Images = require('./images');
const load = require('./load');
const Files = require('./files');
const RESTful = require('./rest');
const IO = require('./io');
const Storage = require('./storage');
const Dialog = require('./dialog');
const read = callbackify(RESTful.read);
const currentFile = require('./current-file');
const DOMTree = require('./dom-tree');
@ -27,10 +26,20 @@ const DOM = {
...new CmdProto(),
};
const read = callbackify(async (...args) => {
const [e, data] = await RESTful.read(...args);
if (e)
throw e;
return data;
});
DOM.Images = Images;
DOM.load = load;
DOM.Files = Files;
DOM.RESTful = RESTful;
DOM.IO = IO;
DOM.Storage = Storage;
DOM.Dialog = Dialog;

214
client/dom/io.js Normal file
View file

@ -0,0 +1,214 @@
'use strict';
/* global CloudCmd*/
const itype = require('itype/legacy');
const {promisify} = require('es6-promisify');
const {FS} = require('../../common/cloudfunc');
const Images = require('./images');
const load = require('./load');
const imgPosition = {
top: true,
};
module.exports._replaceHash = replaceHash;
function replaceHash(url) {
/*
* if we send ajax request -
* no need in hash so we escape #
*/
return url.replace(/#/g, '%23');
}
module.exports.delete = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method : 'DELETE',
url : FS + url,
data,
callback,
imgPosition : { top: !!data },
});
});
module.exports.patch = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method: 'PATCH',
url: FS + url,
data,
callback,
imgPosition,
});
});
module.exports.write = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method: 'PUT',
url: FS + url,
data,
callback,
imgPosition,
});
});
module.exports.read = promisify((url, dataType, callback) => {
const notLog = !url.includes('?');
const isFunc = itype.function(dataType);
if (!callback && isFunc) {
callback = dataType;
dataType = 'text';
}
sendRequest({
method: 'GET',
url: FS + url,
callback,
notLog,
dataType,
});
});
module.exports.cp = promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/cp',
data,
callback,
imgPosition,
});
});
module.exports.pack = promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/pack',
data,
callback,
});
});
module.exports.extract = promisify((data, callback) => {
sendRequest({
method : 'PUT',
url : '/extract',
data,
callback,
});
});
module.exports.mv = promisify((data, callback) => {
sendRequest({
method : 'PUT',
url : '/mv',
data,
callback,
imgPosition,
});
});
module.exports.Config = {
read: promisify((callback) => {
sendRequest({
method: 'GET',
url: '/config',
callback,
imgPosition,
notLog: true,
});
}),
write: promisify((data, callback) => {
sendRequest({
method: 'PATCH',
url: '/config',
data,
callback,
imgPosition,
});
}),
};
module.exports.Markdown = {
read: promisify((url, callback) => {
sendRequest({
method: 'GET',
url: '/markdown' + url,
callback,
imgPosition,
notLog: true,
});
}),
render: promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/markdown',
data,
callback,
imgPosition,
notLog: true,
});
}),
};
function sendRequest(params) {
const p = params;
const {prefixURL} = CloudCmd;
p.url = prefixURL + p.url;
p.url = encodeURI(p.url);
p.url = replaceHash(p.url);
load.ajax({
method : p.method,
url : p.url,
data : p.data,
dataType : p.dataType,
error : (jqXHR) => {
const response = jqXHR.responseText;
const {
statusText,
status,
} = jqXHR;
const text = status === 404 ? response : statusText;
p.callback(Error(text));
},
success: (data) => {
Images.hide();
if (!p.notLog)
CloudCmd.log(data);
p.callback(null, data);
},
});
}

View file

@ -1,221 +1,43 @@
'use strict';
/* global CloudCmd, DOM */
const tryToCatch = require('try-to-catch/legacy');
const itype = require('itype/legacy');
const promisify = require('../../common/try-to-promisify');
const {FS} = require('../../common/cloudfunc');
const {encode} = require('../../common/entity');
const Images = require('./images');
const load = require('./load');
const IO = require('./io');
const Dialog = require('./dialog');
const imgPosition = {
top: true,
const handleError = (promise) => async (...args) => {
const [e, data] = await tryToCatch(promise, ...args);
if (!e)
return [e, data];
const encoded = encode(e.message);
Images.show.error(encoded);
Dialog.alert(encoded);
return [e, data];
};
module.exports._replaceHash = replaceHash;
function replaceHash(url) {
/*
* if we send ajax request -
* no need in hash so we escape #
*/
return url.replace(/#/g, '%23');
}
module.exports.delete = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method : 'DELETE',
url : FS + url,
data,
callback,
imgPosition : { top: !!data },
});
});
module.exports.patch = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method: 'PATCH',
url: FS + url,
data,
callback,
imgPosition,
});
});
module.exports.write = promisify((url, data, callback) => {
const isFunc = itype.function(data);
if (!callback && isFunc) {
callback = data;
data = null;
}
sendRequest({
method: 'PUT',
url: FS + url,
data,
callback,
imgPosition,
});
});
module.exports.read = promisify((url, dataType, callback) => {
const notLog = !url.includes('?');
const isFunc = itype.function(dataType);
if (!callback && isFunc) {
callback = dataType;
dataType = 'text';
}
sendRequest({
method: 'GET',
url: FS + url,
callback,
notLog,
dataType,
});
});
module.exports.cp = promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/cp',
data,
callback,
imgPosition,
});
});
module.exports.pack = promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/pack',
data,
callback,
});
});
module.exports.extract = promisify((data, callback) => {
sendRequest({
method : 'PUT',
url : '/extract',
data,
callback,
});
});
module.exports.mv = promisify((data, callback) => {
sendRequest({
method : 'PUT',
url : '/mv',
data,
callback,
imgPosition,
});
});
module.exports.delete = handleError(IO.delete);
module.exports.patch = handleError(IO.patch);
module.exports.write = handleError(IO.write);
module.exports.read = handleError(IO.read);
module.exports.cp = handleError(IO.cp);
module.exports.pack = handleError(IO.pack);
module.exports.extract = handleError(IO.extract);
module.exports.mv = handleError(IO.mv);
module.exports.Config = {
read: promisify((callback) => {
sendRequest({
method: 'GET',
url: '/config',
callback,
imgPosition,
notLog: true,
});
}),
write: promisify((data, callback) => {
sendRequest({
method: 'PATCH',
url: '/config',
data,
callback,
imgPosition,
});
}),
read: handleError(IO.Config.read),
write: handleError(IO.Config.write),
};
module.exports.Markdown = {
read: promisify((url, callback) => {
sendRequest({
method: 'GET',
url: '/markdown' + url,
callback,
imgPosition,
notLog: true,
});
}),
render: promisify((data, callback) => {
sendRequest({
method: 'PUT',
url: '/markdown',
data,
callback,
imgPosition,
notLog: true,
});
}),
read: handleError(IO.Markdown.read),
render: handleError(IO.Markdown.render),
};
function sendRequest(params) {
const p = params;
const {prefixURL} = CloudCmd;
p.url = prefixURL + p.url;
p.url = encodeURI(p.url);
p.url = replaceHash(p.url);
load.ajax({
method : p.method,
url : p.url,
data : p.data,
dataType : p.dataType,
error : (jqXHR) => {
const response = jqXHR.responseText;
const {
statusText,
status,
} = jqXHR;
const text = status === 404 ? response : statusText;
const encoded = encode(text);
Images.show.error(encoded);
setTimeout(() => {
DOM.Dialog.alert(encoded);
}, 100);
p.callback(Error(text));
},
success: (data) => {
Images.hide();
if (!p.notLog)
CloudCmd.log(data);
p.callback(null, data);
},
});
}

View file

@ -1,38 +0,0 @@
'use strict';
const data = `'use strict';
module.exports = {
'F2 - Rename file': async ({DOM}) => {
await DOM.renameCurrent();
},
};
`;
module.exports = {
'F2 - Rename file': async ({DOM}) => {
await DOM.renameCurrent();
},
'C - Create User Menu File': async ({DOM, CloudCmd}) => {
const {
RESTful,
CurrentInfo,
} = DOM;
const {dirPath} = CurrentInfo;
const path = `${dirPath}.cloudcmd.menu.js`;
const [e] = await RESTful.write(path, data);
if (e)
return;
await CloudCmd.refresh();
DOM.setCurrentByName('.cloudcmd.menu.js');
await CloudCmd.EditFile.show();
},
};
module.exports._data = data;

View file

@ -1,11 +1,6 @@
'use strict';
const defaultUserMenu = require('./default-menu.js');
module.exports = (menuFn) => {
if (!menuFn)
return defaultUserMenu;
const module = {};
const fn = Function('module', menuFn);

View file

@ -122,6 +122,7 @@ const runUserMenu = async (value, options, userMenu) => {
const [e] = await tryToCatch(userMenu[value], {
DOM,
CloudCmd,
tryToCatch,
});
if (e)

View file

@ -1,11 +0,0 @@
'use strict';
const {promisify} = require('es6-promisify');
const wraptile = require('wraptile/legacy');
const tryToCatch = require('try-to-catch/legacy');
module.exports = wraptile((fn, ...args) => {
const promise = promisify(fn);
return tryToCatch(promise, ...args);
});

View file

@ -31,7 +31,7 @@ module.exports = {
'lint': () => run(['putout', 'lint:*', 'spell']),
'lint:server': () => `eslint -c .eslintrc.server ${dirs} --ignore-pattern *.spec.js`,
'lint:test': () => `eslint --ignore-pattern '!.*' ${dirsTest}`,
'lint:client': () => 'eslint --env browser client --ignore-pattern .cloudcmd.menu.js',
'lint:client': () => 'eslint --env browser client static --ignore-pattern .cloudcmd.menu.js',
'lint:css': () => 'stylelint css/*.css',
'spell': () => 'yaspeller .',
'fix:lint': () => run(['putout', 'lint:*'], '--fix'),
@ -86,6 +86,6 @@ module.exports = {
'build:client': () => run('6to5:client'),
'build:client:dev': () => run('6to5:client:dev'),
'heroku-postbuild': () => run('6to5:client'),
'putout': () => 'putout bin client server common test .cloudcmd.menu.js',
'putout': () => 'putout bin client static server common test .cloudcmd.menu.js',
};

View file

@ -2,6 +2,7 @@
const {homedir} = require('os');
const fs = require('fs');
const {join} = require('path');
const {promisify} = require('util');
@ -11,19 +12,32 @@ const findUp = require('find-up');
const readFile = promisify(fs.readFile);
const URL = '/api/v1/user-menu';
const DEFAULT_MENU_PATH = join(__dirname, '../static/user-menu.js');
module.exports = currify(async({menuName}, req, res, next) => {
if (req.url.indexOf('/api/v1/user-menu'))
if (req.url.indexOf(URL))
return next();
const {method} = req;
if (method === 'GET')
return onGET(menuName, req.query, res);
return onGET({
req,
res,
menuName,
});
next();
});
async function onGET(menuName, {dir}, res) {
async function onGET({req, res, menuName}) {
const {dir} = req.query;
const url = req.url.replace(URL, '');
if (url === '/default')
return sendDefaultMenu(res);
const [errorFind, currentMenuPath] = await tryToCatch(findUp, [
menuName,
], {cwd: dir});
@ -33,21 +47,26 @@ async function onGET(menuName, {dir}, res) {
.status(404)
.send(e.message);
if (errorFind && errorFind.code === 'ENOENT')
return res.send('');
const homeMenuPath = join(homedir(), menuName);
const menuPath = currentMenuPath || homeMenuPath;
const [e, data] = await tryToCatch(readFile, menuPath, 'utf8');
if (!e)
return res.send(data);
return res
.type('js')
.send(data);
if (e.code !== 'ENOENT')
return res
.status(404)
.send(e.message);
return res.send('');
sendDefaultMenu(res);
}
function sendDefaultMenu(res) {
res.sendFile(DEFAULT_MENU_PATH, {
cacheControl: false,
});
}

42
static/user-menu.js Normal file
View file

@ -0,0 +1,42 @@
'use strict';
module.exports = {
'F2 - Rename file': async ({DOM}) => {
await DOM.renameCurrent();
},
'C - Create User Menu File': async ({DOM, CloudCmd}) => {
const {CurrentInfo} = DOM;
const {dirPath} = CurrentInfo;
const path = `${dirPath}.cloudcmd.menu.js`;
const {prefix} = CloudCmd;
const data = await readDefaultMenu({prefix});
await createDefaultMenu({
path,
data,
DOM,
CloudCmd,
});
},
};
async function createDefaultMenu({path, data, DOM, CloudCmd}) {
const {IO} = DOM;
await IO.write(path, data);
await CloudCmd.refresh();
DOM.setCurrentByName('.cloudcmd.menu.js');
await CloudCmd.EditFile.show();
}
async function readDefaultMenu({prefix}) {
const res = await fetch(`${prefix}/api/v1/user-menu/default`);
const data = await res.text();
return data;
}