diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 18 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 6 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/FieldView.tsx | 3 | ||||
| -rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 4 | ||||
| -rw-r--r-- | src/client/views/nodes/PresBox.tsx | 79 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 28 |
7 files changed, 78 insertions, 62 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2894d9b65..cdbe506a5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -14,13 +14,8 @@ import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, highlight?: boolean, z: number, transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined; - x?: number; - y?: number; - z?: number; zIndex?: number; highlight?: boolean; - width?: number; - height?: number; jitterRotation: number; transition?: string; fitToBox?: boolean; @@ -38,13 +33,13 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF } get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; } - get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } - get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } + get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } + get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); } get Highlight() { return this.dataProvider?.highlight; } - get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.width : this.layoutDoc[WidthSym](); } + get width() { return this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.width : this.layoutDoc[WidthSym](); } get height() { - const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.height : this.layoutDoc[HeightSym](); + const hgt = this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.height : this.layoutDoc[HeightSym](); return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt; } @computed get freezeDimensions() { return this.props.FreezeDimensions; } @@ -75,10 +70,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1; panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.()); panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.()); - getTransform = (): Transform => this.props.ScreenToLocalTransform() - .translate(-this.X, -this.Y) - .scale(1 / this.contentScaling()) - + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y).scale(1 / this.contentScaling()); focusDoc = (doc: Doc) => this.props.focus(doc, false); NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 749fb98be..81667e549 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -77,11 +77,11 @@ export class HTMLtag extends React.Component<HTMLtagProps> { render() { const style: { [key: string]: any } = {}; const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "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 })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || ""; + }; Object.keys(divKeys).map((prop: string) => { const p = (this.props as any)[prop] as string; - 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 })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || ""; - }; style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer); }); const Tag = this.props.htmltag as keyof JSX.IntrinsicElements; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7c7c03db2..7a16e8836 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -78,7 +78,6 @@ export interface DocumentViewProps { setupDragLines?: () => void; renderDepth: number; ContentScaling: () => number; - RenderData?: () => Doc; PanelWidth: () => number; PanelHeight: () => number; pointerEvents?: boolean; @@ -996,7 +995,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu LayoutTemplate={this.props.LayoutTemplate} makeLink={this.makeLink} rootSelected={this.rootSelected} - RenderData={this.props.RenderData} dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} LibraryPath={this.props.LibraryPath} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 40d55ce38..016d2a1ae 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,12 +50,13 @@ export interface FieldViewProps { setVideoBox?: (player: VideoBox) => void; ContentScaling: () => number; ChromeHeight?: () => number; - RenderData?: () => Doc; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) height?: number; width?: number; background?: string; color?: string; + xMargin?: number; + yMargin?: number; } @observer diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index d43936949..39d7109b1 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -36,7 +36,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> { @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.Document; } + get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; } @action onEnterKey = (e: React.KeyboardEvent): void => { @@ -238,8 +238,8 @@ export class KeyValueBox extends React.Component<FieldViewProps> { const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : []; openItems.push({ description: "Default Perspective", event: () => { - this.props.addDocTab(this.fieldDocToLayout, "inTab"); this.props.addDocTab(this.props.Document, "close"); + this.props.addDocTab(this.fieldDocToLayout, "onRight"); }, icon: "image" }); !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" }); diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 6e3420f22..343e74c87 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -17,6 +17,10 @@ import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; +import { Docs } from "../../documents/Documents"; +import { PrefetchProxy } from "../../../new_fields/Proxy"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { Scripting } from "../../util/Scripting"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -26,7 +30,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } @observable _isChildActive = false; @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } - @computed get currentIndex() { return NumCast(this.rootDoc._itemIndex); } + @computed get currentIndex() { return NumCast(this.presElement?.currentIndex); } + @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } + constructor(props: any) { + super(props); + if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. + Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ + title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" + })); + // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement + // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent + // the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data + // stored on each pres element. + (this.presElement as Doc).lookupField = ScriptField.MakeScript( + `if (field === 'indexInPres') return docList(container[container.presentationFieldKey]).indexOf(data);` + + "if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 50 : 46;" + + "return undefined;", { field: "string", data: Doc.name, container: Doc.name }); + } + this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox + } componentDidMount() { this.rootDoc.presBox = this.rootDoc; @@ -152,7 +174,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const srcContext = aliasOf && await DocCastAsync(aliasOf.context); if (docToJump === curDoc) { //checking if curDoc has navigation open - const target = await DocCastAsync(curDoc.presentationTargetDoc); + const target = (await DocCastAsync(curDoc.presentationTargetDoc)) || curDoc; if (curDoc.presNavButton && target) { DocumentManager.Instance.jumpToDocument(target, false, undefined, srcContext); } else if (curDoc.presZoomButton && target) { @@ -166,17 +188,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } } - //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. public gotoDocument = (index: number, fromDoc: number) => { this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { - this.rootDoc._itemIndex = index; + this.presElement.currentIndex = index; - if (!this.layoutDoc.presStatus) { - this.layoutDoc.presStatus = true; + if (!this.presElement.presStatus) { + this.presElement.presStatus = true; this.startPresentation(index); } @@ -189,10 +210,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { this.updateCurrentPresentation(); - if (this.layoutDoc.presStatus) { + if (this.presElement.presStatus) { this.resetPresentation(); } else { - this.layoutDoc.presStatus = true; + this.presElement.presStatus = true; this.startPresentation(0); this.gotoDocument(0, this.currentIndex); } @@ -204,7 +225,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this.updateCurrentPresentation(); this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1); this.rootDoc._itemIndex = 0; - this.layoutDoc.presStatus = false; + this.presElement.presStatus = false; } //The function that starts the presentation, also checking if actions should be applied @@ -241,43 +262,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } }); - initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => { - const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46; - this.rootDoc.presCollapsedHeight = hgt; - } + @undoBatch + viewChanged = action((e: React.ChangeEvent) => { + //@ts-ignore + const viewType = e.target.selectedOptions[0].value as CollectionViewType; + viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here + this.updateMinimize(e, this.rootDoc._viewType = viewType); + }); + whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); addDocumentFilter = (doc: Doc) => { - doc.presentationTargetDoc = doc.aliasOf; + doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf); + !this.childDocs.includes(doc) && (doc.presZoomButton = true); return true; } - + childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement; removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); - selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.rootDoc._itemIndex)); - getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight - panelHeight = () => this.props.PanelHeight() - 20; - active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) - whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); - - @undoBatch - viewChanged = action((e: React.ChangeEvent) => { - //@ts-ignore - const viewType = e.target.selectedOptions[0].value as CollectionViewType; - viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here - this.updateMinimize(e, this.rootDoc._viewType = viewType); - }); - - returnSelf = () => this.rootDoc; - childLayoutTemplate = () => this.rootDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined; render() { this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.map((child, i) => child)); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - this.initializeViewAliases(this.childDocs, mode); return <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} > <div className="presBox-buttons" style={{ display: this.rootDoc._chromeStatus === "disabled" ? "none" : undefined }}> <select className="presBox-viewPicker" @@ -302,13 +311,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className="presBox-listCont" > {mode !== CollectionViewType.Invalid ? <CollectionView {...this.props} + ContainingCollectionDoc={this.props.Document} PanelWidth={this.props.PanelWidth} PanelHeight={this.panelHeight} moveDocument={returnFalse} childLayoutTemplate={this.childLayoutTemplate} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} - RenderData={this.returnSelf} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} /> : (null) @@ -316,4 +325,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> </div>; } -}
\ No newline at end of file +} +Scripting.addGlobal(function lookupPresBoxField(presLayout: Doc, data: Doc, fieldKey: string) { +}); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3fb3f5644..30c4a45ac 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -58,14 +58,15 @@ import { FieldView, FieldViewProps } from "../FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); +import { ScriptField } from '../../../../new_fields/ScriptField'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); export interface FormattedTextBoxProps { - hideOnLeave?: boolean; - makeLink?: () => Opt<Doc>; - xMargin?: number; + makeLink?: () => Opt<Doc>; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text + hideOnLeave?: boolean; // used by DocumentView for setting caption's hide on leave (bcz: would prefer to have caption-hideOnLeave field set or something similar) + xMargin?: number; // used to override document's settings for xMargin --- see CollectionCarouselView yMargin?: number; } @@ -198,14 +199,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000))); const curText = state.doc.textBetween(0, state.doc.content.size, " \n"); const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField); - if (!this._applyingChange) { + const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); + const json = JSON.stringify(state.toJSON()); + if (!this._applyingChange && json.replace(/"selection":.*/, "") !== curProto?.Data.replace(/"selection":.*/, "")) { this._applyingChange = true; this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); - if (!curTemp || curText) { // if no template, or there's text, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) - this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), curText); + if ((!curTemp && !curProto) || curText) { // if no template, or there's text, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) + this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited } else { // if we've deleted all the text in a note driven by a template, then restore the template data - this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse(curTemp.Data))); + this.dataDoc[this.props.fieldKey] = undefined; + this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data))); this.dataDoc[this.props.fieldKey + "-noTemplate"] = undefined; // mark the data field as not being split from any template it might have } this._applyingChange = false; @@ -1239,6 +1243,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } render() { TraceMobx(); + const style: { [key: string]: any } = {}; + const divKeys = ["width", "height", "background"]; + 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 })?.script.run({ self: this.rootDoc, this: this.layoutDoc }).result as string || ""; + }; + divKeys.map((prop: string) => { + const p = (this.props as any)[prop] as string; + p && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer)); + }); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground; if (this.props.isSelected()) { @@ -1257,6 +1270,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp pointerEvents: interactive ? "none" : undefined, fontSize: Cast(this.layoutDoc._fontSize, "number", null), fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"), + ...style }} onContextMenu={this.specificContextMenu} onKeyDown={this.onKeyPress} |
