diff options
Diffstat (limited to 'src/client/views')
-rw-r--r-- | src/client/views/EditableView.tsx | 11 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 170 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 7 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 82 | ||||
-rw-r--r-- | src/client/views/collections/CollectionView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 41 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 11 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 18 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/HistogramBox.tsx | 6 |
11 files changed, 226 insertions, 134 deletions
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 579d6e6ad..29bf6add7 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -16,6 +16,8 @@ export interface EditableProps { * */ SetValue(value: string): boolean; + OnFillDown?(value: string): void; + /** * The contents to render when not editing */ @@ -36,8 +38,13 @@ export class EditableView extends React.Component<EditableProps> { @action onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - if (e.key == "Enter" && !e.ctrlKey) { - if (this.props.SetValue(e.currentTarget.value)) { + if (e.key == "Enter") { + if (!e.ctrlKey) { + if (this.props.SetValue(e.currentTarget.value)) { + this.editing = false; + } + } else if (this.props.OnFillDown) { + this.props.OnFillDown(e.currentTarget.value); this.editing = false; } } else if (e.key == "Escape") { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 53a5aba6e..6534cb4f7 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -8,6 +8,7 @@ import "./Main.scss"; import { MessageStore } from '../../server/Message'; import { Utils } from '../../Utils'; import * as request from 'request' +import * as rp from 'request-promise' import { Documents } from '../documents/Documents'; import { Server } from '../Server'; import { setupDrag } from '../util/DragManager'; @@ -22,7 +23,7 @@ import "./Main.scss"; import { observer } from 'mobx-react'; import { InkingControl } from './InkingControl'; import { RouteStore } from '../../server/RouteStore'; -import { library } from '@fortawesome/fontawesome-svg-core'; +import { library, IconName } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faFont } from '@fortawesome/free-solid-svg-icons'; import { faImage } from '@fortawesome/free-solid-svg-icons'; @@ -40,7 +41,7 @@ import Measure from 'react-measure'; import { DashUserModel } from '../../server/authentication/models/user_model'; import { ServerUtils } from '../../server/ServerUtil'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { Field, Opt } from '../../fields/Field'; +import { Field, Opt, FieldWaiting } from '../../fields/Field'; import { ListField } from '../../fields/ListField'; import { Gateway, Settings } from '../northstar/manager/Gateway'; import { Catalog, Schema, Attribute, AttributeGroup } from '../northstar/model/idea/idea'; @@ -51,16 +52,26 @@ import '../northstar/utils/Extensions' @observer export class Main extends React.Component { // dummy initializations keep the compiler happy - @observable private mainContainer?: Document; @observable private mainfreeform?: Document; - @observable private userWorkspaces: Document[] = []; @observable public pwidth: number = 0; @observable public pheight: number = 0; - @observable ActiveSchema: Schema | undefined; private _northstarColumns: Document[] = []; - public mainDocId: string | undefined; - private currentUser?: DashUserModel; + @computed private get mainContainer(): Document | undefined { + let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document); + return doc == FieldWaiting ? undefined : doc; + } + + private set mainContainer(doc: Document | undefined) { + if (doc) { + this.userDocument.Set(KeyStore.ActiveWorkspace, doc); + } + } + + private get userDocument(): Document { + return CurrentUserUtils.UserDocument; + } + public static Instance: Main; constructor(props: Readonly<{}>) { @@ -70,9 +81,12 @@ export class Main extends React.Component { configure({ enforceActions: "observed" }); if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); - this.mainDocId = pathname[pathname.length - 1]; + if (pathname.length > 1 && pathname[pathname.length - 2] == 'doc') { + CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; + } }; + // this.initializeNorthstar(); let y = ""; y.ReplaceAll("a", "B"); @@ -92,7 +106,7 @@ export class Main extends React.Component { library.add(faTree); this.initEventListeners(); - Documents.initProtos(() => this.initAuthenticationRouters()); + this.initAuthenticationRouters(); this.initializeNorthstar(); } @@ -100,8 +114,8 @@ export class Main extends React.Component { onHistory = () => { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); - this.mainDocId = pathname[pathname.length - 1]; - Server.GetField(this.mainDocId, action((field: Opt<Field>) => { + CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; + Server.GetField(CurrentUserUtils.MainDocId, action((field: Opt<Field>) => { if (field instanceof Document) { this.openWorkspace(field, true); } @@ -131,63 +145,50 @@ export class Main extends React.Component { initAuthenticationRouters = () => { // Load the user's active workspace, or create a new one if initial session after signup - request.get(ServerUtils.prepend(RouteStore.getActiveWorkspace), (error, response, body) => { - if (this.mainDocId || body) { - Server.GetField(this.mainDocId || body, field => { - if (field instanceof Document) { - this.openWorkspace(field); - this.populateWorkspaces(); - } else { - this.createNewWorkspace(true, this.mainDocId); - } - }); - } else { - this.createNewWorkspace(true, this.mainDocId); - } - }); - } - - @action - createNewWorkspace = (init: boolean, id?: string): void => { - let mainDoc = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: `Main Container ${this.userWorkspaces.length + 1}` }, id); - let newId = mainDoc.Id; - request.post(ServerUtils.prepend(RouteStore.addWorkspace), { - body: { target: newId }, - json: true - }, () => { if (init) this.populateWorkspaces(); }); - - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => { - let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; - mainDoc.SetText(KeyStore.Data, JSON.stringify(dockingLayout)); - mainDoc.Set(KeyStore.ActiveFrame, freeformDoc); - this.openWorkspace(mainDoc); - let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }) - mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); - }, 0); - this.userWorkspaces.push(mainDoc); + if (!CurrentUserUtils.MainDocId) { + this.userDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { + if (doc) { + this.openWorkspace(doc); + } else { + this.createNewWorkspace(); + } + }) + } else { + Server.GetField(CurrentUserUtils.MainDocId).then(field => { + if (field instanceof Document) { + this.openWorkspace(field) + } else { + this.createNewWorkspace(CurrentUserUtils.MainDocId); + } + }) + } } @action - populateWorkspaces = () => { - // retrieve all workspace documents from the server - request.get(ServerUtils.prepend(RouteStore.getAllWorkspaces), (error, res, body) => { - let ids = JSON.parse(body) as string[]; - Server.GetFields(ids, action((fields: { [id: string]: Field }) => this.userWorkspaces = ids.map(id => fields[id] as Document))); - }); + createNewWorkspace = (id?: string): void => { + this.userDocument.GetTAsync<ListField<Document>>(KeyStore.Workspaces, ListField).then(action((list: Opt<ListField<Document>>) => { + if (list) { + let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; + let mainDoc = Documents.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.Data.length + 1}` }, id); + list.Data.push(mainDoc); + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + setTimeout(() => { + mainDoc.Set(KeyStore.ActiveFrame, freeformDoc); + this.openWorkspace(mainDoc); + let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }) + mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); + }, 0); + } + })); } @action openWorkspace = (doc: Document, fromHistory = false): void => { - request.post(ServerUtils.prepend(RouteStore.setActiveWorkspace), { - body: { target: doc.Id }, - json: true - }); this.mainContainer = doc; fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id); this.mainContainer.GetTAsync(KeyStore.ActiveFrame, Document, field => this.mainfreeform = field); - this.mainContainer.GetTAsync(KeyStore.OptionalRightCollection, Document, col => { + this.userDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => { // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(() => { if (col) { @@ -201,10 +202,15 @@ export class Main extends React.Component { }); } + @observable + workspacesShown: boolean = false; + + areWorkspacesShown = () => { + return this.workspacesShown; + } + @action toggleWorkspaces = () => { - if (WorkspacesMenu.Instance) { - WorkspacesMenu.Instance.toggle() - } + this.workspacesShown = !this.workspacesShown; } screenToLocalTransform = () => Transform.Identity @@ -247,7 +253,7 @@ export class Main extends React.Component { let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })) - let btns = [ + let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Document][] = [ [React.createRef<HTMLDivElement>(), "font", "Add Textbox", addTextNode], [React.createRef<HTMLDivElement>(), "image", "Add Image", addImageNode], [React.createRef<HTMLDivElement>(), "file-pdf", "Add PDF", addPDFNode], @@ -268,9 +274,9 @@ export class Main extends React.Component { <div id="add-options-content"> <ul id="add-options-list"> {btns.map(btn => - <li key={btn[1] as string} ><div ref={btn[0] as React.RefObject<HTMLDivElement>}> - <button className="round-button add-button" title={btn[2] as string} onPointerDown={setupDrag(btn[0] as React.RefObject<HTMLDivElement>, btn[3] as any)} onClick={addClick(btn[3] as any)}> - <FontAwesomeIcon icon={btn[1] as any} size="sm" /> + <li key={btn[1]} ><div ref={btn[0]}> + <button className="round-button add-button" title={btn[2]} onPointerDown={setupDrag(btn[0], btn[3])} onClick={addClick(btn[3])}> + <FontAwesomeIcon icon={btn[1]} size="sm" /> </button> </div></li>)} </ul> @@ -300,6 +306,12 @@ export class Main extends React.Component { } render() { + let workspaceMenu: any = null; + let workspaces = this.userDocument.GetT<ListField<Document>>(KeyStore.Workspaces, ListField); + if (workspaces && workspaces !== FieldWaiting) { + workspaceMenu = <WorkspacesMenu active={this.mainContainer} open={this.openWorkspace} new={this.createNewWorkspace} allWorkspaces={workspaces.Data} + isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} /> + } return ( <div id="main-div"> <Measure onResize={(r: any) => runInAction(() => { @@ -316,7 +328,7 @@ export class Main extends React.Component { <ContextMenu /> {this.nodesMenu} {this.miscButtons} - <WorkspacesMenu active={this.mainContainer} open={this.openWorkspace} new={this.createNewWorkspace} allWorkspaces={this.userWorkspaces} /> + {workspaceMenu} <InkingControl /> </div> ); @@ -326,8 +338,8 @@ export class Main extends React.Component { @action SetNorthstarCatalog(ctlog: Catalog) { if (ctlog && ctlog.schemas) { - this.ActiveSchema = ArrayUtil.FirstOrDefault<Schema>(ctlog.schemas!, (s: Schema) => s.displayName === "mimic"); - this._northstarColumns = this.GetAllNorthstarColumnAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! })); + CurrentUserUtils.ActiveSchema = ArrayUtil.FirstOrDefault<Schema>(ctlog.schemas!, (s: Schema) => s.displayName === "mimic"); + this._northstarColumns = CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! })); } } async initializeNorthstar(): Promise<void> { @@ -342,22 +354,10 @@ export class Main extends React.Component { let cat = Gateway.Instance.ClearCatalog(); cat.then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog())); } - public GetAllNorthstarColumnAttributes() { - if (!this.ActiveSchema || !this.ActiveSchema.rootAttributeGroup) { - return []; - } - const recurs = (attrs: Attribute[], g: AttributeGroup) => { - if (g.attributes) { - attrs.push.apply(attrs, g.attributes); - if (g.attributeGroups) { - g.attributeGroups.forEach(ng => recurs(attrs, ng)); - } - } - }; - const allAttributes: Attribute[] = new Array<Attribute>(); - recurs(allAttributes, this.ActiveSchema.rootAttributeGroup); - return allAttributes; - } } -ReactDOM.render(<Main />, document.getElementById('root')); +Documents.initProtos().then(() => { + return CurrentUserUtils.loadCurrentUser() +}).then(() => { + ReactDOM.render(<Main />, document.getElementById('root')); +}); diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index 8b9d178c9..53fe969fe 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -75,7 +75,7 @@ export class CollectionFreeFormView extends CollectionViewBase { @undoBatch @action - drop = (e: Event, de: DragManager.DropEvent): boolean => { + drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de)) { if (de.data instanceof DragManager.DocumentDragData) { let screenX = de.x - (de.data.xOffset as number || 0); @@ -83,6 +83,10 @@ export class CollectionFreeFormView extends CollectionViewBase { const [x, y] = this.getTransform().transformPoint(screenX, screenY); de.data.droppedDocument.SetNumber(KeyStore.X, x); de.data.droppedDocument.SetNumber(KeyStore.Y, y); + if (!de.data.droppedDocument.GetNumber(KeyStore.Width, 0)) { + de.data.droppedDocument.SetNumber(KeyStore.Width, 300); + de.data.droppedDocument.SetNumber(KeyStore.Height, 300); + } this.bringToFront(de.data.droppedDocument); } return true; @@ -262,6 +266,7 @@ export class CollectionFreeFormView extends CollectionViewBase { const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField); if (lvalue && lvalue != FieldWaiting) { return lvalue.Data.map(doc => { + if (!doc) return null; var page = doc.GetNumber(KeyStore.Page, 0); return (page != curPage && page != 0) ? (null) : (<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 696527049..0ff6c3b40 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,6 +1,6 @@ import React = require("react") import { library } from '@fortawesome/fontawesome-svg-core'; -import { faCog } from '@fortawesome/free-solid-svg-icons'; +import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; @@ -8,7 +8,7 @@ import Measure from "react-measure"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; import "react-table/react-table.css"; import { Document } from "../../../fields/Document"; -import { Field, Opt } from "../../../fields/Field"; +import { Field, Opt, FieldWaiting } from "../../../fields/Field"; import { Key } from "../../../fields/Key"; import { KeyStore } from "../../../fields/KeyStore"; import { ListField } from "../../../fields/ListField"; @@ -24,6 +24,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; +import { TextField } from "../../../fields/TextField"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -85,12 +86,31 @@ export class CollectionSchemaView extends CollectionViewBase { ) let reference = React.createRef<HTMLDivElement>(); let onItemDown = setupDrag(reference, () => props.doc, (containingCollection: CollectionView) => this.props.removeDocument(props.doc)); + let applyToDoc = (doc: Document, value: string) => { + let script = CompileScript(value, { this: doc }, true); + if (!script.compiled) { + return false; + } + let field = script(); + if (field instanceof Field) { + doc.Set(props.fieldKey, field); + return true; + } else { + let dataField = ToField(field); + if (dataField) { + doc.Set(props.fieldKey, dataField); + return true; + } + } + return false; + } return ( - <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "36px" }} key={props.doc.Id} ref={reference}> + <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "56px" }} key={props.doc.Id} ref={reference}> <EditableView display={"inline"} contents={contents} - height={36} GetValue={() => { + height={56} + GetValue={() => { let field = props.doc.Get(props.fieldKey); if (field && field instanceof Field) { return field.ToScriptString(); @@ -98,22 +118,14 @@ export class CollectionSchemaView extends CollectionViewBase { return field || ""; }} SetValue={(value: string) => { - let script = CompileScript(value); - if (!script.compiled) { - return false; - } - let field = script(); - if (field instanceof Field) { - props.doc.Set(props.fieldKey, field); - return true; - } else { - let dataField = ToField(field); - if (dataField) { - props.doc.Set(props.fieldKey, dataField); - return true; + return applyToDoc(props.doc, value); + }} + OnFillDown={(value: string) => { + this.props.Document.GetTAsync<ListField<Document>>(this.props.fieldKey, ListField).then((val) => { + if (val) { + val.Data.forEach(doc => applyToDoc(doc, value)); } - } - return false; + }) }}> </EditableView> </div> @@ -238,6 +250,19 @@ export class CollectionSchemaView extends CollectionViewBase { } } + @action + addColumn = () => { + this.columns.push(new Key(this.newKeyName)); + this.newKeyName = ""; + } + + @observable + newKeyName: string = ""; + + @action + newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => { + this.newKeyName = e.currentTarget.value; + } onWheel = (e: React.WheelEvent): void => { if (this.props.active()) e.stopPropagation(); @@ -248,18 +273,29 @@ export class CollectionSchemaView extends CollectionViewBase { OptionsMenuDown = (e: React.PointerEvent) => { this._optionsActivated++; } + + @observable previewScript: string = "this"; + @action + onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => { + this.previewScript = e.currentTarget.value; + } + render() { library.add(faCog); + library.add(faPlus); const columns = this.columns; const children = this.props.Document.GetList<Document>(this.props.fieldKey, []); const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined; //all the keys/columns that will be displayed in the schema const allKeys = this.findAllDocumentKeys; + let doc: any = selected ? selected.Get(new Key(this.previewScript)) : undefined; + + // let doc = CompileScript(this.previewScript, { this: selected }, true)(); let content = this._selectedIndex == -1 || !selected ? (null) : ( <Measure onResize={this.setScaling}> {({ measureRef }) => <div className="collectionSchemaView-content" ref={measureRef}> - <DocumentView Document={selected} + {doc instanceof Document ? <DocumentView Document={doc} AddDocument={this.props.addDocument} RemoveDocument={this.props.removeDocument} isTopMost={false} SelectOnLoad={false} @@ -269,7 +305,9 @@ export class CollectionSchemaView extends CollectionViewBase { PanelHeight={this.getPanelHeight} ContainingCollectionView={this.props.CollectionView} focus={this.focusDocument} - /> + /> : null} + <input value={this.previewScript} onChange={this.onPreviewScriptChange} + style={{ position: 'absolute', bottom: '0px' }} /> </div> } </Measure> @@ -291,6 +329,8 @@ export class CollectionSchemaView extends CollectionViewBase { return (<KeyToggle checked={allKeys[item]} key={item} keyId={item} toggle={this.toggleKey} />) })} </ul> + <input value={this.newKeyName} onChange={this.newKeyChange} /> + <button onClick={this.addColumn}><FontAwesomeIcon style={{ color: "white" }} icon="plus" size="lg" /></button> </div> </div> }> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index be757e22e..a740865ad 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,8 +13,7 @@ import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionViewProps } from "./CollectionViewBase"; import { CollectionTreeView } from "./CollectionTreeView"; import { Field, FieldId, FieldWaiting } from "../../../fields/Field"; -import { Main } from "../Main"; -import { dropPoint } from "prosemirror-transform"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; export enum CollectionViewType { Invalid, @@ -125,7 +124,7 @@ export class CollectionView extends React.Component<CollectionViewProps> { } specificContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != Main.Instance.mainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!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 ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 535a8a8d2..adaf810ea 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -14,10 +14,9 @@ import { RouteStore } from "../../../server/RouteStore"; import { TupleField } from "../../../fields/TupleField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { NumberField } from "../../../fields/NumberField"; -import { DocumentManager } from "../../util/DocumentManager"; import request = require("request"); import { ServerUtils } from "../../../server/ServerUtil"; -import { addHiddenFinalProp } from "mobx/lib/internal"; +import { Server } from "../../Server"; export interface CollectionViewProps { fieldKey: Key; @@ -60,17 +59,20 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> let email = CurrentUserUtils.email; if (id && email) { let textInfo: [string, string] = [id, email]; - doc.GetOrCreateAsync<ListField<CursorEntry>>(KeyStore.Cursors, ListField, field => { - let cursors = field.Data; - if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.Data[0][0] === id)) > -1) { - cursors[ind].Data[1] = position; - } else { - let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); - cursors.push(entry); + doc.GetTAsync(KeyStore.Prototype, Document).then(proto => { + if (!proto) { + return; } + proto.GetOrCreateAsync<ListField<CursorEntry>>(KeyStore.Cursors, ListField, action((field: ListField<CursorEntry>) => { + let cursors = field.Data; + if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.Data[0][0] === id)) > -1) { + cursors[ind].Data[1] = position; + } else { + let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); + cursors.push(entry); + } + })) }) - - } } @@ -115,6 +117,21 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> ctor = Documents.PdfDocument; } if (type.indexOf("html") !== -1) { + if (path.includes('localhost')) { + let s = path.split('/'); + let id = s[s.length - 1]; + Server.GetField(id).then(field => { + if (field instanceof Document) { + let alias = field.CreateAlias(); + alias.SetNumber(KeyStore.X, options.x || 0); + alias.SetNumber(KeyStore.Y, options.y || 0); + alias.SetNumber(KeyStore.Width, options.width || 300); + alias.SetNumber(KeyStore.Height, options.height || options.width || 300); + this.props.addDocument(alias, false); + } + }) + return undefined; + } ctor = Documents.WebDocument; options = { height: options.width, ...options, }; } @@ -134,7 +151,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> e.stopPropagation() e.preventDefault() - if (html && html.indexOf("<img") != 0) { + if (html && html.indexOf("<img") != 0 && !html.startsWith("<a")) { console.log("not good"); let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 }); htmlDoc.SetText(KeyStore.DocumentText, text); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 2f0459f88..12d14eb42 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -47,8 +47,13 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & { } render() { + let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); + if (!lkeys || lkeys === FieldWaiting) { + return <p>Error loading layout keys</p>; + } return <JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }} bindings={this.CreateBindings()} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }} + bindings={this.CreateBindings()} jsx={this.layout} showWarnings={true} onError={(test: any) => { console.log(test) }} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 383341e02..3873a6f89 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -18,6 +18,7 @@ import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); +import { ServerUtils } from "../../../server/ServerUtil"; export interface DocumentViewProps { @@ -284,6 +285,12 @@ export class DocumentView extends React.Component<DocumentViewProps> { ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }) ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) }) ContextMenu.Instance.addItem({ + description: "Copy URL", + event: () => { + Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id)); + } + }); + ContextMenu.Instance.addItem({ description: "Copy ID", event: () => { Utils.CopyText(this.props.Document.Id); @@ -314,10 +321,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { if (!this.props.Document) { return (null); } - let lkeys = this.props.Document.GetT(KeyStore.LayoutKeys, ListField); - if (!lkeys || lkeys === FieldWaiting) { - return <p>Error loading layout keys</p>; - } var scaling = this.props.ContentScaling(); var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f6343c631..4e83ec7b9 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -16,6 +16,9 @@ import { VideoBox } from "./VideoBox"; import { AudioBox } from "./AudioBox"; import { AudioField } from "../../../fields/AudioField"; import { ListField } from "../../../fields/ListField"; +import { DocumentContentsView } from "./DocumentContentsView"; +import { Transform } from "../../util/Transform"; +import { KeyStore } from "../../../fields/KeyStore"; // @@ -65,7 +68,20 @@ export class FieldView extends React.Component<FieldViewProps> { return <AudioBox {...this.props} /> } else if (field instanceof Document) { - return <div>{field.Title}</div> + return (<DocumentContentsView Document={field} + AddDocument={undefined} + RemoveDocument={undefined} + ScreenToLocalTransform={() => Transform.Identity} + ContentScaling={() => 1} + PanelWidth={() => 100} + PanelHeight={() => 100} + isTopMost={true} + SelectOnLoad={false} + focus={() => { }} + isSelected={() => false} + select={() => false} + layoutKey={KeyStore.Layout} + ContainingCollectionView={undefined} />) } else if (field instanceof ListField) { return (<div> diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ba9bd9566..30fa1342e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -167,6 +167,8 @@ export class FormattedTextBox extends React.Component<FieldViewProps> { onKeyPress={this.onKeyPress} onPointerDown={this.onPointerDown} onContextMenu={this.specificContextMenu} + // tfs: do we need this event handler + onKeyDown={this.onKeyPress} onWheel={this.onPointerWheel} ref={this._ref} />) } diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx index 980719a21..1508b201b 100644 --- a/src/client/views/nodes/HistogramBox.tsx +++ b/src/client/views/nodes/HistogramBox.tsx @@ -3,13 +3,12 @@ import { action, computed, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; import { Dictionary } from "typescript-collections"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Utils as DashUtils } from '../../../Utils'; import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; import { FilterModel } from '../../northstar/core/filter/FilterModel'; -import { DateTimeVisualBinRange } from "../../northstar/model/binRanges/DateTimeVisualBinRange"; import { NominalVisualBinRange } from "../../northstar/model/binRanges/NominalVisualBinRange"; -import { QuantitativeVisualBinRange } from "../../northstar/model/binRanges/QuantitativeVisualBinRange"; import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange'; import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper"; import { AggregateBinRange, AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea"; @@ -20,7 +19,6 @@ import { LABColor } from '../../northstar/utils/LABcolor'; import { PIXIRectangle } from "../../northstar/utils/MathUtil"; import { SizeConverter } from "../../northstar/utils/SizeConverter"; import { StyleConstants } from "../../northstar/utils/StyleContants"; -import { Main } from "../Main"; import { FieldView, FieldViewProps } from './FieldView'; import "./HistogramBox.scss"; @@ -51,7 +49,7 @@ export class HistogramBox extends React.Component<FieldViewProps> { componentDidMount() { reaction(() => [this.props.doc.Title], () => { - Main.Instance.GetAllNorthstarColumnAttributes().map(a => { + CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => { if (a.displayName == this.props.doc.Title) { var atmod = new ColumnAttributeModel(a); this._histoOp = new HistogramOperation(new AttributeTransformationModel(atmod, AggregateFunction.None), |