From b4ef60552f226e4022fac5092ea66f1b685bb08c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 22 Jul 2019 18:50:26 -0400 Subject: Started adding schema functionality --- src/client/views/nodes/DocumentView.tsx | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1c03bfc81..7280dbcf6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -37,6 +37,7 @@ import { RouteStore } from '../../../server/RouteStore'; import { FormattedTextBox } from './FormattedTextBox'; import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; +import { ClientUtils } from '../../util/ClientUtils'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -58,6 +59,7 @@ library.add(fa.faCrosshairs); library.add(fa.faDesktop); library.add(fa.faUnlock); library.add(fa.faLock); +library.add(fa.faLaptopCode); // const linkSchema = createSchema({ @@ -551,17 +553,18 @@ export class DocumentView extends DocComponent(Docu this.props.removeDocument && this.props.removeDocument(this.props.Document); }, icon: "window-restore" }); - cm.addItem({ - description: "Find aliases", event: async () => { - const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? - }, icon: "search" - }); - cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); + // cm.addItem({ + // description: "Find aliases", event: async () => { + // const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); + // this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? + // }, icon: "search" + // }); + cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + if (!ClientUtils.RELEASE) { + cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); + cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + } cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; let usersMenu: ContextMenuProps[] = []; -- 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/client/views/nodes') 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 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/client/views/nodes') 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 52dc823c6a4c4b3e8deb994358a10acca4b6bd6c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Jul 2019 12:31:07 -0400 Subject: Added transitions --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 3 --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 70c43bbec..7a9b94bfd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -503,11 +503,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onError(script.errors.map(error => error.messageText).join("\n")); return; } - const docs = DocListCast(doc[dataKey]); - docs.map(d => d.transition = "transform 1s"); doc[key] = new ScriptField(script); overlayDisposer(); - setTimeout(() => docs.map(d => d.transition = undefined), 1200); }} />; overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options); }; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index b09538d1a..389b9f68b 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -82,6 +82,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); if (!ClientUtils.RELEASE) { -- cgit v1.2.3-70-g09d2 From 20d8950b0b3adb676de5ef4c2d625d57de38a9b4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 24 Jul 2019 16:51:33 -0400 Subject: tiny fixes. --- src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0f60bd0fb..89ad18dd6 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -355,7 +355,7 @@ export class ImageBox extends DocComponent(ImageD let rotation = NumCast(this.dataDoc.rotation, 0); let aspect = (rotation % 180) ? this.dataDoc[HeightSym]() / this.dataDoc[WidthSym]() : 1; let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; - let srcpath = paths[Math.min(paths.length, this.Document.curPage || 0)]; + let srcpath = paths[Math.min(paths.length - 1, this.Document.curPage || 0)]; if (!this.props.Document.ignoreAspect && !this.props.leaveNativeSize) this.resize(srcpath, this.props.Document); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index d3d7d584e..64b4acb7b 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -444,7 +444,6 @@ export namespace Doc { } let layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`); if (backgroundLayout) { - layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`); backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`); } let nw = Cast(fieldTemplate.nativeWidth, "number"); -- cgit v1.2.3-70-g09d2 From 74593e4370b554072ebbdef9a683a04a1bcbbde1 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 24 Jul 2019 22:10:00 -0400 Subject: Added a Button document --- src/client/documents/Documents.ts | 17 +++++- src/client/views/MainView.tsx | 5 +- src/client/views/nodes/ButtonBox.scss | 10 ++++ src/client/views/nodes/ButtonBox.tsx | 74 +++++++++++++++++++++++++ src/client/views/nodes/DocumentContentsView.tsx | 3 +- 5 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/client/views/nodes/ButtonBox.scss create mode 100644 src/client/views/nodes/ButtonBox.tsx (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a5b1d6573..3859f2255 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -38,6 +38,7 @@ import { LinkManager } from "../util/LinkManager"; import { DocumentManager } from "../util/DocumentManager"; import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox"; import { Scripting } from "../util/Scripting"; +import { ButtonBox } from "../views/nodes/ButtonBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -56,6 +57,7 @@ export enum DocumentType { IMPORT = "import", LINK = "link", LINKDOC = "linkdoc", + BUTTON = "button", TEMPLATE = "template", EXTENSION = "extension" } @@ -162,6 +164,9 @@ export namespace Docs { data: new List(), layout: { view: EmptyBox }, options: {} + }], + [DocumentType.BUTTON, { + layout: { view: ButtonBox }, }] ]); @@ -277,7 +282,7 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - export function InstanceFromProto(proto: Doc, data: Field, options: DocumentOptions, delegId?: string) { + export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string) { const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys); if (!("author" in protoProps)) { @@ -306,9 +311,11 @@ export namespace Docs { * @param options initial values to apply to this new delegate * @param value the data to store in this new delegate */ - function MakeDataDelegate(proto: Doc, options: DocumentOptions, value: D) { + function MakeDataDelegate(proto: Doc, options: DocumentOptions, value?: D) { const deleg = Doc.MakeDelegate(proto); - deleg.data = value; + if (value !== undefined) { + deleg.data = value; + } return Doc.assign(deleg, options); } @@ -411,6 +418,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Stacking }); } + export function ButtonDocument(options?: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.BUTTON), undefined, { ...(options || {}) }); + } + export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 53be0278e..61a013963 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat, faBolt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; @@ -131,6 +131,7 @@ export class MainView extends React.Component { library.add(faArrowDown); library.add(faArrowUp); library.add(faCloudUploadAlt); + library.add(faBolt); this.initEventListeners(); this.initAuthenticationRouters(); } @@ -378,10 +379,12 @@ export class MainView extends React.Component { let addColNode = action(() => Docs.Create.FreeformDocument([], { width: this.pwidth * .7, height: this.pheight, title: "a freeform collection" })); let addTreeNode = action(() => CurrentUserUtils.UserDocument); let addImageNode = action(() => Docs.Create.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); + let addButtonDocument = action(() => Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })); let addImportCollectionNode = action(() => Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })); let btns: [React.RefObject, IconName, string, () => Doc][] = [ [React.createRef(), "object-group", "Add Collection", addColNode], + [React.createRef(), "bolt", "Add Button", addButtonDocument], // [React.createRef(), "clone", "Add Docking Frame", addDockingNode], [React.createRef(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], ]; diff --git a/src/client/views/nodes/ButtonBox.scss b/src/client/views/nodes/ButtonBox.scss new file mode 100644 index 000000000..97cc91128 --- /dev/null +++ b/src/client/views/nodes/ButtonBox.scss @@ -0,0 +1,10 @@ +.buttonBox-outerDiv { + width: 100%; + height: 100%; + pointer-events: all; +} + +.buttonBox-mainButton { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx new file mode 100644 index 000000000..622595cdc --- /dev/null +++ b/src/client/views/nodes/ButtonBox.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import { FieldViewProps, FieldView } from './FieldView'; +import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { ScriptField } from '../../../new_fields/ScriptField'; +import { DocComponent } from '../DocComponent'; +import { ContextMenu } from '../ContextMenu'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faEdit } from '@fortawesome/free-regular-svg-icons'; +import { emptyFunction } from '../../../Utils'; +import { ScriptBox } from '../ScriptBox'; +import { CompileScript } from '../../util/Scripting'; +import { OverlayView } from '../OverlayView'; +import { Doc } from '../../../new_fields/Doc'; + +import './ButtonBox.scss'; +import { observer } from 'mobx-react'; + +library.add(faEdit); + +const ButtonSchema = createSchema({ + onClick: ScriptField, + text: "string" +}); + +type ButtonDocument = makeInterface<[typeof ButtonSchema]>; +const ButtonDocument = makeInterface(ButtonSchema); + +@observer +export class ButtonBox extends DocComponent(ButtonDocument) { + public static LayoutString() { return FieldView.LayoutString(ButtonBox); } + + onClick = (e: React.MouseEvent) => { + const onClick = this.Document.onClick; + if (!onClick) { + return; + } + e.stopPropagation(); + e.preventDefault(); + onClick.script.run({ this: this.props.Document }); + } + + onContextMenu = () => { + ContextMenu.Instance.addItem({ + description: "Edit OnClick script", icon: "edit", event: () => { + let overlayDisposer: () => void = emptyFunction; + const script = this.Document.onClick; + let originalText: string | undefined = undefined; + if (script) originalText = script.script.originalScript; + // tslint:disable-next-line: no-unnecessary-callback-wrapper + let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + const script = CompileScript(text, { + params: { this: Doc.name }, + typecheck: false + }); + if (!script.compiled) { + onError(script.errors.map(error => error.messageText).join("\n")); + return; + } + this.Document.onClick = new ScriptField(script); + overlayDisposer(); + }} />; + overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` }); + } + }); + } + + render() { + return ( +
    + +
    + ); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index ef65c12cf..91d4fb524 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -11,6 +11,7 @@ import { DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; +import { ButtonBox } from "./ButtonBox"; import { IconBox } from "./IconBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; @@ -97,7 +98,7 @@ export class DocumentContentsView extends React.Component 7) return (null); if (!this.layout && (this.props.layoutKey !== "overlayLayout" || !this.templates.length)) return (null); return Date: Wed, 24 Jul 2019 22:23:23 -0400 Subject: Small fix to button documents --- src/client/views/nodes/ButtonBox.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index 622595cdc..744611661 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -50,7 +50,8 @@ export class ButtonBox extends DocComponent(Butt let scriptingBox = overlayDisposer()} onSave={(text, onError) => { const script = CompileScript(text, { params: { this: Doc.name }, - typecheck: false + typecheck: false, + editable: true }); if (!script.compiled) { onError(script.errors.map(error => error.messageText).join("\n")); -- cgit v1.2.3-70-g09d2 From ab78fa317bdbcf6fcbceb35586604d90c7277446 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 24 Jul 2019 22:48:39 -0400 Subject: allow independent iconization of iconized aliases --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 989b35581..6fecbd3a7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -304,7 +304,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc.height = Number(MINIMIZED_ICON_SIZE); iconDoc.x = NumCast(doc.x); iconDoc.y = NumCast(doc.y) - 24; - iconDoc.maximizedDocs = new List(selected.map(s => s.props.Document.proto!)); + iconDoc.maximizedDocs = new List(selected.map(s => s.props.Document)); selected.length === 1 && (doc.minimizedDoc = iconDoc); selected[0].props.addDocument && selected[0].props.addDocument(iconDoc, false); return iconDoc; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 35a4613af..88a894cd0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -195,10 +195,10 @@ export class DocumentView extends DocComponent(Docu DocumentView.animateBetweenIconFunc(doc, width, height, stime, maximizing, cb); } else { - Doc.GetProto(doc).isMinimized = !maximizing; - Doc.GetProto(doc).isIconAnimating = undefined; + doc.isMinimized = !maximizing; + doc.isIconAnimating = undefined; } - Doc.GetProto(doc).willMaximize = false; + doc.willMaximize = false; }, 2); } @@ -319,20 +319,19 @@ export class DocumentView extends DocComponent(Docu expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; // let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents - let expandedProtoDocs = expandedDocs.map(doc => Doc.GetProto(doc)); let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); if (altKey || ctrlKey) { maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace")); if (!maxLocation || maxLocation === "inPlace") { - let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false); expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); - let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedProtoDocs[0], this.props.ContainingCollectionView); + let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); if (!hasView) { this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(getDispDoc(maxDoc), false)); } - expandedProtoDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); + expandedDocs.forEach(maxDoc => maxDoc.isMinimized = wasMinimized); } } if (maxLocation && maxLocation !== "inPlace" && CollectionDockingView.Instance) { @@ -344,7 +343,7 @@ export class DocumentView extends DocComponent(Docu } } else { let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); - this.collapseTargetsToPoint(scrpt, expandedProtoDocs); + this.collapseTargetsToPoint(scrpt, expandedDocs); } } else if (linkedDocs.length) { -- cgit v1.2.3-70-g09d2 From d6cef0815815c2587b9cc791e6a37c742aba1b45 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 25 Jul 2019 03:31:34 -0400 Subject: cognitive services refactor, buxton python script fixes, covered up imagebox context menu bug --- src/client/cognitive_services/CognitiveServices.ts | 151 +++++++++++---------- src/client/views/InkingCanvas.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 6 +- src/scraping/buxton/scraper.py | 17 +-- 5 files changed, 93 insertions(+), 87 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index dcd27f858..d689b424d 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -1,5 +1,5 @@ import * as request from "request-promise"; -import { Doc, Field } from "../../new_fields/Doc"; +import { Doc, Field, Opt } from "../../new_fields/Doc"; import { Cast } from "../../new_fields/Types"; import { ImageField } from "../../new_fields/URLField"; import { List } from "../../new_fields/List"; @@ -10,7 +10,15 @@ import { CompileScript } from "../util/Scripting"; import { ComputedField } from "../../new_fields/ScriptField"; import { InkData } from "../../new_fields/InkField"; -export enum Services { +type APIManager = { requester: RequestExecutor, applier: AnalysisApplier }; +type RequestExecutor = (apiKey: string, data: D, service: Service) => Promise; +type AnalysisApplier = (target: Doc, ...args: any) => any; +type Converter = (results: any) => Field; + +export type Tag = { name: string, confidence: number }; +export type Rectangle = { top: number, left: number, width: number, height: number }; + +export enum Service { ComputerVision = "vision", Face = "face", Handwriting = "handwriting" @@ -25,11 +33,6 @@ export enum Confidence { Excellent = 0.95 } -export type Tag = { name: string, confidence: number }; -export type Rectangle = { top: number, left: number, width: number, height: number }; -export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle }; -export type Converter = (results: any) => Field; - /** * A file that handles all interactions with Microsoft Azure's Cognitive * Services APIs. These machine learning endpoints allow basic data analytics for @@ -37,19 +40,33 @@ export type Converter = (results: any) => Field; */ export namespace CognitiveServices { + const executeQuery = async (service: Service, executor: RequestExecutor, data: D): Promise> => { + return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => { + let apiKey = await response.text(); + if (!apiKey) { + return undefined; + } + + let results: Opt; + try { + results = await executor(apiKey, data, service).then(json => JSON.parse(json)); + } catch { + results = undefined; + } + return results; + }); + }; + export namespace Image { - export const analyze = async (imageUrl: string, service: Services) => { - return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => { - let apiKey = await response.text(); - if (!apiKey) { - return undefined; - } + export const Manager: APIManager = { + + requester: (async (apiKey: string, imageUrl: string, service: Service) => { let uriBase; let parameters; switch (service) { - case Services.Face: + case Service.Face: uriBase = 'face/v1.0/detect'; parameters = { 'returnFaceId': 'true', @@ -58,7 +75,7 @@ export namespace CognitiveServices { 'emotion,hair,makeup,occlusion,accessories,blur,exposure,noise' }; break; - case Services.ComputerVision: + case Service.ComputerVision: uriBase = 'vision/v2.0/analyze'; parameters = { 'visualFeatures': 'Categories,Description,Color,Objects,Tags,Adult', @@ -78,35 +95,32 @@ export namespace CognitiveServices { } }; - let results: any; - try { - results = await request.post(options).then(response => JSON.parse(response)); - } catch (e) { - results = undefined; - } - return results; - }); - }; + return request.post(options); + }) as RequestExecutor, - const analyzeDocument = async (target: Doc, service: Services, converter: Converter, storageKey: string) => { - let imageData = Cast(target.data, ImageField); - if (!imageData || await Cast(target[storageKey], Doc)) { - return; - } - let toStore: any; - let results = await analyze(imageData.url.href, service); - if (!results) { - toStore = "Cognitive Services could not process the given image URL."; - } else { - if (!results.length) { - toStore = converter(results); + applier: (async (target: Doc, service: Service, converter: Converter, storageKey: string) => { + let imageData = Cast(target.data, ImageField); + if (!imageData || await Cast(target[storageKey], Doc)) { + return; + } + let toStore: any; + let results = await executeQuery(service, Manager.requester, imageData.url.href); + if (!results) { + toStore = "Cognitive Services could not process the given image URL."; } else { - toStore = results.length > 0 ? converter(results) : "Empty list returned."; + if (!results.length) { + toStore = converter(results); + } else { + toStore = results.length > 0 ? converter(results) : "Empty list returned."; + } } - } - target[storageKey] = toStore; + target[storageKey] = toStore; + }) as AnalysisApplier + }; + export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle }; + export const generateMetadata = async (target: Doc, threshold: Confidence = Confidence.Excellent) => { let converter = (results: any) => { let tagDoc = new Doc; @@ -120,7 +134,7 @@ export namespace CognitiveServices { tagDoc.confidence = threshold; return tagDoc; }; - analyzeDocument(target, Services.ComputerVision, converter, "generatedTags"); + Manager.applier(target, Service.ComputerVision, converter, "generatedTags"); }; export const extractFaces = async (target: Doc) => { @@ -129,48 +143,24 @@ export namespace CognitiveServices { results.map((face: Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!)); return faceDocs; }; - analyzeDocument(target, Services.Face, converter, "faces"); + Manager.applier(target, Service.Face, converter, "faces"); }; } 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; - } + export const Manager: APIManager = { + requester: (async (apiKey: string, inkData: InkData) => { let xhttp = new XMLHttpRequest(); let serverAddress = "https://api.cognitive.microsoft.com"; let endpoint = serverAddress + "/inkrecognizer/v1.0-preview/recognize"; - let requestExecutor = (resolve: any, reject: any) => { - let result: any; - let body = format(inkData); - + let promisified = (resolve: any, reject: any) => { xhttp.onreadystatechange = function () { if (this.readyState === 4) { - try { - result = JSON.parse(xhttp.responseText); - } catch (e) { - return reject(e); - } + let result = xhttp.responseText; switch (this.status) { case 200: return resolve(result); @@ -184,11 +174,14 @@ export namespace CognitiveServices { xhttp.open("PUT", endpoint, true); xhttp.setRequestHeader('Ocp-Apim-Subscription-Key', apiKey); xhttp.setRequestHeader('Content-Type', 'application/json'); - xhttp.send(body); + xhttp.send(format(inkData)); }; - let results = await new Promise(requestExecutor); + return new Promise(promisified); + }) as RequestExecutor, + applier: (async (target: Doc, inkData: InkData) => { + let results = await executeQuery(Service.Handwriting, Manager.requester, inkData); if (results) { results.recognitionUnits && (results = results.recognitionUnits); target.inkAnalysis = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis"); @@ -196,9 +189,23 @@ export namespace CognitiveServices { let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); target.handwriting = individualWords.join(" "); } - }); + }) as AnalysisApplier + }; + export interface AzureStrokeData { + id: number; + points: string; + language?: string; + } + + export interface HandwritingUnit { + version: number; + language: string; + unit: string; + strokes: AzureStrokeData[]; + } + const format = (inkData: InkData): string => { let entries = inkData.entries(), next = entries.next(); let strokes: AzureStrokeData[] = [], id = 0; diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index e48b45b56..c4cd863d1 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -6,12 +6,10 @@ import "./InkingCanvas.scss"; import { InkingControl } from "./InkingControl"; import { InkingStroke } from "./InkingStroke"; import React = require("react"); -import { undoBatch, UndoManager } from "../util/UndoManager"; +import { 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; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index bd5c6f84b..4b7ddd49d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -519,7 +519,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!data) { return; } - CognitiveServices.Inking.analyze(data.inkData, Doc.GetProto(this.props.Document)); + CognitiveServices.Inking.Manager.applier(Doc.GetProto(this.props.Document), data.inkData); } }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 89ad18dd6..3d77696fe 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -216,9 +216,9 @@ export class ImageBox extends DocComponent(ImageD }); let modes: ContextMenuProps[] = []; - let dataDoc = Doc.GetProto(this.Document); - modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" }); - modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" }); + // let dataDoc = Doc.GetProto(this.Document); + modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(this.Document), icon: "tag" }); + modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(this.Document), icon: "camera" }); ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs }); ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes }); diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index 700269727..14490cfe4 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -15,6 +15,7 @@ source = "./source" dist = "../../server/public/files" db = MongoClient("localhost", 27017)["Dash"] +target_collection = db.newDocuments schema_guids = [] @@ -84,7 +85,7 @@ def write_schema(parse_results, display_fields, storage_key): "height": 600, "panX": 0, "panY": 0, - "zoomBasis": 0.5, + "zoomBasis": 1, "zIndex": 2, "libraryBrush": False, "viewType": 2 @@ -106,8 +107,8 @@ def write_schema(parse_results, display_fields, storage_key): fields["isPrototype"] = True fields["page"] = -1 - db.newDocuments.insert_one(data_doc) - db.newDocuments.insert_one(view_doc) + target_collection.insert_one(data_doc) + target_collection.insert_one(view_doc) data_doc_guid = data_doc["_id"] print(f"inserted view document ({view_doc_guid})") @@ -158,8 +159,8 @@ def write_text_doc(content): "__type": "Doc" } - db.newDocuments.insert_one(view_doc) - db.newDocuments.insert_one(data_doc) + target_collection.insert_one(view_doc) + target_collection.insert_one(data_doc) return view_doc_guid @@ -209,8 +210,8 @@ def write_image(folder, name): "__type": "Doc" } - db.newDocuments.insert_one(view_doc) - db.newDocuments.insert_one(data_doc) + target_collection.insert_one(view_doc) + target_collection.insert_one(data_doc) return view_doc_guid @@ -372,7 +373,7 @@ parent_guid = write_schema({ }, ["title", "short_description", "original_price"], "data") print("appending parent schema to main workspace...\n") -db.newDocuments.update_one( +target_collection.update_one( {"fields.title": "WS collection 1"}, {"$push": {"fields.data.fields": {"fieldId": parent_guid, "__type": "proxy"}}} ) -- cgit v1.2.3-70-g09d2 From b4888c53bcc4eb9a37ed4b3dac740bfffc64d3c5 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 25 Jul 2019 11:46:28 -0400 Subject: postponed dealing with circular import bug imagebox --- src/client/DocServer.ts | 1 - .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 5 ++++- src/client/views/nodes/ImageBox.tsx | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 077c8e5ba..df9828029 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -5,7 +5,6 @@ import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../new_fields/RefField'; import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; -import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; /** * This class encapsulates the transfer and cross-client synchronization of diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d39d6f255..701574cfc 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -32,7 +32,10 @@ import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { faEye } from "@fortawesome/free-regular-svg-icons"; +library.add(faEye); export const panZoomSchema = createSchema({ panX: "number", @@ -522,7 +525,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let target = Doc.GetProto(this.props.Document); let relevantKeys = ["inkAnalysis", "handwriting"]; CognitiveServices.Inking.Manager.analyzer(target, relevantKeys, data.inkData); - } + }, icon: "eye" }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3d77696fe..c0c64b6d5 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -216,9 +216,9 @@ export class ImageBox extends DocComponent(ImageD }); let modes: ContextMenuProps[] = []; - // let dataDoc = Doc.GetProto(this.Document); - modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(this.Document), icon: "tag" }); - modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(this.Document), icon: "camera" }); + let dataDoc = Doc.GetProto(this.props.Document); + modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" }); + modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" }); ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs }); ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes }); -- cgit v1.2.3-70-g09d2 From eceff76609deaa3e7a60c686b62cb4fd15e9699b Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 25 Jul 2019 15:00:16 -0400 Subject: several fixes and added basic fields to treeview display --- .vscode/launch.json | 4 - .../views/collections/CollectionTreeView.tsx | 106 +++++++++++++-------- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/search/SearchItem.tsx | 6 +- src/new_fields/Doc.ts | 2 +- 6 files changed, 71 insertions(+), 53 deletions(-) (limited to 'src/client/views/nodes') diff --git a/.vscode/launch.json b/.vscode/launch.json index fd67a7647..822a06024 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,10 +7,6 @@ { "type": "chrome", "request": "launch", - "runtimeArgs": [ - "--enable-logging", - "--v=1" - ], "name": "Launch Chrome against localhost", "sourceMaps": true, "breakOnLoad": true, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 006de0c70..ff3221ada 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -3,7 +3,7 @@ import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaret import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, WidthSym, Opt } from '../../../new_fields/Doc'; +import { Doc, DocListCast, HeightSym, WidthSym, Opt, Field } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { Document, listSpec } from '../../../new_fields/Schema'; @@ -26,6 +26,8 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { LinkManager } from '../../util/LinkManager'; +import { ComputedField } from '../../../new_fields/ScriptField'; +import { KeyValueBox } from '../nodes/KeyValueBox'; export interface TreeViewProps { @@ -68,8 +70,7 @@ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); - @observable __chosenKey: string = ""; - @computed get _chosenKey() { return this.__chosenKey ? this.__chosenKey : this.fieldKey; } + @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "data"); } @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); } @observable _collapsed: boolean = true; @@ -125,12 +126,12 @@ class TreeView extends React.Component { } } onPointerLeave = (e: React.PointerEvent): void => { - this.props.document.libraryBrush = undefined; + this.props.document.libraryBrush = false; this._header!.current!.className = "treeViewItem-header"; document.removeEventListener("pointermove", this.onDragMove, true); } onDragMove = (e: PointerEvent): void => { - this.props.document.libraryBrush = undefined; + this.props.document.libraryBrush = false; let x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); let rect = this._header!.current!.getBoundingClientRect(); let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); @@ -191,25 +192,6 @@ class TreeView extends React.Component { OnTab={() => this.props.indentDocument && this.props.indentDocument()} />) - @computed get keyList() { - 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))); - } - let keyList: string[] = keys.reduce((l, key) => { - let listspec = DocListCast(target[key]); - if (listspec && listspec.length) return [...l, key]; - return l; - }, [] as string[]); - 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); - } - keyList.splice(0, 0, this.fieldKey); - return keyList.filter((item, index) => keyList.indexOf(item) >= index); - } /** * Renders the EditableView title element for placement into the tree. */ @@ -218,13 +200,9 @@ class TreeView extends React.Component { let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); let headerElements = ( - { - let ind = this.keyList.indexOf(this._chosenKey); - ind = (ind + 1) % this.keyList.length; - this.__chosenKey = this.keyList[ind]; - })} > - {this._chosenKey} + this.props.document.treeViewExpandedView = this.treeViewExpandedView === "data" ? "fields" : this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : "data")}> + {this.treeViewExpandedView} ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : []; let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : ( @@ -249,7 +227,6 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: (BoolCast(this.props.document.embed) ? "Collapse" : "Expand") + " inline", event: () => this.props.document.embed = !BoolCast(this.props.document.embed), icon: "expand" }); 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" }); @@ -311,8 +288,8 @@ class TreeView extends React.Component { renderLinks = () => { let ele: JSX.Element[] = []; - let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); - let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before); + let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this.fieldKey, doc, addBefore, before); let groups = LinkManager.Instance.getRelatedGroupedLinks(this.props.document); groups.forEach((groupLinkDocs, groupType) => { // let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document)); @@ -358,20 +335,65 @@ class TreeView extends React.Component { noOverlays = (doc: Doc) => ({ title: "", caption: "" }); + expandedField = (doc?: Doc) => { + if (!doc) return
    ; + let realDoc = doc; + + let ids: { [key: string]: string } = {}; + Object.keys(doc).forEach(key => { + if (!(key in ids) && realDoc[key] !== ComputedField.undefined) { + ids[key] = key; + } + }); + + let rows: JSX.Element[] = []; + for (let key of Object.keys(ids).sort()) { + let contents = realDoc[key] ? realDoc[key] : undefined; + let contentElement: JSX.Element[] | JSX.Element = []; + + if (contents instanceof Doc || Cast(contents, listSpec(Doc))) { + let docList = contents; + let remDoc = (doc: Doc) => this.remove(doc, key); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before); + contentElement = key === "links" ? this.renderLinks() : + TreeView.GetChildElements(docList instanceof Doc ? [docList as Doc] : DocListCast(docList), this.props.treeViewId, realDoc, undefined, key, 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 { + contentElement = Field.toKeyValueString(realDoc, key)} + SetValue={(value: string) => KeyValueBox.SetField(realDoc, key, value)} />; + } + rows.push(
    + {key + ":"} +   + {contentElement} +
    ); + } + return rows; + } + render() { let contentElement: (JSX.Element | null) = null; - 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 docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc)); + let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before); 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, + if (this.treeViewExpandedView === "data") { + let doc = Cast(this.props.document[this.fieldKey], Doc); + contentElement =
        + {this.fieldKey === "links" ? this.renderLinks() : + TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this.fieldKey, 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 if (this.treeViewExpandedView === "fields") { + contentElement =
        + {this.expandedField(this.dataDoc)} +
      ; } else { let layoutDoc = this.props.document; contentElement =
      diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b39c77adb..b5e64ed19 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -300,7 +300,7 @@ export class DocumentView extends DocComponent(Docu Doc.UseDetailLayout(fullScreenAlias); this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); - this.props.Document.libraryBrush = undefined; + this.props.Document.libraryBrush = false; } else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && @@ -612,7 +612,7 @@ export class DocumentView extends DocComponent(Docu } onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = undefined; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; isSelected = () => SelectionManager.IsSelected(this); @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3d77696fe..14208ce17 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -175,7 +175,7 @@ export class ImageBox extends DocComponent(ImageD const url = Utils.prepend(files[0]); // upload to server with known URL let audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", x: NumCast(self.props.Document.x), y: NumCast(self.props.Document.y), width: 200, height: 32 }); - audioDoc.embed = true; + audioDoc.treeViewExpandedView = "layout"; let audioAnnos = Cast(self.extensionDoc.audioAnnotations, listSpec(Doc)); if (audioAnnos === undefined) { self.extensionDoc.audioAnnotations = new List([audioDoc]); diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index a995140e2..5c2ced2eb 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -205,13 +205,13 @@ export class SearchItem extends React.Component { let doc1 = Cast(this.props.doc.anchor1, Doc, null); let doc2 = Cast(this.props.doc.anchor2, Doc, null); - doc1 && (doc1.libraryBrush = undefined); - doc2 && (doc2.libraryBrush = undefined); + doc1 && (doc1.libraryBrush = false); + doc2 && (doc2.libraryBrush = false); } } else { let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc); docViews.forEach(element => { - element.props.Document.libraryBrush = undefined; + element.props.Document.libraryBrush = false; }); } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 64b4acb7b..c37c0fd22 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -380,7 +380,7 @@ export namespace Doc { } if (expandedTemplateLayout === undefined) { setTimeout(() => - dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, templateLayoutDoc.title + ".layout"), 0); + dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "["+templateLayoutDoc.title + "]"), 0); } return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } -- cgit v1.2.3-70-g09d2 From 8e567d94618fcac3345a1f495cdea71a543f7804 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 25 Jul 2019 15:09:24 -0400 Subject: added misc icons and updated metadata storange onto field extension doc --- src/client/views/InkingControl.tsx | 2 +- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 9 ++++----- src/client/views/nodes/ImageBox.tsx | 11 ++++++----- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 1910e409b..da388e532 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -20,7 +20,7 @@ export class InkingControl extends React.Component { static Instance: InkingControl = new InkingControl({}); @observable private _selectedTool: InkTool = InkTool.None; @observable private _selectedColor: string = "rgb(244, 67, 54)"; - @observable private _selectedWidth: string = "25"; + @observable private _selectedWidth: string = "5"; @observable public _open: boolean = false; constructor(props: Readonly<{}>) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 15734ce0d..6500b3273 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -34,9 +34,9 @@ import { CompileScript } from "../../../util/Scripting"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye } from "@fortawesome/free-regular-svg-icons"; -import { faTable } from "@fortawesome/free-solid-svg-icons"; +import { faTable, faPaintBrush, faAsterisk } from "@fortawesome/free-solid-svg-icons"; -library.add(faEye, faTable); +library.add(faEye, faTable, faPaintBrush); export const panZoomSchema = createSchema({ panX: "number", @@ -524,10 +524,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!data) { return; } - let target = Doc.GetProto(this.props.Document); let relevantKeys = ["inkAnalysis", "handwriting"]; - CognitiveServices.Inking.Manager.analyzer(target, relevantKeys, data.inkData); - }, icon: "eye" + CognitiveServices.Inking.Manager.analyzer(this.fieldExtensionDoc, relevantKeys, data.inkData); + }, icon: "paint-brush" }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c0c64b6d5..5e93251a3 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faImage, faFileAudio } from '@fortawesome/free-solid-svg-icons'; +import { faImage, faFileAudio, faPaintBrush, faAsterisk } from '@fortawesome/free-solid-svg-icons'; import { action, observable, computed, runInAction } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; @@ -27,13 +27,14 @@ import { Font } from '@react-pdf/renderer'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CognitiveServices } from '../../cognitive_services/CognitiveServices'; import FaceRectangles from './FaceRectangles'; +import { faEye } from '@fortawesome/free-regular-svg-icons'; var requestImageSize = require('../../util/request-image-size'); var path = require('path'); const { Howl, Howler } = require('howler'); -library.add(faImage); -library.add(faFileAudio); +library.add(faImage, faEye, faPaintBrush); +library.add(faFileAudio, faAsterisk); export const pageSchema = createSchema({ @@ -220,8 +221,8 @@ export class ImageBox extends DocComponent(ImageD modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" }); modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" }); - ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs }); - ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes }); + ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes, icon: "eye" }); } } -- cgit v1.2.3-70-g09d2