diff options
Diffstat (limited to 'src/client/views/nodes/DocumentContentsView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 259 |
1 files changed, 150 insertions, 109 deletions
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 96ac3e332..f1d8123da 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,48 +1,48 @@ -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import { AclPrivate, Doc, Opt } from "../../../fields/Doc"; -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 { CollectionDockingView } from "../collections/CollectionDockingView"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import { CollectionSchemaView } from "../collections/collectionSchema/CollectionSchemaView"; -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 { FontIconBox } from "./button/FontIconBox"; -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 { FilterBox } from "./FilterBox"; -import { FormattedTextBox, FormattedTextBoxProps } from "./formattedText/FormattedTextBox"; -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 { MapBox } from "./MapBox/MapBox"; -import { PDFBox } from "./PDFBox"; -import { RecordingBox } from "./RecordingBox"; -import { ScreenshotBox } from "./ScreenshotBox"; -import { ScriptingBox } from "./ScriptingBox"; -import { SliderBox } from "./SliderBox"; -import { PresBox } from "./trails/PresBox"; -import { VideoBox } from "./VideoBox"; -import { WebBox } from "./WebBox"; -import React = require("react"); -import XRegExp = require("xregexp"); +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import { AclPrivate, Doc, Opt } from '../../../fields/Doc'; +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 { CollectionDockingView } from '../collections/CollectionDockingView'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { CollectionSchemaView } from '../collections/collectionSchema/CollectionSchemaView'; +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 { FontIconBox } from './button/FontIconBox'; +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 { FilterBox } from './FilterBox'; +import { FormattedTextBox, FormattedTextBoxProps } from './formattedText/FormattedTextBox'; +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 { MapBox } from './MapBox/MapBox'; +import { PDFBox } from './PDFBox'; +import { RecordingBox } from './RecordingBox'; +import { ScreenshotBox } from './ScreenshotBox'; +import { ScriptingBox } from './ScriptingBox'; +import { SliderBox } from './SliderBox'; +import { PresBox } from './trails/PresBox'; +import { VideoBox } from './VideoBox'; +import { WebBox } from './WebBox'; +import React = require('react'); +import XRegExp = require('xregexp'); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -60,7 +60,6 @@ class ObserverJsxParser1 extends JsxParser { const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; - interface HTMLtagProps { Document: Doc; RootDoc: Doc; @@ -68,16 +67,17 @@ interface HTMLtagProps { onClick?: ScriptField; onInput?: ScriptField; scaling: number; + 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%' -// transform='rotate({2*this.x+this.y}deg)' +//"<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'}/> -// <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' +// <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> @@ -87,45 +87,51 @@ 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 }); - } + }; 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 }); - } + }; render() { const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "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 || ""; + const divKeys = OmitKeys(this.props, ['children', 'htmltag', 'RootDoc', '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) || ''; }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer); }); const Tag = this.props.htmltag as keyof JSX.IntrinsicElements; - return <Tag style={style} onClick={this.click} onInput={this.onInput as any}> - {this.props.children} - </Tag>; + return ( + <Tag style={style} onClick={this.click} onInput={this.onInput as any}> + {this.props.children} + </Tag> + ); } } @observer -export class DocumentContentsView extends React.Component<DocumentViewProps & FormattedTextBoxProps & { - isSelected: (outsideReaction: boolean) => boolean, - select: (ctrl: boolean) => void, - scaling?: () => number, - setHeight?: (height: number) => void, - layoutKey: string, -}> { +export class DocumentContentsView extends React.Component< + DocumentViewProps & + FormattedTextBoxProps & { + isSelected: (outsideReaction: boolean) => boolean; + select: (ctrl: boolean) => void; + scaling?: () => number; + setHeight?: (height: number) => void; + layoutKey: string; + } +> { @computed get layout(): string { TraceMobx(); if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString; - if (!this.layoutDoc) return "<p>awaiting layout</p>"; - if (this.props.layoutKey === "layout_keyValue") return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data")); - const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, "layout")], "string"); - if (layout === undefined) return this.props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : ""); - if (typeof layout === "string") return layout; - return "<p>Loading layout</p>"; + if (!this.layoutDoc) return '<p>awaiting layout</p>'; + if (this.props.layoutKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString('data')); + const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, 'layout')], 'string'); + if (layout === undefined) return this.props.Document.data ? "<FieldView {...props} fieldKey='data' />" : KeyValueBox.LayoutString(this.layoutDoc.proto ? 'proto' : ''); + if (typeof layout === 'string') return layout; + return '<p>Loading layout</p>'; } get dataDoc() { @@ -136,36 +142,39 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo const params = StrCast(this.props.Document.PARAMS); // 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.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined); - const template: Doc = this.props.LayoutTemplate?.() || (this.props.LayoutTemplateString && this.props.Document) || + const template: Doc = + this.props.LayoutTemplate?.() || + (this.props.LayoutTemplateString && this.props.Document) || (this.props.layoutKey && StrCast(this.props.Document[this.props.layoutKey]) && this.props.Document) || Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined); - return Doc.expandTemplateLayout(template, this.props.Document, params ? "(" + params + ")" : this.props.layoutKey); + return Doc.expandTemplateLayout(template, this.props.Document, params ? '(' + params + ')' : this.props.layoutKey); } 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 - "hideResizeHandles", - "hideTitle", - "treeViewDoc", - "contentPointerEvents", - "radialMenu", - "LayoutTemplateString", - "LayoutTemplate", - "dontCenter", - "ContentScaling", - "contextMenuItems", - "onClick", - "onDoubleClick", - "onPointerDown", - "onPointerUp", + const docOnlyProps = [ + // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews + 'hideResizeHandles', + 'hideTitle', + 'treeViewDoc', + 'contentPointerEvents', + 'radialMenu', + 'LayoutTemplateString', + 'LayoutTemplate', + 'dontCenter', + 'ContentScaling', + 'contextMenuItems', + 'onClick', + 'onDoubleClick', + 'onPointerDown', + 'onPointerUp', ]; const list = { - ...OmitKeys(this.props, [...docOnlyProps], "").omit, + ...OmitKeys(this.props, [...docOnlyProps], '').omit, RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, onClick: onClick, - onInput: onInput + onInput: onInput, }; return { props: list }; } @@ -180,17 +189,17 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo // 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'> + // 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.scaling?.() || 1}' htmltag='${p1}'`; }; layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2); - // replace /HTML<tag> with </HTMLdiv> as in: </HTMLdiv> becomes </HTMLtag> + // replace /HTML<tag> with </HTMLdiv> as in: </HTMLdiv> becomes </HTMLtag> const replacer3 = (match: any, p1: string, offset: any, string: any) => { return `</HTMLtag`; }; @@ -200,16 +209,16 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo const makeFuncProp = (func: string) => { const splits = layoutFrame.split(`${func}=`); if (splits.length > 1) { - const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] }); + 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" }); + 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 undefined; // add input function to props }; - const onClick = makeFuncProp("onClick"); - const onInput = makeFuncProp("onInput"); + const onClick = makeFuncProp('onClick'); + const onInput = makeFuncProp('onInput'); const bindings = this.CreateBindings(onClick, onInput); return { bindings, layoutFrame }; } @@ -218,23 +227,55 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo 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} renderInWrapper={false} components={{ - FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, EquationBox, SliderBox, FieldView, - CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox, - PDFBox, VideoBox, AudioBox, RecordingBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox, FunctionPlotBox, - ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, LinkBox, ScriptingBox, MapBox, - ScreenshotBox, DataVizBox, HTMLtag, ComparisonBox + FormattedTextBox, + ImageBox, + DirectoryImportBox, + FontIconBox, + LabelBox, + EquationBox, + SliderBox, + FieldView, + CollectionFreeFormView, + CollectionDockingView, + CollectionSchemaView, + CollectionView, + WebBox, + KeyValueBox, + PDFBox, + VideoBox, + AudioBox, + RecordingBox, + PresBox, + YoutubeBox, + PresElementBox, + SearchBox, + FilterBox, + FunctionPlotBox, + ColorBox, + DashWebRTCVideo, + LinkAnchorBox, + InkingStroke, + LinkBox, + ScriptingBox, + MapBox, + ScreenshotBox, + DataVizBox, + HTMLtag, + ComparisonBox, }} bindings={bindings} jsx={layoutFrame} showWarnings={true} - - onError={(test: any) => { console.log("DocumentContentsView:" + test); }} - />; + onError={(test: any) => { + console.log('DocumentContentsView:' + test); + }} + /> + ); } -}
\ No newline at end of file +} |