Skip to content

Commit

Permalink
feature(user-menu) add
Browse files Browse the repository at this point in the history
  • Loading branch information
coderaiser committed May 5, 2019
1 parent f6dcdb7 commit c416429
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .webpack/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const cssNames = [
'view',
'config',
'terminal',
'user-menu',
...getCSSList('columns'),
];

Expand All @@ -35,7 +36,7 @@ const plugins = clean([

const rules = [{
test: /\.css$/,
exclude: /css\/(nojs|view|config|terminal|columns.*)\.css/,
exclude: /css\/(nojs|view|config|terminal|user-menu|columns.*)\.css/,
use: extractMain.extract([
'css-loader',
]),
Expand Down
4 changes: 2 additions & 2 deletions .webpack/js.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const babelDev = {
babelrc: false,
plugins: [
'module:babel-plugin-macros',
'@babel/plugin-proposal-object-rest-spread',
],
};

Expand All @@ -43,7 +42,7 @@ const rules = clean([
loader: 'babel-loader',
},
isDev && {
test: /sw\.js$/,
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: babelDev,
Expand Down Expand Up @@ -91,6 +90,7 @@ module.exports = {
[modules + '/konsole']: `${dirModules}/konsole.js`,
[modules + '/terminal']: `${dirModules}/terminal.js`,
[modules + '/cloud']: `${dirModules}/cloud.js`,
[modules + '/user-menu']: `${dirModules}/user-menu.js`,
[modules + '/polyfill']: `${dirModules}/polyfill.js`,
},
output: {
Expand Down
3 changes: 3 additions & 0 deletions client/key/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ function KeyProto() {
break;

case Key.F2:
if (CloudCmd.config('userMenu'))
return CloudCmd.UserMenu.show();

DOM.renameCurrent(current);
break;

Expand Down
1 change: 0 additions & 1 deletion client/modules/operation/set-listeners.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

/* global DOM */
/* global CloudCmd */

const {
Dialog,
Expand Down
138 changes: 138 additions & 0 deletions client/modules/user-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
'use strict';

/* global CloudCmd, DOM */

require('../../css/user-menu.css');

const currify = require('currify/legacy');
const {promisify} = require('es6-promisify');
const load = require('load.js');
const createElement = require('@cloudcmd/create-element');
const Images = require('../dom/images');

const loadCSS = promisify(load.css);

const Name = 'UserMenu';
CloudCmd[Name] = module.exports;

const {Key} = CloudCmd;
const {stringify} = JSON;

const userMenuUrl = '/api/v1/user-menu';

module.exports.init = async () => {
await Promise.all([
loadCSS(`${CloudCmd.prefix}/dist/user-menu.css`),
CloudCmd.View(),
]);
};

module.exports.show = show;
module.exports.hide = hide;

const getKey = (a) => a.split(' - ')[0];
const beginWith = (a) => (b) => !b.indexOf(a);

const defaultUserMenu = {
'F2 - Rename file': async ({DOM}) => {
const {element} = DOM.CurrentInfo;
DOM.renameCurrent(element);
},
};

function getUserMenu(menuFn) {
if (!menuFn)
return defaultUserMenu;

const module = {};
const fn = Function('module', menuFn);

fn(module);

return module.exports;
}

const {CurrentInfo} = DOM;

async function show() {
Images.show.load('top');

const {dirPath} = CurrentInfo;
const res = await fetch(`${userMenuUrl}?dir=${dirPath}`);
const userMenu = getUserMenu(await res.text());
const options = Object.keys(userMenu);

const el = createElement('select', {
className: 'cloudcmd-user-menu',
innerHTML: fillTemplate(options),
size: 10,
});

const keys = options.map(getKey);
el.addEventListener('keydown', onKeyDown(keys, options, userMenu));

const afterShow = () => el.focus();
const autoSize = true;

Images.hide();

CloudCmd.View.show(el, {
autoSize,
afterShow,
});
}

function fillTemplate(options) {
const result = [];

for (const option of options) {
result.push(`<option>${option}</option>`);
}

return result.join('');
}

function hide() {
CloudCmd.View.hide();
}

const onKeyDown = currify(async (keys, options, userMenu, e) => {
const {keyCode} = e;
const key = e.key.toUpperCase();

let value;

if (keyCode === Key.ENTER)
({value} = e.target);
else if (keys.includes(key))
value = options.find(beginWith(key));
else
return;

e.preventDefault();
e.stopPropagation();

hide();

const cmd = await userMenu[value]({
DOM,
});

if (!cmd)
return;

const res = await fetch(userMenuUrl, {
method: 'PUT',
body: stringify({
cmd,
}),
});

const data = await res.text();

if (data)
DOM.Dialog.alert(data);

CloudCmd.refresh();
});

14 changes: 14 additions & 0 deletions css/user-menu.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.cloudcmd-user-menu {
font-size: 16px;
font-family: 'Droid Sans Mono', 'Ubuntu Mono', 'Consolas', monospace;
width: 400px;
}

.cloudcmd-user-menu:focus {
outline: 0;
}

.cloudcmd-user-menu > option:checked {
box-shadow: 20px -20px 0 2px rgba(49, 123, 249) inset;
}

3 changes: 2 additions & 1 deletion json/modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"operation",
"konsole",
"terminal",
"cloud"
"cloud",
"user-menu"
],
"remote": [{
"name": "socket",
Expand Down
2 changes: 2 additions & 0 deletions server/cloudcmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const cloudfunc = require(DIR_COMMON + 'cloudfunc');
const authentication = require(DIR + 'auth');
const config = require(DIR + 'config');
const modulas = require(DIR + 'modulas');
const userMenu = require(DIR + 'user-menu');
const rest = require(DIR + 'rest');
const route = require(DIR + 'route');
const validate = require(DIR + 'validate');
Expand Down Expand Up @@ -223,6 +224,7 @@ function cloudcmd(prefix, plugins, modules) {
root,
}),

userMenu,
rest,
route({
html: defaultHtml,
Expand Down
68 changes: 68 additions & 0 deletions server/user-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';

const {homedir} = require('os');
const fs = require('fs');
const {join} = require('path');
const {exec} = require('child_process');

const tryToCatch = require('try-to-catch');
const pullout = require('pullout');
const {promisify} = require('util');
const {parse} = JSON;

const readFile = promisify(fs.readFile);
const execute = promisify(exec);
const menuName = '.cloudcmd.menu.js';
const userMenuPath = join(homedir(), menuName);

module.exports = async (req, res, next) => {
if (req.url.indexOf('/api/v1/user-menu'))
return next();

const {method} = req;

if (method === 'GET')
return onGET(req.query, res);

if (method === 'PUT') {
return onPUT(await pullout(req), res);
}

next();
};

async function onGET({dir}, res) {
const userMenuCurrentPath = join(dir, menuName);
const [dirError, dirData] = await tryToCatch(readFile, userMenuCurrentPath, 'utf8');

if (!dirError)
return res.send(dirData);

if (dirError.code !== 'ENOENT')
return res
.status(404)
.send(dirError.message);

const [e, data] = await tryToCatch(readFile, userMenuPath, 'utf8');

if (!e)
return res.send(data);

if (e.code === 'ENOENT')
return res.send('');

return res
.status(404)
.send(e.message);
}

async function onPUT(str, res) {
const {cmd} = parse(str);
const [e, data] = await tryToCatch(execute, cmd);

if (e)
return res.send(e.message);

return res.send(data);
}

0 comments on commit c416429

Please sign in to comment.