diff options
Diffstat (limited to 'src')
21 files changed, 74 insertions, 167 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index ff149a9ac..1f9bdaac4 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -10,6 +10,8 @@ import { InkTool } from '../../new_fields/InkField'; /// DocComponents returns a generic base class for React views of document fields that are not interactive interface DocComponentProps { Document: Doc; + DataDoc?: Doc; + fieldKey: string; } export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: Doc) => T) { class Component extends React.Component<P> { @@ -18,6 +20,8 @@ export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: D get Document(): T { return schemaCtor(this.props.Document); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc!) : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } } return Component; } @@ -26,6 +30,8 @@ export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: D /// DocStaticProps return a base class for React views of document fields that are interactive only when selected (e.g. ColorBox) interface DocStaticProps { Document: Doc; + DataDoc?: Doc; + fieldKey: string; isSelected: () => boolean; renderDepth: number; } @@ -36,6 +42,8 @@ export function DocStaticComponent<P extends DocStaticProps, T>(schemaCtor: (doc get Document(): T { return schemaCtor(this.props.Document); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc!) : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } active = () => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected() || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools } return Component; @@ -54,12 +62,15 @@ interface DocAnnotatableProps { } export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) { class Component extends React.Component<P> { + _isChildActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } - _isChildActive = false; + @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } + @action.bound removeDocument(doc: Doc): boolean { Doc.GetProto(doc).annotationOn = undefined; @@ -67,23 +78,18 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema let index = value ? Doc.IndexOf(doc, value.map(d => d as Doc), true) : -1; return index !== -1 && value.splice(index, 1) ? true : false; } - - @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } - - @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - // if the moved document is already in this overlay collection nothing needs to be done. // otherwise, if the document can be removed from where it was, it will then be added to this document's overlay collection. @action.bound moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean { return Doc.AreProtosEqual(this.props.Document, targetCollection) ? true : this.removeDocument(doc) ? addDocument(doc) : false; } - @action.bound addDocument(doc: Doc): boolean { Doc.GetProto(doc).annotationOn = this.props.Document; return Doc.AddDocToList(this.extensionDoc, this.props.fieldExt, doc); } + whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive); active = () => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) && (this.props.Document.forceActive || this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0) ? true : false) diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 1ade44250..fa543cc01 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -97,9 +97,11 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { @action.bound addDocument(doc: Doc): boolean { - let targetDataDoc = this.props.Document; + let targetDataDoc = Doc.GetProto(this.props.Document); let targetField = this.props.fieldKey; Doc.AddDocToList(targetDataDoc, targetField, doc); + let extension = Doc.fieldExtensionDoc(targetDataDoc, targetField); + extension && (extension.lastModified = new DateField(new Date(Date.now()))); Doc.GetProto(doc).lastOpened = new DateField; return true; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 23e070750..04bc550ea 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -158,6 +158,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { <CollectionSchemaPreview Document={layoutDoc} DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined} + fieldKey={this.props.fieldKey} childDocs={this.childDocs} renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} @@ -226,7 +227,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } render() { - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); return ( <div className="collectionSchemaView-container" style={{ height: "100%", marginTop: "0", }}> <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={this.onWheel} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createTarget}> @@ -898,6 +898,7 @@ interface CollectionSchemaPreviewProps { childDocs?: Doc[]; renderDepth: number; fitToBox?: boolean; + fieldKey: string; PanelWidth: () => number; PanelHeight: () => number; ruleProvider: Doc | undefined; @@ -993,6 +994,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre <DocumentView {...this.props} DataDoc={this.props.DataDocument} Document={this.props.Document} + fieldKey={this.props.fieldKey} fitToBox={this.props.fitToBox} onClick={this.props.onClick} ruleProvider={this.props.ruleProvider} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 1bb2d2f46..5fb0c0f9f 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -170,6 +170,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return <CollectionSchemaPreview Document={doc} DataDocument={dataDoc} + fieldKey={this.props.fieldKey} showOverlays={this.overlays} renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} @@ -389,7 +390,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { SetValue: this.addGroup, contents: "+ ADD A GROUP" }; - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]; if (this.sectionFilter) { let entries = Array.from(this.Sections.entries()); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 7e54b0f29..fec3d90b9 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, trace } from "mobx"; +import { action, observable, trace, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; @@ -204,7 +204,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC document.removeEventListener("pointerup", this.pointerUp); document.addEventListener("pointerup", this.pointerUp); } - this._createAliasSelected = false; + runInAction(() => this._createAliasSelected = false); } renderColorPicker = () => { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8bd67b880..43147ed20 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -33,6 +33,7 @@ export interface CollectionViewProps extends FieldViewProps { VisibleHeight?: () => number; chromeCollapsed: boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; + fieldKey: string; } export interface SubCollectionViewProps extends CollectionViewProps { @@ -77,7 +78,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { // to its children which may be templates. // The name of the data field comes from fieldExt if it's an extension, or fieldKey otherwise. @computed get dataField() { - return Doc.fieldExtensionDoc(this.props.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt)[this.props.fieldExt || this.props.fieldKey]; + return this.props.fieldExt ? this.extensionDoc[this.props.fieldExt] : this.dataDoc[this.props.fieldKey]; } get childLayoutPairs() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c1b7f7e48..2cad41acb 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -317,6 +317,7 @@ class TreeView extends React.Component<TreeViewProps> { <CollectionSchemaPreview Document={layoutDoc} DataDocument={this.templateDataDoc} + fieldKey={this.fieldKey} renderDepth={this.props.renderDepth} showOverlays={this.noOverlays} ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider} @@ -556,7 +557,6 @@ export class CollectionTreeView extends CollectionSubView(Document) { } render() { - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, false); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4ca6df034..74a388425 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -149,7 +149,7 @@ export class CollectionView extends React.Component<FieldViewProps> { {this.SubView} </CollectionBaseView> - {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => Cast(d.data, ImageField)!.url!.href))} + {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d => Cast(d.data, ImageField)!.url.href))} </> ); } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index a5b7f0181..dd5e630e4 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -480,12 +480,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView getKeySuggestions = async (value: string): Promise<string[]> => { value = value.toLowerCase(); - let docs: Doc | Doc[] | Promise<Doc> | Promise<Doc[]> | (() => DocLike) - = () => DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldExt ? this.props.CollectionView.props.fieldExt : this.props.CollectionView.props.fieldKey]); - if (typeof docs === "function") { - docs = docs(); - } - docs = await docs; + let docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]); if (docs instanceof Doc) { return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); } else { @@ -591,19 +586,9 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewCh if (textwrappedRows.length) { this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>([]); } else { - let docs: Doc | Doc[] | Promise<Doc> | Promise<Doc[]> | (() => DocLike) - = () => DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldExt ? this.props.CollectionView.props.fieldExt : this.props.CollectionView.props.fieldKey]); - if (typeof docs === "function") { - docs = docs(); - } - docs = await docs; - if (docs instanceof Doc) { - let allRows = [docs[Id]]; - this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>(allRows); - } else { - let allRows = docs.map(doc => doc[Id]); - this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>(allRows); - } + let docs = DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey]); + let allRows = docs instanceof Doc ? [docs[Id]] : docs.map(doc => doc[Id]); + this.props.CollectionView.props.Document.textwrappedSchemaRows = new List<string>(allRows); } } @@ -638,63 +623,14 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewCh @observer export class CollectionTreeViewChrome extends React.Component<CollectionViewChromeProps> { - @observable private _currentKey: string = ""; - @observable private suggestions: string[] = []; @computed private get descending() { return Cast(this.props.CollectionView.props.Document.sortAscending, "boolean", null); } - @computed get sectionFilter() { return StrCast(this.props.CollectionView.props.Document.sectionFilter); } - - getKeySuggestions = async (value: string): Promise<string[]> => { - value = value.toLowerCase(); - let docs: Doc | Doc[] | Promise<Doc> | Promise<Doc[]> | (() => DocLike) - = () => DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldExt ? this.props.CollectionView.props.fieldExt : this.props.CollectionView.props.fieldKey]); - if (typeof docs === "function") { - docs = docs(); - } - docs = await docs; - if (docs instanceof Doc) { - return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); - } else { - const keys = new Set<string>(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); - } - } - - @action - onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { - this._currentKey = newValue; - } - - getSuggestionValue = (suggestion: string) => suggestion; - - renderSuggestion = (suggestion: string) => { - return <p>{suggestion}</p>; - } - - onSuggestionFetch = async ({ value }: { value: string }) => { - const sugg = await this.getKeySuggestions(value); - runInAction(() => { - this.suggestions = sugg; - }); - } - - @action - onSuggestionClear = () => { - this.suggestions = []; - } - - setValue = (value: string) => { - this.props.CollectionView.props.Document.sectionFilter = value; - return true; - } @action toggleSort = () => { if (this.props.CollectionView.props.Document.sortAscending) this.props.CollectionView.props.Document.sortAscending = undefined; else if (this.props.CollectionView.props.Document.sortAscending === undefined) this.props.CollectionView.props.Document.sortAscending = false; else this.props.CollectionView.props.Document.sortAscending = true; } - @action resetValue = () => { this._currentKey = this.sectionFilter; }; render() { return ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 430ba582b..33d6b1358 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -113,10 +113,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); } - @computed get fieldExtensionDoc() { - return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey); - } - @action onDrop = (e: React.DragEvent): Promise<void> => { var pt = this.getTransform().transformPoint(e.pageX, e.pageY); @@ -309,7 +305,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); - let ink = Cast(this.fieldExtensionDoc.ink, InkField); + let ink = Cast(this.extensionDoc.ink, InkField); if (ink && ink.inkData) { ink.inkData.forEach((value: StrokeData, key: string) => { let bounds = InkingCanvas.StrokeRect(value); @@ -605,9 +601,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } analyzeStrokes = async () => { - let data = Cast(this.fieldExtensionDoc.ink, InkField); + let data = Cast(this.extensionDoc.ink, InkField); if (data) { - CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, ["inkAnalysis", "handwriting"], data.inkData); + CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.extensionDoc, ["inkAnalysis", "handwriting"], data.inkData); } } @@ -680,7 +676,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.Document.fitH = this.contentBounds && (this.contentBounds.b - this.contentBounds.y); // if isAnnotationOverlay is set, then children will be stored in the extension document for the fieldKey. // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document - Doc.UpdateDocumentExtensionForField(this.props.DataDoc || this.props.Document, this.props.fieldKey); return ( <div className={"collectionfreeformview-container"} ref={this.createDropTarget} onWheel={this.onPointerWheel} style={{ pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined, height: this.isAnnotationOverlay ? (this.props.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight() }} @@ -690,7 +685,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}> <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} easing={this.easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> - <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} AnnotationDocument={this.fieldExtensionDoc} inkFieldKey={"ink"} > + <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} AnnotationDocument={this.extensionDoc} inkFieldKey={"ink"} > {this.childViews} </InkingCanvas> <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 743055875..4ff70daba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -247,12 +247,12 @@ export class MarqueeView extends React.Component<MarqueeViewProps> get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored. let cprops = this.props.container.props; - return Cast(Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink, InkField); + return Cast(this.props.container.extensionDoc.ink, InkField); } set ink(value: InkField | undefined) { let cprops = this.props.container.props; - Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink = value; + this.props.container.extensionDoc.ink = value; } @undoBatch diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 689d44a2f..3e5deb55b 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -7,7 +7,6 @@ import { AudioField } from "../../../new_fields/URLField"; import { DocStaticComponent } from "../DocComponent"; import { makeInterface } from "../../../new_fields/Schema"; import { documentSchema } from "./DocumentView"; -import { InkingControl } from "../InkingControl"; type AudioDocument = makeInterface<[typeof documentSchema]>; const AudioDocument = makeInterface(documentSchema); diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 30554ea36..fdcedb3a5 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -11,7 +11,6 @@ import { trace, reaction, observable, action, IReactionDisposer } from "mobx"; import { SelectionManager } from "../../util/SelectionManager"; import { StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { Doc } from "../../../new_fields/Doc"; type ColorDocument = makeInterface<[typeof documentSchema]>; const ColorDocument = makeInterface(documentSchema); @@ -19,8 +18,11 @@ const ColorDocument = makeInterface(documentSchema); @observer export class ColorBox extends DocStaticComponent<FieldViewProps, ColorDocument>(ColorDocument) { public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(ColorBox, fieldKey); } + _selectedDisposer: IReactionDisposer | undefined; _penDisposer: IReactionDisposer | undefined; + @observable _startupColor = "black"; + componentDidMount() { this._selectedDisposer = reaction(() => SelectionManager.SelectedDocuments(), action(() => this._startupColor = SelectionManager.SelectedDocuments().length ? StrCast(SelectionManager.SelectedDocuments()[0].Document.backgroundColor, "black") : "black"), @@ -28,27 +30,12 @@ export class ColorBox extends DocStaticComponent<FieldViewProps, ColorDocument>( this._penDisposer = reaction(() => CurrentUserUtils.ActivePen, action(() => this._startupColor = CurrentUserUtils.ActivePen ? StrCast(CurrentUserUtils.ActivePen.backgroundColor, "black") : "black"), { fireImmediately: true }); - - // compare to this reaction that used to be in Selection Manager - // reaction(() => manager.SelectedDocuments, sel => { - // let targetColor = "#FFFFFF"; - // if (sel.length > 0) { - // let firstView = sel[0]; - // let doc = firstView.props.Document; - // let targetDoc = doc.isTemplateField ? doc : Doc.GetProto(doc); - // let stored = StrCast(targetDoc.backgroundColor); - // stored.length > 0 && (targetColor = stored); - // } - // InkingControl.Instance.updateSelectedColor(targetColor); - // }, { fireImmediately: true }); } componentWillUnmount() { this._penDisposer && this._penDisposer(); this._selectedDisposer && this._selectedDisposer(); } - @observable _startupColor = "black"; - render() { return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`} onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a41a37e66..089ec77ba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -67,6 +67,7 @@ library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCom export interface DocumentViewProps { ContainingCollectionView: Opt<CollectionView>; ContainingCollectionDoc: Opt<Doc>; + fieldKey: string; Document: Doc; DataDoc?: Doc; fitToBox?: boolean; @@ -598,6 +599,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView} ContainingCollectionDoc={this.props.ContainingCollectionDoc} Document={this.props.Document} + fieldKey={this.props.fieldKey} fitToBox={this.props.fitToBox} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f866e6f7e..020442bf3 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -44,7 +44,6 @@ import React = require("react"); import { ContextMenuProps } from '../ContextMenuItem'; import { ContextMenu } from '../ContextMenu'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { siteVerification } from 'googleapis/build/src/apis/siteVerification'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -143,10 +142,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } - @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - - @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); } - // the document containing the view layout information - will be the Document itself unless the Document has // a layout field. In that case, all layout information comes from there unless overriden by Document @computed get layoutDoc(): Doc { return Doc.Layout(this.props.Document); } @@ -1028,7 +1023,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground ? "none" : "all"; - Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); if (this.props.isSelected()) { FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 426b9cbb4..d80e222c2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -326,11 +326,11 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum } render() { - if (!Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey)) return (null); return (<div className={"imageBox-container"} onContextMenu={this.specificContextMenu}> <CollectionFreeFormView {...this.props} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} + fieldExt={"annotations"} isAnnotationOverlay={true} focus={this.props.focus} isSelected={this.props.isSelected} diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 5795d6f12..78858731f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -229,7 +229,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument> renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling} addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} focus={this.props.focus} - pinToPres={this.props.pinToPres} addDocument={this.props.addDocument} + pinToPres={this.props.pinToPres} addDocument={this.addDocument} ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select} isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged} fieldKey={this.props.fieldKey} extensionDoc={this.extensionDoc} startupLive={this._initialScale < 2.5 ? true : false} /> diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 20383bab1..5e8154233 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -322,7 +322,6 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum InkingControl.Instance.switchTool(InkTool.None); this._isResetClick < 10 && (this.Document.currentTimecode = 0); } - @computed get fieldExtensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } @computed get dataDoc() { return this.props.DataDoc && this.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document); } @computed get youtubeContent() { @@ -337,14 +336,12 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum @action.bound addDocumentWithTimestamp(doc: Doc): boolean { - Doc.GetProto(doc).annotationOn = this.props.Document; var curTime = (this.Document.currentTimecode || -1); curTime !== -1 && (doc.displayTimecode = curTime); - return Doc.AddDocToList(this.fieldExtensionDoc, this.props.fieldExt, doc); + return this.addDocument(doc); } render() { - if (!Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey)) return (null); return (<div className={"videoBox-container"} onContextMenu={this.specificContextMenu}> <CollectionFreeFormView {...this.props} PanelHeight={this.props.PanelHeight} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index d5a1f4e73..907e71627 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -195,11 +195,11 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument> </>); } render() { - Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); return (<div className={"imageBox-container"} > <CollectionFreeFormView {...this.props} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} + fieldExt={"annotations"} focus={this.props.focus} isSelected={this.props.isSelected} isAnnotationOverlay={true} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f3aaca471..361e58c65 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -46,7 +46,6 @@ interface IViewerProps { pdf: Pdfjs.PDFDocumentProxy; url: string; fieldKey: string; - fieldExt: string; Document: Doc; DataDoc?: Doc; ContainingCollectionView: Opt<CollectionView>; @@ -550,7 +549,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument highlight = (color: string) => { // creates annotation documents for current highlights let annotationDoc = this.makeAnnotationDocument(color); - annotationDoc && Doc.AddDocToList(this.props.extensionDoc, this.props.fieldExt, annotationDoc); + annotationDoc && this.props.addDocument && this.props.addDocument(annotationDoc); return annotationDoc; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 71b64d7c3..f60a2e720 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -398,44 +398,6 @@ export namespace Doc { return bounds; } - // - // Resolves a reference to a field by returning 'doc' if no field extension is specified, - // otherwise, it returns the extension document stored in doc.<fieldKey>_ext. - // This mechanism allows any fields to be extended with an extension document that can - // be used to capture field-specific metadata. For example, an image field can be extended - // to store annotations, ink, and other data. - // - export function fieldExtensionDoc(doc: Doc, fieldKey: string, fieldExt: string = "yes") { - return fieldExt && doc[fieldKey + "_ext"] instanceof Doc ? doc[fieldKey + "_ext"] as Doc : doc; - } - - export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { - let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = fieldKey + ".ext"; - docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. - docExtensionForField.type = DocumentType.EXTENSION; - let proto: Doc | undefined = doc; - while (proto && !Doc.IsPrototype(proto) && proto.proto) { - proto = proto.proto; - } - (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); - return docExtensionForField; - } - - export function UpdateDocumentExtensionForField(doc: Doc, fieldKey: string, immediate: boolean = false) { - let docExtensionForField = doc[fieldKey + "_ext"] as Doc; - if (docExtensionForField === undefined) { - if (immediate) { - CreateDocumentExtensionForField(doc, fieldKey); - return true; - } - else { - setTimeout(() => CreateDocumentExtensionForField(doc, fieldKey), 0); - return false; - } - } - return true; - } export function MakeTitled(title: string) { let doc = new Doc(); doc.title = title; @@ -490,13 +452,38 @@ export namespace Doc { let layoutDoc: Doc | undefined = childDocLayout; let resolvedDataDoc = !doc.isTemplateField && dataDoc !== doc && dataDoc ? Doc.GetDataDoc(dataDoc) : undefined; if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) { - Doc.UpdateDocumentExtensionForField(resolvedDataDoc, fieldKey); - let fieldExtensionDoc = Doc.fieldExtensionDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)), "dummy"); - layoutDoc = Doc.expandTemplateLayout(childDocLayout, fieldExtensionDoc !== resolvedDataDoc ? fieldExtensionDoc : undefined); + let extensionDoc = fieldExtensionDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title))); + layoutDoc = Doc.expandTemplateLayout(childDocLayout, extensionDoc !== resolvedDataDoc ? extensionDoc : undefined); } else layoutDoc = childDocLayout; return { layout: layoutDoc, data: resolvedDataDoc }; } + // + // Resolves a reference to a field by returning 'doc' if no field extension is specified, + // otherwise, it returns the extension document stored in doc.<fieldKey>_ext. + // This mechanism allows any fields to be extended with an extension document that can + // be used to capture field-specific metadata. For example, an image field can be extended + // to store annotations, ink, and other data. + // + export function fieldExtensionDoc(doc: Doc, fieldKey: string) { + let extension = doc[fieldKey + "_ext"] as Doc; + (extension === undefined) && setTimeout(() => CreateDocumentExtensionForField(doc, fieldKey), 0); + return extension ? extension : doc; + } + + export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { + let docExtensionForField = new Doc(doc[Id] + fieldKey, true); + docExtensionForField.title = fieldKey + ".ext"; + docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. + docExtensionForField.type = DocumentType.EXTENSION; + let proto: Doc | undefined = doc; + while (proto && !Doc.IsPrototype(proto) && proto.proto) { + proto = proto.proto; + } + (proto ? proto : doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); + return docExtensionForField; + } + export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { Object.keys(doc).forEach(key => { const field = ProxyField.WithoutProxy(() => doc[key]); |