diff --git a/src/main.tsx b/src/main.tsx
index ad70bd4c..fb426f29 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -141,7 +141,7 @@ class LineText extends React.Component<{sw : ScreenWindow, line : LineType}, {}>
let {sw, line} = this.props;
let formattedTime = getLineDateStr(line.ts);
let isSelected = (sw.selectedLine.get() == line.linenum);
- let isFocused = (sw.focusType.get() == "lines");
+ let isFocused = (sw.focusType.get() == "cmd");
return (
@@ -393,11 +393,45 @@ class TextAreaInput extends React.Component<{}, {}> {
lastTab : boolean = false;
lastHistoryUpDown : boolean = false;
lastTabCurLine : mobx.IObservableValue
= mobx.observable.box(null);
-
+ lastFocusType : string = null;
+ mainInputRef : React.RefObject;
+ historyInputRef : React.RefObject;
+
+ constructor(props) {
+ super(props);
+ this.mainInputRef = React.createRef();
+ this.historyInputRef = React.createRef();
+ }
+
+ setFocus() : void {
+ let inputModel = GlobalModel.inputModel;
+ if (inputModel.historyShow.get()) {
+ this.historyInputRef.current.focus();
+ }
+ else {
+ this.mainInputRef.current.focus();
+ }
+ }
+
componentDidMount() {
- let input = document.getElementById("main-cmd-input");
- if (input != null) {
- input.focus();
+ let activeSW = GlobalModel.getActiveSW();
+ if (activeSW != null) {
+ let focusType = activeSW.focusType.get();
+ if (focusType == "input") {
+ this.setFocus();
+ }
+ this.lastFocusType = focusType;
+ }
+ }
+
+ componentDidUpdate() {
+ let activeSW = GlobalModel.getActiveSW();
+ if (activeSW != null) {
+ let focusType = activeSW.focusType.get();
+ if (this.lastFocusType != focusType && focusType == "input") {
+ this.setFocus();
+ }
+ this.lastFocusType = focusType;
}
}
@@ -603,14 +637,16 @@ class TextAreaInput extends React.Component<{}, {}> {
if (inputModel.historyShow.get()) {
e.preventDefault();
inputModel.giveFocus();
+ return;
}
- else {
- inputModel.setPhysicalInputFocused(true);
- }
+ inputModel.setPhysicalInputFocused(true);
}
@boundMethod
handleMainBlur(e : any) {
+ if (document.activeElement == this.mainInputRef.current) {
+ return;
+ }
GlobalModel.inputModel.setPhysicalInputFocused(false);
}
@@ -620,14 +656,16 @@ class TextAreaInput extends React.Component<{}, {}> {
if (!inputModel.historyShow.get()) {
e.preventDefault();
inputModel.giveFocus();
+ return;
}
- else {
- inputModel.setPhysicalInputFocused(true);
- }
+ inputModel.setPhysicalInputFocused(true);
}
@boundMethod
handleHistoryBlur(e : any) {
+ if (document.activeElement == this.historyInputRef.current) {
+ return;
+ }
GlobalModel.inputModel.setPhysicalInputFocused(false);
}
@@ -644,10 +682,14 @@ class TextAreaInput extends React.Component<{}, {}> {
if (disabled) {
displayLines = 1;
}
+ let activeSW = GlobalModel.getActiveSW();
+ if (activeSW != null) {
+ activeSW.focusType.get(); // for reaction
+ }
return (
-
-
+
+
);
}
diff --git a/src/model.ts b/src/model.ts
index 562e9ffa..dc6a00c3 100644
--- a/src/model.ts
+++ b/src/model.ts
@@ -265,15 +265,14 @@ class ScreenWindow {
layout : OV;
lastCols : number;
selectedLine : OV;
- scrollTop : OV;
- focusType : OV<"input"|"lines"> = mobx.observable.box("input");
+ focusType : OV<"input"|"cmd"|"cmd-fg">;
anchorLine : number = null;
anchorOffset : number = 0;
// cmdid => TermWrap
terms : Record = {};
- setScrollTop_debounced : (scrollTop : number) => void;
+ setAnchor_debounced : (anchorLine : number, anchorOffset : number) => void;
constructor(swdata : ScreenWindowType) {
this.sessionId = swdata.sessionid;
@@ -281,9 +280,9 @@ class ScreenWindow {
this.windowId = swdata.windowid;
this.name = mobx.observable.box(swdata.name);
this.layout = mobx.observable.box(swdata.layout);
+ this.focusType = mobx.observable.box(swdata.focustype);
this.selectedLine = mobx.observable.box(swdata.selectedline == 0 ? null : swdata.selectedline);
- this.scrollTop = mobx.observable.box(swdata.scrolltop);
- this.setScrollTop_debounced = debounce(1000, this.setScrollTop.bind(this));
+ this.setAnchor_debounced = debounce(1000, this.setAnchor.bind(this));
if (swdata.selectedline != 0) {
this.anchorLine = swdata.selectedline;
this.anchorOffset = 0;
@@ -295,18 +294,20 @@ class ScreenWindow {
this.name.set(swdata.name);
this.layout.set(swdata.layout);
this.selectedLine.set(swdata.selectedline);
- // do not set scrolltop!
+ this.focusType.set(swdata.focustype);
+ // do not update anchorLine/anchorOffset (only stored)
})();
}
- setFocusType(ftype : "input" | "lines") : void {
+ setFocusType(ftype : "input" | "cmd" | "cmd-fg") : void {
mobx.action(() => {
this.focusType.set(ftype);
})();
}
- setScrollTop(scrollTop : number) : void {
- GlobalCommandRunner.swSetScrollTop(this.sessionId, this.screenId, this.windowId, scrollTop);
+ setAnchor(anchorLine : number, anchorOffset : number) : void {
+ let setVal = ((anchorLine == null || anchorLine == 0) ? "0" : sprintf("%d:%d", anchorLine, anchorOffset));
+ GlobalCommandRunner.swSetAnchor(this.sessionId, this.screenId, this.windowId, setVal);
}
getMaxLineNum() : number {
@@ -784,6 +785,8 @@ class InputModel {
}
giveFocus() : void {
+ return;
+
if (this.historyShow.get()) {
this._focusHistoryInput();
}
@@ -1434,7 +1437,7 @@ class Model {
onLCmd(e : any, mods : KeyModsType) {
let sw = this.getActiveSW();
if (sw != null) {
- sw.setFocusType("lines");
+ sw.setFocusType("cmd");
}
// this.inputModel.giveCmdFocus();
}
@@ -2088,20 +2091,31 @@ class CommandRunner {
GlobalModel.submitCommand("remote", "archive", null, {"remote": remoteid, "nohist": "1"}, true);
}
- swSelectLine(lineArg : string) {
- GlobalModel.submitCommand("sw", "set", null, {"nohist": "1", "line": lineArg}, true);
+ swSelectLine(lineArg : string, focusVal? : string) {
+ let kwargs : Record = {
+ "nohist": "1",
+ "line": lineArg,
+ };
+ if (focusVal != null) {
+ kwargs["focus"] = focusVal;
+ }
+ GlobalModel.submitCommand("sw", "set", null, kwargs, true);
}
- swSetScrollTop(sessionId : string, screenId : string, windowId : string, scrollTopVal : number) {
+ swSetAnchor(sessionId : string, screenId : string, windowId : string, anchorVal : string) : void {
let kwargs = {
"nohist": "1",
- "scrolltop": String(scrollTopVal),
+ "anchor": anchorVal,
"session": sessionId,
"screen": screenId,
"window": windowId,
};
GlobalModel.submitCommand("sw", "set", null, kwargs, true);
}
+
+ swSetFocus(focusVal : string) : void {
+ GlobalModel.submitCommand("sw", "set", null, {"focus": focusVal, "nohist": "1"}, true);
+ }
};
let GlobalModel : Model = null;
diff --git a/src/term.ts b/src/term.ts
index ca274eca..e87dd561 100644
--- a/src/term.ts
+++ b/src/term.ts
@@ -3,7 +3,7 @@ import {Terminal} from 'xterm';
import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator";
import {v4 as uuidv4} from "uuid";
-import {GlobalModel, widthToCols} from "./model";
+import {GlobalModel, widthToCols, GlobalCommandRunner} from "./model";
import {boundInt} from "./util";
import type {TermOptsType, TermWinSize} from "./types";
@@ -71,7 +71,10 @@ class TermWrap {
this.terminal.textarea.addEventListener("focus", () => {
this.setFocus(true);
});
- this.terminal.textarea.addEventListener("blur", () => {
+ this.terminal.textarea.addEventListener("blur", (e : any) => {
+ if (document.activeElement == this.terminal.textarea) {
+ return;
+ }
this.setFocus(false);
});
this.reloadTerminal(0);
@@ -96,10 +99,13 @@ class TermWrap {
mobx.action(() => {
this.isFocused.set(focus);
})();
- if (this.connectedElem != null) {
- let lineElem = this.connectedElem.closest(".line");
+ if (this.connectedElem != null && focus) {
+ let lineElem : HTMLElement = this.connectedElem.closest(".line");
if (lineElem != null) {
- lineElem.scrollIntoView({behavior: "smooth", block: "nearest"});
+ let lineNum = parseInt(lineElem.dataset.linenum);
+ if (!isNaN(lineNum) && lineNum > 0) {
+ GlobalCommandRunner.swSelectLine(String(lineNum), "cmd");
+ }
}
}
}
diff --git a/src/types.ts b/src/types.ts
index 26d36a57..960c29d9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -68,7 +68,8 @@ type ScreenWindowType = {
name : string,
layout : LayoutType,
selectedline : number,
- scrolltop : number,
+ focustype : "input"|"cmd"|"cmd-fg",
+ anchor : {anchorline : number, anchoroffset : number},
// for updates
remove? : boolean,