diff options
-rw-r--r-- | src/client/views/EditableView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionMasonryViewFieldRow.tsx | 311 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.scss | 21 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 58 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTimeView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/WebBoxRenderer.js | 4 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FootnoteView.tsx | 72 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 2 | ||||
-rw-r--r-- | src/fields/SchemaHeaderField.ts | 7 |
12 files changed, 257 insertions, 228 deletions
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<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/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/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..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<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) { + 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<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); +}); |