From 5b69b2cba13f104471dc08e110148704fdc2acca Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Jul 2019 12:45:28 -0400 Subject: fixes for templating miniLayout and detailedLayouts --- src/client/views/collections/CollectionView.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 56750668d..377a46535 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,11 +1,10 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faSquare, faTh, faImage, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; -import { Doc } from '../../../new_fields/Doc'; +import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { Docs } from '../../documents/Documents'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; @@ -16,6 +15,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; +import { StrCast, PromiseValue } from '../../../new_fields/Types'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -24,6 +24,7 @@ library.add(faSquare); library.add(faProjectDiagram); library.add(faSignature); library.add(faThList); +library.add(faImage); @observer export class CollectionView extends React.Component { @@ -63,6 +64,8 @@ export class CollectionView extends React.Component { otherdoc.height = 50; Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")"; Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); + Doc.GetProto(otherdoc).miniLayout = StrCast(this.props.Document.miniLayout); + Doc.GetProto(otherdoc).detailedLayout = Doc.GetProto(otherdoc).layout; this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight"); }), icon: "project-diagram" }); -- cgit v1.2.3-70-g09d2 From 922c418f1207c43150c499e075a9c1be34719b58 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 18 Jul 2019 17:36:37 -0400 Subject: fixes for stacking view and added detailedLayout --- src/client/views/collections/CollectionStackingView.scss | 5 +++-- src/client/views/collections/CollectionStackingView.tsx | 8 ++++---- src/client/views/collections/CollectionView.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 13 ++++--------- src/new_fields/Doc.ts | 11 +++++++++-- 5 files changed, 22 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index b6ad47813..7ebf5f77c 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,8 +1,9 @@ @import "../globalCssVariables"; .collectionStackingView { - overflow-y: auto; height: 100%; - + width: 100%; + position: absolute; + overflow-y: auto; .collectionStackingView-docView-container { width: 45%; margin: 5% 2.5%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index c42a423c1..4424cffe1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -15,6 +15,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; +import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss"; import { string } from "prop-types"; @observer @@ -107,6 +108,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); return this.offsetTransform(doc, translateX, translateY); } + getSingleDocTransform(doc: Doc, ind: number, width: number) { let localY = this.filteredChildren.reduce((height, d, i) => height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); @@ -234,7 +236,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; - return <> + return
{heading ?
{heading}
: (null)}
doc) { > {this.children(docList)} {this.singleColumn ? (null) : this.columnDragger} -
; +
; } render() { let sectionFilter = StrCast(this.props.Document.sectionFilter); @@ -261,8 +263,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); return (
e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 377a46535..1b85a0cdb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -46,6 +46,7 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } + static _applyCount: number = 0; onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 let subItems: ContextMenuProps[] = []; @@ -62,7 +63,7 @@ export class CollectionView extends React.Component { let otherdoc = new Doc(); otherdoc.width = 100; otherdoc.height = 50; - Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")"; + Doc.GetProto(otherdoc).title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); Doc.GetProto(otherdoc).miniLayout = StrCast(this.props.Document.miniLayout); Doc.GetProto(otherdoc).detailedLayout = Doc.GetProto(otherdoc).layout; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 899c47cb3..76b8658a5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -291,7 +291,9 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth) { let fullScreenAlias = Doc.MakeAlias(this.props.Document); fullScreenAlias.templates = new List(); - if (this.props.Document.layout === this.props.Document.miniLayout) fullScreenAlias.layout = this.props.Document.detailedLayout instanceof Doc ? this.props.Document.detailedLayout : StrCast(this.props.Document.detailedLayout); + if (this.props.Document.layout === this.props.Document.miniLayout) { + Doc.ToggleDetailLayout(fullScreenAlias); + } this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = undefined; @@ -557,14 +559,7 @@ export class DocumentView extends DocComponent(Docu }, icon: "search" }); if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { - cm.addItem({ - description: "Toggle detail", event: async () => { - let d = this.props.Document; - let miniLayout = await PromiseValue(d.miniLayout); - let detailLayout = await PromiseValue(d.detailedLayout); - d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); - }, icon: "image" - }); + cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 7180564ea..9a4b817d3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -316,7 +316,7 @@ export namespace Doc { if (extensionDoc === undefined) { setTimeout(() => { let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = "Extension of " + doc.title + "'s field:" + fieldKey; + docExtensionForField.title = doc.title + ":" + fieldKey + ".ext"; docExtensionForField.extendsDoc = doc; let proto: Doc | undefined = doc; while (proto && !Doc.IsPrototype(proto)) { @@ -351,7 +351,7 @@ export namespace Doc { if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title; + (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; // previously: "applied to" (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).isExpandedTemplate = templateLayoutDoc; }, 0); } @@ -420,4 +420,11 @@ export namespace Doc { fieldTemplate.showTitle = "title"; setTimeout(() => fieldTemplate.proto = proto); } + + export async function ToggleDetailLayout(d: Doc) { + let miniLayout = await PromiseValue(d.miniLayout); + let detailLayout = await PromiseValue(d.detailedLayout); + d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); + if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2b98b5484b942361ab5e271fe9e09d09dc83fa60 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 19 Jul 2019 00:51:15 -0400 Subject: more cleanup for templates --- src/client/views/collections/CollectionView.tsx | 6 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +-- src/client/views/nodes/WebBox.tsx | 16 ---------------- src/new_fields/Doc.ts | 14 +++++++++----- 4 files changed, 13 insertions(+), 26 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 1b85a0cdb..b6b690e26 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faProjectDiagram, faSignature, faSquare, faTh, faImage, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; -import { Doc, DocListCast } from '../../../new_fields/Doc'; +import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { undoBatch } from '../../util/UndoManager'; @@ -61,8 +61,8 @@ export class CollectionView extends React.Component { ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { let otherdoc = new Doc(); - otherdoc.width = 100; - otherdoc.height = 50; + otherdoc.width = this.props.Document[WidthSym](); + otherdoc.height = this.props.Document[HeightSym](); Doc.GetProto(otherdoc).title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); Doc.GetProto(otherdoc).miniLayout = StrCast(this.props.Document.miniLayout); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 58218e641..1997a6a4d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from "mobx"; +import { action, computed, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCastAsync, HeightSym, WidthSym, DocListCast } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; @@ -516,7 +516,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ] render() { const easing = () => this.props.Document.panTransformType === "Ease"; - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); return (
{ diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 9a4b817d3..7bf1dec53 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -10,6 +10,7 @@ import { RefField, FieldId } from "./RefField"; import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; import { List } from "./List"; +import { string } from "prop-types"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -344,20 +345,23 @@ export namespace Doc { // ... which means we change the layout to be an expanded view of the template layout. // This allows the view override the template's properties and be referenceable as its own document. - let expandedTemplateLayout = templateLayoutDoc["_expanded_" + dataDoc[Id]]; + let expandedTemplateLayout = dataDoc[templateLayoutDoc[Id]]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { - templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; // previously: "applied to" - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).isExpandedTemplate = templateLayoutDoc; + let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); + expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; + expandedDoc.isExpandedTemplate = templateLayoutDoc; + dataDoc[templateLayoutDoc[Id]] = expandedDoc; }, 0); } - return templateLayoutDoc; + return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } + let _pendingExpansions: Map = new Map(); + export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { -- cgit v1.2.3-70-g09d2 From 64de59fc4250eff5284380ca2743030aa453fce7 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 19 Jul 2019 14:51:36 -0400 Subject: gave templates a type ... but is it the right one? --- src/client/views/collections/CollectionView.tsx | 10 ++++++---- src/new_fields/Doc.ts | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b6b690e26..7e9d35d3d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -16,6 +16,7 @@ import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; +import { DocumentType } from '../../documents/Documents'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -63,10 +64,11 @@ export class CollectionView extends React.Component { let otherdoc = new Doc(); otherdoc.width = this.props.Document[WidthSym](); otherdoc.height = this.props.Document[HeightSym](); - Doc.GetProto(otherdoc).title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" - Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); - Doc.GetProto(otherdoc).miniLayout = StrCast(this.props.Document.miniLayout); - Doc.GetProto(otherdoc).detailedLayout = Doc.GetProto(otherdoc).layout; + otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" + otherdoc.layout = Doc.MakeDelegate(this.props.Document); + otherdoc.miniLayout = StrCast(this.props.Document.miniLayout); + otherdoc.detailedLayout = otherdoc.layout; + otherdoc.type = DocumentType.TEMPLATE; this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight"); }), icon: "project-diagram" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c6b364d8e..2ad6ae5f0 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -423,7 +423,6 @@ export namespace Doc { fieldTemplate.nativeHeight = nh; fieldTemplate.isTemplate = true; fieldTemplate.showTitle = "title"; - fieldTemplate.type = DocumentType.TEMPLATE; setTimeout(() => fieldTemplate.proto = proto); } -- cgit v1.2.3-70-g09d2 From 5e9bcf2e35415fd0ab4dec4f0141511cd4d312d0 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 19 Jul 2019 16:03:09 -0400 Subject: split masonry collection view into its own view type. --- src/client/documents/Documents.ts | 4 ++ .../views/collections/CollectionBaseView.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 58 +++++++--------------- src/client/views/collections/CollectionView.tsx | 10 ++-- 4 files changed, 32 insertions(+), 43 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 11df6c152..47ed33adf 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -410,6 +410,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Stacking }); } + export function MasonryDocument(documents: Array, options: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Masonry }); + } + export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 2603dc60b..72faf52c4 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -18,7 +18,8 @@ export enum CollectionViewType { Schema, Docking, Tree, - Stacking + Stacking, + Masonry } export interface CollectionRenderProps { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 039bd7b3a..0e5f9a321 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -6,7 +6,6 @@ import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, Utils } from "../../../Utils"; -import { ContextMenu } from "../ContextMenu"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @@ -15,16 +14,14 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; -import { COLLECTION_BORDER_WIDTH } from "../../views/globalCssVariables.scss"; -import { string } from "prop-types"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; _draggerRef = React.createRef(); _heightDisposer?: IReactionDisposer; - _gridSize = 1; _docXfs: any[] = []; + _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @@ -33,24 +30,25 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } + @computed get Sections() { + let sectionFilter = StrCast(this.props.Document.sectionFilter); + let fields = new Map(); + sectionFilter && this.filteredChildren.map(d => { + let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; + if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); + else fields.get(sectionValue)!.push(d); + }); + return fields; + } componentDidMount() { this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => { - if (this.singleColumn) { - let sectionFilter = StrCast(this.props.Document.sectionFilter); - let fields = new Map(); - sectionFilter && this.filteredChildren.map(d => { - if (!fields.has(d[sectionFilter] as object)) fields.set(d[sectionFilter] as object, [d]); - else fields.get(d[sectionFilter] as object)!.push(d); - }); - (this.props.Document.height = fields.size * 50 + this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)); - } - } + () => this.singleColumn && + (this.props.Document.height = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => + height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) , { fireImmediately: true }); } componentWillUnmount() { - if (this._heightDisposer) this._heightDisposer(); + this._heightDisposer && this._heightDisposer(); } @action @@ -98,7 +96,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return (nw && nh) ? wid * aspect : d[HeightSym](); } - offsetTransform(doc: Doc, translateX: number, translateY: number) { let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); @@ -133,7 +130,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } else { let dref = React.createRef(); let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); this._docXfs.push({ dxf: dxf, width: width, height: height }); return
{this.getDisplayDoc(layoutDoc, d, dxf)} @@ -142,7 +139,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } - _columnStart: number = 0; columnDividerDown = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -156,7 +152,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; let delta = dragPos - this._columnStart; this._columnStart = dragPos; - this.props.Document.columnWidth = this.columnWidth + delta; } @@ -172,14 +167,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; } - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" - }); - } - } @undoBatch @action @@ -247,7 +234,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { position: "relative", gridGap: this.gridGap, gridTemplateColumns: this.singleColumn ? undefined : templatecols, - gridAutoRows: this.singleColumn ? undefined : `${this._gridSize}px` + gridAutoRows: this.singleColumn ? undefined : "0px" }} > {this.children(docList)} @@ -255,21 +242,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; } render() { - let sectionFilter = StrCast(this.props.Document.sectionFilter); - let fields = new Map(); - sectionFilter && this.filteredChildren.map(d => { - let sectionValue = (d[sectionFilter] ? d[sectionFilter] : "-undefined-") as object; - if (!fields.has(sectionValue)) fields.set(sectionValue, [d]); - else fields.get(sectionValue)!.push(d); - }); return (
e.stopPropagation()} > + ref={this.createRef} onDrop={this.onDrop.bind(this)} onWheel={(e: React.WheelEvent) => e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], ["width = height", this.filteredChildren.filter(f => Math.abs(f[WidthSym]() - f[HeightSym]()) < 1)], ["height > width", this.filteredChildren.filter(f => f[WidthSym]() + 1 <= f[HeightSym]())]]. */} - {sectionFilter ? Array.from(fields.entries()). + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()). map(section => this.section(section[0].toString(), section[1] as Doc[])) : this.section("", this.filteredChildren)}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 7e9d35d3d..045c8531e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSignature, faSquare, faTh, faImage, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faColumns, faSquare, faTh, faImage, faThList, faTree, faEllipsisV } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; @@ -25,6 +25,8 @@ library.add(faSquare); library.add(faProjectDiagram); library.add(faSignature); library.add(faThList); +library.add(faColumns); +library.add(faEllipsisV); library.add(faImage); @observer @@ -37,7 +39,8 @@ export class CollectionView extends React.Component { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: return (); @@ -57,7 +60,8 @@ export class CollectionView extends React.Component { } subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); - subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" }); + subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" }); ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { -- cgit v1.2.3-70-g09d2 From 3442776999d1d7b7bced9bbed601ead637a43cc7 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 10:24:37 -0400 Subject: merged stacking sections branch. --- src/client/views/DocumentDecorations.tsx | 10 +- .../views/collections/CollectionBaseView.tsx | 6 +- .../views/collections/CollectionStackingView.scss | 13 +- .../views/collections/CollectionStackingView.tsx | 247 --------------------- src/client/views/collections/CollectionView.tsx | 28 ++- src/client/views/nodes/WebBox.tsx | 16 -- src/new_fields/Doc.ts | 33 ++- 7 files changed, 64 insertions(+), 289 deletions(-) delete mode 100644 src/client/views/collections/CollectionStackingView.tsx (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fb5104915..2f7bea365 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -28,6 +28,7 @@ import { RichTextField } from '../../new_fields/RichTextField'; import { LinkManager } from '../util/LinkManager'; import { ObjectField } from '../../new_fields/ObjectField'; import { MetadataEntryMenu } from './MetadataEntryMenu'; +import { ImageBox } from './nodes/ImageBox'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -85,8 +86,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.DeselectAll(); let fieldTemplate = fieldTemplateView.props.Document; let docTemplate = fieldTemplateView.props.ContainingCollectionView!.props.Document; - let metaKey = text.slice(1, text.length); - Doc.MakeTemplate(fieldTemplate, metaKey, Doc.GetProto(docTemplate)); + let metaKey = text.startsWith(">>") ? text.slice(2, text.length) : text.slice(1, text.length); + let proto = Doc.GetProto(docTemplate); + Doc.MakeTemplate(fieldTemplate, metaKey, proto); + if (text.startsWith(">>")) { + proto.detailedLayout = proto.layout; + proto.miniLayout = ImageBox.LayoutString(metaKey); + } } else { if (SelectionManager.SelectedDocuments().length > 0) { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index eba69b448..72faf52c4 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -18,7 +18,8 @@ export enum CollectionViewType { Schema, Docking, Tree, - Stacking + Stacking, + Masonry } export interface CollectionRenderProps { @@ -78,7 +79,6 @@ export class CollectionBaseView extends React.Component { @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { - let self = this; var curPage = NumCast(this.props.Document.curPage, -1); Doc.GetProto(doc).page = curPage; if (curPage >= 0) { @@ -146,7 +146,7 @@ export class CollectionBaseView extends React.Component { const viewtype = this.collectionViewType; return (
{viewtype !== undefined ? this.props.children(viewtype, props) : (null)} diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 7e886304d..7ebf5f77c 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,7 +1,9 @@ @import "../globalCssVariables"; .collectionStackingView { + height: 100%; + width: 100%; + position: absolute; overflow-y: auto; - .collectionStackingView-docView-container { width: 45%; margin: 5% 2.5%; @@ -71,4 +73,13 @@ grid-column-end: span 1; height: 100%; } + .collectionStackingView-sectionHeader { + width: 90%; + background: gray; + text-align: center; + margin-left: 5%; + margin-right: 5%; + color: white; + margin-top: 10px; + } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx deleted file mode 100644 index 6d9e942c9..000000000 --- a/src/client/views/collections/CollectionStackingView.tsx +++ /dev/null @@ -1,247 +0,0 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction, untracked, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, Cast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; -import { ContextMenu } from "../ContextMenu"; -import { CollectionSchemaPreview } from "./CollectionSchemaView"; -import "./CollectionStackingView.scss"; -import { CollectionSubView } from "./CollectionSubView"; -import { undoBatch } from "../../util/UndoManager"; -import { DragManager } from "../../util/DragManager"; -import { DocumentType } from "../../documents/Documents"; -import { Transform } from "../../util/Transform"; -import { CursorProperty } from "csstype"; - -@observer -export class CollectionStackingView extends CollectionSubView(doc => doc) { - _masonryGridRef: HTMLDivElement | null = null; - _draggerRef = React.createRef(); - _heightDisposer?: IReactionDisposer; - _gridSize = 1; - _docXfs: any[] = []; - @observable private cursor: CursorProperty = "grab"; - @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } - @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } - @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } - @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } - @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } - @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } - - componentDidMount() { - this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => this.singleColumn && - (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => - height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) - , { fireImmediately: true }); - } - componentWillUnmount() { - if (this._heightDisposer) this._heightDisposer(); - } - - @action - moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { - return this.props.removeDocument(doc) && addDocument(doc); - } - createRef = (ele: HTMLDivElement | null) => { - this._masonryGridRef = ele; - this.createDropTarget(ele!); - } - - overlays = (doc: Doc) => { - return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {}; - } - - getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) { - let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.getDocHeight(layoutDoc); - let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); - return - ; - } - getDocHeight(d: Doc) { - let nw = NumCast(d.nativeWidth); - let nh = NumCast(d.nativeHeight); - let aspect = nw && nh ? nh / nw : 1; - let wid = Math.min(d[WidthSym](), this.columnWidth); - return (nw && nh) ? wid * aspect : d[HeightSym](); - } - - - offsetTransform(doc: Doc, translateX: number, translateY: number) { - let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); - } - getDocTransform(doc: Doc, dref: HTMLDivElement) { - let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); - return this.offsetTransform(doc, translateX, translateY); - } - getSingleDocTransform(doc: Doc, ind: number, width: number) { - let localY = this.filteredChildren.reduce((height, d, i) => - height + (i < ind ? this.getDocHeight(Doc.expandTemplateLayout(d, this.props.DataDoc)) + this.gridGap : 0), this.yMargin); - let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY); - return this.offsetTransform(doc, translate[0], translate[1]); - } - - @computed - get children() { - this._docXfs.length = 0; - return this.filteredChildren.map((d, i) => { - let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); - let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.getDocHeight(layoutDoc); - if (this.singleColumn) { - let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100; - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } else { - let dref = React.createRef(); - let dxf = () => this.getDocTransform(layoutDoc, dref.current!); - let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } - }); - } - - _columnStart: number = 0; - columnDividerDown = (e: React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - runInAction(() => this.cursor = "grabbing"); - document.addEventListener("pointermove", this.onDividerMove); - document.addEventListener('pointerup', this.onDividerUp); - this._columnStart = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; - } - @action - onDividerMove = (e: PointerEvent): void => { - let dragPos = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; - let delta = dragPos - this._columnStart; - this._columnStart = dragPos; - - this.props.Document.columnWidth = this.columnWidth + delta; - } - - @action - onDividerUp = (e: PointerEvent): void => { - runInAction(() => this.cursor = "grab"); - document.removeEventListener("pointermove", this.onDividerMove); - document.removeEventListener('pointerup', this.onDividerUp); - } - - @computed get columnDragger() { - return
- -
; - } - onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "Toggle multi-column", - event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, true), icon: "file-pdf" - }); - } - } - - @undoBatch - @action - drop = (e: Event, de: DragManager.DropEvent) => { - let targInd = -1; - let where = [de.x, de.y]; - if (de.data instanceof DragManager.DocumentDragData) { - this._docXfs.map((cd, i) => { - let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); - if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { - targInd = i; - } - }); - } - if (super.drop(e, de)) { - let newDoc = de.data.droppedDocuments[0]; - let docs = this.childDocList; - if (docs) { - if (targInd === -1) targInd = docs.length; - else targInd = docs.indexOf(this.filteredChildren[targInd]); - let srcInd = docs.indexOf(newDoc); - docs.splice(srcInd, 1); - docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); - } - } - return false; - } - @undoBatch - @action - onDrop = (e: React.DragEvent): void => { - let where = [e.clientX, e.clientY]; - let targInd = -1; - this._docXfs.map((cd, i) => { - let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); - let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); - if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { - targInd = i; - } - }); - super.onDrop(e, {}, () => { - if (targInd !== -1) { - let newDoc = this.childDocs[this.childDocs.length - 1]; - let docs = this.childDocList; - if (docs) { - docs.splice(docs.length - 1, 1); - docs.splice(targInd, 0, newDoc); - } - } - }); - } - render() { - let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, - Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); - let templatecols = ""; - for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; - return ( -
e.stopPropagation()} > -
- {this.children} - {this.singleColumn ? (null) : this.columnDragger} -
-
- ); - } -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 56750668d..045c8531e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,11 +1,10 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faColumns, faSquare, faTh, faImage, faThList, faTree, faEllipsisV } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; -import { Doc } from '../../../new_fields/Doc'; +import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; -import { Docs } from '../../documents/Documents'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; @@ -16,6 +15,8 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; +import { StrCast, PromiseValue } from '../../../new_fields/Types'; +import { DocumentType } from '../../documents/Documents'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -24,6 +25,9 @@ library.add(faSquare); library.add(faProjectDiagram); library.add(faSignature); library.add(faThList); +library.add(faColumns); +library.add(faEllipsisV); +library.add(faImage); @observer export class CollectionView extends React.Component { @@ -35,7 +39,8 @@ export class CollectionView extends React.Component { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: return (); @@ -45,6 +50,7 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } + static _applyCount: number = 0; onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 let subItems: ContextMenuProps[] = []; @@ -54,15 +60,19 @@ export class CollectionView extends React.Component { } subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); - subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" }); + subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" }); ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { let otherdoc = new Doc(); - otherdoc.width = 100; - otherdoc.height = 50; - Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")"; - Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); + otherdoc.width = this.props.Document[WidthSym](); + otherdoc.height = this.props.Document[HeightSym](); + otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" + otherdoc.layout = Doc.MakeDelegate(this.props.Document); + otherdoc.miniLayout = StrCast(this.props.Document.miniLayout); + otherdoc.detailedLayout = otherdoc.layout; + otherdoc.type = DocumentType.TEMPLATE; this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight"); }), icon: "project-diagram" }); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index f0a9ec6d8..162ac1d98 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -9,22 +9,6 @@ import React = require("react"); import { InkTool } from "../../../new_fields/InkField"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; -export function onYouTubeIframeAPIReady() { - console.log("player"); - return; - let player = new YT.Player('player', { - events: { - 'onReady': onPlayerReady - } - }); -} -// must cast as any to set property on window -const _global = (window /* browser */ || global /* node */) as any; -_global.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady; - -function onPlayerReady(event: any) { - event.target.playVideo(); -} @observer export class WebBox extends React.Component { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 59e61023f..2ad6ae5f0 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -10,6 +10,7 @@ import { RefField, FieldId } from "./RefField"; import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; import { List } from "./List"; +import { DocumentType } from "../client/documents/Documents"; import { ComputedField } from "./ScriptField"; export namespace Field { @@ -317,7 +318,7 @@ export namespace Doc { if (extensionDoc === undefined) { setTimeout(() => { let docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = "Extension of " + doc.title + "'s field:" + fieldKey; + docExtensionForField.title = doc.title + ":" + fieldKey + ".ext"; docExtensionForField.extendsDoc = doc; let proto: Doc | undefined = doc; while (proto && !Doc.IsPrototype(proto)) { @@ -345,20 +346,23 @@ export namespace Doc { // ... which means we change the layout to be an expanded view of the template layout. // This allows the view override the template's properties and be referenceable as its own document. - let expandedTemplateLayout = templateLayoutDoc["_expanded_" + dataDoc[Id]]; + let expandedTemplateLayout = dataDoc[templateLayoutDoc[Id]]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { - templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title; - (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).isExpandedTemplate = templateLayoutDoc; + let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); + expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; + expandedDoc.isExpandedTemplate = templateLayoutDoc; + dataDoc[templateLayoutDoc[Id]] = expandedDoc; }, 0); } - return templateLayoutDoc; + return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } + let _pendingExpansions: Map = new Map(); + export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { @@ -386,12 +390,12 @@ export namespace Doc { export function MakeDelegate(doc: Doc, id?: string): Doc; export function MakeDelegate(doc: Opt, id?: string): Opt; export function MakeDelegate(doc: Opt, id?: string): Opt { - if (!doc) { - return undefined; + if (doc) { + const delegate = new Doc(id, true); + delegate.proto = doc; + return delegate; } - const delegate = new Doc(id, true); - delegate.proto = doc; - return delegate; + return undefined; } export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) { @@ -421,4 +425,11 @@ export namespace Doc { fieldTemplate.showTitle = "title"; setTimeout(() => fieldTemplate.proto = proto); } + + export async function ToggleDetailLayout(d: Doc) { + let miniLayout = await PromiseValue(d.miniLayout); + let detailLayout = await PromiseValue(d.detailedLayout); + d.layout !== miniLayout ? miniLayout && (d.layout = d.miniLayout) : detailLayout && (d.layout = detailLayout); + if (d.layout === detailLayout) Doc.GetProto(d).nativeWidth = Doc.GetProto(d).nativeHeight = undefined; + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b4ef60552f226e4022fac5092ea66f1b685bb08c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 22 Jul 2019 18:50:26 -0400 Subject: Started adding schema functionality --- src/client/util/Scripting.ts | 50 +++++++----- src/client/views/OverlayView.scss | 2 +- src/client/views/ScriptingRepl.tsx | 59 ++++++++------ .../views/collections/CollectionSchemaView.tsx | 92 ++++++++++++++++++++-- src/client/views/collections/CollectionView.tsx | 9 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 63 +++++++-------- src/client/views/nodes/DocumentView.tsx | 23 +++--- 7 files changed, 201 insertions(+), 97 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 46dc320b0..1d0916ac0 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -52,10 +52,10 @@ export namespace Scripting { } else { throw new Error("Must either register an object with a name, or give a name and an object"); } - if (scriptingGlobals.hasOwnProperty(n)) { + if (_scriptingGlobals.hasOwnProperty(n)) { throw new Error(`Global with name ${n} is already registered, choose another name`); } - scriptingGlobals[n] = obj; + _scriptingGlobals[n] = obj; } export function makeMutableGlobalsCopy(globals?: { [name: string]: any }) { @@ -188,6 +188,10 @@ class ScriptingCompilerHost { export type Traverser = (node: ts.Node, indentation: string) => boolean | void; export type TraverserParam = Traverser | { onEnter: Traverser, onLeave: Traverser }; +export type Transformer = { + transformer: ts.TransformerFactory, + getVars?: () => { capturedVariables: { [name: string]: Field } } +}; export interface ScriptOptions { requiredType?: string; addReturn?: boolean; @@ -196,7 +200,7 @@ export interface ScriptOptions { typecheck?: boolean; editable?: boolean; traverser?: TraverserParam; - transformer?: ts.TransformerFactory; + transformer?: Transformer; globals?: { [name: string]: any }; } @@ -213,6 +217,27 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp Scripting.setScriptingGlobals(options.globals); } let host = new ScriptingCompilerHost; + if (options.traverser) { + const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true); + const onEnter = typeof options.traverser === "object" ? options.traverser.onEnter : options.traverser; + const onLeave = typeof options.traverser === "object" ? options.traverser.onLeave : undefined; + forEachNode(sourceFile, onEnter, onLeave); + } + if (options.transformer) { + const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true); + const result = ts.transform(sourceFile, [options.transformer.transformer]); + if (options.transformer.getVars) { + const newCaptures = options.transformer.getVars(); + // tslint:disable-next-line: prefer-object-spread + options.capturedVariables = Object.assign(capturedVariables, newCaptures.capturedVariables) as any; + } + const transformed = result.transformed; + const printer = ts.createPrinter({ + newLine: ts.NewLineKind.LineFeed + }); + script = printer.printFile(transformed[0]); + result.dispose(); + } let paramNames: string[] = []; if ("this" in params || "this" in capturedVariables) { paramNames.push("this"); @@ -227,26 +252,11 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp }); for (const key in capturedVariables) { if (key === "this") continue; + const val = capturedVariables[key]; paramNames.push(key); - paramList.push(`${key}: ${capturedVariables[key].constructor.name}`); + paramList.push(`${key}: ${typeof val === "object" ? Object.getPrototypeOf(val).constructor.name : typeof val}`); } let paramString = paramList.join(", "); - if (options.traverser) { - const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true); - const onEnter = typeof options.traverser === "object" ? options.traverser.onEnter : options.traverser; - const onLeave = typeof options.traverser === "object" ? options.traverser.onLeave : undefined; - forEachNode(sourceFile, onEnter, onLeave); - } - if (options.transformer) { - const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true); - const result = ts.transform(sourceFile, [options.transformer]); - const transformed = result.transformed; - const printer = ts.createPrinter({ - newLine: ts.NewLineKind.LineFeed - }); - script = printer.printFile(transformed[0]); - result.dispose(); - } let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} { ${addReturn ? `return ${script};` : script} })`; diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss index 4d1e8cf0b..dc122497f 100644 --- a/src/client/views/OverlayView.scss +++ b/src/client/views/OverlayView.scss @@ -32,7 +32,7 @@ } .overlayWindow-resizeDragger { - background-color: red; + background-color: rgb(0, 0, 0); position: absolute; right: 0px; bottom: 0px; diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 6eabc7b70..52273c357 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import { observable, action } from 'mobx'; import './ScriptingRepl.scss'; -import { Scripting, CompileScript, ts } from '../util/Scripting'; +import { Scripting, CompileScript, ts, Transformer } from '../util/Scripting'; import { DocumentManager } from '../util/DocumentManager'; import { DocumentView } from './nodes/DocumentView'; import { OverlayView } from './OverlayView'; @@ -17,8 +17,11 @@ library.add(faCaretRight); export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> { render() { this.props.view.props.ScreenToLocalTransform(); - this.props.view.props.Document.width; - this.props.view.props.Document.height; + const doc = this.props.view.props.Document; + doc.width; + doc.height; + doc.x; + doc.y; const screenCoords = this.props.view.screenRect(); return ( @@ -26,7 +29,7 @@ export class DocumentIcon extends React.Component<{ view: DocumentView, index: n position: "absolute", transform: `translate(${screenCoords.left + screenCoords.width / 2}px, ${screenCoords.top}px)`, }}> -

