diff options
author | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-05-16 21:24:15 -0400 |
---|---|---|
committer | brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> | 2023-05-16 21:24:15 -0400 |
commit | 3d12a980fee4eb5689bffa6ec82c7899e1509fa9 (patch) | |
tree | 24ffd982396c53c74032303ba66bb6f72ced40f5 | |
parent | d8fe4e0b9924b6f7f6f79da7745642d68bef5436 (diff) | |
parent | 2e6cba3995d82acc15bd34a7035e4a5786795211 (diff) |
Merge branch 'master' into physics_simulation
17 files changed, 338 insertions, 301 deletions
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<P extends ViewBoxAnnotatableProps>() 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/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/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<DocumentViewProps>, property: string): any => { + }; + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<DocumentViewProps>, 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 : ( <> <div className="collectionCarouselView-image" key="image"> - <DocumentView {...OmitKeys(this.props, ["setHeight", "NativeWidth", "NativeHeight", "childLayoutTemplate", "childLayoutString"]).omit} + <DocumentView + {...OmitKeys(this.props, ['setHeight', 'NativeWidth', 'NativeHeight', 'childLayoutTemplate', 'childLayoutString']).omit} onDoubleClick={this.onContentDoubleClick} onClick={this.onContentClick} hideCaptions={showCaptions ? true : false} renderDepth={this.props.renderDepth + 1} - ContainingCollectionView={this} + ContainingCollectionView={this.props.CollectionView} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} Document={curDoc.layout} @@ -65,40 +69,46 @@ export class CollectionCarouselView extends CollectionSubView() { bringToFront={returnFalse} /> </div> - <div className="collectionCarouselView-caption" key="caption" + <div + className="collectionCarouselView-caption" + key="caption" style={{ - display: showCaptions ? undefined : "none", + display: showCaptions ? undefined : 'none', borderRadius: this.props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding), - marginRight: marginX, marginLeft: marginX, - width: `calc(100% - ${marginX * 2}px)` + marginRight: marginX, + marginLeft: marginX, + width: `calc(100% - ${marginX * 2}px)`, }}> - <FormattedTextBox key={index} {...captionProps} - fieldKey={showCaptions} - styleProvider={this.captionStyleProvider} - Document={curDoc.layout} - DataDoc={undefined} /> + <FormattedTextBox key={index} {...captionProps} fieldKey={showCaptions} styleProvider={this.captionStyleProvider} Document={curDoc.layout} DataDoc={undefined} /> </div> - </>; + </> + ); } @computed get buttons() { - return <> - <div key="back" className="carouselView-back" onClick={this.goback}> - <FontAwesomeIcon icon={"chevron-left"} size={"2x"} /> - </div> - <div key="fwd" className="carouselView-fwd" onClick={this.advance}> - <FontAwesomeIcon icon={"chevron-right"} size={"2x"} /> - </div> - </>; + return ( + <> + <div key="back" className="carouselView-back" onClick={this.goback}> + <FontAwesomeIcon icon={'chevron-left'} size={'2x'} /> + </div> + <div key="fwd" className="carouselView-fwd" onClick={this.advance}> + <FontAwesomeIcon icon={'chevron-right'} size={'2x'} /> + </div> + </> + ); } render() { - return <div className="collectionCarouselView-outer" ref={this.createDashEventsTarget} - style={{ - background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), - color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color), - }}> - {this.content} - {this.props.Document._chromeHidden ? (null) : this.buttons} - </div>; + return ( + <div + className="collectionCarouselView-outer" + ref={this.createDashEventsTarget} + style={{ + background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), + color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color), + }}> + {this.content} + {this.props.Document._chromeHidden ? null : this.buttons} + </div> + ); } -}
\ No newline at end of file +} 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<CMVFieldRowProps> { - @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<HTMLDivElement> = React.createRef(); @@ -65,11 +71,11 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr this.props.observeHeight(ele); this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this)); } - } + }; @action componentDidMount() { - this.heading = this.props.headingObject?.heading || ""; - this.color = this.props.headingObject?.color || "#f1efeb"; + this.heading = this.props.headingObject?.heading || ''; + this.color = this.props.headingObject?.color || '#f1efeb'; this.collapsed = this.props.headingObject?.collapsed || false; } componentWillUnmount() { @@ -85,14 +91,13 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr const trueHeight = rawHeight * transformScale; this.props.setDocHeight(this.heading, trueHeight); } - } + }; @undoBatch rowDrop = action((e: Event, de: DragManager.DropEvent) => { 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<CMVFieldRowPr getValue = (value: string): any => { 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<CMVFieldRowPr return true; } return false; - } + }; @action changeColumnColor = (color: string) => { 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<CMVFieldRowPr DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY); } return true; - } + }; @action headerDown = (e: React.PointerEvent<HTMLDivElement>) => { @@ -193,7 +200,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr setupMoveUpEvents(this, e, this.headerMove, emptyFunction, e => !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<CMVFieldRowPr if (Doc.Get(doc, key, true)) return true; }); return false; - } + }; renderColorPicker = () => { 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 ( <div className="collectionStackingView-colorPicker"> <div className="colorOptions"> - <div className={"colorPicker" + (selected === pink ? " active" : "")} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div> - <div className={"colorPicker" + (selected === purple ? " active" : "")} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div> - <div className={"colorPicker" + (selected === blue ? " active" : "")} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div> - <div className={"colorPicker" + (selected === yellow ? " active" : "")} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div> - <div className={"colorPicker" + (selected === red ? " active" : "")} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div> - <div className={"colorPicker" + (selected === gray ? " active" : "")} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div> - <div className={"colorPicker" + (selected === green ? " active" : "")} style={{ backgroundColor: green }} onClick={() => this.changeColumnColor(green!)}></div> - <div className={"colorPicker" + (selected === cyan ? " active" : "")} style={{ backgroundColor: cyan }} onClick={() => this.changeColumnColor(cyan!)}></div> - <div className={"colorPicker" + (selected === orange ? " active" : "")} style={{ backgroundColor: orange }} onClick={() => this.changeColumnColor(orange!)}></div> + <div className={'colorPicker' + (selected === pink ? ' active' : '')} style={{ backgroundColor: pink }} onClick={() => this.changeColumnColor(pink!)}></div> + <div className={'colorPicker' + (selected === purple ? ' active' : '')} style={{ backgroundColor: purple }} onClick={() => this.changeColumnColor(purple!)}></div> + <div className={'colorPicker' + (selected === blue ? ' active' : '')} style={{ backgroundColor: blue }} onClick={() => this.changeColumnColor(blue!)}></div> + <div className={'colorPicker' + (selected === yellow ? ' active' : '')} style={{ backgroundColor: yellow }} onClick={() => this.changeColumnColor(yellow!)}></div> + <div className={'colorPicker' + (selected === red ? ' active' : '')} style={{ backgroundColor: red }} onClick={() => this.changeColumnColor(red!)}></div> + <div className={'colorPicker' + (selected === gray ? ' active' : '')} style={{ backgroundColor: gray }} onClick={() => this.changeColumnColor(gray)}></div> + <div className={'colorPicker' + (selected === green ? ' active' : '')} style={{ backgroundColor: green }} onClick={() => this.changeColumnColor(green!)}></div> + <div className={'colorPicker' + (selected === cyan ? ' active' : '')} style={{ backgroundColor: cyan }} onClick={() => this.changeColumnColor(cyan!)}></div> + <div className={'colorPicker' + (selected === orange ? ' active' : '')} style={{ backgroundColor: orange }} onClick={() => this.changeColumnColor(orange!)}></div> </div> </div> ); - } + }; - 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 (<div className="collectionStackingView-optionPicker"> - <div className="optionOptions"> - <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.toggleAlias}>Create Alias</div> - <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.deleteRow}>Delete</div> + return ( + <div className="collectionStackingView-optionPicker"> + <div className="optionOptions"> + <div className={'optionPicker' + (selected === true ? ' active' : '')} onClick={this.toggleAlias}> + Create Alias + </div> + <div className={'optionPicker' + (selected === true ? ' active' : '')} onClick={this.deleteRow}> + Delete + </div> + </div> </div> - </div>); - } + ); + }; @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) : - <div style={{ position: "relative" }}> - {showChrome ? - <div className="collectionStackingView-addDocumentButton" + return this.collapsed ? null : ( + <div style={{ position: 'relative' }}> + {showChrome ? ( + <div + className="collectionStackingView-addDocumentButton" style={{ //width: style.columnWidth / style.numGroupColumns, - padding: `${NumCast(this.props.parent.layoutDoc._yPadding, this.props.parent.yMargin)}px 0px 0px 0px` + padding: `${NumCast(this.props.parent.layoutDoc._yPadding, this.props.parent.yMargin)}px 0px 0px 0px`, }}> - <EditableView - GetValue={returnEmptyString} - SetValue={this.addDocument} - textCallback={this.textCallback} - contents={"+ NEW"} - toggle={this.toggleVisibility} /> - </div> : null - } - <div className={`collectionStackingView-masonryGrid`} + <EditableView GetValue={returnEmptyString} SetValue={this.addDocument} textCallback={this.textCallback} contents={'+ NEW'} /> + </div> + ) : null} + <div + className={`collectionStackingView-masonryGrid`} ref={this._contRef} style={{ padding: stackPad, width: this.props.parent.NodeWidth, gridGap: this.props.parent.gridGap, - gridTemplateColumns: numberRange(rows).reduce((list: string, i: any) => 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} </div> - </div>; + </div> + ); } @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 = <EditableView - GetValue={() => evContents} - SetValue={this.headingChanged} - contents={evContents} - oneLine={true} - toggle={this.toggleVisibility} />; - return this.props.Document.miniHeaders ? - <div className="collectionStackingView-miniHeader"> - {editableHeaderView} - </div> : - !this.props.headingObject ? (null) : - <div className="collectionStackingView-sectionHeader" ref={this._headerRef} > - <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} - title={evContents === `NO ${key.toUpperCase()} VALUE` ? - `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""} - style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this.color : "lightgrey" }}> - {noChrome ? evContents : editableHeaderView} - {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : - <div className="collectionStackingView-sectionColor"> - <button className="collectionStackingView-sectionColorButton" onClick={action(e => this._paletteOn = !this._paletteOn)}> - <FontAwesomeIcon icon="palette" size="lg" /> + const evContents = this.heading ? this.heading : this.props.type && this.props.type === 'number' ? '0' : `NO ${key.toUpperCase()} VALUE`; + const editableHeaderView = <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} />; + return this.props.Document.miniHeaders ? ( + <div className="collectionStackingView-miniHeader">{editableHeaderView}</div> + ) : !this.props.headingObject ? null : ( + <div className="collectionStackingView-sectionHeader" ref={this._headerRef}> + <div + className="collectionStackingView-sectionHeader-subCont" + onPointerDown={this.headerDown} + title={evContents === `NO ${key.toUpperCase()} VALUE` ? `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ''} + style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this.color : 'lightgrey' }}> + {noChrome ? evContents : editableHeaderView} + {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( + <div className="collectionStackingView-sectionColor"> + <button className="collectionStackingView-sectionColorButton" onClick={action(e => (this._paletteOn = !this._paletteOn))}> + <FontAwesomeIcon icon="palette" size="lg" /> + </button> + {this._paletteOn ? this.renderColorPicker() : null} + </div> + )} + {noChrome ? null : ( + <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}> + <FontAwesomeIcon icon={this.collapsed ? 'chevron-down' : 'chevron-up'} size="lg" /> + </button> + )} + {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( + <div className="collectionStackingView-sectionOptions"> + <Flyout anchorPoint={anchorPoints.TOP_CENTER} content={this.renderMenu()}> + <button className="collectionStackingView-sectionOptionButton"> + <FontAwesomeIcon icon="ellipsis-v" size="lg" /> </button> - {this._paletteOn ? this.renderColorPicker() : (null)} - </div> - } - {noChrome ? (null) : <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}> - <FontAwesomeIcon icon={this.collapsed ? "chevron-down" : "chevron-up"} size="lg" /> - </button>} - {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) : - <div className="collectionStackingView-sectionOptions"> - <Flyout anchorPoint={anchorPoints.TOP_CENTER} content={this.renderMenu()}> - <button className="collectionStackingView-sectionOptionButton"> - <FontAwesomeIcon icon="ellipsis-v" size="lg" /> - </button> - </Flyout> - </div> - } - </div> - </div>; + </Flyout> + </div> + )} + </div> + </div> + ); } render() { const background = this._background; - return <div className="collectionStackingView-masonrySection" - style={{ width: this.props.parent.NodeWidth, background }} - ref={this.createRowDropRef} - onPointerEnter={this.pointerEnteredRow} - onPointerLeave={this.pointerLeaveRow} - > - {this.headingView} - {this.contentLayout} - </div >; + return ( + <div className="collectionStackingView-masonrySection" style={{ width: this.props.parent.NodeWidth, background }} ref={this.createRowDropRef} onPointerEnter={this.pointerEnteredRow} onPointerLeave={this.pointerLeaveRow}> + {this.headingView} + {this.contentLayout} + </div> + ); } -}
\ 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/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<Partial<collection return sections.map((section, i) => (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<Partial<collection rootSelected={this.props.isSelected} removeDocument={this.props.removeDocument} ScreenToLocalTransform={Transform.Identity} - PanelWidth={() => 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/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<CSVFieldC @observable private _background = 'inherit'; private dropDisposer?: DragManager.DragDropDisposer; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _headerRef: React.RefObject<HTMLDivElement> = React.createRef(); @observable _paletteOn = false; @@ -75,7 +76,16 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC } }; + @action + componentDidMount() { + this._disposers.collapser = reaction( + () => 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<CSVFieldC @action collapseSection = () => { this.props.headingObject?.setCollapsed(!this.props.headingObject.collapsed); - this.toggleVisibility(); + this.collapsed = BoolCast(this.props.headingObject?.collapsed); }; headerDown = (e: React.PointerEvent<HTMLDivElement>) => setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); @@ -275,7 +285,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC const heading = this._heading; const columnYMargin = this.props.headingObject ? 0 : this.props.yMargin; const uniqueHeadings = headings.map((i, idx) => 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 ? ( <div key={heading} @@ -285,29 +296,24 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC marginTop: this.props.yMargin, width: this.props.columnWidth / (uniqueHeadings.length + (this.props.chromeHidden ? 0 : 1) || 1), }}> - <div className={'collectionStackingView-collapseBar' + (this.props.headingObject.collapsed === true ? ' active' : '')} onClick={this.collapseSection}></div> {/* 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. */} <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} - title={evContents === `NO ${key.toUpperCase()} VALUE` ? `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ''} - style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : 'inherit' }}> - <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} toggle={this.toggleVisibility} /> - {evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( - <div className="collectionStackingView-sectionColor"> - <button className="collectionStackingView-sectionColorButton" onClick={action(e => (this._paletteOn = !this._paletteOn))}> - <FontAwesomeIcon icon="palette" size="lg" /> - </button> - {this._paletteOn ? this.renderColorPicker() : null} - </div> - )} - { - <button className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}> - <FontAwesomeIcon icon="trash" size="lg" /> + title={evContents === noValueHeader ? `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ''} + style={{ background: evContents !== noValueHeader ? this._color : 'inherit' }}> + <EditableView GetValue={() => evContents} SetValue={this.headingChanged} contents={evContents} oneLine={true} /> + <div className="collectionStackingView-sectionColor" style={{ display: evContents === noValueHeader ? 'none' : undefined }}> + <button className="collectionStackingView-sectionColorButton" onClick={action(e => (this._paletteOn = !this._paletteOn))}> + <FontAwesomeIcon icon="palette" size="lg" /> </button> - } - {evContents === `NO ${key.toUpperCase()} VALUE` ? null : ( + {this._paletteOn ? this.renderColorPicker() : null} + </div> + <button className="collectionStackingView-sectionDelete" onClick={this.deleteColumn}> + <FontAwesomeIcon icon="trash" size="lg" /> + </button> + {/* {evContents === noValueHeader ? null : ( <div className="collectionStackingView-sectionOptions"> <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}> <button className="collectionStackingView-sectionOptionButton"> @@ -315,8 +321,13 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC </button> </Flyout> </div> - )} + )} */} </div> + <div + className={'collectionStackingView-collapseBar' + (this.props.headingObject.collapsed === true ? ' active' : '')} + style={{ display: this.props.headingObject.collapsed === true ? 'block' : undefined }} + onClick={this.collapseSection} + /> </div> ) : null; const templatecols = `${this.props.columnWidth / this.props.numGroupColumns}px `; @@ -348,14 +359,13 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC //TODO: would be great if there was additional space beyond the frame, so that you can actually see your // bottom note //TODO: ok, so we are using a single column, and this is it! - <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" style={{ width: this.props.columnWidth / this.props.numGroupColumns, marginBottom: 10, marginLeft: 25 }}> + <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton" style={{ width: 'calc(100% - 25px)', maxWidth: this.props.columnWidth / this.props.numGroupColumns - 25, marginBottom: 10 }}> <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.textCallback} placeholder={"Type ':' for commands"} contents={<FontAwesomeIcon icon={'plus'} />} - toggle={this.toggleVisibility} menuCallback={this.menuCallback} /> </div> 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/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<Partial<collection const dispTime = NumCast(doc._timecodeToShow, -1); const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5); const curTime = NumCast(this.Document._currentTimecode, -1); - return dispTime === -1 || (curTime - dispTime >= -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<Partial<collection case OpenWhere.inParent: return this.props.addDocument?.(doc) || false; case OpenWhere.inParentFromScreen: + const docContext = DocCast((doc instanceof Doc ? doc : doc?.[0])?.context); return ( - this.props.addDocument?.( + (this.props.addDocument?.( (doc instanceof Doc ? [doc] : doc).map(doc => { 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<Partial<collection doc.y = scr?.[1]; }); this.props.addDocTab(childDocs as any as Doc, OpenWhere.inParentFromScreen); - this.props.ContainingCollectionView?.removeDocument(this.props.Document); }; @undoBatch @@ -1766,7 +1768,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection toggleNativeDimensions = () => 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<Partial<collection }); appearanceItems.push({ description: `Pin View`, event: () => 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<SubCollectionViewProps & Marque @action collection = (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => { 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/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<FieldViewProps> { 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<ViewBoxAnnotatableProps } return this.props.styleProvider?.(doc, props, property); }; - pointerEvents = () => (!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..619c59f0e 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1611,7 +1611,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps @action onBlur = (e: any) => { 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) { + 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)) { 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<FieldViewProps>() { </div> <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}> <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}> - <FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} /> + <FontAwesomeIcon color={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'red' : undefined} icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} /> </div> </Tooltip> <div diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts index 0b51db70b..4b1855cb0 100644 --- a/src/fields/SchemaHeaderField.ts +++ b/src/fields/SchemaHeaderField.ts @@ -2,7 +2,7 @@ import { Deserializable } from '../client/util/SerializationHelper'; import { serializable, primitive } from 'serializr'; import { ObjectField } from './ObjectField'; import { Copy, ToScriptString, ToString, OnUpdate } from './FieldSymbols'; -import { scriptingGlobal } from '../client/util/ScriptingGlobals'; +import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { ColumnType } from '../client/views/collections/collectionSchema/CollectionSchemaView'; export const PastelSchemaPalette = new Map<string, string>([ @@ -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); +}); |