From 5e2f64f3ee172e37d0d3277637a7778b640a2066 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 30 Jan 2023 15:23:40 -0500 Subject: fixed pointerEvents for text box footnotes. fixed keyvalue editing to not typecheck. fixed schema header field editing from keyvalue pane. fixed webBox error causing overlayview to not work for Repls and others. fixed some layout issues with stackingview columns. --- src/client/views/EditableView.tsx | 1 - .../collections/CollectionMasonryViewFieldRow.tsx | 311 +++++++++++---------- .../views/collections/CollectionStackingView.scss | 21 +- .../CollectionStackingViewFieldColumn.tsx | 58 ++-- .../views/collections/CollectionTimeView.tsx | 1 - src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/nodes/WebBoxRenderer.js | 4 +- .../views/nodes/formattedText/FootnoteView.tsx | 72 ++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 2 +- src/fields/SchemaHeaderField.ts | 7 +- 12 files changed, 257 insertions(+), 228 deletions(-) (limited to 'src') diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 8036df471..bb190e93b 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -43,7 +43,6 @@ export interface EditableProps { menuCallback?: (x: number, y: number) => void; textCallback?: (char: string) => boolean; showMenuOnLoad?: boolean; - toggle?: () => void; background?: string | undefined; placeholder?: string; } diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index a94e706eb..befd89e41 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -1,24 +1,24 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { DataSym, Doc, DocListCast } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; -import { ScriptField } from "../../../fields/ScriptField"; -import { NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, numberRange, returnEmptyString, setupMoveUpEvents } from "../../../Utils"; -import { Docs } from "../../documents/Documents"; -import { DragManager } from "../../util/DragManager"; -import { CompileScript } from "../../util/Scripting"; -import { SnappingManager } from "../../util/SnappingManager"; -import { Transform } from "../../util/Transform"; -import { undoBatch } from "../../util/UndoManager"; -import { EditableView } from "../EditableView"; -import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox"; -import { CollectionStackingView } from "./CollectionStackingView"; -import "./CollectionStackingView.scss"; -const higflyout = require("@hig/flyout"); +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { DataSym, Doc, DocListCast } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField'; +import { ScriptField } from '../../../fields/ScriptField'; +import { NumCast, StrCast } from '../../../fields/Types'; +import { emptyFunction, numberRange, returnEmptyString, setupMoveUpEvents } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DragManager } from '../../util/DragManager'; +import { CompileScript } from '../../util/Scripting'; +import { SnappingManager } from '../../util/SnappingManager'; +import { Transform } from '../../util/Transform'; +import { undoBatch } from '../../util/UndoManager'; +import { EditableView } from '../EditableView'; +import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; +import { CollectionStackingView } from './CollectionStackingView'; +import './CollectionStackingView.scss'; +const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -32,7 +32,7 @@ interface CMVFieldRowProps { docList: Doc[]; parent: CollectionStackingView; pivotField: string; - type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; + type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; setDocHeight: (key: string, thisHeight: number) => void; @@ -43,15 +43,21 @@ interface CMVFieldRowProps { @observer export class CollectionMasonryViewFieldRow extends React.Component { - @observable private _background = "inherit"; + @observable private _background = 'inherit'; @observable private _createAliasSelected: boolean = false; - @observable private heading: string = ""; - @observable private color: string = "#f1efeb"; + @observable private heading: string = ''; + @observable private color: string = '#f1efeb'; @observable private collapsed: boolean = false; @observable private _paletteOn = false; - private set _heading(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value)); } - private set _color(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value)); } - private set _collapsed(value: boolean) { runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value)); } + private set _heading(value: string) { + runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value)); + } + private set _color(value: string) { + runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value)); + } + private set _collapsed(value: boolean) { + runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value)); + } private _dropDisposer?: DragManager.DragDropDisposer; private _headerRef: React.RefObject = React.createRef(); @@ -65,11 +71,11 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createAliasSelected = false; if (de.complete.docDragData) { - (this.props.parent.Document.dropConverter instanceof ScriptField) && - this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData }); + this.props.parent.Document.dropConverter instanceof ScriptField && this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData }); const key = this.props.pivotField; const castedValue = this.getValue(this.heading); const onLayoutDoc = this.onLayoutDoc(key); @@ -105,10 +110,10 @@ export class CollectionMasonryViewFieldRow extends React.Component { const parsed = parseInt(value); if (!isNaN(parsed)) return parsed; - if (value.toLowerCase().indexOf("true") > -1) return true; - if (value.toLowerCase().indexOf("false") > -1) return false; + if (value.toLowerCase().indexOf('true') > -1) return true; + if (value.toLowerCase().indexOf('false') > -1) return false; return value; - } + }; @action headingChanged = (value: string, shiftDown?: boolean) => { @@ -126,58 +131,60 @@ export class CollectionMasonryViewFieldRow extends React.Component { this._createAliasSelected = false; this._color = color; - } + }; - pointerEnteredRow = action(() => SnappingManager.GetIsDragging() && (this._background = "#b4b4b4")); + pointerEnteredRow = action(() => SnappingManager.GetIsDragging() && (this._background = '#b4b4b4')); @action pointerLeaveRow = () => { this._createAliasSelected = false; - this._background = "inherit"; - } + this._background = 'inherit'; + }; @action addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { if (!value && !forceEmptyNote) return false; this._createAliasSelected = false; const key = this.props.pivotField; - const newDoc = Docs.Create.TextDocument("", { _autoHeight: true, _width: 200, _fitWidth: true, title: value }); + const newDoc = Docs.Create.TextDocument('', { _autoHeight: true, _width: 200, _fitWidth: true, title: value }); const onLayoutDoc = this.onLayoutDoc(key); FormattedTextBox.SelectOnLoad = newDoc[Id]; FormattedTextBox.SelectOnLoadChar = value; (onLayoutDoc ? newDoc : newDoc[DataSym])[key] = this.getValue(this.props.heading); const docs = this.props.parent.childDocList; return docs ? (docs.splice(0, 0, newDoc) ? true : false) : this.props.parent.props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list) - } + }; - deleteRow = undoBatch(action(() => { - this._createAliasSelected = false; - const key = this.props.pivotField; - this.props.docList.forEach(d => Doc.SetInPlace(d, key, undefined, true)); - if (this.props.parent.columnHeaders && this.props.headingObject) { - const index = this.props.parent.columnHeaders.indexOf(this.props.headingObject); - this.props.parent.columnHeaders.splice(index, 1); - } - })); + deleteRow = undoBatch( + action(() => { + this._createAliasSelected = false; + const key = this.props.pivotField; + this.props.docList.forEach(d => Doc.SetInPlace(d, key, undefined, true)); + if (this.props.parent.columnHeaders && this.props.headingObject) { + const index = this.props.parent.columnHeaders.indexOf(this.props.headingObject); + this.props.parent.columnHeaders.splice(index, 1); + } + }) + ); @action collapseSection = (e: any) => { this._createAliasSelected = false; this.toggleVisibility(); e.stopPropagation(); - } + }; headerMove = (e: PointerEvent) => { const alias = Doc.MakeAlias(this.props.Document); const key = this.props.pivotField; let value = this.getValue(this.heading); - value = typeof value === "string" ? `"${value}"` : value; + value = typeof value === 'string' ? `"${value}"` : value; const script = `return doc.${key} === ${value}`; const compiled = CompileScript(script, { params: { doc: Doc.name } }); if (compiled.compiled) { @@ -185,7 +192,7 @@ export class CollectionMasonryViewFieldRow extends React.Component) => { @@ -193,7 +200,7 @@ export class CollectionMasonryViewFieldRow extends React.Component !this.props.chromeHidden && this.collapseSection(e)); this._createAliasSelected = false; } - } + }; /** * Returns true if a key is on the layout doc of the documents in the collection. @@ -203,143 +210,141 @@ export class CollectionMasonryViewFieldRow extends React.Component { const selected = this.color; - const pink = PastelSchemaPalette.get("pink2"); - const purple = PastelSchemaPalette.get("purple4"); - const blue = PastelSchemaPalette.get("bluegreen1"); - const yellow = PastelSchemaPalette.get("yellow4"); - const red = PastelSchemaPalette.get("red2"); - const green = PastelSchemaPalette.get("bluegreen7"); - const cyan = PastelSchemaPalette.get("bluegreen5"); - const orange = PastelSchemaPalette.get("orange1"); - const gray = "#f1efeb"; + const pink = PastelSchemaPalette.get('pink2'); + const purple = PastelSchemaPalette.get('purple4'); + const blue = PastelSchemaPalette.get('bluegreen1'); + const yellow = PastelSchemaPalette.get('yellow4'); + const red = PastelSchemaPalette.get('red2'); + const green = PastelSchemaPalette.get('bluegreen7'); + const cyan = PastelSchemaPalette.get('bluegreen5'); + const orange = PastelSchemaPalette.get('orange1'); + const gray = '#f1efeb'; return (
-
this.changeColumnColor(pink!)}>
-
this.changeColumnColor(purple!)}>
-
this.changeColumnColor(blue!)}>
-
this.changeColumnColor(yellow!)}>
-
this.changeColumnColor(red!)}>
-
this.changeColumnColor(gray)}>
-
this.changeColumnColor(green!)}>
-
this.changeColumnColor(cyan!)}>
-
this.changeColumnColor(orange!)}>
+
this.changeColumnColor(pink!)}>
+
this.changeColumnColor(purple!)}>
+
this.changeColumnColor(blue!)}>
+
this.changeColumnColor(yellow!)}>
+
this.changeColumnColor(red!)}>
+
this.changeColumnColor(gray)}>
+
this.changeColumnColor(green!)}>
+
this.changeColumnColor(cyan!)}>
+
this.changeColumnColor(orange!)}>
); - } + }; - toggleAlias = action(() => this._createAliasSelected = true); - toggleVisibility = () => this._collapsed = !this.collapsed; + toggleAlias = action(() => (this._createAliasSelected = true)); + toggleVisibility = () => (this._collapsed = !this.collapsed); renderMenu = () => { const selected = this._createAliasSelected; - return (
-
-
Create Alias
-
Delete
+ return ( +
+
+
+ Create Alias +
+
+ Delete +
+
-
); - } + ); + }; @action textCallback = (char: string) => { - return this.addDocument("", false); - } + return this.addDocument('', false); + }; @computed get contentLayout() { const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap)))); const showChrome = !this.props.chromeHidden; const stackPad = showChrome ? `0px ${this.props.parent.xMargin}px` : `${this.props.parent.yMargin}px ${this.props.parent.xMargin}px 0px ${this.props.parent.xMargin}px `; - return this.collapsed ? (null) : -
- {showChrome ? -
+ {showChrome ? ( +
- -
: null - } -
+
+ ) : null} +
list + ` ${this.props.parent.columnWidth}px`, ""), + gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => list + ` ${this.props.parent.columnWidth}px`, ''), }}> {this.props.parent.children(this.props.docList)} - {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : (null)} + {this.props.showHandle && this.props.parent.props.isContentActive() ? this.props.parent.columnDragger : null}
-
; +
+ ); } @computed get headingView() { const noChrome = this.props.chromeHidden; const key = this.props.pivotField; - const evContents = this.heading ? this.heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`; - const editableHeaderView = evContents} - SetValue={this.headingChanged} - contents={evContents} - oneLine={true} - toggle={this.toggleVisibility} />; - return this.props.Document.miniHeaders ? -
- {editableHeaderView} -
: - !this.props.headingObject ? (null) : -
-
- {noChrome ? evContents : editableHeaderView} - {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : -
- + {this._paletteOn ? this.renderColorPicker() : null} +
+ )} + {noChrome ? null : ( + + )} + {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( +
+ + - {this._paletteOn ? this.renderColorPicker() : (null)} -
- } - {noChrome ? (null) : } - {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : -
- - - -
- } -
-
; + +
+ )} + + + ); } render() { const background = this._background; - return
- {this.headingView} - {this.contentLayout} -
; + return ( +
+ {this.headingView} + {this.contentLayout} +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 7385f933b..f3397e2c4 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -150,11 +150,14 @@ } .collectionStackingView-collapseBar { - margin-left: 2px; - margin-right: 2px; margin-top: 2px; background: $medium-gray; height: 5px; + width: 100%; + display: none; + position: absolute; + top: 0; + cursor: default; &.active { margin-left: 0; @@ -236,7 +239,7 @@ .editableView-container-editing-oneLine, .editableView-container-editing { color: grey; - padding: 10px; + //padding: 10px; } .editableView-input:hover, @@ -333,7 +336,7 @@ .collectionStackingView-sectionDelete { position: absolute; - right: 25px; + right: 0px; top: 0; height: 100%; display: none; @@ -352,6 +355,10 @@ .collectionStackingView-sectionDelete { display: unset; } + + .collectionStackingView-collapseBar { + display: block; + } } .collectionStackingView-addDocumentButton, @@ -365,7 +372,7 @@ .editableView-container-editing-oneLine, .editableView-container-editing { color: grey; - padding: 10px; + padding-top: 10px; width: 100%; } @@ -380,7 +387,7 @@ letter-spacing: 2px; color: grey; border: 0px; - padding: 12px 10px 11px 10px; + padding-top: 10px; // 12px 10px 11px 10px; } } @@ -394,7 +401,7 @@ letter-spacing: 2px; color: grey; border: 0px; - padding: 12px 10px 11px 10px; + padding-top: 10px; // : 12px 10px 11px 10px; } } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 7b268cd49..d62c4dc62 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -1,12 +1,12 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { RichTextField } from '../../../fields/RichTextField'; import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { ScriptField } from '../../../fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction, setupMoveUpEvents, returnFalse, returnEmptyString } from '../../../Utils'; @@ -56,6 +56,7 @@ export class CollectionStackingViewFieldColumn extends React.Component = React.createRef(); @observable _paletteOn = false; @@ -75,7 +76,16 @@ export class CollectionStackingViewFieldColumn extends React.Component this.props.headingObject?.collapsed, + collapsed => (this.collapsed = collapsed !== undefined ? BoolCast(collapsed) : false), + { fireImmediately: true } + ); + } componentWillUnmount() { + this._disposers.collapser?.(); this.props.unobserveHeight(this._ele); } @@ -146,7 +156,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { this.props.headingObject?.setCollapsed(!this.props.headingObject.collapsed); - this.toggleVisibility(); + this.collapsed = BoolCast(this.props.headingObject?.collapsed); }; headerDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); @@ -275,7 +285,8 @@ export class CollectionStackingViewFieldColumn extends React.Component headings.indexOf(i) === idx); - const evContents = heading ? heading : this.props?.type === 'number' ? '0' : `NO ${key.toUpperCase()} VALUE`; + const noValueHeader = `NO ${key.toUpperCase()} VALUE`; + const evContents = heading ? heading : this.props?.type === 'number' ? '0' : noValueHeader; const headingView = this.props.headingObject ? (
-
{/* the default bucket (no key value) has a tooltip that describes what it is. Further, it does not have a color and cannot be deleted. */}
- evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} toggle={this.toggleVisibility} /> - {evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( -
- - {this._paletteOn ? this.renderColorPicker() : null} -
- )} - { - - } - {evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( + {this._paletteOn ? this.renderColorPicker() : null} +
+ + {/* {evContents === noValueHeader ? null : (
- )} + )} */}
+
) : null; const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; @@ -348,14 +359,13 @@ export class CollectionStackingViewFieldColumn extends React.Component +
} - toggle={this.toggleVisibility} menuCallback={this.menuCallback} />
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 8c613198d..0ec21cc51 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -239,7 +239,6 @@ export class CollectionTimeView extends CollectionSubView() { } return false; }} - toggle={this.toggleVisibility} background={'#f1efeb'} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; contents={':' + StrCast(this.layoutDoc._pivotField)} showMenuOnLoad={true} diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 18c5b81ec..60417430f 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -66,7 +66,7 @@ export class KeyValueBox extends React.Component { value = eq ? value.substr(1) : value; const dubEq = value.startsWith(':=') ? 'computed' : value.startsWith(';=') ? 'script' : false; value = dubEq ? value.substr(2) : value; - const options: ScriptOptions = { addReturn: true, params: { this: Doc.name, self: Doc.name, _last_: 'any', _readOnly_: 'boolean' }, editable: false }; + const options: ScriptOptions = { addReturn: true, typecheck: false, params: { this: Doc.name, self: Doc.name, _last_: 'any', _readOnly_: 'boolean' }, editable: false }; if (dubEq) options.typecheck = false; const script = CompileScript(value, options); return !script.compiled ? undefined : { script, type: dubEq, onDelegate: eq }; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index acf4fe4b0..d0d638e98 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -981,7 +981,7 @@ export class WebBox extends ViewBoxAnnotatableComponent (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'); + pointerEvents = () => (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance?.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none'); annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None ? 'all' : 'none'); render() { const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js index cebb94d86..20554b858 100644 --- a/src/client/views/nodes/WebBoxRenderer.js +++ b/src/client/views/nodes/WebBoxRenderer.js @@ -216,7 +216,9 @@ var ForeignHtmlRenderer = function (styleSheets) { } const styleElem = document.createElement('style'); - styleElem.innerHTML = cssStyles.replace('>', '>').replace('<', '<'); + styleElem.innerHTML = + '#mw-sidebar-checkbox ~ .vector-main-menu-container { display: none !important; } ' + // hack to prevent wikipedia menu from appearing + cssStyles.replace('>', '>').replace('<', '<'); const styleElemString = new XMLSerializer().serializeToString(styleElem).replace(/>/g, '>').replace(/</g, '<'); diff --git a/src/client/views/nodes/formattedText/FootnoteView.tsx b/src/client/views/nodes/formattedText/FootnoteView.tsx index 1683cc972..531a60297 100644 --- a/src/client/views/nodes/formattedText/FootnoteView.tsx +++ b/src/client/views/nodes/formattedText/FootnoteView.tsx @@ -1,10 +1,10 @@ -import { EditorView } from "prosemirror-view"; -import { EditorState } from "prosemirror-state"; -import { keymap } from "prosemirror-keymap"; -import { baseKeymap, toggleMark } from "prosemirror-commands"; -import { schema } from "./schema_rts"; -import { redo, undo } from "prosemirror-history"; -import { StepMap } from "prosemirror-transform"; +import { EditorView } from 'prosemirror-view'; +import { EditorState } from 'prosemirror-state'; +import { keymap } from 'prosemirror-keymap'; +import { baseKeymap, toggleMark } from 'prosemirror-commands'; +import { schema } from './schema_rts'; +import { redo, undo } from 'prosemirror-history'; +import { StepMap } from 'prosemirror-transform'; export class FootnoteView { innerView: any; @@ -20,38 +20,39 @@ export class FootnoteView { this.getPos = getPos; // The node's representation in the editor (empty, for now) - this.dom = document.createElement("footnote"); + this.dom = document.createElement('footnote'); - this.dom.addEventListener("pointerup", this.toggle, true); + this.dom.addEventListener('pointerup', this.toggle, true); // These are used when the footnote is selected this.innerView = null; } selectNode() { - this.dom.classList.add("ProseMirror-selectednode"); + this.dom.classList.add('ProseMirror-selectednode'); if (!this.innerView) this.open(); } deselectNode() { - this.dom.classList.remove("ProseMirror-selectednode"); + this.dom.classList.remove('ProseMirror-selectednode'); if (this.innerView) this.close(); } open() { // Append a tooltip to the outer node - const tooltip = this.dom.appendChild(document.createElement("div")); - tooltip.className = "footnote-tooltip"; + const tooltip = this.dom.appendChild(document.createElement('div')); + tooltip.className = 'footnote-tooltip'; // And put a sub-ProseMirror into that this.innerView = new EditorView(tooltip, { // You can use any node as an editor document state: EditorState.create({ doc: this.node, - plugins: [keymap(baseKeymap), - keymap({ - "Mod-z": () => undo(this.outerView.state, this.outerView.dispatch), - "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch), - "Mod-b": toggleMark(schema.marks.strong) - }), + plugins: [ + keymap(baseKeymap), + keymap({ + 'Mod-z': () => undo(this.outerView.state, this.outerView.dispatch), + 'Mod-y': () => redo(this.outerView.state, this.outerView.dispatch), + 'Mod-b': toggleMark(schema.marks.strong), + }), // new Plugin({ // view(newView) { // // TODO -- make this work with RichTextMenu @@ -59,7 +60,6 @@ export class FootnoteView { // } // }) ], - }), // This is the magic part dispatchTransaction: this.dispatchInner.bind(this), @@ -69,36 +69,39 @@ export class FootnoteView { // footnote is node-selected (and thus DOM-selected) when // the parent editor is focused. e.stopPropagation(); - document.addEventListener("pointerup", this.ignore, true); + document.addEventListener('pointerup', this.ignore, true); if (this.outerView.hasFocus()) this.innerView.focus(); - }) as any - } + }) as any, + }, }); setTimeout(() => this.innerView?.docView.setSelection(0, 0, this.innerView.root, true), 0); } ignore = (e: PointerEvent) => { e.stopPropagation(); - document.removeEventListener("pointerup", this.ignore, true); - } + document.removeEventListener('pointerup', this.ignore, true); + }; toggle = () => { + console.log('TOGGLE'); if (this.innerView) this.close(); else this.open(); - } + }; close() { + console.log('CLOSE'); this.innerView?.destroy(); this.innerView = null; - this.dom.textContent = ""; + this.dom.textContent = ''; } dispatchInner(tr: any) { const { state, transactions } = this.innerView.state.applyTransaction(tr); this.innerView.updateState(state); - if (!tr.getMeta("fromOutside")) { - const outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1); + if (!tr.getMeta('fromOutside')) { + const outerTr = this.outerView.state.tr, + offsetMap = StepMap.offset(this.getPos() + 1); for (const transaction of transactions) { for (const step of transaction.steps) { outerTr.step(step.map(offsetMap)); @@ -117,11 +120,11 @@ export class FootnoteView { if (start !== null) { let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content); const overlap = start - Math.min(endA, endB); - if (overlap > 0) { endA += overlap; endB += overlap; } - this.innerView.dispatch( - state.tr - .replace(start, endB, node.slice(start, endA)) - .setMeta("fromOutside", true)); + if (overlap > 0) { + endA += overlap; + endB += overlap; + } + this.innerView.dispatch(state.tr.replace(start, endB, node.slice(start, endA)).setMeta('fromOutside', true)); } } return true; @@ -139,4 +142,3 @@ export class FootnoteView { return true; } } - diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 8407eee96..80832c9be 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1611,7 +1611,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (this.ProseRef?.children[0] !== e.nativeEvent.target) return; - this.autoLink(); + if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) { + this.autoLink(); + } FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined); if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) { RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined); diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index ff05dcdcb..d9bc2d981 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2048,7 +2048,7 @@ export class PresBox extends ViewBoxBaseComponent() { {this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}}>
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}> - +
([ @@ -115,9 +115,12 @@ export class SchemaHeaderField extends ObjectField { } [ToScriptString]() { - return `header(${this.heading},${this.type},${this.width}})`; + return `schemaHeaderField("${this.heading}","${this.color}",${this.type},${this.width},${this.desc},${this.collapsed})`; } [ToString]() { return `SchemaHeaderField`; } } +ScriptingGlobals.add(function schemaHeaderField(heading: string, color: string, type: number, width: number, desc?: boolean, collapsed?: boolean) { + return new SchemaHeaderField(heading, color, type, width, desc, collapsed); +}); -- cgit v1.2.3-70-g09d2 From 294412015c0f3dbfaa8982f1dcab100fbfdd036f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 1 Feb 2023 02:22:00 -0500 Subject: fixed ungrouping documents on video/image/etc. fixed undoing deleting collections to reset annotationOn field. fixed setting size in text box with richtext menu buttons and not losing focus and having stored marks get lost. --- src/client/views/DocComponent.tsx | 11 +-- .../views/collections/CollectionCarouselView.tsx | 94 ++++++++++++---------- .../views/collections/CollectionStackingView.tsx | 5 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 20 ++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 ++ 6 files changed, 81 insertions(+), 73 deletions(-) (limited to 'src') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 78ab2b3d4..7c81d92d4 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -151,13 +151,10 @@ export function ViewBoxAnnotatableComponent

() const indocs = doc instanceof Doc ? [doc] : doc; const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin); if (docs.length) { - setTimeout(() => - docs.map(doc => { - // this allows 'addDocument' to see the annotationOn field in order to create a pushin - Doc.SetInPlace(doc, 'followLinkToggle', undefined, true); - doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, 'annotationOn', undefined, true); - }) - ); + docs.map(doc => { + Doc.SetInPlace(doc, 'followLinkToggle', undefined, true); + doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, 'annotationOn', undefined, true); + }); const targetDataDoc = this.dataDoc; const value = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]); const toRemove = value.filter(v => docs.includes(v)); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index abb4b6bc6..32f6207ed 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -9,54 +9,58 @@ import { DragManager } from '../../util/DragManager'; import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; -import "./CollectionCarouselView.scss"; +import './CollectionCarouselView.scss'; import { CollectionSubView } from './CollectionSubView'; @observer export class CollectionCarouselView extends CollectionSubView() { private _dropDisposer?: DragManager.DragDropDisposer; - componentWillUnmount() { this._dropDisposer?.(); } + componentWillUnmount() { + this._dropDisposer?.(); + } - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { + //used for stacking and masonry view this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } - } + }; advance = (e: React.MouseEvent) => { e.stopPropagation(); this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + 1) % this.childLayoutPairs.length; - } + }; goback = (e: React.MouseEvent) => { e.stopPropagation(); this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; - } - captionStyleProvider = (doc: (Doc | undefined), captionProps: Opt, property: string): any => { + }; + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { // first look for properties on the document in the carousel, then fallback to properties on the container - const childValue = doc?.["caption-" + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined; + const childValue = doc?.['caption-' + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this.props.styleProvider?.(this.layoutDoc, captionProps, property); - } + }; panelHeight = () => this.props.PanelHeight() - (StrCast(this.layoutDoc._showCaption) ? 50 : 0); onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); onContentClick = () => ScriptCast(this.layoutDoc.onChildClick); @computed get content() { const index = NumCast(this.layoutDoc._itemIndex); const curDoc = this.childLayoutPairs?.[index]; - const captionProps = { ...OmitKeys(this.props, ["setHeight",]).omit, fieldKey: "caption" }; - const marginX = NumCast(this.layoutDoc["caption-xMargin"]); - const marginY = NumCast(this.layoutDoc["caption-yMargin"]); + const captionProps = { ...OmitKeys(this.props, ['setHeight']).omit, fieldKey: 'caption' }; + const marginX = NumCast(this.layoutDoc['caption-xMargin']); + const marginY = NumCast(this.layoutDoc['caption-yMargin']); const showCaptions = StrCast(this.layoutDoc._showCaption); - return !(curDoc?.layout instanceof Doc) ? (null) : + return !(curDoc?.layout instanceof Doc) ? null : ( <>

-
-
- +
- ; + + ); } @computed get buttons() { - return <> -
- -
-
- -
- ; + return ( + <> +
+ +
+
+ +
+ + ); } render() { - return
- {this.content} - {this.props.Document._chromeHidden ? (null) : this.buttons} -
; + return ( +
+ {this.content} + {this.props.Document._chromeHidden ? null : this.buttons} +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index acf59b5da..2f495d55c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -639,6 +639,7 @@ export class CollectionStackingView extends CollectionSubView (this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1], i === 0))); } + return35 = () => 35; @computed get buttonMenu() { const menuDoc: Doc = Cast(this.rootDoc.buttonMenuDoc, Doc, null); // TODO:glr Allow support for multiple buttons @@ -660,8 +661,8 @@ export class CollectionStackingView extends CollectionSubView 35} - PanelHeight={() => 35} + PanelWidth={this.return35} + PanelHeight={this.return35} renderDepth={this.props.renderDepth} focus={emptyFunction} styleProvider={this.props.styleProvider} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5cf4cb31f..695d500e9 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -12,7 +12,7 @@ import { ObjectField } from '../../../../fields/ObjectField'; import { RichTextField } from '../../../../fields/RichTextField'; import { listSpec } from '../../../../fields/Schema'; import { ScriptField } from '../../../../fields/ScriptField'; -import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; +import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; @@ -269,7 +269,7 @@ export class CollectionFreeFormView extends CollectionSubView= -1e-4 && curTime <= endTime); + return dispTime === -1 || curTime === -1 || (curTime - dispTime >= -1e-4 && curTime <= endTime); } @action @@ -1344,15 +1344,18 @@ export class CollectionFreeFormView extends CollectionSubView { const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; doc.y = pt[1]; return doc; }) - ) || false + ) && + (!docContext || this.props.removeDocument?.(docContext))) || + false ); case OpenWhere.inPlace: if (this.layoutDoc.isInPlaceContainer) { @@ -1747,7 +1750,6 @@ export class CollectionFreeFormView extends CollectionSubView Doc.toggleNativeDimensions(this.layoutDoc, 1, this.nativeWidth, this.nativeHeight); onContextMenu = (e: React.MouseEvent) => { - if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; + if (this.props.isAnnotationOverlay || !ContextMenu.Instance) return; const appearance = ContextMenu.Instance.findByDescription('Appearance...'); const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : []; @@ -1786,7 +1788,7 @@ export class CollectionFreeFormView extends CollectionSubView TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" }); - this.props.ContainingCollectionView && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); + appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' }); this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: () => this.transcribeStrokes(false), icon: 'font' }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index dcbadc5f3..0b7854926 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -433,25 +433,15 @@ export class MarqueeView extends React.Component { const selected = this.marqueeSelect(false); + const activeFrame = selected.reduce((v, d) => v ?? Cast(d._activeFrame, 'number', null), undefined as number | undefined); if (e instanceof KeyboardEvent ? 'cg'.includes(e.key) : true) { - selected.map( - action(d => { - const dx = NumCast(d.x); - const dy = NumCast(d.y); - delete d.x; - delete d.y; - delete d.activeFrame; - delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - d.x = dx - this.Bounds.left - this.Bounds.width / 2; - d.y = dy - this.Bounds.top - this.Bounds.height / 2; - return d; - }) - ); this.props.removeDocument?.(selected); } - // TODO: nda - this is the code to actually get a new grouped collection + const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === 't' ? Docs.Create.StackingDocument : undefined, group); + newCollection._panX = this.Bounds.left + this.Bounds.width / 2; + newCollection._panY = this.Bounds.top + this.Bounds.height / 2; + newCollection._currentFrame = activeFrame; this.props.addDocument?.(newCollection); this.props.selectDocuments([newCollection]); MarqueeOptionsMenu.Instance.fadeOut(true); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 80832c9be..619c59f0e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1612,7 +1612,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (this.ProseRef?.children[0] !== e.nativeEvent.target) return; if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) { + const stordMarks = this._editorView?.state.storedMarks?.slice(); this.autoLink(); + if (this._editorView?.state.tr) { + const tr = stordMarks?.reduce((tr, m) => { + tr.addStoredMark(m); + return tr; + }, this._editorView.state.tr); + tr && this._editorView.dispatch(tr); + } } FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined); if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) { -- cgit v1.2.3-70-g09d2