diff options
Diffstat (limited to 'src/client/views/nodes/DocumentContentsView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 127 |
1 files changed, 62 insertions, 65 deletions
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e1de2fa76..07e179246 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,54 +1,52 @@ -import { computed } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import JsxParser from 'react-jsx-parser'; +import * as XRegExp from 'xregexp'; +import { OmitKeys, Without, emptyPath } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; -import { AclPrivate } from '../../../fields/DocSymbols'; +import { AclPrivate, DocData } from '../../../fields/DocSymbols'; import { ScriptField } from '../../../fields/ScriptField'; import { Cast, StrCast } from '../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -import { emptyPath, OmitKeys, Without } from '../../../Utils'; -import { DirectoryImportBox } from '../../util/Import & Export/DirectoryImportBox'; +import { InkingStroke } from '../InkingStroke'; +import { ObservableReactComponent } from '../ObservableReactComponent'; +import { CollectionCalendarView } from '../collections/CollectionCalendarView'; import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { CollectionView } from '../collections/CollectionView'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionSchemaView } from '../collections/collectionSchema/CollectionSchemaView'; import { SchemaRowBox } from '../collections/collectionSchema/SchemaRowBox'; -import { CollectionView } from '../collections/CollectionView'; -import { InkingStroke } from '../InkingStroke'; import { PresElementBox } from '../nodes/trails/PresElementBox'; import { SearchBox } from '../search/SearchBox'; import { DashWebRTCVideo } from '../webcam/DashWebRTCVideo'; import { YoutubeBox } from './../../apis/youtube/YoutubeBox'; import { AudioBox } from './AudioBox'; -import { ColorBox } from './ColorBox'; import { ComparisonBox } from './ComparisonBox'; import { DataVizBox } from './DataVizBox/DataVizBox'; -import { DocumentViewProps } from './DocumentView'; import './DocumentView.scss'; import { EquationBox } from './EquationBox'; import { FieldView, FieldViewProps } from './FieldView'; import { FontIconBox } from './FontIconBox/FontIconBox'; -import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { FunctionPlotBox } from './FunctionPlotBox'; import { ImageBox } from './ImageBox'; -import { ImportElementBox } from './importBox/ImportElementBox'; import { KeyValueBox } from './KeyValueBox'; import { LabelBox } from './LabelBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { LinkBox } from './LinkBox'; import { LoadingBox } from './LoadingBox'; import { MapBox } from './MapBox/MapBox'; +import { MapPushpinBox } from './MapBox/MapPushpinBox'; import { PDFBox } from './PDFBox'; import { PhysicsSimulationBox } from './PhysicsBox/PhysicsSimulationBox'; import { RecordingBox } from './RecordingBox'; import { ScreenshotBox } from './ScreenshotBox'; import { ScriptingBox } from './ScriptingBox'; -import { PresBox } from './trails/PresBox'; import { VideoBox } from './VideoBox'; import { WebBox } from './WebBox'; -import React = require('react'); -import XRegExp = require('xregexp'); -import { MapPushpinBox } from './MapBox/MapPushpinBox'; - -const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? +import { FormattedTextBox } from './formattedText/FormattedTextBox'; +import { ImportElementBox } from './importBox/ImportElementBox'; +import { PresBox } from './trails/PresBox'; type BindingProps = Without<FieldViewProps, 'fieldKey'>; export interface JsxBindings { @@ -66,7 +64,6 @@ export const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; interface HTMLtagProps { Document: Doc; - RootDoc: Doc; htmltag: string; onClick?: ScriptField; onInput?: ScriptField; @@ -90,18 +87,18 @@ interface HTMLtagProps { export class HTMLtag extends React.Component<HTMLtagProps> { click = (e: React.MouseEvent) => { const clickScript = (this.props as any).onClick as Opt<ScriptField>; - clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, scale: this.props.scaling }); + clickScript?.script.run({ this: this.props.Document, self: this.props.Document, scale: this.props.scaling }); }; onInput = (e: React.FormEvent<HTMLDivElement>) => { const onInputScript = (this.props as any).onInput as Opt<ScriptField>; - onInputScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, value: (e.target as any).textContent }); + onInputScript?.script.run({ this: this.props.Document, self: this.props.Document, value: (e.target as any).textContent }); }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ['children', 'htmltag', 'RootDoc', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; + const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; const replacer = (match: any, expr: string, offset: any, string: any) => { - // bcz: this executes a script to convert a propery expression string: { script } into a value - return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.RootDoc, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; + // bcz: this executes a script to convert a property expression string: { script } into a value + return (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ self: this.props.Document, this: this.props.Document, scale: this.props.scaling }).result as string) || ''; }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; @@ -116,71 +113,72 @@ export class HTMLtag extends React.Component<HTMLtagProps> { } } +export interface DocumentContentsViewProps extends FieldViewProps { + layoutFieldKey: string; +} @observer -export class DocumentContentsView extends React.Component< - DocumentViewProps & { - isSelected: (outsideReaction: boolean) => boolean; - select: (ctrl: boolean) => void; - NativeDimScaling?: () => number; - setHeight?: (height: number) => void; - layout_fieldKey: string; +export class DocumentContentsView extends ObservableReactComponent<DocumentContentsViewProps> { + constructor(props: any) { + super(props); + makeObservable(this); } -> { + @computed get layout(): string { TraceMobx(); - if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString; + if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '<p>awaiting layout</p>'; - if (this.props.layout_fieldKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layout_fieldKey ? this.props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); - if (layout === undefined) return this.props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString(); + if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); + if (layout === undefined) return this._props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '<p>Loading layout</p>'; } - get dataDoc() { - const proto = this.props.DataDoc || Doc.GetProto(this.props.Document); - return proto instanceof Promise ? undefined : proto; - } get layoutDoc() { // bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script - // const template: Doc = this.props.LayoutTemplate?.() || Doc.Layout(this.props.Document, this.props.layout_fieldKey ? Cast(this.props.Document[this.props.layout_fieldKey], Doc, null) : undefined); + // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); const template: Doc = - this.props.LayoutTemplate?.() || - (this.props.LayoutTemplateString && this.props.Document) || - (this.props.layout_fieldKey && StrCast(this.props.Document[this.props.layout_fieldKey]) && this.props.Document) || - Doc.Layout(this.props.Document, this.props.layout_fieldKey ? Cast(this.props.Document[this.props.layout_fieldKey], Doc, null) : undefined); - return Doc.expandTemplateLayout(template, this.props.Document); + this._props.LayoutTemplate?.() || + (this._props.LayoutTemplateString && this._props.Document) || + (this._props.layoutFieldKey && StrCast(this._props.Document[this._props.layoutFieldKey]) && this._props.Document) || + Doc.Layout(this._props.Document, this._props.layoutFieldKey ? Cast(this._props.Document[this._props.layoutFieldKey], Doc, null) : undefined); + return Doc.expandTemplateLayout(template, this._props.Document); } CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings { const docOnlyProps = [ - // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews + // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews 'hideResizeHandles', 'hideTitle', - 'contentPointerEvents', - 'radialMenu', + 'bringToFront', + 'childContentPointerEvents', 'LayoutTemplateString', 'LayoutTemplate', + 'layoutFieldKey', 'dontCenter', 'contextMenuItems', - 'onClick', - 'onDoubleClick', - 'onPointerDown', - 'onPointerUp', + //'onClick', // don't need to omit this since it will be set + 'onDoubleClickScript', + 'onPointerDownScript', + 'onPointerUpScript', ]; - const list = { - ...OmitKeys(this.props, [...docOnlyProps], '').omit, - RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, - Document: this.layoutDoc, - DataDoc: this.dataDoc, - onClick: onClick, - onInput: onInput, + const templateDataDoc = this._props.TemplateDataDocument ?? (this.layoutDoc !== this._props.Document ? this._props.Document[DocData] : undefined); + const list: BindingProps & React.DetailedHTMLProps<React.HtmlHTMLAttributes<HTMLDivElement>, HTMLDivElement> = { + ...this._props, + Document: this.layoutDoc ?? this._props.Document, + TemplateDataDocument: templateDataDoc instanceof Promise ? undefined : templateDataDoc, + onClick: onClick as any as React.MouseEventHandler, // pass onClick script as if it were a real function -- it will be interpreted properly in the HTMLtag + onInput: onInput as any as React.FormEventHandler, + }; + return { + props: { + ...OmitKeys(list, [...docOnlyProps], '').omit, + }, }; - return { props: list }; } // componentWillUpdate(oldProps: any, newState: any) { - // // console.log("willupdate", oldProps, this.props); // bcz: if you get a message saying something invalidated because reactive props changed, then this method allows you to figure out which prop changed + // // console.log("willupdate", oldProps, this._props); // bcz: if you get a message saying something invalidated because reactive props changed, then this method allows you to figure out which prop changed // } @computed get renderData() { @@ -189,13 +187,13 @@ export class DocumentContentsView extends React.Component< // replace code content with a script >{content}< as in <HTMLdiv>{this.title}</HTMLdiv> const replacer = (match: any, prefix: string, expr: string, postfix: string, offset: any, string: any) => { - return prefix + ((ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string) || '') + postfix; + return prefix + ((ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this._props.Document }).result as string) || '') + postfix; }; layoutFrame = layoutFrame.replace(/(>[^{]*)[^=]\{([^.'][^<}]+)\}([^}]*<)/g, replacer); // replace HTML<tag> with corresponding HTML tag as in: <HTMLdiv> becomes <HTMLtag Document={props.Document} htmltag='div'> const replacer2 = (match: any, p1: string, offset: any, string: any) => { - return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} scaling='${this.props.NativeDimScaling?.() || 1}' htmltag='${p1}'`; + return `<HTMLtag Document={props.Document} scaling='${this._props.NativeDimScaling?.() || 1}' htmltag='${p1}'`; }; layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2); @@ -227,7 +225,7 @@ export class DocumentContentsView extends React.Component< TraceMobx(); const { bindings, layoutFrame } = this.renderData; - return this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate ? null : ( + return this._props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate ? null : ( <ObserverJsxParser key={42} blacklistedAttrs={emptyPath} @@ -235,7 +233,6 @@ export class DocumentContentsView extends React.Component< components={{ FormattedTextBox, ImageBox, - DirectoryImportBox, FontIconBox, LabelBox, EquationBox, @@ -243,6 +240,7 @@ export class DocumentContentsView extends React.Component< CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, + CollectionCalendarView, CollectionView, WebBox, KeyValueBox, @@ -255,7 +253,6 @@ export class DocumentContentsView extends React.Component< PresElementBox, SearchBox, FunctionPlotBox, - ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, |