diff options
Diffstat (limited to 'src/client/views/nodes/formattedText/DashFieldView.tsx')
-rw-r--r-- | src/client/views/nodes/formattedText/DashFieldView.tsx | 94 |
1 files changed, 67 insertions, 27 deletions
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index d2f7b5677..21ccf3bc7 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -1,35 +1,39 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable } from 'mobx'; import { observer } from 'mobx-react'; -import * as ReactDOM from 'react-dom'; +import { NodeSelection } from 'prosemirror-state'; +import * as ReactDOM from 'react-dom/client'; import { DataSym, Doc, DocListCast, Field } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; import { ComputedField } from '../../../../fields/ScriptField'; import { Cast, StrCast } from '../../../../fields/Types'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; +import { CollectionViewType } from '../../../documents/DocumentTypes'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; import React = require('react'); -import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; -import { Tooltip } from '@material-ui/core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { CollectionViewType } from '../../../documents/DocumentTypes'; export class DashFieldView { dom: HTMLDivElement; // container for label and value + root: any; + node: any; + tbox: FormattedTextBox; + unclickable = () => !this.tbox.props.isSelected() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { - const { boolVal, strVal } = DashFieldViewInternal.fieldContent(tbox.props.Document, tbox.rootDoc, node.attrs.fieldKey); - + this.node = node; + this.tbox = tbox; this.dom = document.createElement('div'); this.dom.style.width = node.attrs.width; this.dom.style.height = node.attrs.height; - this.dom.style.fontWeight = 'bold'; this.dom.style.position = 'relative'; this.dom.style.display = 'inline-block'; - this.dom.textContent = node.attrs.fieldKey.startsWith('#') ? node.attrs.fieldKey : node.attrs.fieldKey + ' ' + strVal; this.dom.onkeypress = function (e: any) { e.stopPropagation(); }; @@ -43,22 +47,44 @@ export class DashFieldView { e.stopPropagation(); }; - setTimeout(() => ReactDOM.render(<DashFieldViewInternal fieldKey={node.attrs.fieldKey} docid={node.attrs.docid} width={node.attrs.width} height={node.attrs.height} hideKey={node.attrs.hideKey} tbox={tbox} />, this.dom)); - (this as any).dom = this.dom; + this.root = ReactDOM.createRoot(this.dom); + this.root.render( + <DashFieldViewInternal + node={node} + unclickable={this.unclickable} + getPos={getPos} + fieldKey={node.attrs.fieldKey} + docId={node.attrs.docId} + width={node.attrs.width} + height={node.attrs.height} + hideKey={node.attrs.hideKey} + editable={node.attrs.editable} + tbox={tbox} + /> + ); } destroy() { - ReactDOM.unmountComponentAtNode(this.dom); + this.root.unmount(); + } + deselectNode() { + this.dom.classList.remove('ProseMirror-selectednode'); + } + selectNode() { + this.dom.classList.add('ProseMirror-selectednode'); } - selectNode() {} } interface IDashFieldViewInternal { fieldKey: string; - docid: string; + docId: string; hideKey: boolean; tbox: FormattedTextBox; width: number; height: number; + editable: boolean; + node: any; + getPos: any; + unclickable: () => boolean; } @observer @@ -74,8 +100,12 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna this._fieldKey = this.props.fieldKey; this._textBoxDoc = this.props.tbox.props.Document; - if (this.props.docid) { - DocServer.GetRefField(this.props.docid).then(action(async dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc))); + if (this.props.docId) { + DocServer.GetRefField(this.props.docId).then( + action(async dashDoc => { + dashDoc instanceof Doc && (this._dashDoc = dashDoc); + }) + ); } else { this._dashDoc = this.props.tbox.rootDoc; } @@ -116,7 +146,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna return ( <span className="dashFieldView-fieldSpan" - contentEditable={true} + contentEditable={!this.props.unclickable()} style={{ display: strVal.length < 2 ? 'inline-block' : undefined }} suppressContentEditableWarning={true} defaultValue={strVal} @@ -125,7 +155,13 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna r?.addEventListener('blur', e => r && this.updateText(r.textContent!, false)); r?.addEventListener( 'pointerdown', - action(e => e.stopPropagation()) + action(e => { + // let target = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span> + // while (target && !target.dataset?.targethrefs) target = target.parentElement; + this.props.tbox.EditorView!.dispatch(this.props.tbox.EditorView!.state.tr.setSelection(new NodeSelection(this.props.tbox.EditorView!.state.doc.resolve(this.props.getPos())))); + // FormattedTextBoxComment.update(this.props.tbox, this.props.tbox.EditorView!, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc); + // e.stopPropagation(); + }) ); }}> {strVal} @@ -138,6 +174,10 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna // we need to handle all key events on the input span or else they will propagate to prosemirror. @action fieldSpanKeyDown = (e: KeyboardEvent, span: HTMLSpanElement) => { + if (e.key === 'c' && (e.ctrlKey || e.metaKey)) { + navigator.clipboard.writeText(window.getSelection()?.toString() || ''); + return; + } if (e.key === 'Enter') { // handle the enter key by "submitting" the current text to Dash's database. this.updateText(span.textContent!, true); @@ -153,6 +193,9 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna } e.preventDefault(); //prevent default so that all the text in the prosemirror text box isn't selected } + if (!this.props.editable) { + e.preventDefault(); + } e.stopPropagation(); // we need to handle all events or else they will propagate to prosemirror. }; @@ -160,7 +203,6 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna updateText = (nodeText: string, forceMatch: boolean) => { if (nodeText) { const newText = nodeText.startsWith(':=') || nodeText.startsWith('=:=') ? ':=-computed-' : nodeText; - // look for a document whose id === the fieldKey being displayed. If there's a match, then that document // holds the different enumerated values for the field in the titles of its collected documents. // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down. @@ -178,7 +220,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna } else { if (Number(newText).toString() === newText) { if (this._fieldKey.startsWith('_')) Doc.Layout(this._textBoxDoc)[this._fieldKey] = Number(newText); - Doc.SetInPlace(this._dashDoc!, this._fieldKey, newText, true); + Doc.SetInPlace(this._dashDoc!, this._fieldKey, Number(newText), true); } else { const splits = newText.split(DashFieldViewInternal.multiValueDelimeter); if (this._fieldKey !== 'PARAMS' || !this._textBoxDoc[this._fieldKey] || this._dashDoc?.PARAMS) { @@ -207,7 +249,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna list.map(c => c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, '#f1efeb')); list.map(c => c.heading).indexOf('text') === -1 && list.push(new SchemaHeaderField('text', '#f1efeb')); alias._pivotField = this._fieldKey.startsWith('#') ? '#' : this._fieldKey; - this.props.tbox.props.addDocTab(alias, 'add:right'); + this.props.tbox.props.addDocTab(alias, OpenWhere.addRight); } }; @@ -266,14 +308,12 @@ export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> { document.addEventListener('pointerdown', hideMenu, true); }; render() { - const buttons = [ + return this.getElement( <Tooltip key="trash" title={<div className="dash-tooltip">{`Show Pivot Viewer for '${this._fieldKey}'`}</div>}> <button className="antimodeMenu-button" onPointerDown={this.showFields}> <FontAwesomeIcon icon="eye" size="lg" /> </button> - </Tooltip>, - ]; - - return this.getElement(buttons); + </Tooltip> + ); } } |