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/client'; import { DataSym, Doc, Field } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; import { Cast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell'; import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; import React = require('react'); 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) { 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.position = 'relative'; this.dom.style.display = 'inline-block'; this.dom.onkeypress = function (e: any) { e.stopPropagation(); }; this.dom.onkeydown = function (e: any) { e.stopPropagation(); }; this.dom.onkeyup = function (e: any) { e.stopPropagation(); }; this.dom.onmousedown = function (e: any) { e.stopPropagation(); }; this.root = ReactDOM.createRoot(this.dom); this.root.render( ); } destroy() { setTimeout(() => { try { this.root.unmount(); } catch {} }); } @action deselectNode() { this.dom.classList.remove('ProseMirror-selectednode'); } @action selectNode() { this.dom.classList.add('ProseMirror-selectednode'); } } interface IDashFieldViewInternal { fieldKey: string; docId: string; hideKey: boolean; tbox: FormattedTextBox; width: number; height: number; editable: boolean; node: any; getPos: any; unclickable: () => boolean; } @observer export class DashFieldViewInternal extends React.Component { _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; _fieldKey: string; _fieldStringRef = React.createRef(); @observable _dashDoc: Doc | undefined; @observable _expanded = false; constructor(props: IDashFieldViewInternal) { super(props); this._fieldKey = this.props.fieldKey; this._textBoxDoc = this.props.tbox.props.Document; if (this.props.docId) { DocServer.GetRefField(this.props.docId).then(action(dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc))); } else { this._dashDoc = this.props.tbox.rootDoc; } } componentWillUnmount() { this._reactionDisposer?.(); } // set the display of the field's value (checkbox for booleans, span of text for strings) @computed get fieldValueContent() { return !this._dashDoc ? null : (
(this._expanded = !this.props.editable ? !this._expanded : true))} style={{ fontSize: 'smaller', width: this.props.hideKey ? this.props.tbox.props.PanelWidth() - 20 : undefined }}> 100} columnWidth={this.props.hideKey ? () => this.props.tbox.props.PanelWidth() - 20 : returnZero} selectedCell={() => [this._dashDoc!, 0]} fieldKey={this._fieldKey} rowHeight={returnZero} isRowActive={() => this._expanded && this.props.editable} padding={0} getFinfo={emptyFunction} setColumnValues={returnFalse} allowCRs={true} oneLine={!this._expanded} finishEdit={action(() => (this._expanded = false))} />
); } createPivotForField = (e: React.MouseEvent) => { let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement(); if (container) { const embedding = Doc.MakeEmbedding(container.rootDoc); embedding._type_collection = CollectionViewType.Time; const colHdrKey = '_' + container.LayoutFieldKey + '_columnHeaders'; let list = Cast(embedding[colHdrKey], listSpec(SchemaHeaderField)); if (!list) { embedding[colHdrKey] = list = new List(); } 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')); embedding._pivotField = this._fieldKey.startsWith('#') ? 'tags' : this._fieldKey; this.props.tbox.props.addDocTab(embedding, OpenWhere.addRight); } }; // clicking on the label creates a pivot view collection of all documents // in the same collection. The pivot field is the fieldKey of this label onPointerDownLabelSpan = (e: any) => { setupMoveUpEvents(this, e, returnFalse, returnFalse, e => { DashFieldViewMenu.createFieldView = this.createPivotForField; DashFieldViewMenu.Instance.show(e.clientX, e.clientY + 16, this._fieldKey); }); }; render() { return (
{this.props.hideKey ? null : ( {this._fieldKey} )} {this.props.fieldKey.startsWith('#') ? null : this.fieldValueContent}
); } } @observer export class DashFieldViewMenu extends AntimodeMenu { static Instance: DashFieldViewMenu; static createFieldView: (e: React.MouseEvent) => void = emptyFunction; constructor(props: any) { super(props); DashFieldViewMenu.Instance = this; } @action showFields = (e: React.MouseEvent) => { DashFieldViewMenu.createFieldView(e); DashFieldViewMenu.Instance.fadeOut(true); }; @observable _fieldKey = ''; @action public show = (x: number, y: number, fieldKey: string) => { this._fieldKey = fieldKey; this.jumpTo(x, y, true); const hideMenu = () => { this.fadeOut(true); document.removeEventListener('pointerdown', hideMenu, true); }; document.addEventListener('pointerdown', hideMenu, true); }; render() { return this.getElement( {`Show Pivot Viewer for '${this._fieldKey}'`}}> ); } }