diff options
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 262 |
1 files changed, 164 insertions, 98 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 228efdc87..08d17e559 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,19 +1,25 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; -import { action, computed, IReactionDisposer, reaction, trace, observable, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction, trace, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; +import * as rp from "request-promise"; +import { Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { Copy, Id } from '../../../new_fields/FieldSymbols'; import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; -import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; -import { BoolCast, Cast, FieldValue, StrCast, NumCast, PromiseValue } from "../../../new_fields/Types"; +import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; +import { ScriptField } from '../../../new_fields/ScriptField'; +import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { emptyFunction, Utils, returnFalse, returnTrue } from "../../../Utils"; +import { RouteStore } from '../../../server/RouteStore'; +import { emptyFunction, returnTrue, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; -import { Docs, DocUtils, DocumentType } from "../../documents/Documents"; +import { Docs, DocUtils } from "../../documents/Documents"; +import { ClientUtils } from '../../util/ClientUtils'; +import { DictationManager } from '../../util/DictationManager'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, dropActionType } from "../../util/DragManager"; -import { SearchUtil } from "../../util/SearchUtil"; +import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from "../../util/SelectionManager"; import { Transform } from "../../util/Transform"; import { undoBatch, UndoManager } from "../../util/UndoManager"; @@ -22,30 +28,25 @@ import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from "../DocComponent"; +import { EditableView } from '../EditableView'; +import { MainView } from '../MainView'; +import { OverlayView } from '../OverlayView'; import { PresentationView } from "../presentationview/PresentationView"; -import { Template, Templates } from "./../Templates"; +import { ScriptBox } from '../ScriptBox'; +import { ScriptingRepl } from '../ScriptingRepl'; +import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; -import * as rp from "request-promise"; import "./DocumentView.scss"; -import React = require("react"); -import { Id, Copy } from '../../../new_fields/FieldSymbols'; -import { ContextMenuProps } from '../ContextMenuItem'; -import { list, object, createSimpleSchema } from 'serializr'; -import { LinkManager } from '../../util/LinkManager'; -import { RouteStore } from '../../../server/RouteStore'; import { FormattedTextBox } from './FormattedTextBox'; -import { OverlayView } from '../OverlayView'; -import { ScriptingRepl } from '../ScriptingRepl'; -import { ClientUtils } from '../../util/ClientUtils'; -import { EditableView } from '../EditableView'; -import { faHandPointer, faHandPointRight } from '@fortawesome/free-regular-svg-icons'; -import { DocumentDecorations } from '../DocumentDecorations'; +import React = require("react"); import { PresBox } from './PresBox'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); library.add(fa.faShare); +library.add(fa.faDownload); library.add(fa.faExpandArrowsAlt); library.add(fa.faCompressArrowsAlt); library.add(fa.faLayerGroup); @@ -63,7 +64,7 @@ library.add(fa.faCrosshairs); library.add(fa.faDesktop); library.add(fa.faUnlock); library.add(fa.faLock); -library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake); +library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone); // const linkSchema = createSchema({ // title: "string", @@ -81,6 +82,7 @@ export interface DocumentViewProps { Document: Doc; DataDoc?: Doc; fitToBox?: boolean; + onClick?: ScriptField; addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean; removeDocument?: (doc: Doc) => boolean; moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; @@ -94,12 +96,14 @@ export interface DocumentViewProps { selectOnLoad: boolean; parentActive: () => boolean; whenActiveChanged: (isActive: boolean) => void; - bringToFront: (doc: Doc) => void; + bringToFront: (doc: Doc, sendToBack?: boolean) => void; addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => void; collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void; zoomToScale: (scale: number) => void; + backgroundColor: (doc: Doc) => string | undefined; getScale: () => number; animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; + ChromeHeight?: () => number; } const schema = createSchema({ @@ -108,7 +112,8 @@ const schema = createSchema({ nativeHeight: "number", backgroundColor: "string", opacity: "number", - hidden: "boolean" + hidden: "boolean", + onClick: ScriptField, }); export const positionSchema = createSchema({ @@ -118,6 +123,7 @@ export const positionSchema = createSchema({ height: "number", x: "number", y: "number", + z: "number", }); export type PositionDocument = makeInterface<[typeof positionSchema]>; @@ -135,6 +141,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu private _hitExpander = false; private _mainCont = React.createRef<HTMLDivElement>(); private _dropDisposer?: DragManager.DragDropDisposer; + _animateToIconDisposer?: IReactionDisposer; + _reactionDisposer?: IReactionDisposer; public get ContentDiv() { return this._mainCont.current; } @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } @@ -149,12 +157,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu set templates(templates: List<string>) { this.props.Document.templates = templates; } screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); - constructor(props: DocumentViewProps) { - super(props); - } - - _animateToIconDisposer?: IReactionDisposer; - _reactionDisposer?: IReactionDisposer; @action componentDidMount() { if (this._mainCont.current) { @@ -206,9 +208,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } @action componentDidUpdate() { - if (this._dropDisposer) { - this._dropDisposer(); - } + this._dropDisposer && this._dropDisposer(); if (this._mainCont.current) { this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } @@ -217,9 +217,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } @action componentWillUnmount() { - if (this._reactionDisposer) this._reactionDisposer(); - if (this._animateToIconDisposer) this._animateToIconDisposer(); - if (this._dropDisposer) this._dropDisposer(); + this._reactionDisposer && this._reactionDisposer(); + this._animateToIconDisposer && this._animateToIconDisposer(); + this._dropDisposer && this._dropDisposer(); DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } @@ -294,6 +294,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu onClick = async (e: React.MouseEvent) => { if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing. e.stopPropagation(); + if (this.onClickHandler && this.onClickHandler.script) { + this.onClickHandler.script.run({ this: this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }); + e.preventDefault(); + return; + } let altKey = e.altKey; let ctrlKey = e.ctrlKey; if (this._doubleTap && this.props.renderDepth) { @@ -303,7 +308,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu fullScreenAlias.showCaption = true; this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); - this.props.Document.libraryBrush = false; + Doc.UnBrushDoc(this.props.Document); } else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && @@ -361,18 +366,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu if (!linkedFwdDocs.some(l => l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab"); let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined; - DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, document => { - this.props.focus(this.props.Document, true, 1); - setTimeout(() => - this.props.addDocTab(document, undefined, maxLocation), 1000); - } - , linkedFwdPage[altKey ? 1 : 0], targetContext); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, + document => { // open up target if it's not already in view ... + this.props.focus(this.props.Document, true, 1); // by zooming into the button document first + setTimeout(() => this.props.addDocTab(document, undefined, maxLocation), 1000); // then after the 1sec animation, open up the target in a new tab + }, + linkedFwdPage[altKey ? 1 : 0], targetContext); } } } } } onPointerDown = (e: React.PointerEvent): void => { + if (e.nativeEvent.cancelBubble) return; this._downX = e.clientX; this._downY = e.clientY; this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; @@ -411,7 +417,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } @undoBatch - fieldsClicked = (): void => { let kvp = Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.dataDoc, "onRight"); } + fieldsClicked = (): void => { + let kvp = Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }); + this.props.addDocTab(kvp, this.dataDoc, "onRight"); + } @undoBatch makeBtnClicked = (): void => { @@ -440,17 +449,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu e.stopPropagation(); let annotationDoc = de.data.annotationDocument; annotationDoc.linkedToDoc = true; + de.data.targetContext = this.props.ContainingCollectionView!.props.Document; let targetDoc = this.props.Document; + targetDoc.targetContext = de.data.targetContext; let annotations = await DocListCastAsync(annotationDoc.annotations); - if (annotations) { - annotations.forEach(anno => { - anno.target = targetDoc; - }); - } - let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc); - if (pdfDoc) { - DocUtils.MakeLink(annotationDoc, targetDoc, undefined, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title)); - } + annotations && annotations.forEach(anno => anno.target = targetDoc); + + DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Link from ${StrCast(annotationDoc.title)}`); } if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; @@ -524,7 +529,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @undoBatch @action makeBackground = (): void => { - this.props.Document.isBackground = true; + this.props.Document.isBackground = !this.props.Document.isBackground; + this.props.Document.isBackground && this.props.bringToFront(this.props.Document, true); } @undoBatch @@ -533,6 +539,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true; } + listen = async () => { + Doc.GetProto(this.props.Document).transcript = await DictationManager.Controls.listen({ + continuous: { indefinite: true }, + interimHandler: (results: string) => { + let main = MainView.Instance; + main.dictationSuccess = true; + main.dictatedPhrase = results; + main.isListening = { interim: true }; + } + }); + } + @action onContextMenu = async (e: React.MouseEvent): Promise<void> => { e.persist(); @@ -553,12 +571,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); - cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); - cm.addItem({ description: "Pin to Presentation", event: () => PresBox.Instance.PinDoc(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle! - cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); - let makes: ContextMenuProps[] = []; - makes.push({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); + let existingMake = ContextMenu.Instance.findByDescription("Make..."); + let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : []; + makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); + makes.push({ description: "Edit OnClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick") }); makes.push({ description: "Make Portal", event: () => { let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" }); @@ -573,21 +590,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu }, icon: "window-restore" }); - cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); - // cm.addItem({ - // description: "Find aliases", event: async () => { - // const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - // this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? - // }, icon: "search" - // }); - if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { - cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); - } - cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); + !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); let existing = ContextMenu.Instance.findByDescription("Layout..."); let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; + + layoutItems.push({ description: `${this.props.Document.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.props.Document.chromeStatus = (this.props.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); + layoutItems.push({ description: `${this.props.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.props.Document.autoHeight = !this.props.Document.autoHeight, icon: "plus" }); + layoutItems.push({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); + layoutItems.push({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); + if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { + layoutItems.push({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); + } !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" }); if (!ClientUtils.RELEASE) { let copies: ContextMenuProps[] = []; @@ -595,6 +610,51 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" }); } + let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers..."); + let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; + analyzers.push({ description: "Transcribe Speech", event: this.listen, icon: "microphone" }); + !existingAnalyze && cm.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" }); + cm.addItem({ description: "Pin to Presentation", event: () => PresBox.Instance.PinDoc(this.props.Document), icon: "map-pin" }); //I think this should work... and it does! A miracle! + cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); + cm.addItem({ + description: "Download document", icon: "download", event: () => { + const a = document.createElement("a"); + const url = Utils.prepend(`/downloadId/${this.props.Document[Id]}`); + a.href = url; + a.download = `DocExport-${this.props.Document[Id]}.zip`; + a.click(); + } + }); + + cm.addItem({ + description: "Import document", icon: "upload", event: () => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".zip"; + input.onchange = async _e => { + const files = input.files; + if (!files) return; + const file = files[0]; + let formData = new FormData(); + formData.append('file', file); + formData.append('remap', "true"); + const upload = Utils.prepend("/uploadDoc"); + const response = await fetch(upload, { method: "POST", body: formData }); + const json = await response.json(); + if (json === "error") { + return; + } + const doc = await DocServer.GetRefField(json); + if (!doc || !(doc instanceof Doc)) { + return; + } + const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY); + doc.x = x, doc.y = y; + this.props.addDocument && this.props.addDocument(doc, false); + }; + input.click(); + } + }); cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; let usersMenu: ContextMenuProps[] = []; @@ -635,64 +695,70 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu }); } - onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; + onPointerEnter = (e: React.PointerEvent): void => { Doc.BrushDoc(this.props.Document); }; + onPointerLeave = (e: React.PointerEvent): void => { Doc.UnBrushDoc(this.props.Document); }; isSelected = () => SelectionManager.IsSelected(this); @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; - @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } + @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } @computed get contents() { return (<DocumentContentsView {...this.props} - isSelected={this.isSelected} select={this.select} + ChromeHeight={this.chromeHeight} + isSelected={this.isSelected} + select={this.select} + onClick={this.onClickHandler} selectOnLoad={this.props.selectOnLoad} layoutKey={"layout"} fitToBox={BoolCast(this.props.Document.fitToBox) ? true : this.props.fitToBox} DataDoc={this.dataDoc} />); } + chromeHeight = () => { + let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; + let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle); + return showTitle ? 25 : 0; + } + get layoutDoc() { // if this document's layout field contains a document (ie, a rendering template), then we will use that // to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string. return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; } + + render() { - if (this.Document.hidden) { - return null; - } - let self = this; - let backgroundColor = StrCast(this.layoutDoc.backgroundColor); + let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ? + this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : + StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; - let showTitle = showOverlays && showOverlays.title !== "undefined" ? showOverlays.title : StrCast(this.layoutDoc.showTitle); - let showCaption = showOverlays && showOverlays.caption !== "undefined" ? showOverlays.caption : StrCast(this.layoutDoc.showCaption); + let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle); + let showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : StrCast(this.layoutDoc.showCaption); let templates = Cast(this.layoutDoc.templates, listSpec("string")); if (!showOverlays && templates instanceof List) { templates.map(str => { - if (str.indexOf("{props.Document.title}") !== -1) showTitle = "title"; - if (str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption"; + if (!showTitle && str.indexOf("{props.Document.title}") !== -1) showTitle = "title"; + if (!showCaption && str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption"; }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined; + let brushDegree = Doc.IsBrushedDegree(this.props.Document); + let borderRounding = StrCast(Doc.GetProto(this.props.Document).borderRounding); + let localScale = this.props.ScreenToLocalTransform().Scale * brushDegree; return ( <div className={`documentView-node${this.topMost ? "-topmost" : ""}`} ref={this._mainCont} style={{ - pointerEvents: this.layoutDoc.isBackground ? "none" : "all", + pointerEvents: this.layoutDoc.isBackground && !this.isSelected() ? "none" : "all", color: foregroundColor, - outlineColor: "maroon", - outlineStyle: "dashed", - outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? - `${this.props.ScreenToLocalTransform().Scale}px` : "0px", - marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? - `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined, - marginTop: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? - `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined, - border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? - `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined, + outlineColor: ["transparent", "maroon", "maroon"][brushDegree], + outlineStyle: ["none", "dashed", "solid"][brushDegree], + outlineWidth: brushDegree && !borderRounding ? `${localScale}px` : "0px", + border: brushDegree && borderRounding ? `${["none", "dashed", "solid"][brushDegree]} ${["transparent", "maroon", "maroon"][brushDegree]} ${localScale}px` : undefined, borderRadius: "inherit", background: backgroundColor, width: nativeWidth, @@ -717,18 +783,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu transformOrigin: "top left", transform: `scale(${1 / this.props.ContentScaling()})` }}> <EditableView - contents={this.layoutDoc[showTitle]} + contents={(this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle]} display={"block"} height={72} fontSize={12} - GetValue={() => StrCast(this.layoutDoc[showTitle!])} - SetValue={(value: string) => (Doc.GetProto(this.layoutDoc)[showTitle!] = value) ? true : true} + GetValue={() => StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle!])} + SetValue={(value: string) => ((this.layoutDoc.isTemplate ? this.layoutDoc : Doc.GetProto(this.layoutDoc))[showTitle!] = value) ? true : true} /> </div> } {!showCaption ? (null) : <div style={{ position: "absolute", bottom: 0, transformOrigin: "bottom left", width: `${100 * this.props.ContentScaling()}%`, transform: `scale(${1 / this.props.ContentScaling()})` }}> - <FormattedTextBox {...this.props} DataDoc={this.dataDoc} active={returnTrue} isSelected={this.isSelected} focus={emptyFunction} select={this.select} selectOnLoad={this.props.selectOnLoad} fieldExt={""} hideOnLeave={true} fieldKey={showCaption} /> + <FormattedTextBox {...this.props} onClick={this.onClickHandler} DataDoc={this.dataDoc} active={returnTrue} isSelected={this.isSelected} focus={emptyFunction} select={this.select} selectOnLoad={this.props.selectOnLoad} fieldExt={""} hideOnLeave={true} fieldKey={showCaption} /> </div> } </div> |