From 9ea0f409cfc2a6c11bb1cf6e00015eb97900507b Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 10 Apr 2019 10:45:59 -0400 Subject: fixed uploading of csv files. --- src/client/documents/Documents.ts | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 72e6e57ab..f8438e093 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,6 +1,6 @@ import { AudioField } from "../../fields/AudioField"; import { Document } from "../../fields/Document"; -import { Field } from "../../fields/Field"; +import { Field, Opt } from "../../fields/Field"; import { HtmlField } from "../../fields/HtmlField"; import { ImageField } from "../../fields/ImageField"; import { InkField, StrokeData } from "../../fields/InkField"; @@ -26,6 +26,12 @@ import { KeyValueBox } from "../views/nodes/KeyValueBox"; import { PDFBox } from "../views/nodes/PDFBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; +import { Gateway } from "../northstar/manager/Gateway"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { action } from "mobx"; +import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; +import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; +import { AggregateFunction } from "../northstar/model/idea/idea"; export interface DocumentOptions { x?: number; @@ -200,6 +206,31 @@ export namespace Documents { export function PdfDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); } + export async function DBDocument(url: string, options: DocumentOptions = {}) { + let schemaName = options.title ? options.title : "-no schema-"; + let ctlog = await Gateway.Instance.GetSchema(url, schemaName) + if (ctlog && ctlog.schemas) { + let schema = ctlog.schemas[0]; + let schemaDoc = Documents.TreeDocument([], { ...options, nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: schema.displayName! }); + let schemaDocuments = schemaDoc.GetList(KeyStore.Data, [] as Document[]); + CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { + Server.GetField(attr.displayName! + ".alias", action((field: Opt) => { + if (field instanceof Document) { + schemaDocuments.push(field); + } else { + var atmod = new ColumnAttributeModel(attr); + let histoOp = new HistogramOperation(schema.displayName!, + new AttributeTransformationModel(atmod, AggregateFunction.None), + new AttributeTransformationModel(atmod, AggregateFunction.Count), + new AttributeTransformationModel(atmod, AggregateFunction.Count)); + schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); + } + })); + }); + return schemaDoc; + }; + return Documents.TreeDocument([], { width: 50, height: 100, title: schemaName }); + } export function WebDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(webProto, options, [new URL(url), WebField]).MakeDelegate(), options); } @@ -242,13 +273,15 @@ export namespace Documents {
` + FormattedTextBox.LayoutString("CaptionKey") + `
- `; } + `; + } export function FixedCaption(fieldName: string = "Caption") { return `
` + FormattedTextBox.LayoutString(fieldName + "Key") + `
-
`; } + `; + } function OuterCaption() { return (` -- cgit v1.2.3-70-g09d2 From 7f0b7a3e02d2d5ea3bd9f8554f1828d0470b1d04 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 14 Apr 2019 17:46:54 -0400 Subject: tweaks to text input --- src/client/documents/Documents.ts | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 9 ++++++--- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3c36fe500..4febfa7eb 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -127,7 +127,7 @@ export namespace Documents { function CreateImagePrototype(): Document { let imageProto = setupPrototypeOptions(imageProtoId, "IMAGE_PROTO", CollectionView.LayoutString("AnnotationsKey"), - { x: 0, y: 0, nativeWidth: 300, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); + { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); imageProto.SetText(KeyStore.BackgroundLayout, ImageBox.LayoutString()); imageProto.SetNumber(KeyStore.CurPage, 0); return imageProto; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1c927c78d..d3d69b1af 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -197,7 +197,7 @@ export class CollectionSubView extends React.Component { }).then(async (res: Response) => { (await res.json()).map(action((file: any) => { let path = window.location.origin + file; - let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName }); + let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName }); docPromise.then(action((doc?: Document) => { let docs = this.props.Document.GetT(KeyStore.Data, ListField); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e9e942b78..6c382a353 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -4,7 +4,6 @@ import Measure from "react-measure"; import { Document } from "../../../../fields/Document"; import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; -import { NumberField } from "../../../../fields/NumberField"; import { TextField } from "../../../../fields/TextField"; import { emptyFunction, returnFalse } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; @@ -18,7 +17,7 @@ import { Main } from "../../Main"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps } from "../../nodes/DocumentView"; -import { CollectionSubView } from "../CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; @@ -294,7 +293,11 @@ export class CollectionFreeFormView extends CollectionSubView { } return prev; }, [] as JSX.Element[]); - untracked(() => this._selectOnLoaded = ""); + + setTimeout(() => { // bcz: surely there must be a better way .... + this._selectOnLoaded = ""; + }, 600); + return docviews; } -- cgit v1.2.3-70-g09d2 From c6ecd219f61811c3af9776ad8c08c2232db20dfd Mon Sep 17 00:00:00 2001 From: Fawn Date: Mon, 15 Apr 2019 20:04:01 -0400 Subject: template menu works when switching between diff docs --- src/client/documents/Documents.ts | 1 + src/client/views/DocumentDecorations.scss | 63 +++++++++++--------- src/client/views/DocumentDecorations.tsx | 12 +++- src/client/views/TemplateEditButton.tsx | 92 ----------------------------- src/client/views/TemplateMenu.tsx | 88 +++++++++++++++++++++++++++ src/client/views/Templates.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 +-- src/client/views/nodes/FormattedTextBox.tsx | 4 +- 8 files changed, 140 insertions(+), 130 deletions(-) delete mode 100644 src/client/views/TemplateEditButton.tsx create mode 100644 src/client/views/TemplateMenu.tsx (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4febfa7eb..8db1a1c6d 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -130,6 +130,7 @@ export namespace Documents { { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); imageProto.SetText(KeyStore.BackgroundLayout, ImageBox.LayoutString()); imageProto.SetNumber(KeyStore.CurPage, 0); + imageProto.SetData(KeyStore.LayoutFields, [KeyStore.Title], ListField); return imageProto; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index e926c2be6..14f3359ca 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -104,15 +104,6 @@ margin-left: 25px; } -.documentDecorations-extra { - display: flex; - position: absolute; -} - -.documentDecorations-ex-wrapper { - margin-right: 10px; -} - .linkButton-linker { position: absolute; bottom: 0px; @@ -164,25 +155,43 @@ } } -.templating-button-wrapper { - position: relative; -} - -#template-list { +.templating-menu { position: absolute; - top: 0; - left: 30px; - width: 150px; - line-height: 25px; - max-height: 175px; - font-family: $sans-serif; - font-size: 12px; - background-color: $light-color-secondary; - padding: 2px 12px; - - input { - margin-right: 10px; - } + bottom: 0; + left: 50px; + pointer-events: auto; + .templating-button { + width: 20px; + height: 20px; + border-radius: 50%; + opacity: 0.9; + background-color: $dark-color; + color: $light-color; + text-align: center; + cursor: pointer; + &:hover { + background: $main-accent; + transform: scale(1.05); + } + } + + #template-list { + position: absolute; + top: 0; + left: 30px; + width: 150px; + line-height: 25px; + max-height: 175px; + font-family: $sans-serif; + font-size: 12px; + background-color: $light-color-secondary; + padding: 2px 12px; + list-style: none; + + input { + margin-right: 10px; + } + } } \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 51c085038..1e936a881 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -14,8 +14,9 @@ import './DocumentDecorations.scss'; import { MainOverlayTextBox } from "./MainOverlayTextBox"; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; -import { TemplateEditButton } from "./TemplateEditButton"; +import { TemplateMenu } from "./TemplateMenu"; import React = require("react"); +import { Template, Templates } from "./Templates"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -404,6 +405,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{linkCount}
); } + + let templates: Map = new Map(); + let doc = SelectionManager.SelectedDocuments()[0]; + Array.from(Object.values(Templates)).map(template => { + templates.set(template, doc.hasTemplate(template)); + }); + return (
{linkButton}
- +
); diff --git a/src/client/views/TemplateEditButton.tsx b/src/client/views/TemplateEditButton.tsx deleted file mode 100644 index 6542ac7ec..000000000 --- a/src/client/views/TemplateEditButton.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { observable, computed, action } from "mobx"; -import React = require("react"); -import { SelectionManager } from "../util/SelectionManager"; -import { observer } from "mobx-react"; -import './DocumentDecorations.scss' -import { Templates, Template } from "./Templates"; -import { DocumentView } from "./nodes/DocumentView"; -const higflyout = require("@hig/flyout"); -export const { anchorPoints } = higflyout; -export const Flyout = higflyout.default; - -@observer -class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent, template: Template) => void }> { - render() { - if (this.props.template) { - return ( -
  • - this.props.toggle(event, this.props.template)} /> - {this.props.template.Name} -
  • - ) - } - return (null); - } -} - -export interface TemplateButtonProps { - Document: DocumentView; -} - -@observer -export class TemplateEditButton extends React.Component { - - @observable private _templatesActive: boolean = false; - @observable private _showBase: boolean = true; - - toggleTemplate = (event: React.ChangeEvent, template: Template): void => { - let view = this.props.Document; - if (event.target.checked) { - view.addTemplate(template); - } else { - view.removeTemplate(template); - } - - // const docs = view.props.ContainingCollectionView; - // const docs = view.props.Document.GetList(view.props.fieldKey, []); - - } - - @action - toggleBase = (event: React.ChangeEvent): void => { - let view = this.props.Document; - view.toggleBase(event.target.checked); - this._showBase = !this._showBase; - } - - @action - toggleTemplateActivity = (): void => { - this._templatesActive = !this._templatesActive; - } - - render() { - let templateMenu = !this._templatesActive ? (null) : ( -
      -
    • this.toggleBase(event)} defaultChecked={true} />Base layout
    • - {console.log("mm")} - {Array.from(Object.values(Templates)).map(template => { - let view = this.props.Document - let checked = view.hasTemplate(template); - return ( - - ) - - // return ( - //
    • - // {console.log(template.Name, checked)} - // this.toggleTemplate(event, template)} defaultChecked={checked} /> - // {template.Name} - //
    • - // ) - })} -
    - ) - return ( -
    -
    this.toggleTemplateActivity()}>T
    - {templateMenu} -
    - ) - } -} \ No newline at end of file diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx new file mode 100644 index 000000000..7f670aec0 --- /dev/null +++ b/src/client/views/TemplateMenu.tsx @@ -0,0 +1,88 @@ +import { observable, computed, action } from "mobx"; +import React = require("react"); +import { SelectionManager } from "../util/SelectionManager"; +import { observer } from "mobx-react"; +import './DocumentDecorations.scss'; +import { Templates, Template } from "./Templates"; +import { DocumentView } from "./nodes/DocumentView"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; + +@observer +class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent, template: Template) => void }> { + render() { + if (this.props.template) { + return ( +
  • + this.props.toggle(event, this.props.template)} /> + {this.props.template.Name} +
  • + ); + } else { + return (null); + } + } +} + +export interface TemplateMenuProps { + doc: DocumentView; + templates: Map; +} + +@observer +export class TemplateMenu extends React.Component { + + @observable private _hidden: boolean = true; + @observable private _showBase: boolean = true; + @observable private _templates: Map = this.props.templates; + + + @action + toggleTemplate = (event: React.ChangeEvent, template: Template): void => { + if (event.target.checked) { + this.props.doc.addTemplate(template); + this._templates.set(template, true); + } else { + this.props.doc.removeTemplate(template); + this._templates.set(template, false); + } + + // const docs = view.props.ContainingCollectionView; + // const docs = view.props.Document.GetList(view.props.fieldKey, []); + + } + + @action + componentWillReceiveProps(nextProps: TemplateMenuProps) { + this._templates = nextProps.templates; + } + + @action + toggleBase = (event: React.ChangeEvent): void => { + this.props.doc.toggleBase(event.target.checked); + this._showBase = !this._showBase; + } + + @action + toggleTemplateActivity = (): void => { + this._hidden = !this._hidden; + } + + render() { + let templateMenu: Array = []; + this._templates.forEach((checked, template) => { + templateMenu.push(); + }); + + return ( +
    +
    this.toggleTemplateActivity()}>T
    +
      +
    • this.toggleBase(event)} defaultChecked={true} />Base layout
    • + {templateMenu} +
    +
    + ); + } +} \ No newline at end of file diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index a6ba2243d..b82b383bb 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -54,7 +54,7 @@ export namespace Templates { {layout}
    - + {Title}
    `); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3c61810e2..ef1420027 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,8 +1,4 @@ -<<<<<<< HEAD -import { action, computed, IReactionDisposer, reaction, runInAction, observable } from "mobx"; -======= -import { action, computed, runInAction } from "mobx"; ->>>>>>> 6c0b421db6aa3204bbc6e42139d240f503000b5d +import { action, computed, runInAction, observable } from "mobx"; import { observer } from "mobx-react"; import { BooleanField } from "../../../fields/BooleanField"; import { Document } from "../../../fields/Document"; @@ -25,7 +21,7 @@ import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; -import { Template } from "./../Templates" +import { Template } from "./../Templates"; import "./DocumentView.scss"; import React = require("react"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ad1ed5df0..9f71609d5 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -105,7 +105,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } ); } else { - this._proxyReactionDisposer = reaction(() => this.props.isSelected(), + this._proxyReactionDisposer = reaction(() => { }/*this.props.isSelected()*/, () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform())); } @@ -241,7 +241,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte render() { return (
    Date: Fri, 19 Apr 2019 16:34:32 -0400 Subject: played with iconifying things in a different way. fixed some things with schemas. --- src/Utils.ts | 2 +- src/client/documents/Documents.ts | 16 ++++ src/client/northstar/dash-nodes/HistogramBox.scss | 6 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 42 ++++++---- src/client/views/Main.tsx | 8 +- .../views/collections/CollectionSchemaView.scss | 9 ++- .../views/collections/CollectionSchemaView.tsx | 5 +- .../CollectionFreeFormLinkView.tsx | 8 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 9 +-- src/client/views/globalCssVariables.scss | 2 + src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 26 +++---- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/DocumentView.scss | 16 +--- src/client/views/nodes/DocumentView.tsx | 71 ++++++++--------- src/client/views/nodes/FieldView.tsx | 5 ++ src/client/views/nodes/IconBox.scss | 12 +++ src/client/views/nodes/IconBox.tsx | 90 ++++++++++++++++++++++ src/fields/IconFIeld.ts | 25 ++++++ src/fields/KeyStore.ts | 10 +-- src/server/Message.ts | 2 +- src/server/ServerUtil.ts | 2 + 24 files changed, 264 insertions(+), 121 deletions(-) create mode 100644 src/client/views/nodes/IconBox.scss create mode 100644 src/client/views/nodes/IconBox.tsx create mode 100644 src/fields/IconFIeld.ts (limited to 'src/client/documents') diff --git a/src/Utils.ts b/src/Utils.ts index dec6245ef..98f75d3b9 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,7 +1,7 @@ import v4 = require('uuid/v4'); import v5 = require("uuid/v5"); import { Socket } from 'socket.io'; -import { Message, Types, Transferable } from './server/Message'; +import { Message } from './server/Message'; import { Document } from './fields/Document'; export class Utils { diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4febfa7eb..b0bb74d89 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,6 +32,9 @@ import { action } from "mobx"; import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; +import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; +import { IconBox } from "../views/nodes/IconBox"; +import { IconField } from "../../fields/IconFIeld"; export interface DocumentOptions { x?: number; @@ -63,6 +66,7 @@ export namespace Documents { let videoProto: Document; let audioProto: Document; let pdfProto: Document; + let iconProto: Document; const textProtoId = "textProto"; const histoProtoId = "histoProto"; const pdfProtoId = "pdfProto"; @@ -72,6 +76,7 @@ export namespace Documents { const kvpProtoId = "kvpProto"; const videoProtoId = "videoProto"; const audioProtoId = "audioProto"; + const iconProtoId = "iconProto"; export function initProtos(): Promise { return Server.GetFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => { @@ -84,6 +89,7 @@ export namespace Documents { videoProto = fields[videoProtoId] as Document || CreateVideoPrototype(); audioProto = fields[audioProtoId] as Document || CreateAudioPrototype(); pdfProto = fields[pdfProtoId] as Document || CreatePdfPrototype(); + iconProto = fields[iconProtoId] as Document || CreateIconPrototype(); }); } function assignOptions(doc: Document, options: DocumentOptions): Document { @@ -92,6 +98,8 @@ export namespace Documents { if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); } if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); } if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); } + if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); } + if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); } if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } @@ -139,6 +147,11 @@ export namespace Documents { histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString()); return histoProto; } + function CreateIconPrototype(): Document { + let iconProto = setupPrototypeOptions(iconProtoId, "ICON_PROTO", IconBox.LayoutString(), + { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data] }); + return iconProto; + } function CreateTextPrototype(): Document { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); @@ -203,6 +216,9 @@ export namespace Documents { export function TextDocument(options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(textProto, options, ["", TextField]).MakeDelegate(), options); } + export function IconDocument(icon: string, options: DocumentOptions = {}) { + return assignToDelegate(SetInstanceOptions(iconProto, { width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data], layout: IconBox.LayoutString(), ...options }, [icon, IconField]), options); + } export function PdfDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); } diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index e899cf15e..06d781263 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -1,12 +1,12 @@ .histogrambox-container { padding: 0vw; position: absolute; - top: 0; - left:0; + top: -50%; + left:-50%; text-align: center; width: 100%; height: 100%; - background: black; + background: black; } .histogrambox-xaxislabel { position:absolute; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 0e84ace50..e2ecc8c83 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -146,7 +146,7 @@ export class HistogramBox extends React.Component { return ( runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}> {({ measureRef }) => -
    +
    {labelY} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cfb9befd5..da2c7a3be 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,17 +5,18 @@ import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; +import { Document } from "../../fields/Document"; import { emptyFunction } from "../../Utils"; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; import { MainOverlayTextBox } from "./MainOverlayTextBox"; -import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); import { CompileScript } from "../util/Scripting"; +import { IconBox } from "./nodes/IconBox"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -191,6 +192,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointerup", this.onMinimizeUp); } } + + @observable _minimizedX = 0; + @observable _minimizedY = 0; @action onMinimizeMove = (e: PointerEvent): void => { e.stopPropagation(); @@ -201,12 +205,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let xf = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().inverse().transformPoint(0, 0); let dx = e.pageX - xf[0]; let dy = e.pageY - xf[1]; - if (Math.abs(dx) < 20 && Math.abs(dy) < 20) - dx = dy = 0; + this._minimizedX = e.clientX; + this._minimizedY = e.clientY; + if (Math.abs(dx) < 20 && Math.abs(dy) < 20) { + this._minimizedX = xf[0]; + this._minimizedY = xf[1]; + } SelectionManager.SelectedDocuments().map(dv => { - let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformDirection(dx, dy); - dv.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - dv.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + let minDoc = dv.props.Document.Get(KeyStore.MinimizedDoc); + if (minDoc instanceof Document) { + let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformPoint(this._minimizedX, this._minimizedY); + let minDocument = minDoc as Document; + minDocument.SetNumber(KeyStore.X, where[0] + dv.props.Document.GetNumber(KeyStore.X, 0)); + minDocument.SetNumber(KeyStore.Y, where[1] + dv.props.Document.GetNumber(KeyStore.Y, 0)); + } }); } } @@ -219,6 +231,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (Math.abs(dx) < 4 && Math.abs(dy) < 4 && !this._iconifying) { SelectionManager.SelectedDocuments().map(dv => dv.minimize()); SelectionManager.DeselectAll(); + } else { + this._minimizedX = this._minimizedY = 0; } document.removeEventListener("pointermove", this.onMinimizeMove); document.removeEventListener("pointerup", this.onMinimizeUp); @@ -404,24 +418,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (bounds.x === Number.MAX_VALUE || !seldoc) { return (null); } - let minvec = [seldoc.props.Document.GetNumber(KeyStore.MinimizedX, 0), seldoc.props.Document.GetNumber(KeyStore.MinimizedY, 0)]; - minvec = seldoc.props.ScreenToLocalTransform().scale(seldoc.props.ContentScaling()).inverse().transformDirection(minvec[0], minvec[1]); - let selpos = minvec[0] !== 0 || minvec[1] !== 0 ? - [minvec[0] - 12 + (!this._iconifying ? 8 : 0), minvec[1] - 12 + (!this._iconifying ? 28 : 0)] : + let selpos = this._minimizedX !== 0 || this._minimizedY !== 0 ? + [this._minimizedX - 12 + (!this._iconifying ? 8 : 0), this._minimizedY - 12 + (!this._iconifying ? 28 : 0)] : [0, this._iconifying ? -18 : 0]; let minimizeIcon = (
    - {SelectionManager.SelectedDocuments().length == 1 ? SelectionManager.SelectedDocuments()[0].minimizedIcon : "..."} + {SelectionManager.SelectedDocuments().length == 1 ? IconBox.DocumentIcon(SelectionManager.SelectedDocuments()[0].props.Document.GetText(KeyStore.Layout, "...")) : "..."}
    ); if (this._iconifying) { - let xfpt = seldoc.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - return (
    - {minimizeIcon} -
    ); + return (
    {minimizeIcon}
    ); } - // console.log(this._documents.length) - // let test = this._documents[0].props.Document.Title; + if (this.Hidden) { return (null); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 503a11b35..09ef30f6b 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -85,11 +85,11 @@ export class Main extends React.Component { this.initEventListeners(); this.initAuthenticationRouters(); - // try { - // this.initializeNorthstar(); - // } catch (e) { + try { + this.initializeNorthstar(); + } catch (e) { - // } + } } componentDidMount() { window.onpopstate = this.onHistory; } diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 6eabbe17c..cfdb3ab22 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,6 +1,7 @@ @import "../globalCssVariables"; + .collectionSchemaView-container { border-width: $COLLECTION_BORDER_WIDTH; border-color : $intermediate-color; @@ -10,6 +11,10 @@ position: absolute; width: 100%; height: 100%; + + .collectionSchemaView-cellContents { + height: $MAX_ROW_HEIGHT; + } .collectionSchemaView-previewRegion { position: relative; @@ -104,7 +109,7 @@ } .rt-tr-group { direction: ltr; - max-height: 44px; + max-height: $MAX_ROW_HEIGHT; } .rt-td { border-width: 1px; @@ -136,7 +141,7 @@ } .ReactTable .rt-th, .ReactTable .rt-td { - max-height: 44; + max-height: $MAX_ROW_HEIGHT; padding: 3px 7px; font-size: 13px; text-align: center; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b61eb342d..90077b053 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' import "react-table/react-table.css"; import { Document } from "../../../fields/Document"; import { Field, Opt } from "../../../fields/Field"; @@ -99,11 +100,11 @@ export class CollectionSchemaView extends CollectionSubView { return false; }; return ( -
    +
    { let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 8868f7df0..20c5a84bf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { - console.log("DROP Aat " + de.x + " off " + de.data.xOffset); const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; let dropX = dragDoc.GetNumber(KeyStore.X, 0); let dropY = dragDoc.GetNumber(KeyStore.Y, 0); de.data.droppedDocuments.map(d => { - let minimized = d.GetBoolean(KeyStore.Minimized, false); - d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedX, 0) : 0)) - dropX); - d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedY, 0) : 0)) - dropY); - if (!minimized) { + d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX); + d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY); + if (!d.GetBoolean(KeyStore.IsMinimized, false)) { if (!d.GetNumber(KeyStore.Width, 0)) { d.SetNumber(KeyStore.Width, 300); } @@ -264,7 +263,9 @@ export class CollectionFreeFormView extends CollectionSubView { let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); if (page === curPage || page === -1) { - prev.push(); + let minim = doc.GetT(KeyStore.IsMinimized, BooleanField); + if (minim === undefined || (minim && !minim.Data)) + prev.push(); } return prev; }, [] as JSX.Element[]); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8b94374fa..bf918beba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -208,12 +208,11 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { - let minimized = doc.GetBoolean(KeyStore.Minimized, false); var z = doc.GetNumber(KeyStore.Zoom, 1); - var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0); - var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0); - var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z; - var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z; + var x = doc.GetNumber(KeyStore.X, 0); + var y = doc.GetNumber(KeyStore.Y, 0); + var w = doc.Width() / z; + var h = doc.Height() / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index f154f8158..4f68b71b0 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -24,8 +24,10 @@ $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; $MINIMIZED_ICON_SIZE:25; +$MAX_ROW_HEIGHT: 44px; :export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; + MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index cc77d987a..9788d31f7 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -3,6 +3,7 @@ interface IGlobalScss { contextMenuZindex: string; // context menu shows up over everything COLLECTION_BORDER_WIDTH: string; MINIMIZED_ICON_SIZE: string; + MAX_ROW_HEIGHT: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a3689414d..1d42b3899 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -46,10 +46,10 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() @@ -57,8 +57,8 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth(); - panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight(); + panelWidth = () => this.props.PanelWidth(); + panelHeight = () => this.props.PanelHeight(); @computed get docView() { @@ -70,19 +70,17 @@ export class CollectionFreeFormDocumentView extends React.Component; } - get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); } - render() { let zoomFade = 1; //var zoom = doc.GetNumber(KeyStore.Zoom, 1); - let transform = this.getTransform().scale(this.contentScaling()).inverse(); - var [sptX, sptY] = transform.transformPoint(0, 0); - let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); - let w = bptX - sptX; - //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; - let fadeUp = .75 * 1800; - let fadeDown = .075 * 1800; - zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; + // let transform = this.getTransform().scale(this.contentScaling()).inverse(); + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); + // let w = bptX - sptX; + // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; + // let fadeUp = .75 * 1800; + // let fadeDown = .075 * 1800; + // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; return (
    Error loading layout keys

    ; } return ; @@ -189,10 +179,10 @@ export class DocumentView extends React.Component { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - if (!SelectionManager.IsSelected(this) && e.button !== 2 && - Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { - SelectionManager.SelectDoc(this, e.ctrlKey); - } + if (!SelectionManager.IsSelected(this) && e.button !== 2) + if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { + SelectionManager.SelectDoc(this, e.ctrlKey); + } } stopPropagation = (e: React.SyntheticEvent) => { e.stopPropagation(); @@ -221,13 +211,33 @@ export class DocumentView extends React.Component { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } + @action createIcon = (layoutString: string): void => { + let iconDoc = Documents.IconDocument(layoutString); + iconDoc.SetBoolean(KeyStore.IsMinimized, false); + iconDoc.SetNumber(KeyStore.NativeWidth, 0); + iconDoc.SetNumber(KeyStore.NativeHeight, 0); + iconDoc.Set(KeyStore.Prototype, this.props.Document); + iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document); + this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc); + this.props.addDocument && this.props.addDocument(iconDoc, false); + } + @action - public minimize = (where: number[]): void => { - this.props.Document.SetBoolean(KeyStore.Minimized, true); - if (where[0] !== 0 || where[1] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - if (where[1] !== 0 || where[0] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + public minimize = (): void => { + this.props.Document.SetBoolean(KeyStore.IsMinimized, true); + this.props.Document.GetAsync(KeyStore.MinimizedDoc, mindoc => { + if (mindoc === undefined) { + this.props.Document.GetAsync(KeyStore.BackgroundLayout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + else this.props.Document.GetAsync(KeyStore.Layout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + }); + }); + } + else if (mindoc instanceof Document) { + this.props.addDocument && this.props.addDocument(mindoc, false); + } + }); } @undoBatch @@ -295,7 +305,6 @@ export class DocumentView extends React.Component { } e.preventDefault(); - !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: () => this.minimize([0, 0]) }); ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }); ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }); @@ -309,9 +318,6 @@ export class DocumentView extends React.Component { SelectionManager.SelectDoc(this, false); } - @action - expand = (e: React.MouseEvent) => { this.props.Document.SetBoolean(KeyStore.Minimized, false); SelectionManager.SelectDoc(this, e.ctrlKey); } - isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false); isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); @@ -319,27 +325,12 @@ export class DocumentView extends React.Component { @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get contents() { return (); } - @computed get minimizedIcon() { - let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf : - this.layout.indexOf("ImageBox") !== -1 ? faImage : - this.layout.indexOf("Formatted") !== -1 ? faStickyNote : - this.layout.indexOf("Video") !== -1 ? faFilm : - this.layout.indexOf("Collection") !== -1 ? faObjectGroup : - faCaretUp; - return - } render() { var scaling = this.props.ContentScaling(); var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%"; var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%"; - if (this.isMinimized()) { - return ( -
    - {this.minimizedIcon} -
    ); - } return (
    { else if (field instanceof ImageField) { return ; } + else if (field instanceof IconField) { + return ; + } else if (field instanceof VideoField) { return ; } diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss new file mode 100644 index 000000000..ce0ee2e09 --- /dev/null +++ b/src/client/views/nodes/IconBox.scss @@ -0,0 +1,12 @@ + +@import "../globalCssVariables"; +.iconBox-container { + position: absolute; + left:0; + top:0; + svg { + width: 100% !important; + height: 100%; + background: white; + } +} \ No newline at end of file diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx new file mode 100644 index 000000000..5ada2186d --- /dev/null +++ b/src/client/views/nodes/IconBox.tsx @@ -0,0 +1,90 @@ +import React = require("react"); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Document } from '../../../fields/Document'; +import { IconField } from "../../../fields/IconFIeld"; +import { KeyStore } from "../../../fields/KeyStore"; +import { SelectionManager } from "../../util/SelectionManager"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./IconBox.scss"; + + +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + +@observer +export class IconBox extends React.Component { + public static LayoutString() { return FieldView.LayoutString(IconBox); } + + @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } + @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

    Error loading layout data

    " as string); } + @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } + + public static DocumentIcon(layout: string) { + let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf : + layout.indexOf("ImageBox") !== -1 ? faImage : + layout.indexOf("Formatted") !== -1 ? faStickyNote : + layout.indexOf("Video") !== -1 ? faFilm : + layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return + } + + animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) { + setTimeout(() => { + let now = Date.now(); + let progress = Math.min(1, (now - stime) / 200); + let pval = maximizing ? + [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] : + [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress]; + target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress); + target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress); + target.SetNumber(KeyStore.X, pval[0]); + target.SetNumber(KeyStore.Y, pval[1]); + if (now < stime + 200) { + this.animateTransition(icon, targ, width, height, stime, target, maximizing); + } + else { + if (!maximizing) { + target.SetBoolean(KeyStore.IsMinimized, true); + target.SetNumber(KeyStore.X, targ[0]); + target.SetNumber(KeyStore.Y, targ[1]); + target.SetNumber(KeyStore.Width, width); + target.SetNumber(KeyStore.Height, height); + } + this._completed = true; + } + }, + 2); + } + + _completed = true; + + @action + public toggleMinimize = (): void => { + SelectionManager.DeselectAll(); + if (this.maximized instanceof Document && this._completed) { + this._completed = false; + let minimized = this.maximized.GetBoolean(KeyStore.IsMinimized, false); + this.maximized.SetBoolean(KeyStore.IsMinimized, false); + this.animateTransition( + [this.props.Document.GetNumber(KeyStore.X, 0), this.props.Document.GetNumber(KeyStore.Y, 0)], + [this.maximized.GetNumber(KeyStore.X, 0), this.maximized.GetNumber(KeyStore.Y, 0)], + this.maximized.GetNumber(KeyStore.Width, 0), this.maximized.GetNumber(KeyStore.Width, 0), + Date.now(), this.maximized, minimized); + } + } + + render() { + return ( +
    + {this.minimizedIcon} +
    ); + } +} \ No newline at end of file diff --git a/src/fields/IconFIeld.ts b/src/fields/IconFIeld.ts new file mode 100644 index 000000000..a6694cc49 --- /dev/null +++ b/src/fields/IconFIeld.ts @@ -0,0 +1,25 @@ +import { BasicField } from "./BasicField"; +import { FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class IconField extends BasicField { + constructor(data: string = "", id?: FieldId, save: boolean = true) { + super(data, save, id); + } + + ToScriptString(): string { + return `new IconField("${this.Data}")`; + } + + Copy() { + return new IconField(this.Data); + } + + ToJson() { + return { + type: Types.Icon, + data: this.Data, + id: this.Id + }; + } +} \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index ff2f31003..a347f8bcf 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -4,8 +4,6 @@ export namespace KeyStore { export const Prototype = new Key("Prototype"); export const X = new Key("X"); export const Y = new Key("Y"); - export const MinimizedX = new Key("MinimizedX"); - export const MinimizedY = new Key("MinimizedY"); export const Page = new Key("Page"); export const Title = new Key("Title"); export const Author = new Key("Author"); @@ -47,14 +45,16 @@ export namespace KeyStore { export const OptionalRightCollection = new Key("OptionalRightCollection"); export const Archives = new Key("Archives"); export const Workspaces = new Key("Workspaces"); - export const Minimized = new Key("Minimized"); + export const IsMinimized = new Key("IsMinimized"); + export const MinimizedDoc = new Key("MinimizedDoc"); + export const MaximizedDoc = new Key("MaximizedDoc"); export const CopyDraggedItems = new Key("CopyDraggedItems"); - export const KeyList: Key[] = [Prototype, X, Y, MinimizedX, MinimizedY, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, + export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, - Archives, Workspaces, Minimized, CopyDraggedItems + Archives, Workspaces, IsMinimized, MinimizedDoc, MaximizedDoc, CopyDraggedItems ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { diff --git a/src/server/Message.ts b/src/server/Message.ts index bbe4ffcad..15916ef12 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -14,7 +14,7 @@ export class Message { } export enum Types { - Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, + Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference, Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, } diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 818230c1a..79ca5e55d 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -18,6 +18,7 @@ import { NumberField } from "./../fields/NumberField"; import { RichTextField } from "./../fields/RichTextField"; import { TextField } from "./../fields/TextField"; import { Transferable, Types } from "./Message"; +import { IconField } from "../fields/IconFIeld"; export class ServerUtils { public static prepend(extension: string): string { @@ -37,6 +38,7 @@ export class ServerUtils { case Types.Boolean: return new BooleanField(json.data, json.id, false); case Types.Number: return new NumberField(json.data, json.id, false); case Types.Text: return new TextField(json.data, json.id, false); + case Types.Icon: return new IconField(json.data, json.id, false); case Types.Html: return new HtmlField(json.data, json.id, false); case Types.Web: return new WebField(new URL(json.data), json.id, false); case Types.RichText: return new RichTextField(json.data, json.id, false); -- cgit v1.2.3-70-g09d2 From 7ceac5f7f4cc8172bde90c2d495da3779901ef84 Mon Sep 17 00:00:00 2001 From: Fawn Date: Fri, 19 Apr 2019 18:31:38 -0400 Subject: templating saves --- src/client/documents/Documents.ts | 8 ++++- src/client/views/DocumentDecorations.tsx | 20 +++--------- src/client/views/TemplateMenu.tsx | 13 -------- src/client/views/Templates.tsx | 55 +++++++++++++++----------------- src/client/views/nodes/DocumentView.tsx | 37 ++++++++------------- src/fields/KeyStore.ts | 4 ++- src/fields/TemplateField.ts | 35 ++++++++++++++++++++ src/server/Message.ts | 2 +- src/server/ServerUtil.ts | 3 ++ 9 files changed, 92 insertions(+), 85 deletions(-) create mode 100644 src/fields/TemplateField.ts (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8db1a1c6d..eba53273f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,6 +32,8 @@ import { action } from "mobx"; import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; +import { Template } from "../views/Templates"; +import { TemplateField } from "../../fields/TemplateField"; export interface DocumentOptions { x?: number; @@ -46,7 +48,9 @@ export interface DocumentOptions { pany?: number; page?: number; scale?: number; + baseLayout?: string; layout?: string; + template?: Template; layoutKeys?: Key[]; viewType?: number; backgroundColor?: string; @@ -95,7 +99,9 @@ export namespace Documents { if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); } if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } + if (options.baseLayout !== undefined) { doc.SetText(KeyStore.BaseLayout, options.baseLayout); } if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); } + if (options.template !== undefined) { doc.Set(KeyStore.Template, new TemplateField(options.template)); } if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); } if (options.copyDraggedItems !== undefined) { doc.SetBoolean(KeyStore.CopyDraggedItems, options.copyDraggedItems); } return doc; @@ -112,7 +118,7 @@ export namespace Documents { } function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document { - return assignOptions(new Document(protoId), { ...options, title: title, layout: layout }); + return assignOptions(new Document(protoId), { ...options, title: title, layout: layout , baseLayout: layout}); } function SetInstanceOptions(doc: Document, options: DocumentOptions, value: [T, { new(): U }] | Document, id?: string) { var deleg = doc.MakeDelegate(id); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3dcdc596d..2a40d7347 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -17,25 +17,11 @@ import { LinkMenu } from "./nodes/LinkMenu"; import { TemplateMenu } from "./TemplateMenu"; import React = require("react"); import { Template, Templates } from "./Templates"; +import { TemplateField } from "../../fields/TemplateField"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; -// @observer -// class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent, template: Template) => void }> { -// render() { -// if (this.props.template) { -// return ( -//
  • -// this.props.toggle(event, this.props.template)} /> -// {this.props.template.Name} -//
  • -// ) -// } -// return (null); -// } -// } - @observer export class DocumentDecorations extends React.Component<{}, { value: string }> { static Instance: DocumentDecorations; @@ -409,8 +395,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let templates: Map = new Map(); let doc = SelectionManager.SelectedDocuments()[0]; Array.from(Object.values(Templates)).map(template => { - templates.set(template, doc.Template === template); + templates.set(template, doc.template.Name === template.Name); }); + // let docSrc = doc.props.Document.GetT(KeyStore.Prototype, TemplateField); + // console.log(docSrc); return (
    { @observable private _hidden: boolean = true; - @observable private _useBase: boolean = true; @observable private _templates: Map = this.props.templates; @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { - this._useBase = false; - this.props.doc.toggleBase(false); this.props.doc.changeTemplate(template); this._templates.forEach((checked, temp) => { this._templates.set(temp, false); @@ -57,15 +54,6 @@ export class TemplateMenu extends React.Component { this._templates = nextProps.templates; } - @action - toggleBase = (event: React.MouseEvent): void => { - this._useBase = true; - this.props.doc.toggleBase(true); - this._templates.forEach((checked, temp) => { - this._templates.set(temp, false); - }); - } - @action toggleTemplateActivity = (): void => { this._hidden = !this._hidden; @@ -81,7 +69,6 @@ export class TemplateMenu extends React.Component {
    this.toggleTemplateActivity()}>T
      -
    • this.toggleBase(event)} checked={this._useBase} />Base layout
    • {templateMenu}
    diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index c22b22286..3afdc711c 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -24,39 +24,34 @@ export class Template { } export namespace Templates { + export const BasicLayout = new Template("Basic layout", "{layout}"); + export const OuterCaption = new Template("Outer caption", - ` -
    -
    - {layout} -
    -
    - -
    -
    - `); + `
    {layout}
    ` + ); + export const InnerCaption = new Template("Inner caption", - ` -
    -
    - {layout} -
    -
    - -
    -
    - `); + `
    +
    + {layout} +
    +
    + +
    +
    ` + ); export const Title = new Template("Title", - ` -
    -
    - {layout} -
    -
    - {Title} -
    -
    - `); + `
    +
    + {layout} +
    +
    + {Title} +
    +
    ` + ); + + } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 12332348b..440269e36 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -21,9 +21,10 @@ import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; -import { Template } from "./../Templates"; +import { Template, Templates } from "./../Templates"; import "./DocumentView.scss"; import React = require("react"); +import { TemplateField } from "../../../fields/TemplateField"; export interface DocumentViewProps { @@ -92,13 +93,19 @@ export class DocumentView extends React.Component { } private _downX: number = 0; private _downY: number = 0; - private _base: string = this.props.Document.GetText(KeyStore.Layout, "

    Error loading layout data

    "); - @observable private _template: Template = new Template("", ""); + @computed get base(): string { return this.props.Document.GetText(KeyStore.BaseLayout, "

    Error loading base layout data

    "); } @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } @computed get topMost(): boolean { return this.props.isTopMost; } @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "

    Error loading layout data

    "); } @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array()); } @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array()); } + @computed get template(): Template { + let field = this.props.Document.GetT(KeyStore.Template, TemplateField); + return !field || field === FieldWaiting ? Templates.BasicLayout : field.Data; + } + set template(template: Template) { + this.props.Document.SetData(KeyStore.Template, template, TemplateField); + } screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; @@ -303,33 +310,17 @@ export class DocumentView extends React.Component { } updateLayout = (): void => { - if (this._template.Name === "") { - this.props.Document.SetText(KeyStore.Layout, this._base); - } else { - let temp = this._template.Layout; - let layout = temp.replace("{layout}", this._base); - this.props.Document.SetText(KeyStore.Layout, layout); - } - } - - @action - toggleBase = (useBase: boolean) => { - if (useBase) { - this._template = new Template("", ""); - } - this.updateLayout(); + let temp = this.template.Layout; + let layout = temp.replace("{layout}", this.base); + this.props.Document.SetText(KeyStore.Layout, layout); } @action changeTemplate = (template: Template) => { - this._template = template; + this.template = template; this.updateLayout(); } - get Template() { - return this._template; - } - @action onContextMenu = (e: React.MouseEvent): void => { e.stopPropagation(); diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 16a909eb8..1602c3776 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -19,7 +19,9 @@ export namespace KeyStore { export const Data = new Key("Data"); export const Annotations = new Key("Annotations"); export const ViewType = new Key("ViewType"); + export const BaseLayout = new Key("BaseLayout"); export const Layout = new Key("Layout"); + export const Template = new Key("Template"); export const BackgroundColor = new Key("BackgroundColor"); export const BackgroundLayout = new Key("BackgroundLayout"); export const OverlayLayout = new Key("OverlayLayout"); @@ -49,7 +51,7 @@ export namespace KeyStore { export const CopyDraggedItems = new Key("CopyDraggedItems"); export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, - Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, + Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, BaseLayout, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, Archives, Workspaces, Minimized, CopyDraggedItems diff --git a/src/fields/TemplateField.ts b/src/fields/TemplateField.ts new file mode 100644 index 000000000..bc1e67d7b --- /dev/null +++ b/src/fields/TemplateField.ts @@ -0,0 +1,35 @@ +import { BasicField } from "./BasicField"; +import { Types } from "../server/Message"; +import { FieldId } from "./Field"; +import { Template, Templates } from "../client/views/Templates"; + + +export class TemplateField extends BasicField