From 0a39ac7f93f2035115aa929c77ad0e8b797f9fb1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 18 Jul 2019 01:20:58 -0400 Subject: stackingViewwithSections --- src/client/views/nodes/DocumentView.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01db40fc7..feded711c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -608,7 +608,12 @@ export class DocumentView extends DocComponent(Docu @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } @computed get contents() { - return (); + return (); } render() { -- cgit v1.2.3-70-g09d2 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/DocumentDecorations.tsx | 10 ++++++++-- src/client/views/collections/CollectionView.tsx | 9 ++++++--- src/client/views/nodes/DocumentView.tsx | 11 +++++++++++ src/new_fields/Doc.ts | 10 +++++----- 4 files changed, 30 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/DocumentView.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/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" }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index feded711c..899c47cb3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -291,6 +291,7 @@ 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); this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = undefined; @@ -555,6 +556,16 @@ export class DocumentView extends DocComponent(Docu this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc? }, 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: "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" }); cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 769c6aa73..7180564ea 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -385,12 +385,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) { -- 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/nodes/DocumentView.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 6f8f9bd2eaba36dc64e7335dee53a372542bad46 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Mon, 22 Jul 2019 17:17:09 -0400 Subject: basic stuff working, column headers don tmatch add group button --- src/client/views/MetadataEntryMenu.tsx | 1 + .../views/collections/CollectionStackingView.scss | 55 ++++-- .../views/collections/CollectionStackingView.tsx | 113 +++++------- .../CollectionStackingViewFieldColumn.tsx | 202 +++++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 3 - 5 files changed, 286 insertions(+), 88 deletions(-) create mode 100644 src/client/views/collections/CollectionStackingViewFieldColumn.tsx (limited to 'src/client/views/nodes/DocumentView.tsx') diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index bd5a307b3..7fce3dd0c 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -74,6 +74,7 @@ export class MetadataEntryMenu extends React.Component{ this.userModified = e.target.value.trim() !== ""; } + @action onValueKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { const script = KeyValueBox.CompileKVPScript(this._currentValue); diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 7ebf5f77c..3e389225a 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -1,9 +1,12 @@ @import "../globalCssVariables"; + .collectionStackingView { height: 100%; width: 100%; position: absolute; + display: flex; overflow-y: auto; + .collectionStackingView-docView-container { width: 45%; margin: 5% 2.5%; @@ -18,21 +21,23 @@ align-items: center; } - .collectionStackingView-masonrySingle, .collectionStackingView-masonryGrid { - width:100%; - height:100%; + .collectionStackingView-masonrySingle, + .collectionStackingView-masonryGrid { + width: 100%; + height: 100%; position: absolute; - display:grid; + display: grid; top: 0; left: 0; width: 100%; position: absolute; } + .collectionStackingView-masonrySingle { - width:100%; - height:100%; + width: 100%; + height: 100%; position: absolute; - display:flex; + display: flex; flex-direction: column; top: 0; left: 0; @@ -52,34 +57,50 @@ } .collectionStackingView-columnDragger { - width: 15; - height: 15; + width: 15; + height: 15; position: absolute; margin-left: -5; } - .collectionStackingView-columnDoc{ + .collectionStackingView-columnDoc { display: inline-block; } - .collectionStackingView-columnDoc, + .collectionStackingView-columnDoc, .collectionStackingView-masonryDoc { margin-left: auto; margin-right: auto; } - + .collectionStackingView-masonryDoc { transform-origin: top left; grid-column-end: span 1; height: 100%; } - .collectionStackingView-sectionHeader { - width: 90%; + + .collectionStackingView-sectionHeader { background: gray; text-align: center; - margin-left: 5%; - margin-right: 5%; - color: white; + margin-left: 10px; + margin-right: 10px; margin-top: 10px; + color: $light-color; + text-transform: uppercase; + letter-spacing: 2px; + padding: 10px; + + .editableView-input { + color: black; + } + } + + .collectionStackingView-addDocumentButton, + .collectionStackingView-addGroupButton { + display: inline-block; + margin: 0 10px; + overflow: hidden; + width: 90%; + color: lightgrey; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0e5f9a321..0ddd5528b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -14,6 +14,7 @@ import { DragManager } from "../../util/DragManager"; import { DocumentType } from "../../documents/Documents"; import { Transform } from "../../util/Transform"; import { CursorProperty } from "csstype"; +import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -35,8 +36,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { 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); + let parsed = parseInt(sectionValue.toString()); + let castedSectionValue: any = sectionValue; + if (!isNaN(parsed)) { + castedSectionValue = parsed; + } + if (!fields.has(castedSectionValue)) fields.set(castedSectionValue, [d]); + else fields.get(castedSectionValue)!.push(d); }); return fields; } @@ -66,7 +72,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { 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 headings = Array.from(this.Sections.keys()); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth) / (uniqueHeadings.length + 1); let height = () => this.getDocHeight(layoutDoc); let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]()); return 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); - 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]); - } - - children(docs: Doc[]) { - this._docXfs.length = 0; - return docs.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) { - //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. - let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); - let rowHgtPcnt = height(); - 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.gridGap); - this._docXfs.push({ dxf: dxf, width: width, height: height }); - return
- {this.getDisplayDoc(layoutDoc, d, dxf)} -
; - } - }); - } - columnDividerDown = (e: React.PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -218,30 +183,37 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } }); } - section(heading: string, docList: Doc[]) { - let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, + section = (heading: string, docList: Doc[]) => { + let key = StrCast(this.props.Document.sectionFilter); + let types = docList.map(d => typeof d[key]); + let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined; + if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { + type = types[0]; + } + let parsed = parseInt(heading); + if (!isNaN(parsed)) { + heading = parsed.toString(); + } + 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
- {heading ?
{heading}
: (null)} -
- {this.children(docList)} - {this.singleColumn ? (null) : this.columnDragger} -
; + return Array.from(this.Sections.keys())} + heading={heading} + docList={docList} + parent={this} + type={type} + createDropTarget={this.createDropTarget} />; + } + + @action + addGroup = () => { + } + render() { + let headings = Array.from(this.Sections.keys()); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); return (
e.stopPropagation()} > @@ -249,9 +221,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ["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]())]]. */} - {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()). + {this.props.Document.sectionFilter ? Array.from(this.Sections.entries()).sort((a, b) => a[0].toString() > b[0].toString() ? 1 : -1). map(section => this.section(section[0].toString(), section[1] as Doc[])) : this.section("", this.filteredChildren)} + {this.props.Document.sectionFilter ? +
+ +
: null}
); } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx new file mode 100644 index 000000000..9f64a4e93 --- /dev/null +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -0,0 +1,202 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { number } from "prop-types"; +import { Doc, WidthSym } from "../../../new_fields/Doc"; +import { CollectionStackingView } from "./CollectionStackingView"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { Utils } from "../../../Utils"; +import { NumCast, StrCast } from "../../../new_fields/Types"; +import { EditableView } from "../EditableView"; +import { action, observable } from "mobx"; +import { undoBatch } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; +import { DocumentManager } from "../../util/DocumentManager"; +import { SelectionManager } from "../../util/SelectionManager"; +import "./CollectionStackingView.scss"; +import { Docs } from "../../documents/Documents"; + + +interface CSVFieldColumnProps { + cols: () => number; + headings: () => object[]; + heading: string; + docList: Doc[]; + parent: CollectionStackingView; + type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined; + createDropTarget: (ele: HTMLDivElement) => void; +} + +@observer +export class CollectionStackingViewFieldColumn extends React.Component { + @observable private _background = "white"; + + private _dropRef: HTMLDivElement | null = null; + private dropDisposer?: DragManager.DragDropDisposer; + + createColumnDropRef = (ele: HTMLDivElement | null) => { + this._dropRef = ele; + this.dropDisposer && this.dropDisposer(); + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.columnDrop.bind(this) } }); + } + } + + @undoBatch + @action + columnDrop = (e: Event, de: DragManager.DropEvent) => { + if (de.data instanceof DragManager.DocumentDragData) { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let castedValue = this.getValue(this.props.heading); + if (castedValue) { + de.data.droppedDocuments.forEach(d => d[key] = castedValue); + } + this.props.parent.drop(e, de); + e.stopPropagation(); + } + } + + children(docs: Doc[]) { + let style = this.props.parent; + this.props.parent._docXfs.length = 0; + return docs.map((d, i) => { + let layoutDoc = Doc.expandTemplateLayout(d, this.props.parent.props.DataDoc); + let headings = this.props.headings(); + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let width = () => (d.nativeWidth ? Math.min(layoutDoc[WidthSym](), style.columnWidth) : style.columnWidth) / (uniqueHeadings.length + 1); + let height = () => this.props.parent.getDocHeight(layoutDoc); + if (style.singleColumn) { + let dxf; + let dref = React.createRef(); + if (uniqueHeadings.length > 0) { + dxf = () => this.getDocTransform(layoutDoc, dref.current!); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + } + else { + //have to add the height of all previous single column sections or the doc decorations will be in the wrong place. + dxf = () => this.getSingleDocTransform(layoutDoc, i, width()); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + } + let rowHgtPcnt = height(); + return
+ {this.props.parent.getDisplayDoc(layoutDoc, d, dxf)} +
; + } else { + let dref = React.createRef(); + let dxf = () => this.getDocTransform(layoutDoc, dref.current!); + let rowSpan = Math.ceil((height() + style.gridGap) / style.gridGap); + this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height }); + return
+ {this.props.parent.getDisplayDoc(layoutDoc, d, dxf)} +
; + } + }); + } + + getSingleDocTransform(doc: Doc, ind: number, width: number) { + let localY = this.props.parent.filteredChildren.reduce((height, d, i) => + height + (i < ind ? this.props.parent.getDocHeight(Doc.expandTemplateLayout(d, this.props.parent.props.DataDoc)) + this.props.parent.gridGap : 0), this.props.parent.yMargin); + let translate = this.props.parent.props.ScreenToLocalTransform().inverse().transformPoint((this.props.parent.props.PanelWidth() - width) / 2, localY); + return this.offsetTransform(doc, translate[0], translate[1]); + } + + offsetTransform(doc: Doc, translateX: number, translateY: number) { + let outerXf = Utils.GetScreenTransform(this.props.parent._masonryGridRef!); + let offset = this.props.parent.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.props.parent.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.props.parent.columnWidth); + } + + getDocTransform(doc: Doc, dref: HTMLDivElement) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + return this.offsetTransform(doc, translateX, translateY); + } + + getValue = (value: string): any => { + let parsed = parseInt(value); + if (!isNaN(parsed)) { + return parsed; + } + if (value.toLowerCase().indexOf("true") > -1) { + return true; + } + if (value.toLowerCase().indexOf("false") > -1) { + return false; + } + return value; + } + + headingChanged = (value: string, shiftDown?: boolean) => { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let castedValue = this.getValue(value); + if (castedValue) { + this.props.docList.forEach(d => d[key] = castedValue); + return true; + } + return false; + } + + @action + pointerEntered = () => { + if (SelectionManager.GetIsDragging()) { + this._background = "#b4b4b4"; + } + } + + @action + pointerLeave = () => { + this._background = "white"; + } + + @action + addDocument = () => { + let key = StrCast(this.props.parent.props.Document.sectionFilter); + let newDoc = Docs.Create.TextDocument({ height: 18, title: "new text document" }); + newDoc[key] = this.getValue(this.props.heading); + this.props.parent.props.addDocument(newDoc); + } + + render() { + let cols = this.props.cols(); + let templatecols = ""; + let headings = this.props.headings(); + let heading = this.props.heading; + let style = this.props.parent; + let singleColumn = style.singleColumn; + let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx); + let editableViewProps = { + GetValue: () => heading, + SetValue: this.headingChanged, + contents: heading, + } + let headingView = heading ? +
+ +
: (null); + for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `; + return ( +
+ {headingView} +
+ {this.children(this.props.docList)} + {singleColumn ? (null) : this.props.parent.columnDragger} +
+
+ +
+
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f4052c2c3..0d766cded 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -565,10 +565,7 @@ export class DocumentView extends DocComponent(Docu if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } -<<<<<<< HEAD -======= cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) }); ->>>>>>> fc1dbb1327d10bd1832d33a87d18cff1e836ecfb 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" }); cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" }); -- cgit v1.2.3-70-g09d2