${this.props.index}

+

${this.props.index}

); } @@ -106,31 +109,35 @@ export class ScriptingRepl extends React.Component { private args: any = {}; - getTransformer: ts.TransformerFactory = context => { - const knownVars: { [name: string]: number } = {}; - const usedDocuments: number[] = []; - Scripting.getGlobals().forEach(global => knownVars[global] = 1); - return root => { - function visit(node: ts.Node) { - node = ts.visitEachChild(node, visit, context); + getTransformer = (): Transformer => { + return { + transformer: context => { + const knownVars: { [name: string]: number } = {}; + const usedDocuments: number[] = []; + Scripting.getGlobals().forEach(global => knownVars[global] = 1); + return root => { + function visit(node: ts.Node) { + node = ts.visitEachChild(node, visit, context); - if (ts.isIdentifier(node)) { - const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; - const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; - if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) { - const match = node.text.match(/\$([0-9]+)/); - if (match) { - const m = parseInt(match[1]); - usedDocuments.push(m); - } else { - return ts.createPropertyAccess(ts.createIdentifier("args"), node); + if (ts.isIdentifier(node)) { + const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; + const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; + if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) { + const match = node.text.match(/\$([0-9]+)/); + if (match) { + const m = parseInt(match[1]); + usedDocuments.push(m); + } else { + return ts.createPropertyAccess(ts.createIdentifier("args"), node); + } + } } - } - } - return node; + return node; + } + return ts.visitNode(root, visit); + }; } - return ts.visitNode(root, visit); }; } @@ -142,7 +149,7 @@ export class ScriptingRepl extends React.Component { const docGlobals: { [name: string]: any } = {}; DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`$${i}`] = dv.props.Document); const globals = Scripting.makeMutableGlobalsCopy(docGlobals); - const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer, globals }); + const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer(), globals }); if (!script.compiled) { return; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index f72b1aa07..479fe2b0a 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -15,7 +15,7 @@ import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_field import { Docs } from "../../documents/Documents"; import { Gateway } from "../../northstar/manager/Gateway"; import { SetupDrag, DragManager } from "../../util/DragManager"; -import { CompileScript } from "../../util/Scripting"; +import { CompileScript, ts, Transformer } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; import { COLLECTION_BORDER_WIDTH, MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'; import { ContextMenu } from "../ContextMenu"; @@ -31,6 +31,7 @@ import { CollectionVideoView } from "./CollectionVideoView"; import { CollectionView } from "./CollectionView"; import { undoBatch } from "../../util/UndoManager"; import { timesSeries } from "async"; +import { ComputedField } from "../../../new_fields/ScriptField"; library.add(faCog); @@ -97,6 +98,78 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { return this.props.Document; } + getField(row: number, col?: number) { + const docs = DocListCast(this.props.Document[this.props.fieldKey]); + row = row % docs.length; + while (row < 0) row += docs.length; + const columns = this.columns; + const doc = docs[row]; + if (col === undefined) { + return doc; + } + if (col >= 0 && col < columns.length) { + const column = this.columns[col]; + return doc[column]; + } + return undefined; + } + + createTransformer = (row: number, col: number): Transformer => { + const self = this; + const captures: { [name: string]: Field } = {}; + + const transformer: ts.TransformerFactory = context => { + return root => { + function visit(node: ts.Node) { + node = ts.visitEachChild(node, visit, context); + if (ts.isIdentifier(node)) { + const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node; + const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node; + if (isntPropAccess && isntPropAssign) { + if (node.text === "$r") { + return ts.createNumericLiteral(row.toString()); + } else if (node.text === "$c") { + return ts.createNumericLiteral(col.toString()); + } else if (node.text === "$") { + if (ts.isCallExpression(node.parent)) { + captures.doc = self.props.Document; + captures.key = self.props.fieldKey; + } + } + } + } + + return node; + } + return ts.visitNode(root, visit); + }; + }; + + const getVars = () => { + return { capturedVariables: captures }; + }; + + return { transformer, getVars }; + } + + setComputed(script: string, doc: Doc, field: string, row: number, col: number): boolean { + script = + `const $ = (row:number, col?:number) => { + if(col === undefined) { + return (doc as any)[key][row + ${row}]; + } + return (doc as any)[key][row + ${row}][(doc as any).schemaColumns[col + ${col}]]; + } + return ${script}`; + const compiled = CompileScript(script, { params: { this: Doc.name }, typecheck: true, transformer: this.createTransformer(row, col) }); + if (compiled.compiled) { + doc[field] = new ComputedField(compiled); + return true; + } + + return false; + } + renderCell = (rowProps: CellInfo) => { let props: FieldViewProps = { Document: rowProps.original, @@ -122,12 +195,13 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { (!this.props.CollectionView.props.isSelected() ? undefined : SetupDrag(reference, () => props.Document, this.props.moveDocument, this.props.Document.schemaDoc ? "copy" : undefined)(e)); }; - let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => { - const res = run({ this: doc }); + let applyToDoc = (doc: Doc, row: number, column: number, run: (args?: { [name: string]: any }) => any) => { + const res = run({ this: doc, $r: row, $c: column, $: (r: number = 0, c: number = 0) => this.getField(r + row, c + column) }); if (!res.success) return false; doc[props.fieldKey] = res.result; return true; }; + const colIndex = this.columns.indexOf(rowProps.column.id!); return (
doc) { return ""; }} SetValue={(value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); + if (value.startsWith(":=")) { + return this.setComputed(value.substring(2), props.Document, rowProps.column.id!, rowProps.index, colIndex); + } + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); if (!script.compiled) { return false; } - return applyToDoc(props.Document, script.run); + return applyToDoc(props.Document, rowProps.index, colIndex, script.run); }} OnFillDown={async (value: string) => { - let script = CompileScript(value, { addReturn: true, params: { this: Doc.name } }); + let script = CompileScript(value, { addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); if (!script.compiled) { return; } const run = script.run; - //TODO This should be able to be refactored to compile the script once const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); - val && val.forEach(doc => applyToDoc(doc, run)); + val && val.forEach((doc, i) => applyToDoc(doc, i, colIndex, run)); }}>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 56750668d..ae99e930b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; +import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree, faFingerprint, faLaptopCode } from '@fortawesome/free-solid-svg-icons'; import { observer } from "mobx-react"; import * as React from 'react'; import { Doc } from '../../../new_fields/Doc'; @@ -24,6 +24,7 @@ library.add(faSquare); library.add(faProjectDiagram); library.add(faSignature); library.add(faThList); +library.add(faFingerprint); @observer export class CollectionView extends React.Component { @@ -55,6 +56,12 @@ export class CollectionView extends React.Component { subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" }); subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" }); subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" }); + switch (this.props.Document.viewType) { + case CollectionViewType.Freeform: { + subItems.push({ description: "Custom", icon: "fingerprint", event: CollectionFreeFormView.AddCustomLayout(this.props.Document, this.props.fieldKey) }); + break; + } + } ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 703873681..dd577a467 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -477,43 +477,44 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } }); - ContextMenu.Instance.addItem({ - description: "Add freeform arrangement", - event: () => { - let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record, requiredType?: string) => { - let overlayDisposer: () => void = emptyFunction; - const script = this.Document[key]; - let originalText: string | undefined = undefined; - if (script) originalText = script.script.originalScript; - // tslint:disable-next-line: no-unnecessary-callback-wrapper - let scriptingBox = overlayDisposer()} onSave={(text, onError) => { - const script = CompileScript(text, { - params, - requiredType, - typecheck: false - }); - if (!script.compiled) { - onError(script.errors.map(error => error.messageText).join("\n")); - return; - } - const docs = DocListCast(this.Document[this.props.fieldKey]); - docs.map(d => d.transition = "transform 1s"); - this.Document[key] = new ScriptField(script); - overlayDisposer(); - setTimeout(() => docs.map(d => d.transition = undefined), 1200); - }} />; - overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options); - }; - addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined); - addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); - } - }); } private childViews = () => [ , ...this.views ] + + public static AddCustomLayout(doc: Doc, dataKey: string): () => void { + return () => { + let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record, requiredType?: string) => { + let overlayDisposer: () => void = emptyFunction; + const script = Cast(doc[key], ScriptField); + let originalText: string | undefined = undefined; + if (script) originalText = script.script.originalScript; + // tslint:disable-next-line: no-unnecessary-callback-wrapper + let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + const script = CompileScript(text, { + params, + requiredType, + typecheck: false + }); + if (!script.compiled) { + onError(script.errors.map(error => error.messageText).join("\n")); + return; + } + const docs = DocListCast(doc[dataKey]); + docs.map(d => d.transition = "transform 1s"); + doc[key] = new ScriptField(script); + overlayDisposer(); + setTimeout(() => docs.map(d => d.transition = undefined), 1200); + }} />; + overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options); + }; + addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined); + addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}"); + }; + } + render() { const easing = () => this.props.Document.panTransformType === "Ease"; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1c03bfc81..7280dbcf6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -37,6 +37,7 @@ import { RouteStore } from '../../../server/RouteStore'; import { FormattedTextBox } from './FormattedTextBox'; import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; +import { ClientUtils } from '../../util/ClientUtils'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -58,6 +59,7 @@ library.add(fa.faCrosshairs); library.add(fa.faDesktop); library.add(fa.faUnlock); library.add(fa.faLock); +library.add(fa.faLaptopCode); // const linkSchema = createSchema({ @@ -551,17 +553,18 @@ export class DocumentView extends DocComponent(Docu this.props.removeDocument && this.props.removeDocument(this.props.Document); }, icon: "window-restore" }); - cm.addItem({ - description: "Find aliases", event: async () => { - const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? - }, icon: "search" - }); - cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); - cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); + // cm.addItem({ + // description: "Find aliases", event: async () => { + // const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); + // this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? + // }, icon: "search" + // }); + cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + if (!ClientUtils.RELEASE) { + cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); + cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + } cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; let usersMenu: ContextMenuProps[] = []; -- cgit v1.2.3-70-g09d2 From 3b740e1c1ac74e7aac45c136ec9df1b37e2dbc16 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Tue, 23 Jul 2019 16:32:43 -0400 Subject: pretty ui for changing section fitler and added base for colletion chromes --- src/client/views/EditableView.scss | 10 +- src/client/views/EditableView.tsx | 30 +++- .../views/collections/CollectionBaseView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 34 ++++- .../views/collections/CollectionViewChromes.scss | 54 ++++++++ .../views/collections/CollectionViewChromes.tsx | 152 +++++++++++++++++++++ 6 files changed, 268 insertions(+), 14 deletions(-) create mode 100644 src/client/views/collections/CollectionViewChromes.scss create mode 100644 src/client/views/collections/CollectionViewChromes.tsx (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss index a5150cd66..19512362e 100644 --- a/src/client/views/EditableView.scss +++ b/src/client/views/EditableView.scss @@ -1,20 +1,24 @@ -.editableView-container-editing, .editableView-container-editing-oneLine { +.editableView-container-editing, +.editableView-container-editing-oneLine { overflow-wrap: break-word; word-wrap: break-word; hyphens: auto; overflow: hidden; } + .editableView-container-editing-oneLine { span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - display:block; + display: block; } + input { - display:block; + display: block; } } + .editableView-input { width: 100%; background: inherit; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index f2cdffd38..a5bb40243 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -2,6 +2,7 @@ import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, trace } from 'mobx'; import "./EditableView.scss"; +import * as Autosuggest from 'react-autosuggest'; export interface EditableProps { /** @@ -28,6 +29,13 @@ export interface EditableProps { fontSize?: number; height?: number; display?: string; + autosuggestProps?: { + resetValue: () => void; + value: string, + onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void, + autosuggestProps: Autosuggest.AutosuggestProps + + }; oneLine?: boolean; editing?: boolean; onClick?: (e: React.MouseEvent) => boolean; @@ -85,10 +93,26 @@ export class EditableView extends React.Component { render() { if (this._editing) { - return this._editing = false)} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} - style={{ display: this.props.display, fontSize: this.props.fontSize }} />; + return this.props.autosuggestProps + ? this._editing = false), + onPointerDown: this.stopPropagation, + onClick: this.stopPropagation, + onPointerUp: this.stopPropagation, + value: this.props.autosuggestProps.value, + onChange: this.props.autosuggestProps.onChange + }} + /> + : this._editing = false)} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} + style={{ display: this.props.display, fontSize: this.props.fontSize }} />; } else { + if (this.props.autosuggestProps) this.props.autosuggestProps.resetValue(); return (
void; - children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null; + children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null | (JSX.Element | null)[]; className?: string; contentRef?: React.Ref; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 045c8531e..ba9780c24 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,6 +17,7 @@ import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; +import { CollectionStackingViewChrome } from './CollectionViewChromes'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -33,21 +34,40 @@ library.add(faImage); export class CollectionView extends React.Component { public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); } - private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { + private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { - case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); - case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } - case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: - return (); + return (); } return (null); } + private Chrome = (type: CollectionViewType) => { + if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { + return (null); + } + + switch (type) { + case CollectionViewType.Stacking: return (); + default: + return null; + } + } + + private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { + return [ + this.Chrome(type), + this.SubViewHelper(type, renderProps) + ] + } + get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } static _applyCount: number = 0; diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss new file mode 100644 index 000000000..e5cb1b546 --- /dev/null +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -0,0 +1,54 @@ +@import "../globalCssVariables"; + +.collectionStackingViewChrome { + display: grid; + grid-template-columns: 1fr 1fr; + padding-bottom: 10px; + border-bottom: .5px solid lightgrey; + margin: 10px; + + .collectionStackingViewChrome-sectionFilter-cont { + justify-self: right; + display: flex; + font-size: 75%; + text-transform: uppercase; + letter-spacing: 2px; + + .collectionStackingViewChrome-sectionFilter-label { + vertical-align: center; + padding: 10px; + } + + .collectionStackingViewChrome-sectionFilter { + color: white; + width: fit-content; + text-align: center; + background: rgb(238, 238, 238); + height: 37px; + + .editable-view-input, + input, + .editableView-container-editing-oneLine, + .editableView-container-editing { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + height: 100%; + } + + .react-autosuggest__container { + margin: 0; + color: grey; + padding: 0px; + } + } + } + + .collectionStackingViewChrome-sectionFilter:hover { + cursor: text; + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx new file mode 100644 index 000000000..ca1480ff2 --- /dev/null +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -0,0 +1,152 @@ +import * as React from "react"; +import { CollectionView } from "./CollectionView"; +import "./CollectionViewChromes.scss"; +import { CollectionViewType } from "./CollectionBaseView"; +import { undoBatch } from "../../util/UndoManager"; +import { action, observable, runInAction, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { DocLike } from "../MetadataEntryMenu"; +const higflyout = require("@hig/flyout"); +export const Flyout = higflyout.default; +import * as Autosuggest from 'react-autosuggest'; +import { EditableView } from "../EditableView"; +import { StrCast } from "../../../new_fields/Types"; + +interface CollectionViewChromeProps { + CollectionView: CollectionView; +} + +class CollectionViewBaseChrome extends React.Component { + @undoBatch + viewChanged = (e: React.ChangeEvent) => { + //@ts-ignore + switch (e.target.selectedOptions[0].value) { + case "freeform": + this.props.CollectionView.props.Document.viewType = CollectionViewType.Freeform; + break; + case "schema": + this.props.CollectionView.props.Document.viewType = CollectionViewType.Schema; + break; + case "treeview": + this.props.CollectionView.props.Document.viewType = CollectionViewType.Tree; + break; + case "stacking": + this.props.CollectionView.props.Document.viewType = CollectionViewType.Stacking; + break; + case "masonry": + this.props.CollectionView.props.Document.viewType = CollectionViewType.Masonry; + break; + default: + break; + } + } + + render() { + return ( +
+ +
+ ) + } +} + +@observer +export class CollectionStackingViewChrome extends React.Component { + @observable private _currentKey: string = ""; + @observable private suggestions: string[] = []; + + @computed get sectionFilter() { return StrCast(this.props.CollectionView.props.Document.sectionFilter); } + + getKeySuggestions = async (value: string): Promise => { + value = value.toLowerCase(); + let docs: Doc | Doc[] | Promise | Promise | (() => DocLike) + = () => DocListCast(this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldExt ? this.props.CollectionView.props.fieldExt : this.props.CollectionView.props.fieldKey]); + if (typeof docs === "function") { + docs = docs(); + } + docs = await docs; + if (docs instanceof Doc) { + return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value)); + } else { + const keys = new Set(); + docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); + return Array.from(keys).filter(key => key.toLowerCase().startsWith(value)); + } + } + + @action + onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => { + this._currentKey = newValue; + } + + getSuggestionValue = (suggestion: string) => suggestion; + + renderSuggestion = (suggestion: string) => { + return

{suggestion}

; + } + + onSuggestionFetch = async ({ value }: { value: string }) => { + const sugg = await this.getKeySuggestions(value); + runInAction(() => { + this.suggestions = sugg; + }); + } + + @action + onSuggestionClear = () => { + this.suggestions = []; + } + + setValue = (value: string) => { + this.props.CollectionView.props.Document.sectionFilter = value; + return true; + } + + @action resetValue = () => { this._currentKey = this.sectionFilter; } + + render() { + return ( +
+ +
+
+ Group items by: +
+
+ this.sectionFilter} + autosuggestProps={ + { + resetValue: this.resetValue, + value: this._currentKey, + onChange: this.onKeyChange, + autosuggestProps: { + inputProps: + { + value: this._currentKey, + onChange: this.onKeyChange + }, + getSuggestionValue: this.getSuggestionValue, + suggestions: this.suggestions, + alwaysRenderSuggestions: true, + renderSuggestion: this.renderSuggestion, + onSuggestionsFetchRequested: this.onSuggestionFetch, + onSuggestionsClearRequested: this.onSuggestionClear + } + }} + SetValue={this.setValue} + contents={this.sectionFilter ? this.sectionFilter : "N/A"} + /> +
+
+
+ ) + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 86971952237b8bd01a23b52db662740126bd8477 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 23 Jul 2019 18:00:52 -0400 Subject: some fixes for fitToBox, templates, and showTitle --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/EditableView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 76 +++++++++++++--------- src/client/views/collections/CollectionView.tsx | 15 +---- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +-- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 17 ++--- src/new_fields/Doc.ts | 26 ++++++-- 9 files changed, 87 insertions(+), 67 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2f7bea365..989b35581 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -525,8 +525,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); - let proto = Doc.GetProto(element.props.Document); - let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight); + let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... + let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect) && nwidth && nheight); if (fixedAspect && (!nwidth || !nheight)) { proto.nativeWidth = nwidth = doc.width || 0; proto.nativeHeight = nheight = doc.height || 0; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index f2cdffd38..c66a92f48 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -93,7 +93,7 @@ export class EditableView extends React.Component {
- {this.props.contents} + {this.props.contents}
); } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0e5f9a321..54b0e37b5 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, Utils } from "../../../Utils"; +import { emptyFunction, Utils, returnTrue } from "../../../Utils"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; @@ -74,6 +74,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { DataDocument={resolvedDataDoc} showOverlays={this.overlays} renderDepth={this.props.renderDepth} + fitToBox={true} width={width} height={height} getTransform={finalDxf} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d05cc375e..f98629c5b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -74,15 +74,15 @@ class TreeView extends React.Component { @observable _collapsed: boolean = true; @computed get fieldKey() { - let keys = Array.from(Object.keys(this.resolvedDataDoc)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set - if (this.resolvedDataDoc.proto instanceof Doc) { - let arr = Array.from(Object.keys(this.resolvedDataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + let keys = Array.from(Object.keys(this.dataDoc)); // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set + if (this.dataDoc.proto instanceof Doc) { + let arr = Array.from(Object.keys(this.dataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set keys.push(...arr); while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } let keyList: string[] = []; keys.map(key => { - let docList = Cast(this.resolvedDataDoc[key], listSpec(Doc)); + let docList = Cast(this.dataDoc[key], listSpec(Doc)); if (docList && docList.length > 0) { keyList.push(key); } @@ -94,7 +94,16 @@ class TreeView extends React.Component { return keyList.length ? keyList[0] : "data"; } - @computed get resolvedDataDoc() { return BoolCast(this.props.document.isTemplate) && this.props.dataDoc ? this.props.dataDoc : this.props.document; } + @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; } + @computed get resolvedDataDoc() { + if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) { + // if there is no dataDoc (ie, we're not rendering a template layout), but this document + // has a template layout document, then we will render the template layout but use + // this document as the data document for the layout. + return this.props.document; + } + return this.props.dataDoc ? this.props.dataDoc : undefined; + } protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); @@ -103,7 +112,7 @@ class TreeView extends React.Component { } } - @undoBatch delete = () => this.props.deleteDoc(this.resolvedDataDoc); + @undoBatch delete = () => this.props.deleteDoc(this.dataDoc); @undoBatch openRight = async () => this.props.addDocTab(this.props.document, undefined, "onRight"); onPointerDown = (e: React.PointerEvent) => e.stopPropagation(); @@ -135,7 +144,7 @@ class TreeView extends React.Component { @action remove = (document: Document, key: string): boolean => { - let children = Cast(this.resolvedDataDoc[key], listSpec(Doc), []); + let children = Cast(this.dataDoc[key], listSpec(Doc), []); if (children.indexOf(document) !== -1) { children.splice(children.indexOf(document), 1); return true; @@ -151,8 +160,8 @@ class TreeView extends React.Component { indent = () => this.props.addDocument(this.props.document) && this.delete() renderBullet() { - let docList = Cast(this.resolvedDataDoc[this.fieldKey], listSpec(Doc)); - let doc = Cast(this.resolvedDataDoc[this.fieldKey], Doc); + let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc)); + let doc = Cast(this.dataDoc[this.fieldKey], Doc); let isDoc = doc instanceof Doc || docList; let c; return
this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}> @@ -164,16 +173,17 @@ class TreeView extends React.Component { editableView = (key: string, style?: string) => ( StrCast(this.props.document[key])} - SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc)[key] = value) ? true : true} + SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true} OnFillDown={(value: string) => { - Doc.GetProto(this.resolvedDataDoc)[key] = value; - let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + Doc.GetProto(this.dataDoc)[key] = value; + let doc = this.props.document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.detailedLayout)) : undefined; + if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; return this.props.addDocument(doc); }} @@ -181,16 +191,16 @@ class TreeView extends React.Component { />) @computed get keyList() { - let keys = Array.from(Object.keys(this.resolvedDataDoc)); - if (this.resolvedDataDoc.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto))); + let keys = Array.from(Object.keys(this.dataDoc)); + if (this.dataDoc.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(this.dataDoc.proto))); } let keyList: string[] = keys.reduce((l, key) => { - let listspec = DocListCast(this.resolvedDataDoc[key]); + let listspec = DocListCast(this.dataDoc[key]); if (listspec && listspec.length) return [...l, key]; return l; }, [] as string[]); - keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key)); + keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && (Cast(this.dataDoc[key], Doc) as Doc).type !== undefined && keyList.push(key)); if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links"); if (keyList.indexOf(this.fieldKey) !== -1) { keyList.splice(keyList.indexOf(this.fieldKey), 1); @@ -203,7 +213,7 @@ class TreeView extends React.Component { */ renderTitle() { let reference = React.createRef(); - let onItemDown = SetupDrag(reference, () => this.resolvedDataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); + let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); let headerElements = ( { {this._chosenKey} ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : []; - let openRight = dataDocs && dataDocs.indexOf(this.resolvedDataDoc) !== -1 ? (null) : ( + let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
); @@ -241,12 +251,12 @@ class TreeView extends React.Component { if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" }); - if (DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).length) { - ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" }); + if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) { + ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.dataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" }); } ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)), icon: "trash-alt" }); } else { - ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.resolvedDataDoc)), icon: "caret-square-right" }); + ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.dataDoc)), icon: "caret-square-right" }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.props.document)), icon: "trash-alt" }); } ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.Create.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" }); @@ -274,7 +284,7 @@ class TreeView extends React.Component { if (de.data.draggedDocuments[0] === this.props.document) return true; let addDoc = (doc: Doc) => this.props.addDocument(doc, this.resolvedDataDoc, before); if (inside) { - let docList = Cast(this.resolvedDataDoc.data, listSpec(Doc)); + let docList = Cast(this.dataDoc.data, listSpec(Doc)); if (docList !== undefined) { addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }; } @@ -326,7 +336,7 @@ class TreeView extends React.Component { @computed get boundsOfCollectionDocument() { if (StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1) return undefined; - let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + let layoutDoc = this.props.document; return Doc.ComputeContentBounds(DocListCast(layoutDoc.data)); } docWidth = () => { @@ -344,27 +354,30 @@ class TreeView extends React.Component { })()); } + noOverlays = (doc: Doc) => { return { title: "", caption: "" } }; + render() { let contentElement: (JSX.Element | null) = null; - let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc)); + let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); - let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.resolvedDataDoc, this._chosenKey, doc, addBefore, before); - let doc = Cast(this.resolvedDataDoc[this._chosenKey], Doc); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before); + let doc = Cast(this.dataDoc[this._chosenKey], Doc); if (!this._collapsed) { if (!this.props.document.embed) { contentElement =
    {this._chosenKey === "links" ? this.renderLinks() : - TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.props.dataDoc, this._chosenKey, addDoc, remDoc, this.move, + TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this._chosenKey, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
; } else { - let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + let layoutDoc = this.props.document; contentElement =
(Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true} OnFillDown={(value: string) => { Doc.GetProto(this.props.Document).title = value; - let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); + let doc = this.props.Document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.detailedLayout)) : undefined; + if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true); }} /> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 045c8531e..4a51a1f58 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -50,7 +50,6 @@ export class CollectionView extends React.Component { get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } - static _applyCount: number = 0; onContextMenu = (e: React.MouseEvent): void => { if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 let subItems: ContextMenuProps[] = []; @@ -63,19 +62,7 @@ export class CollectionView extends React.Component { subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" }); subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" }); ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); - ContextMenu.Instance.addItem({ - description: "Apply Template", event: undoBatch(() => { - let otherdoc = new Doc(); - otherdoc.width = this.props.Document[WidthSym](); - otherdoc.height = this.props.Document[HeightSym](); - otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied" - otherdoc.layout = Doc.MakeDelegate(this.props.Document); - otherdoc.miniLayout = StrCast(this.props.Document.miniLayout); - otherdoc.detailedLayout = otherdoc.layout; - otherdoc.type = DocumentType.TEMPLATE; - this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight"); - }), icon: "project-diagram" - }); + ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 703873681..6bb082b66 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -195,10 +195,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._pheight / this.zoomScaling()); let panelwidth = panelDim[0]; let panelheight = panelDim[1]; - if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2; - if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2; - if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2; - if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2; + // if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2; + // if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2; + // if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2; + // if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2; } this.setPan(x - dx, y - dy); this._lastX = e.pageX; @@ -358,6 +358,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps { let self = this; let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined; + resolvedDataDoc && Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey); let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc); return { DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined, diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index ed6b224a7..ef65c12cf 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -64,7 +64,7 @@ export class DocumentContentsView extends React.Component(Docu @undoBatch @action freezeNativeDimensions = (): void => { - let proto = Doc.GetProto(this.props.Document); + let proto = this.props.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document); if (proto.ignoreAspect === undefined && !proto.nativeWidth) { proto.nativeWidth = this.props.PanelWidth(); proto.nativeHeight = this.props.PanelHeight(); @@ -629,10 +629,10 @@ export class DocumentView extends DocComponent(Docu var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.props.Document) : undefined; - let showTitle = showOverlays && showOverlays.title ? showOverlays.title : StrCast(this.props.Document.showTitle); - let showCaption = showOverlays && showOverlays.caption ? showOverlays.caption : StrCast(this.props.Document.showCaption); + let showTitle = showOverlays && showOverlays.title !== "undefined" ? showOverlays.title : StrCast(this.props.Document.showTitle); + let showCaption = showOverlays && showOverlays.caption !== "undefined" ? showOverlays.caption : StrCast(this.props.Document.showCaption); let templates = Cast(this.props.Document.templates, listSpec("string")); - if (templates instanceof List) { + if (!showOverlays && templates instanceof List) { templates.map(str => { if (str.indexOf("{props.Document.title}") !== -1) showTitle = "title"; if (str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption"; @@ -663,12 +663,12 @@ export class DocumentView extends DocComponent(Docu {!showTitle && !showCaption ? this.contents :
-
+
{this.contents}
{!showTitle ? (null) :
(Docu contents={this.props.Document[showTitle]} display={"block"} height={72} - GetValue={() => StrCast(this.props.Document[showTitle])} - SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle] = value) ? true : true} + fontSize={12} + GetValue={() => StrCast(this.props.Document[showTitle!])} + SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle!] = value) ? true : true} />
} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2ad6ae5f0..5ae0753d8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -244,7 +244,7 @@ export namespace Doc { let r = (doc === other); let r2 = (doc.proto === other); let r3 = (other.proto === doc); - let r4 = (doc.proto === other.proto); + let r4 = (doc.proto === other.proto && other.proto !== undefined); return r || r2 || r3 || r4; } @@ -298,7 +298,7 @@ export namespace Doc { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) }; - }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); + }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE }); return bounds; } @@ -350,19 +350,21 @@ export namespace Doc { if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; } + expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]]; + if (expandedTemplateLayout instanceof Doc) { + return expandedTemplateLayout; + } if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) { setTimeout(() => { let expandedDoc = Doc.MakeDelegate(templateLayoutDoc); expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]"; expandedDoc.isExpandedTemplate = templateLayoutDoc; - dataDoc[templateLayoutDoc[Id]] = expandedDoc; + dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]] = expandedDoc; }, 0); } return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending. } - let _pendingExpansions: Map = new Map(); - export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { @@ -398,6 +400,20 @@ export namespace Doc { return undefined; } + let _applyCount: number = 0; + export function ApplyTemplate(templateDoc: Doc) { + if (!templateDoc) return undefined; + let otherdoc = new Doc(); + otherdoc.width = templateDoc[WidthSym](); + otherdoc.height = templateDoc[HeightSym](); + otherdoc.title = templateDoc.title + "(..." + _applyCount++ + ")"; + otherdoc.layout = Doc.MakeDelegate(templateDoc); + otherdoc.miniLayout = StrCast(templateDoc.miniLayout); + otherdoc.detailedLayout = otherdoc.layout; + otherdoc.type = DocumentType.TEMPLATE; + return otherdoc; + } + export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); -- cgit v1.2.3-70-g09d2 From ede0719d96cc2551490398caf3e1f41fe7992931 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Wed, 24 Jul 2019 22:27:37 -0400 Subject: view specs almost entirely done, refactored some chrome impl --- .../views/collections/CollectionStackingView.scss | 1 + .../views/collections/CollectionStackingView.tsx | 6 +- src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/collections/CollectionView.tsx | 42 ++-- .../views/collections/CollectionViewChromes.scss | 156 +++++++-------- .../views/collections/CollectionViewChromes.tsx | 214 ++++++++++++--------- 6 files changed, 227 insertions(+), 193 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index e0ced8af4..f43340967 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -7,6 +7,7 @@ display: flex; overflow-y: auto; flex-wrap: wrap; + transition: top .5s; .collectionStackingView-docView-container { width: 45%; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a78a47ffb..31ec80d76 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -8,7 +8,7 @@ import { BoolCast, NumCast, Cast, StrCast, FieldValue } from "../../../new_field import { emptyFunction, Utils } from "../../../Utils"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; -import { CollectionSubView } from "./CollectionSubView"; +import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView"; import { undoBatch } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; @@ -19,6 +19,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; import { List } from "../../../new_fields/List"; import { EditableView } from "../EditableView"; +import { CollectionViewProps } from "./CollectionBaseView"; let valuesCreated = 1; @@ -32,6 +33,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } + get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @@ -265,7 +267,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return ( -
e.stopPropagation()} > {/* {sectionFilter as boolean ? [ ["width > height", this.filteredChildren.filter(f => f[WidthSym]() >= 1 + f[HeightSym]())], diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 24c8adb35..98447e824 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -30,6 +30,7 @@ export interface CollectionViewProps extends FieldViewProps { moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; PanelWidth: () => number; PanelHeight: () => number; + chromeCollapsed: boolean; } export interface SubCollectionViewProps extends CollectionViewProps { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ba9780c24..e2f652908 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,7 +17,8 @@ import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; -import { CollectionStackingViewChrome } from './CollectionViewChromes'; +import { CollectionStackingViewChrome, CollectionViewBaseChrome } from './CollectionViewChromes'; +import { observable } from 'mobx'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -32,40 +33,39 @@ library.add(faImage); @observer export class CollectionView extends React.Component { + @observable private _collapsed = false; + public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { - case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); - case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } - case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } case CollectionViewType.Freeform: default: - return (); + return (); } return (null); } - private Chrome = (type: CollectionViewType) => { - if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { - return (null); - } - - switch (type) { - case CollectionViewType.Stacking: return (); - default: - return null; - } + private collapse = (value: boolean) => { + this._collapsed = value; } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - return [ - this.Chrome(type), - this.SubViewHelper(type, renderProps) - ] + if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { + return [(null), this.SubViewHelper(type, renderProps)]; + } + else { + return [ + (), + this.SubViewHelper(type, renderProps) + ]; + } } get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 3103cd309..d37228bde 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -1,98 +1,104 @@ @import "../globalCssVariables"; @import '~js-datepicker/dist/datepicker.min.css'; -.collectionViewBaseChrome { - display: flex; - - .collectionViewBaseChrome-viewPicker { - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - background: rgb(238, 238, 238); - color: grey; - outline-color: black; - border: none; - padding: 12px 10px 11px 10px; - } - - .collectionViewBaseChrome-viewPicker:active { - outline-color: black; - } - - .collectionViewBaseChrome-collapse { - margin-right: 10px; - transition: all .5s; - } +.collectionViewChrome { + display: grid; + grid-template-columns: 1fr auto; + padding-bottom: 10px; + border-bottom: .5px solid lightgrey; + margin: 10px; + position: relative; + z-index: 9001; + transition: top .5s; - .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; - display: grid; + .collectionViewBaseChrome { + display: flex; - .collectionViewBaseChrome-viewSpecsInput { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - text-align: center; + .collectionViewBaseChrome-viewPicker { + font-size: 75%; text-transform: uppercase; letter-spacing: 2px; - outline-color: black; - font-size: 75%; background: rgb(238, 238, 238); - height: 100%; - width: 150px; + color: grey; + outline-color: black; + border: none; + padding: 12px 10px 11px 10px; + margin-left: 50px; } - .collectionViewBaseChrome-viewSpecsMenu { - overflow: hidden; - transition: height .5s, display .5s; + .collectionViewBaseChrome-viewPicker:active { + outline-color: black; + } + + .collectionViewBaseChrome-collapse { + transition: all .5s; position: absolute; - top: 60px; - z-index: 100; - display: flex; - flex-direction: column; - background: rgb(238, 238, 238); - box-shadow: grey 2px 2px 4px; + width: 40px; + } + + .collectionViewBaseChrome-viewSpecs { + margin-left: 10px; + display: grid; - .qs-datepicker { - left: unset; - right: 0; + .collectionViewBaseChrome-viewSpecsInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + font-size: 75%; + background: rgb(238, 238, 238); + height: 100%; + width: 150px; } - .collectionViewBaseChrome-viewSpecsMenu-row { - display: grid; - grid-template-columns: 150px 200px 150px; - margin-top: 10px; - margin-right: 10px; - - .collectionViewBaseChrome-viewSpecsMenu-rowLeft, - .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, - .collectionViewBaseChrome-viewSpecsMenu-rowRight { - font-size: 75%; - letter-spacing: 2px; - color: grey; - margin-left: 10px; - padding: 5px; - border: none; - outline-color: black; + .collectionViewBaseChrome-viewSpecsMenu { + overflow: hidden; + transition: height .5s, display .5s; + position: absolute; + top: 60px; + z-index: 100; + display: flex; + flex-direction: column; + background: rgb(238, 238, 238); + box-shadow: grey 2px 2px 4px; + + .qs-datepicker { + left: unset; + right: 0; + } + + .collectionViewBaseChrome-viewSpecsMenu-row { + display: grid; + grid-template-columns: 150px 200px 150px; + margin-top: 10px; + margin-right: 10px; + + .collectionViewBaseChrome-viewSpecsMenu-rowLeft, + .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, + .collectionViewBaseChrome-viewSpecsMenu-rowRight { + font-size: 75%; + letter-spacing: 2px; + color: grey; + margin-left: 10px; + padding: 5px; + border: none; + outline-color: black; + } } - } - .collectionViewBaseChrome-viewSpecsMenu-lastRow { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 10px; - margin: 10px; + .collectionViewBaseChrome-viewSpecsMenu-lastRow { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + margin: 10px; + } } } } -} -.collectionStackingViewChrome { - display: grid; - grid-template-columns: 1fr auto; - padding-bottom: 10px; - border-bottom: .5px solid lightgrey; - margin: 10px; .collectionStackingViewChrome-cont { display: flex; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 2edac384d..24d13d5cb 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -19,16 +19,19 @@ const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { CollectionView: CollectionView; + type: CollectionViewType; + collapse?: (value: boolean) => any; } let stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation(); @observer -class CollectionViewBaseChrome extends React.Component { +export class CollectionViewBaseChrome extends React.Component { @observable private _viewSpecsOpen: boolean = false; @observable private _dateWithinValue: string = ""; @observable private _dateValue: Date = new Date(); @observable private _keyRestrictions: [JSX.Element, string][] = []; + @observable private _collapsed: boolean = false; @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); } private _picker: any; @@ -124,68 +127,92 @@ class CollectionViewBaseChrome extends React.Component { + this._collapsed = !this._collapsed; + this.props.collapse(this._collapsed); + } + + subChrome = () => { + + switch (this.props.type) { + case CollectionViewType.Stacking: return ( + ); + default: + return null; + } + } + render() { return ( -
- - -
- -
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: +
+
+ + +
+ +
+ {this._keyRestrictions.map(i => i[0])} +
+
+ CREATED WITHIN:
- - -
-
-
+
+ - +
+ {this.subChrome()}
) } @@ -249,48 +276,45 @@ export class CollectionStackingViewChrome extends React.Component - -
- -
-
- Group items by: -
-
- this.sectionFilter} - autosuggestProps={ - { - resetValue: this.resetValue, - value: this._currentKey, - onChange: this.onKeyChange, - autosuggestProps: { - inputProps: - { - value: this._currentKey, - onChange: this.onKeyChange - }, - getSuggestionValue: this.getSuggestionValue, - suggestions: this.suggestions, - alwaysRenderSuggestions: true, - renderSuggestion: this.renderSuggestion, - onSuggestionsFetchRequested: this.onSuggestionFetch, - onSuggestionsClearRequested: this.onSuggestionClear - } - }} - oneLine - SetValue={this.setValue} - contents={this.sectionFilter ? this.sectionFilter : "N/A"} - /> +
+ +
+ +
+
+ Group items by:
+
+ this.sectionFilter} + autosuggestProps={ + { + resetValue: this.resetValue, + value: this._currentKey, + onChange: this.onKeyChange, + autosuggestProps: { + inputProps: + { + value: this._currentKey, + onChange: this.onKeyChange + }, + getSuggestionValue: this.getSuggestionValue, + suggestions: this.suggestions, + alwaysRenderSuggestions: true, + renderSuggestion: this.renderSuggestion, + onSuggestionsFetchRequested: this.onSuggestionFetch, + onSuggestionsClearRequested: this.onSuggestionClear + } + }} + oneLine + SetValue={this.setValue} + contents={this.sectionFilter ? this.sectionFilter : "N/A"} + />
-- cgit v1.2.3-70-g09d2 From db560a8c43f77b9342e55a48dd96f695813b32ef Mon Sep 17 00:00:00 2001 From: yipstanley Date: Thu, 25 Jul 2019 12:53:09 -0400 Subject: oof a lot of stuff here --- .../views/collections/CollectionSchemaView.scss | 1 + .../views/collections/CollectionSchemaView.tsx | 2 + .../views/collections/CollectionStackingView.tsx | 5 +- .../views/collections/CollectionTreeView.scss | 27 ++- .../views/collections/CollectionTreeView.tsx | 2 + src/client/views/collections/CollectionView.tsx | 18 +- .../views/collections/CollectionViewChromes.scss | 258 +++++++++++---------- .../views/collections/CollectionViewChromes.tsx | 137 ++++++----- .../authentication/models/current_user_utils.ts | 4 + 9 files changed, 251 insertions(+), 203 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 186e006f3..1e6d1fe99 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -12,6 +12,7 @@ width: 100%; height: 100%; overflow: hidden; + transition: top 0.5s; .collectionSchemaView-cellContents { height: $MAX_ROW_HEIGHT; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2cf50e551..bdcedea10 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -69,6 +69,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { @observable _newKeyName: string = ""; @observable previewScript: string = ""; + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get previewWidth() { return () => NumCast(this.props.Document.schemaPreviewWidth); } @computed get previewHeight() { return () => this.props.PanelHeight() - 2 * this.borderWidth; } @computed get tableWidth() { return this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH - this.previewWidth(); } @@ -390,6 +391,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { render() { return (
this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}> {this.reactTable} {this.dividerDragger} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 31ec80d76..b5c0fb3d6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -21,8 +21,6 @@ import { List } from "../../../new_fields/List"; import { EditableView } from "../EditableView"; import { CollectionViewProps } from "./CollectionBaseView"; -let valuesCreated = 1; - @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { _masonryGridRef: HTMLDivElement | null = null; @@ -33,7 +31,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { _columnStart: number = 0; @observable private cursor: CursorProperty = "grab"; get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } - get chromeCollapsed() { return this.props.chromeCollapsed; } + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); } @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); } @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @@ -84,7 +82,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { () => StrCast(this.props.Document.sectionFilter), () => { this.props.Document.sectionHeaders = new List(); - valuesCreated = 1; } ) } diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index 5205f4313..db3652ff6 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -31,6 +31,7 @@ margin-top: 4px; transform: scale(1.3, 1.3); } + .editableView-container { font-weight: bold; } @@ -43,18 +44,20 @@ display: inline; } - .editableView-input, .editableView-container-editing { + .editableView-input, + .editableView-container-editing { display: block; text-overflow: ellipsis; font-size: 24px; white-space: nowrap; } } + .collectionTreeView-keyHeader { font-style: italic; font-size: 8pt; margin-left: 3px; - display:none; + display: none; background: lightgray; } @@ -72,28 +75,31 @@ // width:100%;//width: max-content; } + .treeViewItem-openRight { display: none; } .treeViewItem-border { - display:inherit; + display: inherit; border-left: dashed 1px #00000042; } .treeViewItem-header:hover { .collectionTreeView-keyHeader { - display:inherit; + display: inherit; } + .treeViewItem-openRight { display: inline-block; - height:13px; - margin-top:2px; + height: 13px; + margin-top: 2px; margin-left: 5px; + // display: inline; svg { - display:block; - padding:0px; + display: block; + padding: 0px; margin: 0px; } } @@ -101,14 +107,17 @@ .treeViewItem-header { border: transparent 1px solid; - display:flex; + display: flex; } + .treeViewItem-header-above { border-top: black 1px solid; } + .treeViewItem-header-below { border-bottom: black 1px solid; } + .treeViewItem-header-inside { border: black 1px solid; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d05cc375e..cbf32c667 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -456,6 +456,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; + @computed get chromeCollapsed() { return this.props.chromeCollapsed; } + protected createTreeDropTarget = (ele: HTMLDivElement) => { this.treedropDisposer && this.treedropDisposer(); if (this._mainEle = ele) { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e2f652908..1c6dd661d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -18,7 +18,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; import { CollectionStackingViewChrome, CollectionViewBaseChrome } from './CollectionViewChromes'; -import { observable } from 'mobx'; +import { observable, action, runInAction } from 'mobx'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -37,11 +37,20 @@ export class CollectionView extends React.Component { public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); } + componentDidMount = () => { + // chrome status is one of disabled, collapsed, or visible. this determines initial state from document + let chromeStatus = this.props.Document.chromeStatus; + if (chromeStatus && (chromeStatus === "disabled" || chromeStatus === "collapsed")) { + runInAction(() => this._collapsed = true); + } + } + private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); + // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip + case CollectionViewType.Docking: return (); case CollectionViewType.Tree: return (); case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } @@ -52,12 +61,15 @@ export class CollectionView extends React.Component { return (null); } + @action private collapse = (value: boolean) => { this._collapsed = value; + this.props.Document.chromeStatus = value ? "collapsed" : "visible"; } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - if (this.isAnnotationOverlay || this.props.Document === CurrentUserUtils.UserDocument.sidebar) { + // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip + if (this.isAnnotationOverlay || this.props.Document.chromeStatus === "disabled" || type === CollectionViewType.Docking) { return [(null), this.SubViewHelper(type, renderProps)]; } else { diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index d37228bde..0faca0607 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -1,167 +1,171 @@ @import "../globalCssVariables"; @import '~js-datepicker/dist/datepicker.min.css'; -.collectionViewChrome { - display: grid; - grid-template-columns: 1fr auto; - padding-bottom: 10px; - border-bottom: .5px solid lightgrey; - margin: 10px; +.collectionViewChrome-cont { position: relative; z-index: 9001; transition: top .5s; + background: rgb(238, 238, 238); + padding: 10px; - .collectionViewBaseChrome { - display: flex; + .collectionViewChrome { + display: grid; + grid-template-columns: 1fr auto; + padding-bottom: 10px; + border-bottom: .5px solid lightgrey; - .collectionViewBaseChrome-viewPicker { - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - background: rgb(238, 238, 238); - color: grey; - outline-color: black; - border: none; - padding: 12px 10px 11px 10px; - margin-left: 50px; - } - - .collectionViewBaseChrome-viewPicker:active { - outline-color: black; - } - - .collectionViewBaseChrome-collapse { - transition: all .5s; - position: absolute; - width: 40px; - } - - .collectionViewBaseChrome-viewSpecs { - margin-left: 10px; - display: grid; + .collectionViewBaseChrome { + display: flex; - .collectionViewBaseChrome-viewSpecsInput { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; - text-align: center; + .collectionViewBaseChrome-viewPicker { + font-size: 75%; text-transform: uppercase; letter-spacing: 2px; - outline-color: black; - font-size: 75%; background: rgb(238, 238, 238); - height: 100%; - width: 150px; + color: grey; + outline-color: black; + border: none; + padding: 12px 10px 11px 10px; + margin-left: 50px; + } + + .collectionViewBaseChrome-viewPicker:active { + outline-color: black; } - .collectionViewBaseChrome-viewSpecsMenu { - overflow: hidden; - transition: height .5s, display .5s; + .collectionViewBaseChrome-collapse { + transition: all .5s; position: absolute; - top: 60px; - z-index: 100; - display: flex; - flex-direction: column; - background: rgb(238, 238, 238); - box-shadow: grey 2px 2px 4px; + width: 40px; + } - .qs-datepicker { - left: unset; - right: 0; + .collectionViewBaseChrome-viewSpecs { + margin-left: 10px; + display: grid; + + .collectionViewBaseChrome-viewSpecsInput { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + font-size: 75%; + background: rgb(238, 238, 238); + height: 100%; + width: 150px; } - .collectionViewBaseChrome-viewSpecsMenu-row { - display: grid; - grid-template-columns: 150px 200px 150px; - margin-top: 10px; - margin-right: 10px; - - .collectionViewBaseChrome-viewSpecsMenu-rowLeft, - .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, - .collectionViewBaseChrome-viewSpecsMenu-rowRight { - font-size: 75%; - letter-spacing: 2px; - color: grey; - margin-left: 10px; - padding: 5px; - border: none; - outline-color: black; + .collectionViewBaseChrome-viewSpecsMenu { + overflow: hidden; + transition: height .5s, display .5s; + position: absolute; + top: 60px; + z-index: 100; + display: flex; + flex-direction: column; + background: rgb(238, 238, 238); + box-shadow: grey 2px 2px 4px; + + .qs-datepicker { + left: unset; + right: 0; } - } - .collectionViewBaseChrome-viewSpecsMenu-lastRow { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 10px; - margin: 10px; + .collectionViewBaseChrome-viewSpecsMenu-row { + display: grid; + grid-template-columns: 150px 200px 150px; + margin-top: 10px; + margin-right: 10px; + + .collectionViewBaseChrome-viewSpecsMenu-rowLeft, + .collectionViewBaseChrome-viewSpecsMenu-rowMiddle, + .collectionViewBaseChrome-viewSpecsMenu-rowRight { + font-size: 75%; + letter-spacing: 2px; + color: grey; + margin-left: 10px; + padding: 5px; + border: none; + outline-color: black; + } + } + + .collectionViewBaseChrome-viewSpecsMenu-lastRow { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; + margin: 10px; + } } } } - } - .collectionStackingViewChrome-cont { - display: flex; - justify-content: space-between; - } + .collectionStackingViewChrome-cont { + display: flex; + justify-content: space-between; + } - .collectionStackingViewChrome-sort { - display: flex; - align-items: center; - justify-content: space-between; + .collectionStackingViewChrome-sort { + display: flex; + align-items: center; + justify-content: space-between; - .collectionStackingViewChrome-sortIcon { - transition: transform .5s; - margin-left: 10px; + .collectionStackingViewChrome-sortIcon { + transition: transform .5s; + margin-left: 10px; + } } - } - - button:hover { - transform: scale(1); - } + button:hover { + transform: scale(1); + } - .collectionStackingViewChrome-sectionFilter-cont { - justify-self: right; - display: flex; - font-size: 75%; - text-transform: uppercase; - letter-spacing: 2px; - .collectionStackingViewChrome-sectionFilter-label { - vertical-align: center; - padding: 10px; - } + .collectionStackingViewChrome-sectionFilter-cont { + justify-self: right; + display: flex; + font-size: 75%; + text-transform: uppercase; + letter-spacing: 2px; - .collectionStackingViewChrome-sectionFilter { - color: white; - width: 100px; - text-align: center; - background: rgb(238, 238, 238); + .collectionStackingViewChrome-sectionFilter-label { + vertical-align: center; + padding: 10px; + } - .editable-view-input, - input, - .editableView-container-editing-oneLine, - .editableView-container-editing { - padding: 12px 10px 11px 10px; - border: 0px; - color: grey; + .collectionStackingViewChrome-sectionFilter { + color: white; + width: 100px; text-align: center; - text-transform: uppercase; - letter-spacing: 2px; - outline-color: black; - height: 100%; - } + background: rgb(238, 238, 238); - .react-autosuggest__container { - margin: 0; - color: grey; - padding: 0px; + .editable-view-input, + input, + .editableView-container-editing-oneLine, + .editableView-container-editing { + padding: 12px 10px 11px 10px; + border: 0px; + color: grey; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + outline-color: black; + height: 100%; + } + + .react-autosuggest__container { + margin: 0; + color: grey; + padding: 0px; + } } } - } - .collectionStackingViewChrome-sectionFilter:hover { - cursor: text; + .collectionStackingViewChrome-sectionFilter:hover { + cursor: text; + } } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 24d13d5cb..4129781f7 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -47,6 +47,20 @@ export class CollectionViewBaseChrome extends React.Component { this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]); this._keyRestrictions.push([ runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]); + + // chrome status is one of disabled, collapsed, or visible. this determines initial state from document + let chromeStatus = this.props.CollectionView.props.Document.chromeStatus; + if (chromeStatus) { + if (chromeStatus === "disabled") { + throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!"); + } + else if (chromeStatus === "collapsed") { + this._collapsed = true; + if (this.props.collapse) { + this.props.collapse(true); + } + } + } }); } @@ -130,11 +144,12 @@ export class CollectionViewBaseChrome extends React.Component { this._collapsed = !this._collapsed; - this.props.collapse(this._collapsed); + if (this.props.collapse) { + this.props.collapse(this._collapsed); + } } subChrome = () => { - switch (this.props.type) { case CollectionViewType.Stacking: return ( -
- - -
- -
- {this._keyRestrictions.map(i => i[0])} -
-
- CREATED WITHIN: -
- - +
+
+
+ + +
+ +
+ {this._keyRestrictions.map(i => i[0])} +
+
+ CREATED WITHIN:
-
-
+
+ - +
+ {this.subChrome()}
- {this.subChrome()}
) } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 1c52a3f11..41eb1aa0c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -50,6 +50,7 @@ export class CurrentUserUtils { if (doc.workspaces === undefined) { const workspaces = Docs.Create.TreeDocument([], { title: "Workspaces", height: 100 }); workspaces.excludeFromLibrary = true; + workspaces.chromeStatus = "disabled"; workspaces.workspaceLibrary = true; workspaces.boxShadow = "0 0"; doc.workspaces = workspaces; @@ -57,6 +58,7 @@ export class CurrentUserUtils { if (doc.recentlyClosed === undefined) { const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 }); recentlyClosed.excludeFromLibrary = true; + recentlyClosed.chromeStatus = "disabled"; recentlyClosed.boxShadow = "0 0"; doc.recentlyClosed = recentlyClosed; } @@ -65,11 +67,13 @@ export class CurrentUserUtils { sidebar.excludeFromLibrary = true; sidebar.gridGap = 5; sidebar.xMargin = 5; + sidebar.chromeStatus = "disabled"; sidebar.yMargin = 5; Doc.GetProto(sidebar).backgroundColor = "#aca3a6"; sidebar.boxShadow = "1 1 3"; doc.sidebar = sidebar; } + doc.chromeStatus = "disabled"; StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library"); } -- cgit v1.2.3-70-g09d2 From eb24b07405b902f34f9b335ef86f5ec2c6d7d062 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 26 Jul 2019 22:16:57 -0400 Subject: ui improvements --- src/client/views/ContextMenu.scss | 48 +++++++++++++++++----- src/client/views/ContextMenu.tsx | 4 +- src/client/views/ContextMenuItem.tsx | 6 +-- src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 6 +-- .../views/collections/CollectionTreeView.tsx | 8 ++-- src/client/views/collections/CollectionView.tsx | 5 ++- src/client/views/nodes/DocumentView.tsx | 23 +++++++---- src/client/views/nodes/FormattedTextBox.tsx | 6 +-- src/client/views/nodes/IconBox.tsx | 10 +++-- src/client/views/nodes/VideoBox.tsx | 6 ++- src/client/views/search/SearchItem.tsx | 7 ++-- 12 files changed, 85 insertions(+), 46 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 254163b53..195304b2c 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -6,6 +6,9 @@ z-index: $contextMenu-zindex; box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw; flex-direction: column; + background: whitesmoke; + padding-bottom: 10px; + border-radius: 15px; } // .contextMenu-item:first-child { @@ -33,7 +36,7 @@ .contextMenu-item { // width: 11vw; //10vw height: 30px; //2vh - background: #DDDDDD; + background: whitesmoke; display: flex; //comment out to allow search icon to be inline with search text justify-content: left; align-items: center; @@ -44,13 +47,22 @@ -ms-user-select: none; user-select: none; transition: all .1s; + border-style: none; + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 13px; + color: grey; + letter-spacing: 2px; + text-transform: uppercase; + padding-right: 10px; +} + +.contextMenu-item:hover { border-width: .11px; border-style: none; border-color: $intermediate-color; // rgb(187, 186, 186); border-bottom-style: solid; - // padding: 10px 0px 10px 0px; - white-space: nowrap; - font-size: 20px; + border-top-style: solid; } .contextMenu-itemSelected { @@ -60,7 +72,7 @@ .contextMenu-group { // width: 11vw; //10vw height: 30px; //2vh - background: rgb(200, 200, 200); + background: lightgoldenrodyellow; display: flex; //comment out to allow search icon to be inline with search text justify-content: left; align-items: center; @@ -74,27 +86,41 @@ border-width: .11px; border-style: none; border-color: $intermediate-color; // rgb(187, 186, 186); - border-bottom-style: solid; // padding: 10px 0px 10px 0px; white-space: nowrap; - font-size: 20px; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 2px; + padding-left: 5px; } .contextMenu-item:hover { - transition: all 0.1s; + transition: all 0.1s ease; background: $lighter-alt-accent; } .contextMenu-description { - font-size: 20px; + margin-left: 5px; text-align: left; display: inline; //need this? } +.search-icon { + margin: 10px; +} + +.search { + margin-left: 10px; + padding-left: 10px; + border: solid black 1px; + border-radius: 5px; +} + .icon-background { pointer-events: none; - background-color: #DDDDDD; + background-color: transparent; width: 35px; text-align: center; - font-size: 22px; + font-size: 20px; + margin-left: 5px; } \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index c163c56a0..5caf27327 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -165,11 +165,11 @@ export class ContextMenu extends React.Component { const contents = ( <> - + - + {this.menuItems} diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 9bbb97d7e..4a7cd309d 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -10,14 +10,14 @@ library.add(faAngleRight); export interface OriginalMenuProps { description: string; event: () => void; - icon?: IconProp; //maybe should be optional (icon?) + icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } export interface SubmenuProps { description: string; subitems: ContextMenuProps[]; - icon?: IconProp; //maybe should be optional (icon?) + icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } @@ -94,7 +94,7 @@ export class ContextMenuItem extends React.Component {this.props.description} - +
{submenu}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 61a013963..8606b52b3 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -390,7 +390,7 @@ export class MainView extends React.Component { ]; if (!ClientUtils.RELEASE) btns.unshift([React.createRef(), "cat", "Add Cat Image", addImageNode]); - return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} > + return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 20, bottom: 20 }} > diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 119aa7c19..91137f841 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, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { faCog, faPlus, faTable } 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"; @@ -34,7 +34,7 @@ import { ComputedField } from "../../../new_fields/ScriptField"; library.add(faCog); -library.add(faPlus); +library.add(faPlus, faTable); // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -321,7 +321,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // 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: "Make DB", event: this.makeDB }); + ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" }); } } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a1697f9b4..1c7fe4bee 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt, faPlus, faMinus } 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"; @@ -61,7 +61,7 @@ library.add(faCaretRight); library.add(faCaretSquareDown); library.add(faCaretSquareRight); library.add(faArrowsAltH); - +library.add(faPlus, faMinus); @observer /** * Component that takes in a document prop and a boolean whether it's collapsed or not. @@ -520,8 +520,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document - ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) }); - ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) }); + ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()), icon: "plus" }); + ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)), icon: "minus" }); e.stopPropagation(); e.preventDefault(); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 7781b26d9..0695029c7 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,6 +17,7 @@ import { CollectionStackingView } from './CollectionStackingView'; import { CollectionTreeView } from "./CollectionTreeView"; import { StrCast, PromiseValue } from '../../../new_fields/Types'; import { DocumentType } from '../../documents/Documents'; +import { faEye } from '@fortawesome/free-regular-svg-icons'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -28,7 +29,7 @@ library.add(faThList); library.add(faFingerprint); library.add(faColumns); library.add(faEllipsisV); -library.add(faImage); +library.add(faImage, faEye); @observer export class CollectionView extends React.Component { @@ -68,7 +69,7 @@ export class CollectionView extends React.Component { break; } } - ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); + ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" }); } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index bae0b5b96..da72f212c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -39,6 +39,7 @@ import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; import { ClientUtils } from '../../util/ClientUtils'; import { EditableView } from '../EditableView'; +import { faHandPointer, faHandPointRight } from '@fortawesome/free-regular-svg-icons'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -60,7 +61,7 @@ library.add(fa.faCrosshairs); library.add(fa.faDesktop); library.add(fa.faUnlock); library.add(fa.faLock); -library.add(fa.faLaptopCode); +library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, faHandPointRight); // const linkSchema = createSchema({ @@ -547,11 +548,12 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); - cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); - cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); - cm.addItem({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); - cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); - cm.addItem({ + cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); + cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); + let makes: ContextMenuProps[] = []; + makes.push({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); + makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); + makes.push({ description: "Make Portal", event: () => { let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" }); Doc.GetProto(this.props.Document).subBulletDocs = new List([portal]); @@ -562,6 +564,7 @@ export class DocumentView extends DocComponent(Docu this.props.removeDocument && this.props.removeDocument(this.props.Document); }, icon: "window-restore" }); + cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); // cm.addItem({ // description: "Find aliases", event: async () => { // const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); @@ -575,8 +578,10 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); if (!ClientUtils.RELEASE) { - cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); - cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + let copies: ContextMenuProps[] = []; + copies.push({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); + copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" }); + cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" }); } cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; @@ -600,7 +605,7 @@ export class DocumentView extends DocComponent(Docu notifDoc.data = new List([sharedDoc]); } } - } + }, icon: "male" })); } catch { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0a79677e2..febb567e1 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons'; +import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons'; import { action, IReactionDisposer, observable, reaction, runInAction, computed, trace } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; @@ -38,7 +38,7 @@ import { thisExpression } from 'babel-types'; import { Utils } from '../../../Utils'; library.add(faEdit); -library.add(faSmile); +library.add(faSmile, faTextHeight); // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -462,7 +462,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe description: BoolCast(this.props.Document.autoHeight, false) ? "Manual Height" : "Auto Height", event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight, false)), icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems }); + ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" }); } render() { let self = this; diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index d6ab2a34a..64d869ecf 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -1,6 +1,6 @@ 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 { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTag, faTextHeight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -18,7 +18,7 @@ library.add(faCaretUp); library.add(faObjectGroup); library.add(faStickyNote); library.add(faFilePdf); -library.add(faFilm); +library.add(faFilm, faTag, faTextHeight); @observer export class IconBox extends React.Component { @@ -47,13 +47,15 @@ export class IconBox extends React.Component { specificContextMenu = (): void => { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon", - event: this.setLabelField + event: this.setLabelField, + icon: "tag" }); let maxDocs = DocListCast(this.props.Document.maximizedDocs); if (maxDocs.length === 1 && !BoolCast(this.props.Document.hideLabel)) { ContextMenu.Instance.addItem({ description: BoolCast(this.props.Document.useOwnTitle) ? "Use target title for label" : "Use own title label", - event: this.setUseOwnTitleField + event: this.setUseOwnTitleField, + icon: "text-height" }); } } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 30ad75000..34cb47b20 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -19,10 +19,14 @@ import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { faVideo } from "@fortawesome/free-solid-svg-icons"; type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const VideoDocument = makeInterface(positionSchema, pageSchema); +library.add(faVideo); + @observer export class VideoBox extends DocComponent(VideoDocument) { private _reactionDisposer?: IReactionDisposer; @@ -179,7 +183,7 @@ export class VideoBox extends DocComponent(VideoD }, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems }); + ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" }); } } diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 5c2ced2eb..562594210 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote, faFingerprint } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; @@ -38,7 +38,7 @@ library.add(faFilm); library.add(faMusic); library.add(faLink); library.add(faChartBar); -library.add(faGlobeAsia); +library.add(faGlobeAsia, faFingerprint); @observer export class SelectorContextMenu extends React.Component { @@ -223,7 +223,8 @@ export class SearchItem extends React.Component { ContextMenu.Instance.addItem({ description: "Copy ID", event: () => { Utils.CopyText(this.props.doc[Id]); - } + }, + icon: "fingerprint" }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } -- cgit v1.2.3-70-g09d2 From cc806ebbe8d48d1c5a4c3c49231a5d38d6f39943 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 27 Jul 2019 04:12:07 -0400 Subject: fixed a bunch of template and stacking view issues among others. --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/GlobalKeyHandler.ts | 1 + src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 39 +++++-------- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 68 +++++++++------------- src/client/views/collections/CollectionView.tsx | 2 - .../collectionFreeForm/CollectionFreeFormView.tsx | 22 +++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +---- src/client/views/nodes/DocumentView.tsx | 14 +++-- src/new_fields/Doc.ts | 13 ++++- 11 files changed, 75 insertions(+), 108 deletions(-) (limited to 'src/client/views/collections/CollectionView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 255855b45..c08a84742 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -533,7 +533,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> proto.nativeHeight = nheight = doc.height || 0; proto.ignoreAspect = true; } - if (nwidth > 0 && nheight > 0) { + if (nwidth > 0 && nheight > 0 && !BoolCast(proto.ignoreAspect)) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true); @@ -553,7 +553,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } else { dW && (doc.width = actualdW); dH && (doc.height = actualdH); - Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true); + dH && Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true); } } }); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 7477c5b4f..5050f34ab 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -67,6 +67,7 @@ export default class KeyManager { } } MainView.Instance.toggleColorPicker(true); + SelectionManager.DeselectAll(); break; case "delete": case "backspace": diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 61a013963..bfb50bc75 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -407,7 +407,7 @@ export class MainView extends React.Component {
)}
  • -