Add features:

- Improvement application list in market place
- Allow triplet keyboard shortcut in GUI
- CodePad allows setting shortcut in CommandPalette commands
- CodePad should have recent menu entry that remember top n file opened
- Improve File application grid view
- Label text should be selectable
This commit is contained in:
lxsang 2021-03-14 21:12:27 +01:00
parent 94a0c097a8
commit de5878c349
8 changed files with 166 additions and 92 deletions

View File

@ -82,12 +82,7 @@ namespace OS {
setting.applications[this.name] = {};
}
this.setting = setting.applications[this.name];
this.keycomb = {
ALT: {},
CTRL: {},
SHIFT: {},
META: {},
};
this.keycomb = {};
this.subscribe("appregistry", (m) => {
if (m.name === this.name) {
this.applySetting(m.data.m);
@ -199,14 +194,29 @@ namespace OS {
k: string,
f: (e: JQuery.KeyboardEventBase) => void
): void {
const arr = k.split("-");
if (arr.length !== 2) {
const arr = k.toUpperCase().split("-");
const c = arr.pop();
let fnk = "";
if (arr.includes("META")) {
fnk += "META";
}
if (arr.includes("CTRL")) {
fnk += "CTRL";
}
if (arr.includes("ALT")) {
fnk += "ALT";
}
if (arr.includes("SHIFT")) {
fnk += "SHIFT";
}
if ( fnk == "") {
return;
}
const fnk = arr[0].toUpperCase();
const c = arr[1].toUpperCase();
fnk = `fn_${fnk.hash()}`;
if (!this.keycomb[fnk]) {
return;
this.keycomb[fnk] = {};
}
this.keycomb[fnk][c] = f;
}
@ -246,7 +256,7 @@ namespace OS {
* @returns {boolean} return whether the shortcut is executed
* @memberof BaseApplication
*/
shortcut(fnk: string, c: string, e: JQuery.KeyDownEvent): boolean {
shortcut(fnk: string, c: string, e: JQuery.KeyUpEvent): boolean {
if (!this.keycomb[fnk]) {
return true;
}

View File

@ -34,47 +34,16 @@ namespace OS {
*/
export interface ShortcutType {
/**
* Placeholder for all shortcut callbacks attached to `ALT` key, eg.
* Placeholder for all shortcut callbacks, example:
* ```typescript
* ALT.c = function() {..}
* fn_193462204.c = function() {..}
* // this function will be called when the hotkey `ALT-C` is triggered
* // fn_${"ALT".hash()} is fn_193462204
* ```
*
* @memberof ShortcutType
*/
ALT: GenericObject<(e: JQuery.MouseDownEvent) => void>;
/**
* Placeholder for all shortcut callbacks attached to `CTRL` key, eg.
* ```typescript
* CTRL.c = function() {..}
* // this function will be called when the hotkey `CTRL-C` is triggered
* ```
*
* @memberof ShortcutType
*/
CTRL: GenericObject<(e: JQuery.MouseDownEvent) => void>;
/**
* Placeholder for all shortcut callbacks attached to `SHIFT` key, eg.
* ```typescript
* SHIFT.c = function() {..}
* // this function will be called when the hotkey `SHIFT-C` is triggered
* ```
*
* @memberof ShortcutType
*/
SHIFT: GenericObject<(e: JQuery.MouseDownEvent) => void>;
/**
* Placeholder for all shortcut callbacks attached to `META` key, eg.
* ```typescript
* META[" "] = function() {..}
* // this function will be called when the hotkey `META-[space]` is triggered
* ```
*
* @memberof ShortcutType
*/
META: GenericObject<(e: JQuery.MouseDownEvent) => void>;
[propName: string]: GenericObject<(e: JQuery.KeyUpEvent) => void>;
}
/**
@ -129,12 +98,7 @@ namespace OS {
/**
* Placeholder for system shortcuts
*/
var shortcut: ShortcutType = {
ALT: {},
CTRL: {},
SHIFT: {},
META: {},
};
var shortcut: ShortcutType = {};
/**
* Convert an application html scheme to
@ -764,17 +728,32 @@ namespace OS {
*/
export function bindKey(
k: string,
f: (e: JQuery.MouseDownEvent) => void,
f: (e: JQuery.KeyUpEvent) => void,
force: boolean = true
): void {
const arr = k.split("-");
if (arr.length !== 2) {
const arr = k.toUpperCase().split("-");
const c = arr.pop();
let fnk = "";
if (arr.includes("META")) {
fnk += "META";
}
if (arr.includes("CTRL")) {
fnk += "CTRL";
}
if (arr.includes("ALT")) {
fnk += "ALT";
}
if (arr.includes("SHIFT")) {
fnk += "SHIFT";
}
if ( fnk == "") {
return;
}
const fnk = arr[0].toUpperCase();
const c = arr[1].toUpperCase();
fnk = `fn_${fnk.hash()}`;
if (!shortcut[fnk]) {
return;
shortcut[fnk] = {};
}
if (shortcut[fnk][c] && !force) return;
shortcut[fnk][c] = f;
@ -907,7 +886,7 @@ namespace OS {
$("#wrapper").append(scheme);
announcer.observable.one("sysdockloaded", () => {
$(window).bind("keydown", function (event) {
$(window).on("keyup", function (event) {
const dock = $("#sysdock")[0] as tag.AppDockTag;
if (!dock) {
return;
@ -915,20 +894,24 @@ namespace OS {
const app = dock.selectedApp;
//return true unless app
const c = String.fromCharCode(event.which).toUpperCase();
let fnk = undefined;
if (event.ctrlKey) {
fnk = "CTRL";
} else if (event.metaKey) {
fnk = "META";
} else if (event.shiftKey) {
fnk = "SHIFT";
} else if (event.altKey) {
fnk = "ALT";
let fnk = "";
if (event.metaKey) {
fnk += "META";
}
if (!fnk) {
if (event.ctrlKey) {
fnk += "CTRL";
}
if (event.altKey) {
fnk += "ALT";
}
if (event.shiftKey) {
fnk += "SHIFT";
}
if ( fnk == "") {
return;
}
fnk = `fn_${fnk.hash()}`;
const r = app ? app.shortcut(fnk, c, event) : true;
if (!r) {
return event.preventDefault();

View File

@ -224,8 +224,9 @@ namespace OS {
const bt = ($(e.target).closest(
"afx-button"
)[0] as any) as ButtonTag;
const app = bt.data;
const app = bt.data as application.BaseApplication;
m.items = [
{ text: "__(New window)", dataid: "new" },
{ text: "__(Show)", dataid: "show" },
{ text: "__(Hide)", dataid: "hide" },
{ text: "__(Close)", dataid: "quit" },
@ -235,6 +236,17 @@ namespace OS {
if (app[item.dataid]) {
return app[item.dataid]();
}
else
{
switch (item.dataid) {
case "new":
GUI.launch(app.name, []);
break;
default:
break;
}
}
};
return m.show(e);
};

View File

@ -6,19 +6,23 @@
"actions" : [
{
"text": "__(New Project)",
"name": "create"
"name": "create",
"shortcut": "CTRL-ALT-N"
},
{
"text": "__(New project from current folder)",
"name": "init"
"name": "init",
"shortcut": "CTRL-ALT-C"
},
{
"text": "__(Build and Run)",
"name": "buildnrun"
"name": "buildnrun",
"shortcut": "CTRL-ALT-B"
},
{
"text": "__(Build release)",
"name": "release"
"name": "release",
"shortcut": "CTRL-ALT-R"
}
]
},

View File

@ -285,6 +285,7 @@ namespace OS {
});
let file = "Untitled".asFileHandle() as CodePadFileHandle;
if (this.args && this.args.length > 0) {
this.addRecent(this.args[0].path);
if (this.args[0].type === "dir") {
this.currdir = this.args[0].path.asFileHandle() as CodePadFileHandle;
} else {
@ -311,6 +312,7 @@ namespace OS {
if (e.data.type === "dir") {
return;
}
this.addRecent(e.data.path);
return this.eum.active.openFile(
e.data.path.asFileHandle() as CodePadFileHandle
);
@ -359,7 +361,7 @@ namespace OS {
this.bindKey("ALT-N", () => this.menuAction("new"));
this.bindKey("ALT-O", () => this.menuAction("open"));
this.bindKey("ALT-F", () => this.menuAction("opendir"));
this.bindKey("CTRL-ALT-F", () => this.menuAction("opendir"));
this.bindKey("CTRL-S", () => this.menuAction("save"));
this.bindKey("ALT-W", () => this.menuAction("saveas"));
@ -432,7 +434,7 @@ namespace OS {
this.langstat.text = stat.langmode.text;
this.filestat.text = stat.file
let win = this.scheme as GUI.tag.WindowTag;
if(win.apptitle != stat.file)
if (win.apptitle != stat.file)
win.apptitle = stat.file;
}
@ -595,7 +597,7 @@ namespace OS {
* @return {*} {Promise<void>}
* @memberof CodePad
*/
private loadExtensionMetaFromFile(path: string| API.VFS.BaseFileHandle): Promise<void> {
private loadExtensionMetaFromFile(path: string | API.VFS.BaseFileHandle): Promise<void> {
return new Promise((resolve, reject) => {
path
.asFileHandle()
@ -613,7 +615,13 @@ namespace OS {
);
this.extensions[ext.name].name = ext.name;
for (let v of Array.from(ext.actions)) {
const action = v as any;
this.extensions[ext.name].addAction(v);
if (action.shortcut) {
this.bindKey(action.shortcut, (e) => {
return this.loadAndRunExtensionAction(action);
})
}
}
this.spotlight.addAction(
this.extensions[ext.name]
@ -649,9 +657,9 @@ namespace OS {
.then(() => {
// try to load local extension
this.loadExtensionMetaFromFile("home://.codepad/extensions.json")
.catch((e)=>{
// ignore any error
});
.catch((e) => {
// ignore any error
});
})
.catch((e) => {
return this.error(
@ -711,7 +719,7 @@ namespace OS {
*
* @type {{ name: any, ext: any, rootpath?:string }}
*/
parent: { name: any, ext: any, rootpath?:string };
parent: { name: any, ext: any, rootpath?: string };
/**
* Action name
@ -726,7 +734,7 @@ namespace OS {
if (!CodePad.extensions[name]) {
//load the extension
let path = `${this.meta().path}/${name}.js`;
if(data.parent.rootpath)
if (data.parent.rootpath)
path = `${data.parent.rootpath}/${name}.js`;
this._api
.requires(path, true)
@ -750,15 +758,41 @@ namespace OS {
* @memberof CodePad
*/
private fileMenu(): GUI.BasicItemType {
const recent = this.setting.recent.map((i: string) => {
return { text: i };
});
return {
text: __("File"),
nodes: [
{ text: __("New"), dataid: "new", shortcut: "A-N" },
{
text: __("Open Recent"),
dataid: "recent",
nodes: recent,
onchildselect: (
e: GUI.TagEventType<GUI.tag.MenuEventData>,
r: CodePad
) => {
const handle = e.data.item.data.text.asFileHandle();
handle.onready().then((meta: any) => {
if (!meta) {
return;
}
if (meta.type == "dir") {
this.currdir = handle;
this.toggleSideBar();
}
else {
this.eum.active.openFile(handle);
}
});
}
},
{ text: __("Open"), dataid: "open", shortcut: "A-O" },
{
text: __("Open Folder"),
dataid: "opendir",
shortcut: "A-F",
shortcut: "C-A-F",
},
{ text: __("Save"), dataid: "save", shortcut: "C-S" },
{
@ -906,8 +940,22 @@ namespace OS {
}
/**
* Add a file to recent files setting
*
* @private
* @param {string} file
* @memberof CodePad
*/
private addRecent(file: string): void {
if (!this.setting.recent)
this.setting.recent = [];
if (this.setting.recent.includes(file)) {
return;
}
this.setting.recent.push(file);
this.setting.recent.slice(0, 10);
}
/**
* Menu action definition
@ -934,9 +982,10 @@ namespace OS {
(v) => v !== "dir"
),
})
.then((f: API.FileInfoType) =>
me.eum.active.openFile(f.file.path.asFileHandle())
);
.then((f: API.FileInfoType) => {
this.addRecent(f.file.path);
me.eum.active.openFile(f.file.path.asFileHandle());
});
case "opendir":
return me
.openDialog("FileDialog", {
@ -944,6 +993,7 @@ namespace OS {
mimes: ["dir"],
})
.then(function (f: API.FileInfoType) {
me.addRecent(f.file.path);
me.currdir = f.file.path.asFileHandle();
return me.toggleSideBar();
});
@ -1057,7 +1107,7 @@ namespace OS {
*/
class CMDMenu {
text: string | FormattedString;
private shortcut: string;
shortcut: string;
nodes: GenericObject<any>[];
parent: CMDMenu;
rootpath: string;
@ -1075,6 +1125,9 @@ namespace OS {
*/
constructor(text: string | FormattedString, shortcut?: string) {
this.text = text;
if (shortcut) {
this.text += `(${shortcut})`;
}
this.shortcut = shortcut;
this.nodes = [];
this.parent = undefined;
@ -1091,6 +1144,9 @@ namespace OS {
*/
addAction(v: ActionType): CMDMenu {
v.parent = this;
if (v.shortcut) {
v.text = `${v.text.__()} (${v.shortcut})`;
}
this.nodes.push(v);
return this;
}
@ -1140,7 +1196,7 @@ namespace OS {
}
CMDMenu.fromMenu = function (mn): CMDMenu {
const m = new CMDMenu(mn.text, mn.shortcut);
const m = new CMDMenu(mn.text, undefined);
m.onchildselect(mn.onchildselect);
for (let it of Array.from(mn.nodes)) {
let v = it as ActionType;

View File

@ -32,6 +32,11 @@ afx-app-window[data-id ='files-app-window'] afx-vbox[data-id = "nav-bar"]{
afx-app-window[data-id ='files-app-window'] afx-grid-view afx-grid-row.grid_row_header div{
border-top:1px solid #A6A6A6;
}
afx-app-window[data-id ='files-app-window'] afx-grid-view afx-grid-row afx-label span {
white-space: nowrap;
}
afx-app-window[data-id ='files-app-window'] button{
height: 23px;
border-radius: 0;

View File

@ -96,6 +96,9 @@ namespace OS {
this.bindKey("CTRL-R", () => {
return this.menuOptionsHandle("repos");
});
this.bindKey("CTRL-I", () => {
return this.menuOptionsHandle("install");
});
$(this.searchbox).keyup((e) => this.search(e));

View File

@ -5,4 +5,5 @@ afx-label i.label-text{
font-weight: normal;
font-style: normal;
margin-left: 3px;
user-select:text;
}