From 767901272eeea30137330e710cc8cf70fd34f1de Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 03:13:08 -0400 Subject: autotag based on confidence, allow concealment of computed fields that resolve to undefined with namespace constant ComputedField.undefined --- src/new_fields/ScriptField.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/new_fields') diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index e8a1ea28a..e5ec34f57 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -107,6 +107,8 @@ export namespace ComputedField { useComputed = true; } + export const undefined = "__undefined"; + export function WithoutComputed(fn: () => T) { DisableComputedFields(); try { -- cgit v1.2.3-70-g09d2 From 93c81b9fcc93dd05d723f7f103bc38fff9e21786 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 23 Jul 2019 15:19:34 -0400 Subject: Added async deserialization and got captures for script fields working again --- src/client/DocServer.ts | 11 +++++------ src/client/util/SerializationHelper.ts | 15 +++++++++------ src/client/views/InkingControl.tsx | 4 ++-- src/new_fields/Doc.ts | 13 ++++++++++--- src/new_fields/Proxy.ts | 4 ++-- src/new_fields/ScriptField.ts | 22 ++++++++++++++++++++-- 6 files changed, 48 insertions(+), 21 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 8c64d2b2f..077c8e5ba 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -126,12 +126,11 @@ export namespace DocServer { // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. const deserializeField = getSerializedField.then(async fieldJson => { // deserialize - const field = SerializationHelper.Deserialize(fieldJson); + const field = await SerializationHelper.Deserialize(fieldJson); // either way, overwrite or delete any promises cached at this id (that we inserted as flags // to indicate that the field was in the process of being fetched). Now everything // should be an actual value within or entirely absent from the cache. if (field !== undefined) { - await field.proto; _cache[id] = field; } else { delete _cache[id]; @@ -202,18 +201,18 @@ export namespace DocServer { // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. const deserializeFields = getSerializedFields.then(async fields => { const fieldMap: { [id: string]: RefField } = {}; - const protosToLoad: any = []; + // const protosToLoad: any = []; for (const field of fields) { if (field !== undefined) { // deserialize - let deserialized: any = SerializationHelper.Deserialize(field); + let deserialized = await SerializationHelper.Deserialize(field); fieldMap[field.id] = deserialized; // adds to a list of promises that will be awaited asynchronously - protosToLoad.push(deserialized.proto); + // protosToLoad.push(deserialized.proto); } } // this actually handles the loading of prototypes - await Promise.all(protosToLoad); + // await Promise.all(protosToLoad); return fieldMap; }); diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index dca539f3b..692d07c74 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -28,7 +28,7 @@ export namespace SerializationHelper { return json; } - export function Deserialize(obj: any): any { + export async function Deserialize(obj: any): Promise { if (obj === undefined || obj === null) { return undefined; } @@ -52,16 +52,19 @@ export namespace SerializationHelper { } const type = serializationTypes[obj.__type]; - const value = deserialize(type.ctor, obj); + const value = await new Promise(res => deserialize(type.ctor, obj, (err, result) => res(result))); if (type.afterDeserialize) { - type.afterDeserialize(value); + const currentSerialization = serializing; + serializing = 0; + await type.afterDeserialize(value); + serializing = currentSerialization; } serializing -= 1; return value; } } -let serializationTypes: { [name: string]: { ctor: { new(): any }, afterDeserialize?: (obj: any) => void } } = {}; +let serializationTypes: { [name: string]: { ctor: { new(): any }, afterDeserialize?: (obj: any) => void | Promise } } = {}; let reverseMap: { [ctor: string]: string } = {}; export interface DeserializableOpts { @@ -69,7 +72,7 @@ export interface DeserializableOpts { withFields(fields: string[]): Function; } -export function Deserializable(name: string, afterDeserialize?: (obj: any) => void): DeserializableOpts; +export function Deserializable(name: string, afterDeserialize?: (obj: any) => void | Promise): DeserializableOpts; export function Deserializable(constructor: { new(...args: any[]): any }): void; export function Deserializable(constructor: { new(...args: any[]): any } | string, afterDeserialize?: (obj: any) => void): DeserializableOpts | void { function addToMap(name: string, ctor: { new(...args: any[]): any }) { @@ -135,6 +138,6 @@ export namespace Deserializable { export function autoObject(): PropSchema { return custom( (s) => SerializationHelper.Serialize(s), - (s) => SerializationHelper.Deserialize(s) + (json: any, context: any, oldValue: any, cb: (err: any, result: any) => void) => SerializationHelper.Deserialize(json).then(res => cb(null, res)) ); } \ No newline at end of file diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index c7f7bdb66..1910e409b 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,5 +1,5 @@ import { observable, action, computed, runInAction } from "mobx"; -import { ColorResult } from 'react-color'; +import { ColorState } from 'react-color'; import React = require("react"); import { observer } from "mobx-react"; import "./InkingControl.scss"; @@ -41,7 +41,7 @@ export class InkingControl extends React.Component { } @undoBatch - switchColor = action((color: ColorResult): void => { + switchColor = action((color: ColorState): void => { this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff"); if (InkingControl.Instance.selectedTool === InkTool.None) { if (MainOverlayTextBox.Instance.SetColor(color.hex)) return; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 59e61023f..45eb2e514 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -67,8 +67,15 @@ export function DocListCast(field: FieldResult): Doc[] { export const WidthSym = Symbol("Width"); export const HeightSym = Symbol("Height"); +function fetchProto(doc: Doc) { + const proto = doc.proto; + if (proto instanceof Promise) { + return proto; + } +} + @scriptingGlobal -@Deserializable("doc").withFields(["id"]) +@Deserializable("doc", fetchProto).withFields(["id"]) export class Doc extends RefField { constructor(id?: FieldId, forceSave?: boolean) { super(id); @@ -133,14 +140,14 @@ export class Doc extends RefField { return "invalid"; } - public [HandleUpdate](diff: any) { + public async [HandleUpdate](diff: any) { const set = diff.$set; if (set) { for (const key in set) { if (!key.startsWith("fields.")) { continue; } - const value = SerializationHelper.Deserialize(set[key]); + const value = await SerializationHelper.Deserialize(set[key]); const fKey = key.substring(7); this[fKey] = value; } diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index 38d874a68..14f08814e 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -48,7 +48,7 @@ export class ProxyField extends ObjectField { private failed = false; private promise?: Promise; - value(): T | undefined | FieldWaiting { + value(): T | undefined | FieldWaiting { if (this.cache) { return this.cache; } @@ -63,6 +63,6 @@ export class ProxyField extends ObjectField { return field; })); } - return this.promise; + return this.promise as any; } } diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index e8a1ea28a..e1f65fc9c 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -2,10 +2,11 @@ import { ObjectField } from "./ObjectField"; import { CompiledScript, CompileScript, scriptingGlobal } from "../client/util/Scripting"; import { Copy, ToScriptString, Parent, SelfProxy } from "./FieldSymbols"; import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; -import { Deserializable } from "../client/util/SerializationHelper"; +import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Doc } from "../new_fields/Doc"; import { Plugins } from "./util"; import { computedFn } from "mobx-utils"; +import { ProxyField } from "./Proxy"; function optional(propSchema: PropSchema) { return custom(value => { @@ -34,7 +35,16 @@ const scriptSchema = createSimpleSchema({ originalScript: true }); -function deserializeScript(script: ScriptField) { +async function deserializeScript(script: ScriptField) { + const captures: ProxyField = (script as any).captures; + if (captures) { + const doc = (await captures.value())!; + const captured: any = {}; + const keys = Object.keys(doc); + const vals = await Promise.all(keys.map(key => doc[key]) as any); + keys.forEach((key, i) => captured[key] = vals[i]); + (script.script.options as any).capturedVariables = captured; + } const comp = CompileScript(script.script.originalScript, script.script.options); if (!comp.compiled) { throw new Error("Couldn't compile loaded script"); @@ -48,9 +58,17 @@ export class ScriptField extends ObjectField { @serializable(object(scriptSchema)) readonly script: CompiledScript; + @serializable(autoObject()) + private captures?: ProxyField; + constructor(script: CompiledScript) { super(); + if (script && script.options.capturedVariables) { + const doc = Doc.assign(new Doc, script.options.capturedVariables); + this.captures = new ProxyField(doc); + } + this.script = script; } -- cgit v1.2.3-70-g09d2 From 86971952237b8bd01a23b52db662740126bd8477 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 23 Jul 2019 18:00:52 -0400 Subject: some fixes for fitToBox, templates, and showTitle --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/EditableView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 76 +++++++++++++--------- src/client/views/collections/CollectionView.tsx | 15 +---- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +-- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 17 ++--- src/new_fields/Doc.ts | 26 ++++++-- 9 files changed, 87 insertions(+), 67 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2f7bea365..989b35581 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -525,8 +525,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - let proto = Doc.GetProto(element.props.Document); - let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight); + let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... + let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect) && nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { proto.nativeWidth = nwidth = doc.width || 0; proto.nativeHeight = nheight = doc.height || 0; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index f2cdffd38..c66a92f48 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -93,7 +93,7 @@ export class EditableView extends React.Component {
- {this.props.contents} + {this.props.contents}
); } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0e5f9a321..54b0e37b5 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; +import { emptyFunction, Utils, returnTrue } from "../../../Utils"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @@ -74,6 +74,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { DataDocument={resolvedDataDoc} showOverlays={this.overlays} renderDepth={this.props.renderDepth} + fitToBox={true} width={width} height={height} getTransform={finalDxf} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d05cc375e..f98629c5b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -74,15 +74,15 @@ class TreeView extends React.Component { @observable _collapsed: boolean = true; @computed get fieldKey() { - let keys = Array.from(Object.keys(this.resolvedDataDoc)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set - if (this.resolvedDataDoc.proto instanceof Doc) { - let arr = Array.from(Object.keys(this.resolvedDataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + let keys = Array.from(Object.keys(this.dataDoc)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + if (this.dataDoc.proto instanceof Doc) { + let arr = Array.from(Object.keys(this.dataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set keys.push(...arr); while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } let keyList: string[] = []; keys.map(key => { - let docList = Cast(this.resolvedDataDoc[key], listSpec(Doc)); + let docList = Cast(this.dataDoc[key], listSpec(Doc)); if (docList && docList.length > 0) { keyList.push(key); } @@ -94,7 +94,16 @@ class TreeView extends React.Component { return keyList.length ? keyList[0] : "data"; } - @computed get resolvedDataDoc() { return BoolCast(this.props.document.isTemplate) && this.props.dataDoc ? this.props.dataDoc : this.props.document; } + @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; } + @computed get resolvedDataDoc() { + if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) { + // if there is no dataDoc (ie, we're not rendering a template layout), but this document + // has a template layout document, then we will render the template layout but use + // this document as the data document for the layout. + return this.props.document; + } + return this.props.dataDoc ? this.props.dataDoc : undefined; + } protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); @@ -103,7 +112,7 @@ class TreeView extends React.Component { } } - @undoBatch delete = () => this.props.deleteDoc(this.resolvedDataDoc); + @undoBatch delete = () => this.props.deleteDoc(this.dataDoc); @undoBatch openRight = async () => this.props.addDocTab(this.props.document, undefined, "onRight"); onPointerDown = (e: React.PointerEvent) => e.stopPropagation(); @@ -135,7 +144,7 @@ class TreeView extends React.Component { @action remove = (document: Document, key: string): boolean => { - let children = Cast(this.resolvedDataDoc[key], listSpec(Doc), []); + let children = Cast(this.dataDoc[key], listSpec(Doc), []); if (children.indexOf(document) !== -1) { children.splice(children.indexOf(document), 1); return true; @@ -151,8 +160,8 @@ class TreeView extends React.Component { indent = () => this.props.addDocument(this.props.document) && this.delete() renderBullet() { - let docList = Cast(this.resolvedDataDoc[this.fieldKey], listSpec(Doc)); - let doc = Cast(this.resolvedDataDoc[this.fieldKey], Doc); + let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc)); + let doc = Cast(this.dataDoc[this.fieldKey], Doc); let isDoc = doc instanceof Doc || docList; let c; return
this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}> @@ -164,16 +173,17 @@ class TreeView extends React.Component { editableView = (key: string, style?: string) => ( StrCast(this.props.document[key])} - SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc)[key] = value) ? true : true} + SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true} OnFillDown={(value: string) => { - Doc.GetProto(this.resolvedDataDoc)[key] = value; - let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + Doc.GetProto(this.dataDoc)[key] = value; + let doc = this.props.document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.detailedLayout)) : undefined; + if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; return this.props.addDocument(doc); }} @@ -181,16 +191,16 @@ class TreeView extends React.Component { />) @computed get keyList() { - let keys = Array.from(Object.keys(this.resolvedDataDoc)); - if (this.resolvedDataDoc.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto))); + let keys = Array.from(Object.keys(this.dataDoc)); + if (this.dataDoc.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(this.dataDoc.proto))); } let keyList: string[] = keys.reduce((l, key) => { - let listspec = DocListCast(this.resolvedDataDoc[key]); + let listspec = DocListCast(this.dataDoc[key]); if (listspec && listspec.length) return [...l, key]; return l; }, [] as string[]); - keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key)); + keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && (Cast(this.dataDoc[key], Doc) as Doc).type !== undefined && keyList.push(key)); if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links"); if (keyList.indexOf(this.fieldKey) !== -1) { keyList.splice(keyList.indexOf(this.fieldKey), 1); @@ -203,7 +213,7 @@ class TreeView extends React.Component { */ renderTitle() { let reference = React.createRef(); - let onItemDown = SetupDrag(reference, () => this.resolvedDataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); + let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); let headerElements = ( { {this._chosenKey} ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : []; - let openRight = dataDocs && dataDocs.indexOf(this.resolvedDataDoc) !== -1 ? (null) : ( + let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
); @@ -241,12 +251,12 @@ class TreeView extends React.Component { if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" }); - if (DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).length) { - ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" }); + if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) { + ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.dataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" }); } ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)), icon: "trash-alt" }); } else { - ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.resolvedDataDoc)), icon: "caret-square-right" }); + ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.dataDoc)), icon: "caret-square-right" }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.props.document)), icon: "trash-alt" }); } ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.Create.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" }); @@ -274,7 +284,7 @@ class TreeView extends React.Component { if (de.data.draggedDocuments[0] === this.props.document) return true; let addDoc = (doc: Doc) => this.props.addDocument(doc, this.resolvedDataDoc, before); if (inside) { - let docList = Cast(this.resolvedDataDoc.data, listSpec(Doc)); + let docList = Cast(this.dataDoc.data, listSpec(Doc)); if (docList !== undefined) { addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }; } @@ -326,7 +336,7 @@ class TreeView extends React.Component { @computed get boundsOfCollectionDocument() { if (StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1) return undefined; - let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + let layoutDoc = this.props.document; return Doc.ComputeContentBounds(DocListCast(layoutDoc.data)); } docWidth = () => { @@ -344,27 +354,30 @@ class TreeView extends React.Component { })()); } + noOverlays = (doc: Doc) => { return { title: "", caption: "" } }; + render() { let contentElement: (JSX.Element | null) = null; - let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc)); + let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); - let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.resolvedDataDoc, this._chosenKey, doc, addBefore, before); - let doc = Cast(this.resolvedDataDoc[this._chosenKey], Doc); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before); + let doc = Cast(this.dataDoc[this._chosenKey], Doc); if (!this._collapsed) { if (!this.props.document.embed) { contentElement =
    {this._chosenKey === "links" ? this.renderLinks() : - TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.props.dataDoc, this._chosenKey, addDoc, remDoc, this.move, + TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this._chosenKey, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
; } else { - let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + let layoutDoc = this.props.document; contentElement =
(Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true} OnFillDown={(value: string) => { Doc.GetProto(this.props.Document).title = value; - let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + let doc = this.props.Document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.detailedLayout)) : undefined; + if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true); }} /> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 045c8531e..4a51a1f58 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -50,7 +50,6 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } - static _applyCount: number = 0; onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 let subItems: ContextMenuProps[] = []; @@ -63,19 +62,7 @@ export class CollectionView extends React.Component { subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" }); subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" }); ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); - ContextMenu.Instance.addItem({ - description: "Apply Template", event: undoBatch(() => { - let otherdoc = new Doc(); - otherdoc.width = this.props.Document[WidthSym](); - otherdoc.height = this.props.Document[HeightSym](); - otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" - otherdoc.layout = Doc.MakeDelegate(this.props.Document); - otherdoc.miniLayout = StrCast(this.props.Document.miniLayout); - otherdoc.detailedLayout = otherdoc.layout; - otherdoc.type = DocumentType.TEMPLATE; - this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight"); - }), icon: "project-diagram" - }); + ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 703873681..6bb082b66 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -195,10 +195,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._pheight / this.zoomScaling()); let panelwidth = panelDim[0]; let panelheight = panelDim[1]; - if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2; - if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2; - if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2; - if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2; + // if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2; + // if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2; + // if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2; + // if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2; } this.setPan(x - dx, y - dy); this._lastX = e.pageX; @@ -358,6 +358,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { let self = this; let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; + resolvedDataDoc && Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey); let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc); return { DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined, diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index ed6b224a7..ef65c12cf 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -64,7 +64,7 @@ export class DocumentContentsView extends React.Component(Docu @undoBatch @action freezeNativeDimensions = (): void => { - let proto = Doc.GetProto(this.props.Document); + let proto = this.props.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document); if (proto.ignoreAspect === undefined && !proto.nativeWidth) { proto.nativeWidth = this.props.PanelWidth(); proto.nativeHeight = this.props.PanelHeight(); @@ -629,10 +629,10 @@ export class DocumentView extends DocComponent(Docu var nativeWidth = this.nativeWidth > 0 ? `${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.props.Document) : undefined; - let showTitle = showOverlays && showOverlays.title ? showOverlays.title : StrCast(this.props.Document.showTitle); - let showCaption = showOverlays && showOverlays.caption ? showOverlays.caption : StrCast(this.props.Document.showCaption); + let showTitle = showOverlays && showOverlays.title !== "undefined" ? showOverlays.title : StrCast(this.props.Document.showTitle); + let showCaption = showOverlays && showOverlays.caption !== "undefined" ? showOverlays.caption : StrCast(this.props.Document.showCaption); let templates = Cast(this.props.Document.templates, listSpec("string")); - if (templates instanceof List) { + 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"; @@ -663,12 +663,12 @@ export class DocumentView extends DocComponent(Docu {!showTitle && !showCaption ? this.contents :
-
+
{this.contents}
{!showTitle ? (null) :
(Docu contents={this.props.Document[showTitle]} display={"block"} height={72} - GetValue={() => StrCast(this.props.Document[showTitle])} - SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle] = value) ? true : true} + fontSize={12} + GetValue={() => StrCast(this.props.Document[showTitle!])} + SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle!] = value) ? true : true} />
} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2ad6ae5f0..5ae0753d8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -244,7 +244,7 @@ export namespace Doc { let r = (doc === other); let r2 = (doc.proto === other); let r3 = (other.proto === doc); - let r4 = (doc.proto === other.proto); + let r4 = (doc.proto === other.proto && other.proto !== undefined); return r || r2 || r3 || r4; } @@ -298,7 +298,7 @@ export namespace Doc { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) }; - }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); + }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE }); return bounds; } @@ -350,19 +350,21 @@ export namespace Doc { if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } + expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]]; + if (expandedTemplateLayout instanceof Doc) { + return expandedTemplateLayout; + } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; expandedDoc.isExpandedTemplate = templateLayoutDoc; - dataDoc[templateLayoutDoc[Id]] = expandedDoc; + dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]] = expandedDoc; }, 0); } return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } - let _pendingExpansions: Map = new Map(); - export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { @@ -398,6 +400,20 @@ export namespace Doc { return undefined; } + let _applyCount: number = 0; + export function ApplyTemplate(templateDoc: Doc) { + if (!templateDoc) return undefined; + let otherdoc = new Doc(); + otherdoc.width = templateDoc[WidthSym](); + otherdoc.height = templateDoc[HeightSym](); + otherdoc.title = templateDoc.title + "(..." + _applyCount++ + ")"; + otherdoc.layout = Doc.MakeDelegate(templateDoc); + otherdoc.miniLayout = StrCast(templateDoc.miniLayout); + otherdoc.detailedLayout = otherdoc.layout; + otherdoc.type = DocumentType.TEMPLATE; + return otherdoc; + } + export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); -- cgit v1.2.3-70-g09d2 From 35b1450709c751ae9782f60140d31718fed8146d Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 23 Jul 2019 18:22:19 -0400 Subject: Fixed async deserialization --- src/client/util/SerializationHelper.ts | 18 +++++++++--------- src/new_fields/Doc.ts | 8 ++++---- src/new_fields/List.ts | 4 ++-- src/new_fields/RefField.ts | 3 ++- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index 692d07c74..94b640afa 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -1,9 +1,14 @@ import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema, primitive, SKIP } from "serializr"; -import { Field } from "../../new_fields/Doc"; +import { Field, Doc } from "../../new_fields/Doc"; import { ClientUtils } from "./ClientUtils"; +let serializing = 0; +export function afterDocDeserialize(cb: (err: any, val: any) => void, err: any, newValue: any) { + serializing++; + cb(err, newValue); + serializing--; +} export namespace SerializationHelper { - let serializing: number = 0; export function IsSerializing() { return serializing > 0; } @@ -17,14 +22,14 @@ export namespace SerializationHelper { return obj; } - serializing += 1; + serializing++; if (!(obj.constructor.name in reverseMap)) { throw Error(`type '${obj.constructor.name}' not registered. Make sure you register it using a @Deserializable decorator`); } const json = serialize(obj); json.__type = reverseMap[obj.constructor.name]; - serializing -= 1; + serializing--; return json; } @@ -37,7 +42,6 @@ export namespace SerializationHelper { return obj; } - serializing += 1; if (!obj.__type) { if (ClientUtils.RELEASE) { console.warn("No property 'type' found in JSON."); @@ -54,12 +58,8 @@ export namespace SerializationHelper { const type = serializationTypes[obj.__type]; const value = await new Promise(res => deserialize(type.ctor, obj, (err, result) => res(result))); if (type.afterDeserialize) { - const currentSerialization = serializing; - serializing = 0; await type.afterDeserialize(value); - serializing = currentSerialization; } - serializing -= 1; return value; } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 45eb2e514..f0a2f7e07 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -1,6 +1,6 @@ import { observable, action } from "mobx"; -import { serializable, primitive, map, alias, list } from "serializr"; -import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive, map, alias, list, PropSchema, custom } from "serializr"; +import { autoObject, SerializationHelper, Deserializable, afterDocDeserialize } from "../client/util/SerializationHelper"; import { DocServer } from "../client/DocServer"; import { setter, getter, getField, updateFunction, deleteProperty, makeEditable, makeReadOnly } from "./util"; import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast, BoolCast, StrCast } from "./Types"; @@ -61,7 +61,7 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { } export function DocListCast(field: FieldResult): Doc[] { - return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; + return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; j } export const WidthSym = Symbol("Width"); @@ -108,7 +108,7 @@ export class Doc extends RefField { proto: Opt; [key: string]: FieldResult; - @serializable(alias("fields", map(autoObject()))) + @serializable(alias("fields", map(autoObject(), { afterDeserialize: afterDocDeserialize }))) private get __fields() { return this.___fields; } diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index a2133a990..0c7b77fa5 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,4 +1,4 @@ -import { Deserializable, autoObject } from "../client/util/SerializationHelper"; +import { Deserializable, autoObject, afterDocDeserialize } from "../client/util/SerializationHelper"; import { Field } from "./Doc"; import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; @@ -254,7 +254,7 @@ class ListImpl extends ObjectField { [key: number]: T | (T extends RefField ? Promise : never); - @serializable(alias("fields", list(autoObject()))) + @serializable(alias("fields", list(autoObject(), { afterDeserialize: afterDocDeserialize }))) private get __fields() { return this.___fields; } diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts index 75ce4287f..5414df2b9 100644 --- a/src/new_fields/RefField.ts +++ b/src/new_fields/RefField.ts @@ -1,10 +1,11 @@ import { serializable, primitive, alias } from "serializr"; import { Utils } from "../Utils"; import { Id, HandleUpdate, ToScriptString } from "./FieldSymbols"; +import { afterDocDeserialize } from "../client/util/SerializationHelper"; export type FieldId = string; export abstract class RefField { - @serializable(alias("id", primitive())) + @serializable(alias("id", primitive({ afterDeserialize: afterDocDeserialize }))) private __id: FieldId; readonly [Id]: FieldId; -- cgit v1.2.3-70-g09d2 From 6d25848a9e8614c1debc8550e42fc706f77883db Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 23 Jul 2019 19:07:08 -0400 Subject: more template stuff --- src/client/views/collections/CollectionTreeView.tsx | 20 +++++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +++++++-- src/new_fields/Doc.ts | 9 +++++++-- 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f98629c5b..ca5812eba 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -74,9 +74,10 @@ class TreeView extends React.Component { @observable _collapsed: boolean = true; @computed get fieldKey() { - let keys = Array.from(Object.keys(this.dataDoc)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set - if (this.dataDoc.proto instanceof Doc) { - let arr = Array.from(Object.keys(this.dataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + let target = this.props.document.layout && this.dataDoc ? this.dataDoc : this.props.document; + let keys = Array.from(Object.keys(target)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + if (target.proto instanceof Doc) { + let arr = Array.from(Object.keys(target.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set keys.push(...arr); while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } @@ -191,16 +192,17 @@ class TreeView extends React.Component { />) @computed get keyList() { - let keys = Array.from(Object.keys(this.dataDoc)); - if (this.dataDoc.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.dataDoc.proto))); + let target = this.props.document.layout && this.dataDoc ? this.dataDoc : this.props.document; + let keys = Array.from(Object.keys(target)); + if (target.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(target.proto))); } let keyList: string[] = keys.reduce((l, key) => { - let listspec = DocListCast(this.dataDoc[key]); + let listspec = DocListCast(target[key]); if (listspec && listspec.length) return [...l, key]; return l; }, [] as string[]); - keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && (Cast(this.dataDoc[key], Doc) as Doc).type !== undefined && keyList.push(key)); + keys.map(key => Cast(target[key], Doc) instanceof Doc && keyList.push(key)); if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links"); if (keyList.indexOf(this.fieldKey) !== -1) { keyList.splice(keyList.indexOf(this.fieldKey), 1); @@ -361,7 +363,7 @@ class TreeView extends React.Component { let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before); - let doc = Cast(this.dataDoc[this._chosenKey], Doc); + let doc = Cast((this.props.document.layout ? this.dataDoc : this.props.document)[this._chosenKey], Doc); if (!this._collapsed) { if (!this.props.document.embed) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6bb082b66..e7d2a66e5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -31,6 +31,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; +import { resolve } from "bluebird"; export const panZoomSchema = createSchema({ @@ -358,8 +359,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { let self = this; let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; - resolvedDataDoc && Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey); - let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc); + let layoutDoc = childDocLayout; + if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) { + Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey); + let fieldExtensionDoc = Doc.resolvedFieldDataDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)), "dummy"); + layoutDoc = Doc.expandTemplateLayout(childDocLayout, fieldExtensionDoc !== resolvedDataDoc ? fieldExtensionDoc : undefined); + } else layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc); return { DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined, Document: layoutDoc, diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5ae0753d8..e4bf4a6c1 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -337,11 +337,15 @@ export namespace Doc { return Doc.MakeDelegate(doc); // bcz? } - export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { + export function WillExpandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { let resolvedDataDoc = (templateLayoutDoc !== dataDoc) ? dataDoc : undefined; if (!dataDoc || !(templateLayoutDoc && !(Cast(templateLayoutDoc.layout, Doc) instanceof Doc) && resolvedDataDoc && resolvedDataDoc !== templateLayoutDoc)) { - return templateLayoutDoc; + return false; } + return true; + } + export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { + if (!WillExpandTemplateLayout(templateLayoutDoc, dataDoc) || !dataDoc) return templateLayoutDoc; // if we have a data doc that doesn't match the layout, then we're rendering a template. // ... which means we change the layout to be an expanded view of the template layout. // This allows the view override the template's properties and be referenceable as its own document. @@ -433,6 +437,7 @@ export namespace Doc { layoutDelegate.layout = layout; fieldTemplate.title = metaKey; + fieldTemplate.templateField = metaKey; fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout; fieldTemplate.backgroundLayout = backgroundLayout; fieldTemplate.nativeWidth = nw; -- cgit v1.2.3-70-g09d2 From cb95d4b43238538f59babcaa0b0d9dabb9b393b7 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 22:07:13 -0400 Subject: Ink recognition and presentation view toggle --- src/client/cognitive_services/CognitiveServices.ts | 86 +++++++++++++++++++++- src/client/views/InkingCanvas.tsx | 4 +- src/client/views/MainView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++ .../views/presentationview/PresentationView.tsx | 12 ++- src/new_fields/FieldSymbols.ts | 2 +- src/new_fields/InkField.ts | 6 +- src/server/index.ts | 19 ++--- 8 files changed, 124 insertions(+), 18 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index d4085cf76..71e4276dc 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -8,10 +8,12 @@ import { RouteStore } from "../../server/RouteStore"; import { Utils } from "../../Utils"; import { CompileScript } from "../util/Scripting"; import { ComputedField } from "../../new_fields/ScriptField"; +import { InkData } from "../../new_fields/InkField"; export enum Services { ComputerVision = "vision", - Face = "face" + Face = "face", + Handwriting = "handwriting" } export enum Confidence { @@ -132,4 +134,86 @@ export namespace CognitiveServices { } + export namespace Inking { + + export interface AzureStrokeData { + id: number; + points: string; + language?: string; + } + + export interface HandwritingUnit { + version: number; + language: string; + unit: string; + strokes: AzureStrokeData[]; + } + + export const analyze = async (inkData: InkData, target: Doc) => { + return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${Services.Handwriting}`)).then(async response => { + let apiKey = await response.text(); + if (!apiKey) { + return undefined; + } + + let xhttp = new XMLHttpRequest(); + let serverAddress = "https://api.cognitive.microsoft.com"; + let endpoint = serverAddress + "/inkrecognizer/v1.0-preview/recognize"; + + let results = await new Promise((resolve, reject) => { + let result: any; + xhttp.onreadystatechange = function () { + if (this.readyState === 4) { + try { + result = JSON.parse(xhttp.responseText); + } catch (e) { + return reject(e); + } + switch (this.status) { + case 200: + return resolve(result); + case 400: + default: + return reject(result); + } + } + }; + + xhttp.open("PUT", endpoint, true); + xhttp.setRequestHeader('Ocp-Apim-Subscription-Key', apiKey); + xhttp.setRequestHeader('Content-Type', 'application/json'); + xhttp.send(JSON.stringify(toHandwritingUnit(inkData))); + }); + + let recognizedText = results.recognitionUnits.map((unit: any) => unit.recognizedText); + let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); + target.inkAnalysis = Docs.Get.DocumentHierarchyFromJson(results.recognitionUnits, "Ink Analysis"); + target.handwriting = individualWords.join(" "); + }); + }; + + const toHandwritingUnit = (inkData: InkData): HandwritingUnit => { + let entries = inkData.entries(), next = entries.next(); + let strokes: AzureStrokeData[] = []; + let id = 0; + while (!next.done) { + let entry = next.value; + let data = { + id: id++, + points: entry[1].pathData.map(point => `${point.x},${point.y}`).join(","), + language: "en-US" + }; + strokes.push(data); + next = entries.next(); + } + return { + version: 1, + language: "en-US", + unit: "mm", + strokes: strokes + }; + }; + + } + } \ No newline at end of file diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 3e0d7b476..e48b45b56 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -10,6 +10,8 @@ import { undoBatch, UndoManager } from "../util/UndoManager"; import { StrokeData, InkField, InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; +import { CognitiveServices } from "../cognitive_services/CognitiveServices"; +import { ContextMenu } from "./ContextMenu"; interface InkCanvasProps { getScreenTransform: () => Transform; @@ -178,7 +180,7 @@ export class InkingCanvas extends React.Component { render() { let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect"; return ( -
+
{this.props.children()} {this.drawnPaths} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 94a4835a1..53be0278e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -394,6 +394,7 @@ export class MainView extends React.Component {
  • +
  • {btns.map(btn => @@ -444,7 +445,6 @@ export class MainView extends React.Component { this.isSearchVisible = !this.isSearchVisible; } - render() { return (
    diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 703873681..3fd86e950 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -31,6 +31,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; +import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; export const panZoomSchema = createSchema({ @@ -51,6 +52,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _lastY: number = 0; private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } + private inkKey = "ink"; @computed get contentBounds() { let bounds = this.props.fitToBox && !NumCast(this.nativeWidth) ? Doc.ComputeContentBounds(DocListCast(this.props.Document.data)) : undefined; @@ -477,6 +479,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } }); + ContextMenu.Instance.addItem({ + description: "Analyze Strokes", event: async () => { + let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); + if (!data) { + return; + } + CognitiveServices.Inking.analyze(data.inkData, Doc.GetProto(this.props.Document)); + } + }); ContextMenu.Instance.addItem({ description: "Add freeform arrangement", event: () => { diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index f80840f96..966ade3de 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -31,6 +31,8 @@ export interface PresViewProps { Documents: List; } +const expandedWidth = 400; + @observer export class PresentationView extends React.Component { public static Instance: PresentationView; @@ -67,6 +69,14 @@ export class PresentationView extends React.Component { PresentationView.Instance = this; } + toggle = (forcedValue: boolean | undefined) => { + if (forcedValue !== undefined) { + this.curPresentation.width = forcedValue ? expandedWidth : 0; + } else { + this.curPresentation.width = this.curPresentation.width === expandedWidth ? 0 : expandedWidth; + } + } + //The first lifecycle function that gets called to set up the current presentation. async componentWillMount() { this.props.Documents.forEach(async (doc, index: number) => { @@ -543,7 +553,7 @@ export class PresentationView extends React.Component { this.curPresentation.data = new List([doc]); } - this.curPresentation.width = 400; + this.toggle(true); } //Function that sets the store of the children docs. diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts index a436dcf2b..b5b3aa588 100644 --- a/src/new_fields/FieldSymbols.ts +++ b/src/new_fields/FieldSymbols.ts @@ -7,4 +7,4 @@ export const Id = Symbol("Id"); export const OnUpdate = Symbol("OnUpdate"); export const Parent = Symbol("Parent"); export const Copy = Symbol("Copy"); -export const ToScriptString = Symbol("Copy"); \ No newline at end of file +export const ToScriptString = Symbol("ToScriptString"); \ No newline at end of file diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 39c6c8ce3..8f64c1c2e 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -19,6 +19,8 @@ export interface StrokeData { page: number; } +export type InkData = Map; + const pointSchema = createSimpleSchema({ x: true, y: true }); @@ -31,9 +33,9 @@ const strokeDataSchema = createSimpleSchema({ @Deserializable("ink") export class InkField extends ObjectField { @serializable(map(object(strokeDataSchema))) - readonly inkData: Map; + readonly inkData: InkData; - constructor(data?: Map) { + constructor(data?: InkData) { super(); this.inkData = data || new Map; } diff --git a/src/server/index.ts b/src/server/index.ts index 5b086a2cf..66c982adc 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -284,18 +284,15 @@ addSecureRoute( RouteStore.getCurrUser ); +const ServicesApiKeyMap = new Map([ + ["face", process.env.FACE], + ["vision", process.env.VISION], + ["handwriting", process.env.HANDWRITING] +]); + addSecureRoute(Method.GET, (user, res, req) => { - let requested = req.params.requestedservice; - switch (requested) { - case "face": - res.send(process.env.FACE); - break; - case "vision": - res.send(process.env.VISION); - break; - default: - res.send(undefined); - } + let service = req.params.requestedservice; + res.send(ServicesApiKeyMap.get(service)); }, undefined, `${RouteStore.cognitiveServices}/:requestedservice`); class NodeCanvasFactory { -- cgit v1.2.3-70-g09d2 From 2bba7deec5e16671b4a1bbed6eac6008ca01ff7c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 23 Jul 2019 22:28:58 -0400 Subject: cleanup of templates for treeview --- src/client/views/collections/CollectionTreeView.tsx | 8 ++++---- src/client/views/nodes/FieldView.tsx | 3 ++- src/new_fields/Doc.ts | 21 +++++++++++++++------ 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ca5812eba..2ff9e43fe 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -74,7 +74,7 @@ class TreeView extends React.Component { @observable _collapsed: boolean = true; @computed get fieldKey() { - let target = this.props.document.layout && this.dataDoc ? this.dataDoc : this.props.document; + let target = this.props.document; let keys = Array.from(Object.keys(target)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set if (target.proto instanceof Doc) { let arr = Array.from(Object.keys(target.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set @@ -89,7 +89,7 @@ class TreeView extends React.Component { } }); let layout = StrCast(this.props.document.layout); - if (layout.indexOf("fieldKey={\"") !== -1) { + if (layout.indexOf("fieldKey={\"") !== -1 && layout.indexOf("fieldExt=") === -1) { return layout.split("fieldKey={\"")[1].split("\"")[0]; } return keyList.length ? keyList[0] : "data"; @@ -192,7 +192,7 @@ class TreeView extends React.Component { />) @computed get keyList() { - let target = this.props.document.layout && this.dataDoc ? this.dataDoc : this.props.document; + let target = this.props.document; let keys = Array.from(Object.keys(target)); if (target.proto instanceof Doc) { keys.push(...Array.from(Object.keys(target.proto))); @@ -363,10 +363,10 @@ class TreeView extends React.Component { let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before); - let doc = Cast((this.props.document.layout ? this.dataDoc : this.props.document)[this._chosenKey], Doc); if (!this._collapsed) { if (!this.props.document.embed) { + let doc = Cast(this.props.document[this._chosenKey], Doc); contentElement =
      {this._chosenKey === "links" ? this.renderLinks() : TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this._chosenKey, addDoc, remDoc, this.move, diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ea6730cd0..ffaee8042 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -87,7 +87,8 @@ export class FieldView extends React.Component { return

      {field.date.toLocaleString()}

      ; } else if (field instanceof Doc) { - return

      {field.title + " : id= " + field[Id]}

      ; + return

      {field.title}

      ; + //return

      {field.title + " : id= " + field[Id]}

      ; // let returnHundred = () => 100; // return ( // { let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = doc.title + ":" + fieldKey + ".ext"; + docExtensionForField.title = fieldKey + "[" + StrCast(doc.title).match(/\.\.\.[0-9]*/) + "].ext"; docExtensionForField.extendsDoc = doc; let proto: Doc | undefined = doc; while (proto && !Doc.IsPrototype(proto)) { @@ -337,9 +337,16 @@ export namespace Doc { return Doc.MakeDelegate(doc); // bcz? } - export function WillExpandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { - let resolvedDataDoc = (templateLayoutDoc !== dataDoc) ? dataDoc : undefined; - if (!dataDoc || !(templateLayoutDoc && !(Cast(templateLayoutDoc.layout, Doc) instanceof Doc) && resolvedDataDoc && resolvedDataDoc !== templateLayoutDoc)) { + // + // Determines whether the combination of the layoutDoc and dataDoc represents + // a template relationship. If so, the layoutDoc will be expanded into a new + // document that inherits the properties of the original layout while allowing + // for individual layout properties to be overridden in the expanded layout. + // + export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) { + let resolvedDataDoc = (layoutDoc !== dataDoc) ? dataDoc : undefined; + if (!dataDoc || !(layoutDoc && !(Cast(layoutDoc.layout, Doc) instanceof Doc) && + resolvedDataDoc && resolvedDataDoc !== layoutDoc)) { return false; } return true; @@ -354,16 +361,18 @@ export namespace Doc { if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } - expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]]; + // expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]]; + expandedTemplateLayout = dataDoc["Layout[" + templateLayoutDoc[Id] + "]"]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); + //expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; expandedDoc.isExpandedTemplate = templateLayoutDoc; - dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]] = expandedDoc; + dataDoc["Layout[" + templateLayoutDoc[Id] + "]"] = expandedDoc; }, 0); } return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. -- cgit v1.2.3-70-g09d2 From 189cf09a7c81e8b4b2f5313cf093097cc9eba03e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jul 2019 00:16:52 -0400 Subject: more cleanup --- src/client/documents/Documents.ts | 3 ++- src/new_fields/Doc.ts | 53 ++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 27 deletions(-) (limited to 'src/new_fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7563fda20..a5b1d6573 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -56,7 +56,8 @@ export enum DocumentType { IMPORT = "import", LINK = "link", LINKDOC = "linkdoc", - TEMPLATE = "template" + TEMPLATE = "template", + EXTENSION = "extension" } export interface DocumentOptions { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5a9a0eab4..2a697e621 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -314,20 +314,22 @@ export namespace Doc { } export function UpdateDocumentExtensionForField(doc: Doc, fieldKey: string) { - let extensionDoc = doc[fieldKey + "_ext"]; - if (extensionDoc === undefined) { + let docExtensionForField = doc[fieldKey + "_ext"] as Doc; + if (docExtensionForField === undefined) { setTimeout(() => { - let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = fieldKey + "[" + StrCast(doc.title).match(/\.\.\.[0-9]*/) + "].ext"; - docExtensionForField.extendsDoc = doc; + 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 : doc)[fieldKey + "_ext"] = docExtensionForField; }, 0); - } else if (extensionDoc instanceof Doc && extensionDoc.extendsDoc === undefined) { - setTimeout(() => (extensionDoc as Doc).extendsDoc = doc, 0); + } else if (doc instanceof Doc) { // backward compatibility -- add fields for docs that don't have them already + docExtensionForField.extendsDoc === undefined && setTimeout(() => (docExtensionForField as Doc).extendsDoc = doc, 0); + docExtensionForField.type === undefined && setTimeout(() => (docExtensionForField as Doc).type = DocumentType.EXTENSION, 0); } } export function MakeAlias(doc: Doc) { @@ -344,13 +346,16 @@ export namespace Doc { // for individual layout properties to be overridden in the expanded layout. // export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) { - let resolvedDataDoc = (layoutDoc !== dataDoc) ? dataDoc : undefined; - if (!dataDoc || !(layoutDoc && !(Cast(layoutDoc.layout, Doc) instanceof Doc) && - resolvedDataDoc && resolvedDataDoc !== layoutDoc)) { - return false; - } - return true; + return BoolCast(layoutDoc.isTemplate) && dataDoc && layoutDoc !== dataDoc && !(layoutDoc.layout instanceof Doc); } + + // + // Returns an expanded template layout for a target data document. + // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc + // using the template layout doc's id as the field key. + // If it doesn't find the expanded layout, then it makes a delegate of the template layout and + // saves it on the data doc indexed by the template layout's id + // export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { if (!WillExpandTemplateLayout(templateLayoutDoc, dataDoc) || !dataDoc) return templateLayoutDoc; // if we have a data doc that doesn't match the layout, then we're rendering a template. @@ -361,19 +366,14 @@ export namespace Doc { if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } - // expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]]; - expandedTemplateLayout = dataDoc["Layout[" + templateLayoutDoc[Id] + "]"]; + let expandedLayoutFieldKey = "Layout[" + templateLayoutDoc[Id] + "]"; + expandedTemplateLayout = dataDoc[expandedLayoutFieldKey]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } - if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { - setTimeout(() => { - let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); - //expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; - expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; - expandedDoc.isExpandedTemplate = templateLayoutDoc; - dataDoc["Layout[" + templateLayoutDoc[Id] + "]"] = expandedDoc; - }, 0); + if (expandedTemplateLayout === undefined) { + setTimeout(() => + dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, templateLayoutDoc.title + ".layout"), 0); } return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } @@ -402,12 +402,13 @@ export namespace Doc { return copy; } - export function MakeDelegate(doc: Doc, id?: string): Doc; - export function MakeDelegate(doc: Opt, id?: string): Opt; - export function MakeDelegate(doc: Opt, id?: string): Opt { + export function MakeDelegate(doc: Doc, id?: string, title?: string): Doc; + export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt; + export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt { if (doc) { const delegate = new Doc(id, true); delegate.proto = doc; + title && (delegate.title = title); return delegate; } return undefined; -- cgit v1.2.3-70-g09d2 From 5bc848bde4f37ec3dc812b22d81ded16f2a86f93 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jul 2019 00:35:29 -0400 Subject: fixed reordering tree view items. restored double-click to view detail view. --- src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 1 + src/new_fields/Doc.ts | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/new_fields') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2ff9e43fe..fe636942c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -448,7 +448,7 @@ class TreeView extends React.Component { dataDoc={dataDoc} containingCollection={containingCollection} treeViewId={treeViewId} - key={child[Id] + "child " + i} + key={child[Id]} indentDocument={indent} renderDepth={renderDepth} deleteDoc={remove} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 09a1b49fe..8d7b3d835 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -295,6 +295,7 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth) { let fullScreenAlias = Doc.MakeAlias(this.props.Document); fullScreenAlias.templates = new List(); + Doc.UseDetailLayout(fullScreenAlias); this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = undefined; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2a697e621..a1241aac3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -463,4 +463,12 @@ export namespace Doc { d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; } + export async function UseDetailLayout(d: Doc) { + let miniLayout = await PromiseValue(d.miniLayout); + let detailLayout = await PromiseValue(d.detailedLayout); + if (miniLayout && d.layout === miniLayout && detailLayout) { + d.layout = detailLayout; + Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; + } + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 384ed4ab5c1b471678f12611f2b741f9771c7b16 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jul 2019 01:00:25 -0400 Subject: changed nativeheight stuff for detailed layouts --- src/new_fields/Doc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/new_fields') diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index a1241aac3..bf6cd2fa6 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -468,7 +468,7 @@ export namespace Doc { let detailLayout = await PromiseValue(d.detailedLayout); if (miniLayout && d.layout === miniLayout && detailLayout) { d.layout = detailLayout; - Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; + d.nativeWidth = d.nativeHeight = undefined; } } } \ No newline at end of file -- cgit v1.2.3-70-g09d2