diff options
Diffstat (limited to 'src/client/views/nodes/DocumentContentsView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 143 |
1 files changed, 32 insertions, 111 deletions
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e729e2fa2..18529a429 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,67 +1,24 @@ +/* eslint-disable react/require-default-props */ 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 { OmitKeys } from '../../../ClientUtils'; +import { Without, emptyPath } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { AclPrivate, DocData } from '../../../fields/DocSymbols'; import { ScriptField } from '../../../fields/ScriptField'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -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 { 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 { ComparisonBox } from './ComparisonBox'; -import { DataVizBox } from './DataVizBox/DataVizBox'; +import { ObservableReactComponent, ObserverJsxParser } from '../ObservableReactComponent'; import './DocumentView.scss'; -import { EquationBox } from './EquationBox'; -import { FieldView, FieldViewProps } from './FieldView'; -import { FontIconBox } from './FontIconBox/FontIconBox'; -import { FunctionPlotBox } from './FunctionPlotBox'; -import { ImageBox } from './ImageBox'; -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 { VideoBox } from './VideoBox'; -import { WebBox } from './WebBox'; -import { FormattedTextBox } from './formattedText/FormattedTextBox'; -import { ImportElementBox } from './importBox/ImportElementBox'; -import { PresBox } from './trails/PresBox'; +import { FieldViewProps } from './FieldView'; type BindingProps = Without<FieldViewProps, 'fieldKey'>; export interface JsxBindings { props: BindingProps; } -class ObserverJsxParser1 extends JsxParser { - constructor(props: any) { - super(props); - observer(this as any); - } -} - -export const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; - interface HTMLtagProps { Document: Doc; htmltag: string; @@ -71,8 +28,8 @@ interface HTMLtagProps { children?: JSX.Element[]; } -//"<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} overflow='hidden' position='absolute' width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'> <ImageBox {...props} fieldKey={'data'}/> <HTMLspan width='200px' top='0' height='35px' textAlign='center' paddingTop='10px' transform='translate(-40px, 45px) rotate(-45deg)' position='absolute' color='{this.bannerColor===`green`?`light`:`dark`}blue' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}blue'> {this.title}</HTMLspan></HTMLdiv>" -//"<HTMLdiv borderRadius='100px' overflow='hidden' position='absolute' width='100%' height='100%' +// "<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} overflow='hidden' position='absolute' width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'> <ImageBox {...props} fieldKey={'data'}/> <HTMLspan width='200px' top='0' height='35px' textAlign='center' paddingTop='10px' transform='translate(-40px, 45px) rotate(-45deg)' position='absolute' color='{this.bannerColor===`green`?`light`:`dark`}blue' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}blue'> {this.title}</HTMLspan></HTMLdiv>" +// "<HTMLdiv borderRadius='100px' overflow='hidden' position='absolute' width='100%' height='100%' // transform='rotate({2*this.x+this.y}deg)' // onClick = { this.bannerColor = this.bannerColor === 'red' ? 'green' : 'red' } > // <ImageBox {...props} fieldKey={'data'}/> @@ -85,22 +42,21 @@ interface HTMLtagProps { // </HTMLdiv>" @observer export class HTMLtag extends React.Component<HTMLtagProps> { - click = (e: React.MouseEvent) => { + click = () => { const clickScript = (this.props as any).onClick as Opt<ScriptField>; - clickScript?.script.run({ this: this.props.Document, self: this.props.Document, scale: this.props.scaling }); + clickScript?.script.run({ this: 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.Document, value: (e.target as any).textContent }); + onInputScript?.script.run({ this: this.props.Document, value: (e.target as any).textContent }); }; render() { const style: { [key: string]: any } = {}; 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) => { + const replacer = (match: any, expr: 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) => { + (ScriptField.MakeFunction(expr, { this: Doc.name, scale: 'number' })?.script.run({ this: this.props.Document, scale: this.props.scaling }).result as string) || ''; + Object.keys(divKeys).forEach((prop: string) => { const p = (this.props as any)[prop] as string; style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer); }); @@ -118,20 +74,28 @@ export interface DocumentContentsViewProps extends FieldViewProps { } @observer export class DocumentContentsView extends ObservableReactComponent<DocumentContentsViewProps> { + private static DefaultLayoutString: string; + /** + * Set of all available rendering componets for Docs (e.g., ImageBox, CollectionFreeFormView, etc) + */ + private static Components: { [key: string]: any }; + public static Init(defaultLayoutString: string, components:{ [key: string]: any}) { + DocumentContentsView.DefaultLayoutString = defaultLayoutString; + DocumentContentsView.Components = components; + } constructor(props: any) { super(props); makeObservable(this); } - @computed get layout(): string { TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '<p>awaiting layout</p>'; - if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, DocumentContentsView.DefaultLayoutString); const tempLayout = DocCast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')]); const layoutDoc = tempLayout ?? this.layoutDoc; const layout = Cast(layoutDoc[layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(layoutDoc.layout_fieldKey, 'layout')], 'string'); - if (layout === undefined) return this._props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString(); + if (layout === undefined) return this._props.Document.data ? "<FieldView {...props} fieldKey='data' />" : DocumentContentsView.DefaultLayoutString; if (typeof layout === 'string') return layout; return '<p>Loading layout</p>'; } @@ -158,7 +122,7 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte 'dontCenter', 'DataTransition', 'contextMenuItems', - //'onClick', // don't need to omit this since it will be set + // 'onClick', // don't need to omit this since it will be set 'onDoubleClickScript', 'onPointerDownScript', 'onPointerUpScript', @@ -187,21 +151,16 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte let layoutFrame = this.layout; // 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; - }; + const replacer = (match: any, prefix: string, expr: string, postfix: string) => prefix + ((ScriptField.MakeFunction(expr, { 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 Document={props.Document} scaling='${this._props.NativeDimScaling?.() || 1}' htmltag='${p1}'`; - }; + const replacer2 = (match: any, p1: string) => `<HTMLtag Document={props.Document} scaling='${this._props.NativeDimScaling?.() || 1}' htmltag='${p1}'`; layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2); // replace /HTML<tag> with </HTMLdiv> as in: </HTMLdiv> becomes </HTMLtag> - const replacer3 = (match: any, p1: string, offset: any, string: any) => { - return `</HTMLtag`; - }; + const replacer3 = (/* match: any, p1: string, offset: any, string: any */) => `</HTMLtag`; + layoutFrame = layoutFrame.replace(/<\/HTML([a-zA-Z0-9_-]+)/g, replacer3); // add onClick function to props @@ -211,7 +170,7 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte const code = XRegExp.matchRecursive(splits[1], '{', '}', '', { valueNames: ['between', 'left', 'match', 'right', 'between'] }); layoutFrame = splits[0] + ` ${func}={props.${func}} ` + splits[1].substring(code[1].end + 1); const script = code[1].value.replace(/^‘/, '').replace(/’$/, ''); // ‘’ are not valid quotes in javascript so get rid of them -- they may be present to make it easier to write complex scripts - see headerTemplate in currentUserUtils.ts - return ScriptField.MakeScript(script, { this: Doc.name, self: Doc.name, scale: 'number', value: 'string' }); + return ScriptField.MakeScript(script, { this: Doc.name, scale: 'number', value: 'string' }); } return undefined; // add input function to props @@ -231,48 +190,10 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte key={42} blacklistedAttrs={emptyPath} renderInWrapper={false} - components={{ - FormattedTextBox, - ImageBox, - FontIconBox, - LabelBox, - EquationBox, - FieldView, - CollectionFreeFormView, - CollectionDockingView, - CollectionSchemaView, - CollectionCalendarView, - CollectionView, - WebBox, - KeyValueBox, - PDFBox, - VideoBox, - AudioBox, - RecordingBox, - PresBox, - YoutubeBox, - PresElementBox, - SearchBox, - FunctionPlotBox, - DashWebRTCVideo, - LinkAnchorBox, - InkingStroke, - LinkBox, - ScriptingBox, - MapBox, - ScreenshotBox, - DataVizBox, - HTMLtag, - ComparisonBox, - LoadingBox, - PhysicsSimulationBox, - SchemaRowBox, - ImportElementBox, - MapPushpinBox, - }} + components={DocumentContentsView.Components} bindings={bindings} jsx={layoutFrame} - showWarnings={true} + showWarnings onError={(test: any) => { console.log('DocumentContentsView:' + test, bindings, layoutFrame); }} |