aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/SettingsManager.tsx5
-rw-r--r--src/client/views/DocumentDecorations.tsx8
-rw-r--r--src/client/views/MainView.scss4
-rw-r--r--src/client/views/MainView.tsx5
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.tsx7
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx176
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts6
8 files changed, 119 insertions, 94 deletions
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index ff0b22381..e20434461 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -8,6 +8,8 @@ import { SelectionManager } from "./SelectionManager";
import "./SettingsManager.scss";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Networking } from "../Network";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { Utils } from "../../Utils";
library.add(fa.faWindowClose);
@@ -90,6 +92,9 @@ export default class SettingsManager extends React.Component<{}> {
<div className="settings-type">
<button onClick={this.onClick} value="password">reset password</button>
<button onClick={this.onClick} value="data">reset data</button>
+ <button onClick={() => window.location.assign(Utils.prepend("/logout"))}>
+ {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
+ </button>
</div>
{this.settingsContent === "password" ?
<div className="settings-content">
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9669c21a9..a3c476125 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -237,6 +237,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
return false;
}
+ _initialAutoHeight = false;
@action
onPointerDown = (e: React.PointerEvent): void => {
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { });
@@ -251,6 +252,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
this._snapX = e.pageX;
this._snapY = e.pageY;
+ this._initialAutoHeight = true;
}
onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
@@ -353,7 +355,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
} else {
dW && (doc._width = actualdW);
dH && (doc._height = actualdH);
- dH && doc._autoHeight && (doc._autoHeight = false);
+ dH && this._initialAutoHeight && (doc._autoHeight = this._initialAutoHeight = false);
}
}
}));
@@ -362,6 +364,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@action
onPointerUp = (e: PointerEvent): void => {
+ SelectionManager.SelectedDocuments().map(dv => {
+ dv.layoutDoc._delayAutoHeight && (dv.layoutDoc._autoHeight = true);
+ dv.layoutDoc._delayAutoHeight = undefined;
+ });
this._resizeHdlId = "";
this.Interacting = false;
(e.button === 0) && this._resizeUndo?.end();
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 753ba700c..dca2a1e3e 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -107,7 +107,9 @@
position: absolute;
left: 0;
bottom: 0;
- font-size: 8px;
+ border-radius: 25%;
+ margin-left: -5px;
+ background: darkblue;
}
.mainView-settings:hover {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 560dd5d11..62496b01f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -493,10 +493,7 @@ export class MainView extends React.Component {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
<button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
- Settings
- </button>
- <button className="mainView-logout" key="logout" onClick={() => window.location.assign(Utils.prepend("/logout"))}>
- {CurrentUserUtils.GuestWorkspace ? "Exit" : "Log Out"}
+ <FontAwesomeIcon icon="cog" size="lg" />
</button>
</div>
{this.docButtons}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6c9ade83f..5cccec776 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1084,7 +1084,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
<DocumentContentsView {...OmitKeys(this.props, ['children']).omit}
hideOnLeave={true}
LayoutTemplateString={`<FormattedTextBox {...props} fieldKey={'${showCaption}'}/>`}
- ContentScaling={this.childScaling}
+ ContentScaling={returnOne}
ChromeHeight={this.chromeHeight}
isSelected={this.isSelected}
select={this.select}
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index d5a28fd14..3c6841f08 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -79,11 +79,13 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
this._reactionDisposer?.();
}
+ multiValueDelimeter = ";";
+
// set the display of the field's value (checkbox for booleans, span of text for strings)
@computed get fieldValueContent() {
if (this._dashDoc) {
const dashVal = this._dashDoc[this._fieldKey] || (this._fieldKey === "PARAMS" ? this._textBoxDoc[this._fieldKey] : "");
- const fval = StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(this._textBoxDoc)[this._fieldKey] : dashVal;
+ const fval = dashVal instanceof List ? dashVal.join(this.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(this._textBoxDoc)[this._fieldKey] : dashVal;
const boolVal = Cast(fval, "boolean", null);
const strVal = Field.toString(fval as Field) || "";
@@ -153,8 +155,9 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
} else if (nodeText.startsWith("=:=")) {
Doc.Layout(this._textBoxDoc)[this._fieldKey] = ComputedField.MakeFunction(nodeText.substring(3));
} else {
+ const splits = newText.split(this.multiValueDelimeter);
if (this._fieldKey !== "PARAMS" || !this._textBoxDoc[this._fieldKey] || this._dashDoc?.PARAMS) {
- this._dashDoc![this._fieldKey] = newText;
+ this._dashDoc![this._fieldKey] = splits.length > 1 ? new List<string>(splits) : newText;
}
}
});
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2c51397eb..3a586ff66 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -658,11 +658,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
);
this._disposers.autoHeight = reaction(
() => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight],
- () => this.tryUpdateHeight()
+ () => setTimeout(() => this.tryUpdateHeight(), 0)
);
this._disposers.height = reaction(
() => this.layoutDoc[HeightSym](),
- height => height <= 20 && (this.layoutDoc._autoHeight = true)
+ action(height => {
+ if (height <= 20) {
+ if (this.layoutDoc._nativeWidth || this.layoutDoc._nativeHeight) {
+ Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.PanelWidth(), this.props.PanelHeight());
+ }
+ this.layoutDoc._delayAutoHeight = true;
+ }
+ })
);
this.setupEditor(this.config, this.props.fieldKey);
@@ -1184,8 +1191,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
tryUpdateHeight(limitHeight?: number) {
let scrollHeight = this._ref.current?.scrollHeight;
- if (this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight &&
- getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ if (this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ scrollHeight = scrollHeight * NumCast(this.layoutDoc.scale, 1);
if (limitHeight && scrollHeight > limitHeight) {
scrollHeight = limitHeight;
this.layoutDoc.limitHeight = undefined;
@@ -1234,87 +1241,90 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
FormattedTextBoxComment.Hide();
}
return (
-
- <div className={`formattedTextBox-cont`} ref={this._ref}
- style={{
- height: this.props.height ? this.props.height : this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : `calc(100% - ${this.props.ChromeHeight?.() || 0}px`,
- background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : ""),
- opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
- color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.hideOnLeave ? "white" : "inherit"),
- pointerEvents: interactive ? "none" : undefined,
- fontSize: Cast(this.layoutDoc._fontSize, "number", null),
- fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
- ...style
- }}
- onContextMenu={this.specificContextMenu}
- onKeyDown={this.onKeyPress}
- onFocus={this.onFocused}
- onClick={this.onClick}
- onPointerMove={e => this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, true)}
- onBlur={this.onBlur}
- onPointerUp={this.onPointerUp}
- onPointerDown={this.onPointerDown}
- onMouseUp={this.onMouseUp}
- onWheel={this.onPointerWheel}
- onPointerEnter={action(() => this._entered = true)}
- onPointerLeave={action((e: React.PointerEvent<HTMLDivElement>) => {
- this._entered = false;
- const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y);
- for (let child: any = target; child; child = child?.parentElement) {
- if (child === this._ref.current!) {
- this._entered = true;
+ <div className={"formattedTextBox-cont"} style={{
+ transform: `scale(${scale})`,
+ transformOrigin: "top left",
+ width: `${100 / scale}%`,
+ height: `${100 / scale}%`,
+ }}>
+ <div className={`formattedTextBox-cont`} ref={this._ref}
+ style={{
+ width: "100%",
+ height: this.props.height ? this.props.height : this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : `calc(100% - ${this.props.ChromeHeight?.() || 0}px`,
+ background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : ""),
+ opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
+ color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.hideOnLeave ? "white" : "inherit"),
+ pointerEvents: interactive ? "none" : undefined,
+ fontSize: Cast(this.layoutDoc._fontSize, "number", null),
+ fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
+ ...style
+ }}
+ onContextMenu={this.specificContextMenu}
+ onKeyDown={this.onKeyPress}
+ onFocus={this.onFocused}
+ onClick={this.onClick}
+ onPointerMove={e => this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, true)}
+ onBlur={this.onBlur}
+ onPointerUp={this.onPointerUp}
+ onPointerDown={this.onPointerDown}
+ onMouseUp={this.onMouseUp}
+ onWheel={this.onPointerWheel}
+ onPointerEnter={action(() => this._entered = true)}
+ onPointerLeave={action((e: React.PointerEvent<HTMLDivElement>) => {
+ this._entered = false;
+ const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y);
+ for (let child: any = target; child; child = child?.parentElement) {
+ if (child === this._ref.current!) {
+ this._entered = true;
+ }
}
- }
- })}
- >
- <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} onScroll={this.onscrolled} ref={this._scrollRef}>
- <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
- style={{
- transform: `scale(${scale})`,
- transformOrigin: "top left",
- width: `${100 / scale}%`,
- height: `${100 / scale}%`,
- padding: `${NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0)}px`,
- pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
- }} />
+ })}
+ >
+ <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} onScroll={this.onscrolled} ref={this._scrollRef}>
+ <div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
+ style={{
+ padding: `${NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0)}px`,
+ pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
+ }} />
+ </div>
+ {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> :
+ <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
+ style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ <CollectionFreeFormView {...this.props}
+ PanelHeight={this.props.PanelHeight}
+ PanelWidth={this.sidebarWidth}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ annotationsKey={this.annotationKey}
+ isAnnotationOverlay={false}
+ focus={this.props.focus}
+ isSelected={this.props.isSelected}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ ContentScaling={returnOne}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={this.sidebarScreenToLocal}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+ </CollectionFreeFormView>
+ <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} />
+ </div>}
+ {!this.layoutDoc._showAudio ? (null) :
+ <div className="formattedTextBox-dictation"
+ onPointerDown={e => {
+ runInAction(() => this._recording = !this._recording);
+ setTimeout(() => this._editorView!.focus(), 500);
+ e.stopPropagation();
+ }} >
+ <FontAwesomeIcon className="formattedTExtBox-audioFont"
+ style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.5, display: this.props.isSelected() ? "" : "none" }} icon={"microphone"} size="sm" />
+ </div>}
</div>
- {!this.layoutDoc._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
- <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> :
- <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")}
- style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
- <CollectionFreeFormView {...this.props}
- PanelHeight={this.props.PanelHeight}
- PanelWidth={this.sidebarWidth}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- annotationsKey={this.annotationKey}
- isAnnotationOverlay={false}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
- select={emptyFunction}
- active={this.annotationsActive}
- ContentScaling={returnOne}
- whenActiveChanged={this.whenActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.addDocument}
- CollectionView={undefined}
- ScreenToLocalTransform={this.sidebarScreenToLocal}
- renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
- </CollectionFreeFormView>
- <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} />
- </div>}
- {!this.layoutDoc._showAudio ? (null) :
- <div className="formattedTextBox-dictation"
- onPointerDown={e => {
- runInAction(() => this._recording = !this._recording);
- setTimeout(() => this._editorView!.focus(), 500);
- e.stopPropagation();
- }} >
- <FontAwesomeIcon className="formattedTExtBox-audioFont"
- style={{ color: this._recording ? "red" : "blue", opacity: this._recording ? 1 : 0.5, display: this.props.isSelected() ? "" : "none" }} icon={"microphone"} size="sm" />
- </div>}
</div>
);
}
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index d619bc4a0..0ba591fec 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -11,6 +11,7 @@ import { FormattedTextBox } from "./FormattedTextBox";
import { wrappingInputRule } from "./prosemirrorPatches";
import RichTextMenu from "./RichTextMenu";
import { schema } from "./schema_rts";
+import { List } from "../../../../new_fields/List";
export class RichTextRules {
public Document: Doc;
@@ -64,11 +65,12 @@ export class RichTextRules {
// create an inline view of a tag stored under the '#' field
new InputRule(
- new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_\-0-9]*)\s$/),
+ new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_;\-0-9]*)\s$/),
(state, match, start, end) => {
const tag = match[1];
if (!tag) return state.tr;
- this.Document[DataSym]["#"] = tag;
+ const multiple = tag.split(";");
+ this.Document[DataSym]["#"] = multiple.length > 1 ? new List(multiple) : tag;
const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" });
return state.tr.deleteRange(start, end).insert(start, fieldView);
}),