From d4068447e5b6aab667930398bfe8b285282cffdb Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 15:58:40 -0500 Subject: show resizers on hover --- .../collections/CollectionMulticolumnView.scss | 1 + .../collections/CollectionMulticolumnView.tsx | 62 ++++++++++++---------- 2 files changed, 36 insertions(+), 27 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss index a54af748b..acb194983 100644 --- a/src/client/views/collections/CollectionMulticolumnView.scss +++ b/src/client/views/collections/CollectionMulticolumnView.scss @@ -18,6 +18,7 @@ .resizer { background: black; cursor: ew-resize; + transition: 0.5s opacity ease; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 955e87f13..ebe033d1f 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -1,14 +1,14 @@ import { observer } from 'mobx-react'; import { makeInterface } from '../../../new_fields/Schema'; import { documentSchema } from '../../../new_fields/documentSchemas'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import * as React from "react"; import { Doc } from '../../../new_fields/Doc'; import { NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView'; import { Utils } from '../../../Utils'; import "./collectionMulticolumnView.scss"; -import { computed, trace } from 'mobx'; +import { computed, trace, observable, action } from 'mobx'; import { Transform } from '../../util/Transform'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; @@ -34,7 +34,7 @@ interface LayoutData { const resolvedUnits = ["*", "px"]; const resizerWidth = 2; -const resizerOpacity = 0.4; +const resizerOpacity = 1; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { @@ -210,31 +210,10 @@ interface SpacerProps { toRight?: Doc; } -interface WidthLabelProps { - layout: Doc; - collectionDoc: Doc; - decimals?: number; -} - -@observer -class WidthLabel extends React.Component { - - @computed - private get contents() { - const { layout, decimals } = this.props; - const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); - const unit = StrCast(layout.widthUnit); - return {magnitude} {unit}; - } - - render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); - } - -} - @observer class ResizeBar extends React.Component { + @observable private isHoverActive = false; + private isResizingActive = false; private registerResizing = (e: React.PointerEvent) => { e.stopPropagation(); @@ -257,6 +236,7 @@ class ResizeBar extends React.Component { } private get isActivated() { + this.isResizingActive = true; const { toLeft, toRight } = this.props; if (toLeft && toRight) { if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { @@ -277,7 +257,10 @@ class ResizeBar extends React.Component { return false; } + @action private onPointerUp = () => { + this.isResizingActive = false; + this.isHoverActive = false; window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); } @@ -288,11 +271,36 @@ class ResizeBar extends React.Component { className={"resizer"} style={{ width: this.props.width, - opacity: this.isActivated ? resizerOpacity : 0 + opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0 }} onPointerDown={this.registerResizing} + onPointerEnter={action(() => this.isHoverActive = true)} + onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} /> ); } +} + +interface WidthLabelProps { + layout: Doc; + collectionDoc: Doc; + decimals?: number; +} + +@observer +class WidthLabel extends React.Component { + + @computed + private get contents() { + const { layout, decimals } = this.props; + const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); + const unit = StrCast(layout.widthUnit); + return {magnitude} {unit}; + } + + render() { + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + } + } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 03dafe7743dc3e70f9e936aec8bf2e49efbfb041 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 Jan 2020 17:09:29 -0500 Subject: changed view types around to be stored on extension doc. added stuff to stackingview to create views of fields using ';" --- src/client/util/DropConverter.ts | 5 +++-- src/client/views/TemplateMenu.tsx | 4 ++++ .../collections/CollectionStackingViewFieldColumn.tsx | 19 +++++++++++++++++++ src/client/views/collections/CollectionView.tsx | 19 +++++++++++++++---- src/client/views/nodes/DocumentView.tsx | 17 ++++++++++++++++- 5 files changed, 57 insertions(+), 7 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index da0ad7efe..dc66bceee 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -27,7 +27,8 @@ function makeTemplate(doc: Doc): boolean { export function convertDropDataToButtons(data: DragManager.DocumentDragData) { data && data.draggedDocuments.map((doc, i) => { let dbox = doc; - if (!doc.onDragStart && !doc.onClick && doc.viewType !== CollectionViewType.Linear) { + // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant + if (!doc.onDragStart && !doc.onClick && !doc.isButtonBar) { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; if (layoutDoc.type === DocumentType.COL) { layoutDoc.isTemplateDoc = makeTemplate(layoutDoc); @@ -38,7 +39,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { dbox.dragFactory = layoutDoc; dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); - } else if (doc.viewType === CollectionViewType.Linear) { + } else if (doc.isButtonBar) { dbox.ignoreClick = true; } data.droppedDocuments[i] = dbox; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 8f2ec4bef..d953d3bab 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -58,6 +58,9 @@ export class TemplateMenu extends React.Component { toggleCustom = (e: React.ChangeEvent): void => { this.props.docs.map(dv => dv.setCustomView(e.target.checked)); } + toggleNarrative = (e: React.ChangeEvent): void => { + this.props.docs.map(dv => dv.setNarrativeView(e.target.checked)); + } toggleFloat = (e: React.ChangeEvent): void => { SelectionManager.DeselectAll(); @@ -146,6 +149,7 @@ export class TemplateMenu extends React.Component { templateMenu.push()); templateMenu.push(); templateMenu.push(); + templateMenu.push(); templateMenu.push(); return ( { + if (value === ":freeForm") { + return this.props.parent.props.addDocument(Docs.Create.FreeformDocument([], { width: 200, height: 200 })); + } else if (value.startsWith(":")) { + const field = value.substring(1); + if (this.props.parent.props.Document[field] instanceof ImageField) { + let doc = Docs.Create.ImageDocument((this.props.parent.props.Document[field] as ImageField).url.href, {}); + doc.layout = ImageBox.LayoutString(field); + doc.proto = Doc.GetProto(this.props.parent.props.Document); + return this.props.parent.props.addDocument(doc); + } else { + let doc = Docs.Create.TextDocument({ width: 200, height: 25, autoHeight: true }); + doc.layout = FormattedTextBox.LayoutString(field); + doc.proto = Doc.GetProto(this.props.parent.props.Document); + return this.props.parent.props.addDocument(doc); + } + } this._createAliasSelected = false; const key = StrCast(this.props.parent.props.Document.sectionFilter); const newDoc = Docs.Create.TextDocument({ height: 18, width: 200, documentText: "@@@" + value, title: value, autoHeight: true }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4bd456233..db4da30d1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEye } from '@fortawesome/free-regular-svg-icons'; import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons'; -import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { action, IReactionDisposer, observable, reaction, runInAction, computed } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; @@ -10,7 +10,7 @@ import { DateField } from '../../../new_fields/DateField'; import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { listSpec } from '../../../new_fields/Schema'; -import { BoolCast, Cast, StrCast } from '../../../new_fields/Types'; +import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types'; import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; @@ -50,7 +50,8 @@ export enum CollectionViewType { Pivot, Linear, Staff, - Multicolumn + Multicolumn, + Timeline } export namespace CollectionViewType { @@ -90,8 +91,18 @@ export class CollectionView extends Touchable { @observable private static _safeMode = false; public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } + get collectionViewType(): CollectionViewType | undefined { - const viewField = Cast(this.props.Document.viewType, "number"); + if (!this.extensionDoc) return CollectionViewType.Invalid; + NumCast(this.props.Document.viewType) && setTimeout(() => { + if (this.props.Document.viewType) { + this.extensionDoc!.viewType = NumCast(this.props.Document.viewType); + } + Doc.GetProto(this.props.Document).viewType = this.props.Document.viewType = undefined; + }); + const viewField = NumCast(this.extensionDoc.viewType, Cast(this.props.Document.viewType, "number")); if (CollectionView._safeMode) { if (viewField === CollectionViewType.Freeform) { return CollectionViewType.Tree; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dabe5a7aa..60dc253f7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -44,6 +44,7 @@ import { InkTool } from '../../../new_fields/InkField'; import { TraceMobx } from '../../../new_fields/util'; import { List } from '../../../new_fields/List'; import { FormattedTextBoxComment } from './FormattedTextBoxComment'; +import { CollectionStackingView } from '../collections/CollectionStackingView'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -551,6 +552,20 @@ export class DocumentView extends DocComponent(Docu } } + @undoBatch + @action + setNarrativeView = (custom: boolean): void => { + if (custom) { + this.props.Document.layout_narrative = CollectionView.LayoutString("narrative"); + this.props.Document.nativeWidth = this.props.Document.nativeHeight = undefined; + !this.props.Document.narrative && (Doc.GetProto(this.props.Document).narrative = new List([])); + this.props.Document.viewType = CollectionViewType.Stacking; + this.props.Document.layoutKey = "layout_narrative"; + } else { + DocumentView.makeNativeViewClicked(this.props.Document) + } + } + @undoBatch @action setCustomView = (custom: boolean): void => { @@ -744,7 +759,7 @@ export class DocumentView extends DocComponent(Docu return (showTitle && !showTitleHover ? 0 : 0) + 1; } - @computed get finalLayoutKey() { return this.props.layoutKey || "layout"; } + @computed get finalLayoutKey() { return this.props.layoutKey || StrCast(this.props.Document.layoutKey, "layout"); } childScaling = () => (this.layoutDoc.fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); @computed get contents() { TraceMobx(); -- cgit v1.2.3-70-g09d2 From e4c8cd2fef1242cfb3e4a14e3e3d7bfc852126bd Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 18:26:18 -0500 Subject: fixed resize hover and added pinned resize to mc view --- .../collections/CollectionMulticolumnView.tsx | 42 +++++++++++++--------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index ebe033d1f..aa84e0db6 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -20,11 +20,6 @@ interface Unresolved { unit: string; } -interface Resolved { - target: Doc; - pixels: number; -} - interface LayoutData { unresolved: Unresolved[]; numFixed: number; @@ -65,9 +60,13 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu // space is allocated as if the document were absent from the configuration list } + setTimeout(() => { - const minimum = Math.min(...this.ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); - this.ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + const { ratioDefinedDocs } = this; + if (ratioDefinedDocs.length > 1) { + const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); + ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + } }); return { unresolved, numRatio, numFixed, starSum }; @@ -203,7 +202,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } -interface SpacerProps { +interface ResizerProps { width: number; columnUnitLength(): number | undefined; toLeft?: Doc; @@ -211,9 +210,9 @@ interface SpacerProps { } @observer -class ResizeBar extends React.Component { +class ResizeBar extends React.Component { @observable private isHoverActive = false; - private isResizingActive = false; + @observable private isResizingActive = false; private registerResizing = (e: React.PointerEvent) => { e.stopPropagation(); @@ -222,21 +221,30 @@ class ResizeBar extends React.Component { window.removeEventListener("pointerup", this.onPointerUp); window.addEventListener("pointermove", this.onPointerMove); window.addEventListener("pointerup", this.onPointerUp); + this.isResizingActive = true; } private onPointerMove = ({ movementX }: PointerEvent) => { const { toLeft, toRight, columnUnitLength } = this.props; - const target = movementX > 0 ? toRight : toLeft; - let scale = columnUnitLength(); - if (target && scale) { - const { widthUnit, widthMagnitude } = target; - scale = widthUnit === "*" ? scale : 1; - target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; + const movingRight = movementX > 0; + const toNarrow = movingRight ? toRight : toLeft; + const toWiden = movingRight ? toLeft : toRight; + const unitLength = columnUnitLength(); + if (unitLength) { + if (toNarrow) { + const { widthUnit, widthMagnitude } = toNarrow; + const scale = widthUnit === "*" ? unitLength : 1; + toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; + } + if (toWiden) { + const { widthUnit, widthMagnitude } = toWiden; + const scale = widthUnit === "*" ? unitLength : 1; + toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale; + } } } private get isActivated() { - this.isResizingActive = true; const { toLeft, toRight } = this.props; if (toLeft && toRight) { if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { -- cgit v1.2.3-70-g09d2 From 6fe419d5545dce871376fa5540665f8ef07f5ae2 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 18:43:26 -0500 Subject: added resize mode functionality based on location of drag initiation, pinned above and global below --- .../collections/CollectionMulticolumnView.scss | 7 ++++++ .../collections/CollectionMulticolumnView.tsx | 27 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss index acb194983..5fbc35df6 100644 --- a/src/client/views/collections/CollectionMulticolumnView.scss +++ b/src/client/views/collections/CollectionMulticolumnView.scss @@ -19,6 +19,13 @@ background: black; cursor: ew-resize; transition: 0.5s opacity ease; + display: flex; + flex-direction: column; + + .internal { + width: 100%; + height: 100%; + } } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index aa84e0db6..ef15b29eb 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -28,7 +28,7 @@ interface LayoutData { } const resolvedUnits = ["*", "px"]; -const resizerWidth = 2; +const resizerWidth = 4; const resizerOpacity = 1; @observer @@ -209,14 +209,22 @@ interface ResizerProps { toRight?: Doc; } +enum ResizeMode { + Global, + Pinned, + Undefined +} + @observer class ResizeBar extends React.Component { @observable private isHoverActive = false; @observable private isResizingActive = false; + private resizeMode = ResizeMode.Undefined; - private registerResizing = (e: React.PointerEvent) => { + private registerResizing = (e: React.PointerEvent, mode: ResizeMode) => { e.stopPropagation(); e.preventDefault(); + this.resizeMode = mode; window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); window.addEventListener("pointermove", this.onPointerMove); @@ -236,7 +244,7 @@ class ResizeBar extends React.Component { const scale = widthUnit === "*" ? unitLength : 1; toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; } - if (toWiden) { + if (this.resizeMode === ResizeMode.Pinned && toWiden) { const { widthUnit, widthMagnitude } = toWiden; const scale = widthUnit === "*" ? unitLength : 1; toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale; @@ -267,6 +275,7 @@ class ResizeBar extends React.Component { @action private onPointerUp = () => { + this.resizeMode = ResizeMode.Undefined; this.isResizingActive = false; this.isHoverActive = false; window.removeEventListener("pointermove", this.onPointerMove); @@ -281,10 +290,18 @@ class ResizeBar extends React.Component { width: this.props.width, opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0 }} - onPointerDown={this.registerResizing} onPointerEnter={action(() => this.isHoverActive = true)} onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} - /> + > +
this.registerResizing(e, ResizeMode.Pinned)} + /> +
this.registerResizing(e, ResizeMode.Global)} + /> +
); } -- cgit v1.2.3-70-g09d2 From d9e8815ad25b413b825ae72267b85782e787407c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 21:33:55 -0500 Subject: created files for mcview subcomponents, removed excess zeros in width labels and added colored feedback for resize mode. Need to implement more useful version of 'global' resize mode --- .../collections/CollectionMulticolumnView.scss | 31 -- .../collections/CollectionMulticolumnView.tsx | 331 --------------------- src/client/views/collections/CollectionView.tsx | 2 +- .../CollectionMulticolumnView.scss | 31 ++ .../CollectionMulticolumnView.tsx | 205 +++++++++++++ .../collectionMulticolumn/MulticolumnResizer.tsx | 115 +++++++ .../MulticolumnWidthLabel.tsx | 28 ++ 7 files changed, 380 insertions(+), 363 deletions(-) delete mode 100644 src/client/views/collections/CollectionMulticolumnView.scss delete mode 100644 src/client/views/collections/CollectionMulticolumnView.tsx create mode 100644 src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss create mode 100644 src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx create mode 100644 src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx create mode 100644 src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss deleted file mode 100644 index 5fbc35df6..000000000 --- a/src/client/views/collections/CollectionMulticolumnView.scss +++ /dev/null @@ -1,31 +0,0 @@ -.collectionMulticolumnView_contents { - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - - .document-wrapper { - display: flex; - flex-direction: column; - - .display { - text-align: center; - height: 20px; - } - - } - - .resizer { - background: black; - cursor: ew-resize; - transition: 0.5s opacity ease; - display: flex; - flex-direction: column; - - .internal { - width: 100%; - height: 100%; - } - } - -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx deleted file mode 100644 index ef15b29eb..000000000 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ /dev/null @@ -1,331 +0,0 @@ -import { observer } from 'mobx-react'; -import { makeInterface } from '../../../new_fields/Schema'; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; -import * as React from "react"; -import { Doc } from '../../../new_fields/Doc'; -import { NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; -import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView'; -import { Utils } from '../../../Utils'; -import "./collectionMulticolumnView.scss"; -import { computed, trace, observable, action } from 'mobx'; -import { Transform } from '../../util/Transform'; - -type MulticolumnDocument = makeInterface<[typeof documentSchema]>; -const MulticolumnDocument = makeInterface(documentSchema); - -interface Unresolved { - target: Doc; - magnitude: number; - unit: string; -} - -interface LayoutData { - unresolved: Unresolved[]; - numFixed: number; - numRatio: number; - starSum: number; -} - -const resolvedUnits = ["*", "px"]; -const resizerWidth = 4; -const resizerOpacity = 1; - -@observer -export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { - - @computed - private get ratioDefinedDocs() { - return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*"); - } - - @computed - private get resolvedLayoutInformation(): LayoutData { - const unresolved: Unresolved[] = []; - let starSum = 0, numFixed = 0, numRatio = 0; - - for (const { layout } of this.childLayoutPairs) { - const unit = StrCast(layout.widthUnit); - const magnitude = NumCast(layout.widthMagnitude); - if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - if (unit === "*") { - starSum += magnitude; - numRatio++; - } else { - numFixed++; - } - unresolved.push({ target: layout, magnitude, unit }); - } - // otherwise, the particular configuration entry is ignored and the remaining - // space is allocated as if the document were absent from the configuration list - } - - - setTimeout(() => { - const { ratioDefinedDocs } = this; - if (ratioDefinedDocs.length > 1) { - const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); - ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); - } - }); - - return { unresolved, numRatio, numFixed, starSum }; - } - - /** - * This returns the total quantity, in pixels, that this - * view needs to reserve for child documents that have - * (with higher priority) requested a fixed pixel width. - * - * If the underlying resolvedLayoutInformation returns null - * because we're waiting on promises to resolve, this value will be undefined as well. - */ - @computed - private get totalFixedAllocation(): number | undefined { - return this.resolvedLayoutInformation?.unresolved.reduce( - (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0); - } - - /** - * This returns the total quantity, in pixels, that this - * view needs to reserve for child documents that have - * (with lower priority) requested a certain relative proportion of the - * remaining pixel width not allocated for fixed widths. - * - * If the underlying totalFixedAllocation returns undefined - * because we're waiting indirectly on promises to resolve, this value will be undefined as well. - */ - @computed - private get totalRatioAllocation(): number | undefined { - const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; - if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); - } - } - - /** - * This returns the total quantity, in pixels, that - * 1* (relative / star unit) is worth. For example, - * if the configuration has three documents, with, respectively, - * widths of 2*, 2* and 1*, and the panel width returns 1000px, - * this accessor returns 1000 / (2 + 2 + 1), or 200px. - * Elsewhere, this is then multiplied by each relative-width - * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px). - * - * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined - * because we're waiting indirectly on promises to resolve, this value will be undefined as well. - */ - @computed - private get columnUnitLength(): number | undefined { - if (this.resolvedLayoutInformation && this.totalRatioAllocation !== undefined) { - return this.totalRatioAllocation / this.resolvedLayoutInformation.starSum; - } - } - - private getColumnUnitLength = () => this.columnUnitLength; - - private lookupPixels = (layout: Doc): number => { - const columnUnitLength = this.columnUnitLength; - if (columnUnitLength === undefined) { - return 0; // we're still waiting on promises to resolve - } - let width = NumCast(layout.widthMagnitude); - if (StrCast(layout.widthUnit) === "*") { - width *= columnUnitLength; - } - return width; - } - - private lookupIndividualTransform = (layout: Doc) => { - const columnUnitLength = this.columnUnitLength; - if (columnUnitLength === undefined) { - return Transform.Identity(); // we're still waiting on promises to resolve - } - let offset = 0; - for (const { layout: candidate } of this.childLayoutPairs) { - if (candidate === layout) { - const shift = offset; - return this.props.ScreenToLocalTransform().translate(-shift, 0); - } - offset += this.lookupPixels(candidate) + resizerWidth; - } - return Transform.Identity(); // type coersion, this case should never be hit - } - - @computed - private get contents(): JSX.Element[] | null { - trace(); - const { childLayoutPairs } = this; - const { Document, PanelHeight } = this.props; - const collector: JSX.Element[] = []; - for (let i = 0; i < childLayoutPairs.length; i++) { - const { layout } = childLayoutPairs[i]; - collector.push( -
- this.lookupPixels(layout)} - PanelHeight={() => PanelHeight() - (BoolCast(Document.showWidthLabels) ? 20 : 0)} - getTransform={() => this.lookupIndividualTransform(layout)} - /> - -
, - - ); - } - collector.pop(); // removes the final extraneous resize bar - return collector; - } - - render(): JSX.Element { - return ( -
- {this.contents} -
- ); - } - -} - -interface ResizerProps { - width: number; - columnUnitLength(): number | undefined; - toLeft?: Doc; - toRight?: Doc; -} - -enum ResizeMode { - Global, - Pinned, - Undefined -} - -@observer -class ResizeBar extends React.Component { - @observable private isHoverActive = false; - @observable private isResizingActive = false; - private resizeMode = ResizeMode.Undefined; - - private registerResizing = (e: React.PointerEvent, mode: ResizeMode) => { - e.stopPropagation(); - e.preventDefault(); - this.resizeMode = mode; - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - window.addEventListener("pointermove", this.onPointerMove); - window.addEventListener("pointerup", this.onPointerUp); - this.isResizingActive = true; - } - - private onPointerMove = ({ movementX }: PointerEvent) => { - const { toLeft, toRight, columnUnitLength } = this.props; - const movingRight = movementX > 0; - const toNarrow = movingRight ? toRight : toLeft; - const toWiden = movingRight ? toLeft : toRight; - const unitLength = columnUnitLength(); - if (unitLength) { - if (toNarrow) { - const { widthUnit, widthMagnitude } = toNarrow; - const scale = widthUnit === "*" ? unitLength : 1; - toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; - } - if (this.resizeMode === ResizeMode.Pinned && toWiden) { - const { widthUnit, widthMagnitude } = toWiden; - const scale = widthUnit === "*" ? unitLength : 1; - toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale; - } - } - } - - private get isActivated() { - const { toLeft, toRight } = this.props; - if (toLeft && toRight) { - if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { - return false; - } - return true; - } else if (toLeft) { - if (StrCast(toLeft.widthUnit) === "px") { - return false; - } - return true; - } else if (toRight) { - if (StrCast(toRight.widthUnit) === "px") { - return false; - } - return true; - } - return false; - } - - @action - private onPointerUp = () => { - this.resizeMode = ResizeMode.Undefined; - this.isResizingActive = false; - this.isHoverActive = false; - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - } - - render() { - return ( -
this.isHoverActive = true)} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} - > -
this.registerResizing(e, ResizeMode.Pinned)} - /> -
this.registerResizing(e, ResizeMode.Global)} - /> -
- ); - } - -} - -interface WidthLabelProps { - layout: Doc; - collectionDoc: Doc; - decimals?: number; -} - -@observer -class WidthLabel extends React.Component { - - @computed - private get contents() { - const { layout, decimals } = this.props; - const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); - const unit = StrCast(layout.widthUnit); - return {magnitude} {unit}; - } - - render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); - } - -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index db4da30d1..a665b678b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -27,7 +27,7 @@ import { CollectionDockingView } from "./CollectionDockingView"; import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionLinearView } from './CollectionLinearView'; -import { CollectionMulticolumnView } from './CollectionMulticolumnView'; +import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionPivotView } from './CollectionPivotView'; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss new file mode 100644 index 000000000..062b8ac11 --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -0,0 +1,31 @@ +.collectionMulticolumnView_contents { + display: flex; + width: 100%; + height: 100%; + overflow: hidden; + + .document-wrapper { + display: flex; + flex-direction: column; + + .display { + text-align: center; + height: 20px; + } + + } + + .resizer { + cursor: ew-resize; + transition: 0.5s opacity ease; + display: flex; + flex-direction: column; + + .internal { + width: 100%; + height: 100%; + transition: 0.5s background-color ease; + } + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx new file mode 100644 index 000000000..e57e5eb26 --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -0,0 +1,205 @@ +import { observer } from 'mobx-react'; +import { makeInterface } from '../../../../new_fields/Schema'; +import { documentSchema } from '../../../../new_fields/documentSchemas'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import * as React from "react"; +import { Doc } from '../../../../new_fields/Doc'; +import { NumCast, StrCast, BoolCast } from '../../../../new_fields/Types'; +import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; +import { Utils } from '../../../../Utils'; +import "./collectionMulticolumnView.scss"; +import { computed, trace, observable, action } from 'mobx'; +import { Transform } from '../../../util/Transform'; +import WidthLabel from './MulticolumnWidthLabel'; +import ResizeBar from './MulticolumnResizer'; + +type MulticolumnDocument = makeInterface<[typeof documentSchema]>; +const MulticolumnDocument = makeInterface(documentSchema); + +interface Unresolved { + target: Doc; + magnitude: number; + unit: string; +} + +interface LayoutData { + unresolved: Unresolved[]; + numFixed: number; + numRatio: number; + starSum: number; +} + +const resolvedUnits = ["*", "px"]; +const resizerWidth = 4; + +@observer +export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + + @computed + private get ratioDefinedDocs() { + return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*"); + } + + @computed + private get resolvedLayoutInformation(): LayoutData { + const unresolved: Unresolved[] = []; + let starSum = 0, numFixed = 0, numRatio = 0; + + for (const { layout } of this.childLayoutPairs) { + const unit = StrCast(layout.widthUnit); + const magnitude = NumCast(layout.widthMagnitude); + if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { + if (unit === "*") { + starSum += magnitude; + numRatio++; + } else { + numFixed++; + } + unresolved.push({ target: layout, magnitude, unit }); + } + // otherwise, the particular configuration entry is ignored and the remaining + // space is allocated as if the document were absent from the configuration list + } + + + setTimeout(() => { + const { ratioDefinedDocs } = this; + if (ratioDefinedDocs.length > 1) { + const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); + ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + } + }); + + return { unresolved, numRatio, numFixed, starSum }; + } + + /** + * This returns the total quantity, in pixels, that this + * view needs to reserve for child documents that have + * (with higher priority) requested a fixed pixel width. + * + * If the underlying resolvedLayoutInformation returns null + * because we're waiting on promises to resolve, this value will be undefined as well. + */ + @computed + private get totalFixedAllocation(): number | undefined { + return this.resolvedLayoutInformation?.unresolved.reduce( + (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0); + } + + /** + * This returns the total quantity, in pixels, that this + * view needs to reserve for child documents that have + * (with lower priority) requested a certain relative proportion of the + * remaining pixel width not allocated for fixed widths. + * + * If the underlying totalFixedAllocation returns undefined + * because we're waiting indirectly on promises to resolve, this value will be undefined as well. + */ + @computed + private get totalRatioAllocation(): number | undefined { + const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; + if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { + return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); + } + } + + /** + * This returns the total quantity, in pixels, that + * 1* (relative / star unit) is worth. For example, + * if the configuration has three documents, with, respectively, + * widths of 2*, 2* and 1*, and the panel width returns 1000px, + * this accessor returns 1000 / (2 + 2 + 1), or 200px. + * Elsewhere, this is then multiplied by each relative-width + * document's (potentially decimal) * count to compute its actual width (400px, 400px and 200px). + * + * If the underlying totalRatioAllocation or this.resolveLayoutInformation return undefined + * because we're waiting indirectly on promises to resolve, this value will be undefined as well. + */ + @computed + private get columnUnitLength(): number | undefined { + if (this.resolvedLayoutInformation && this.totalRatioAllocation !== undefined) { + return this.totalRatioAllocation / this.resolvedLayoutInformation.starSum; + } + } + + private getColumnUnitLength = () => this.columnUnitLength; + + private lookupPixels = (layout: Doc): number => { + const columnUnitLength = this.columnUnitLength; + if (columnUnitLength === undefined) { + return 0; // we're still waiting on promises to resolve + } + let width = NumCast(layout.widthMagnitude); + if (StrCast(layout.widthUnit) === "*") { + width *= columnUnitLength; + } + return width; + } + + private lookupIndividualTransform = (layout: Doc) => { + const columnUnitLength = this.columnUnitLength; + if (columnUnitLength === undefined) { + return Transform.Identity(); // we're still waiting on promises to resolve + } + let offset = 0; + for (const { layout: candidate } of this.childLayoutPairs) { + if (candidate === layout) { + const shift = offset; + return this.props.ScreenToLocalTransform().translate(-shift, 0); + } + offset += this.lookupPixels(candidate) + resizerWidth; + } + return Transform.Identity(); // type coersion, this case should never be hit + } + + @computed + private get contents(): JSX.Element[] | null { + const { childLayoutPairs } = this; + const { Document, PanelHeight } = this.props; + const collector: JSX.Element[] = []; + for (let i = 0; i < childLayoutPairs.length; i++) { + const { layout } = childLayoutPairs[i]; + collector.push( +
+ this.lookupPixels(layout)} + PanelHeight={() => PanelHeight() - (BoolCast(Document.showWidthLabels) ? 20 : 0)} + getTransform={() => this.lookupIndividualTransform(layout)} + /> + +
, + + ); + } + collector.pop(); // removes the final extraneous resize bar + return collector; + } + + render(): JSX.Element { + return ( +
+ {this.contents} +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx new file mode 100644 index 000000000..aab98ecfd --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -0,0 +1,115 @@ +import * as React from "react"; +import { observer } from "mobx-react"; +import { observable, action } from "mobx"; +import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, StrCast } from "../../../../new_fields/Types"; + +interface ResizerProps { + width: number; + columnUnitLength(): number | undefined; + toLeft?: Doc; + toRight?: Doc; +} + +enum ResizeMode { + Global = "blue", + Pinned = "red", + Undefined = "black" +} + +const resizerOpacity = 1; + +@observer +export default class ResizeBar extends React.Component { + @observable private isHoverActive = false; + @observable private isResizingActive = false; + @observable private resizeMode = ResizeMode.Undefined; + + @action + private registerResizing = (e: React.PointerEvent, mode: ResizeMode) => { + e.stopPropagation(); + e.preventDefault(); + this.resizeMode = mode; + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + window.addEventListener("pointermove", this.onPointerMove); + window.addEventListener("pointerup", this.onPointerUp); + this.isResizingActive = true; + } + + private onPointerMove = ({ movementX }: PointerEvent) => { + const { toLeft, toRight, columnUnitLength } = this.props; + const movingRight = movementX > 0; + const toNarrow = movingRight ? toRight : toLeft; + const toWiden = movingRight ? toLeft : toRight; + const unitLength = columnUnitLength(); + if (unitLength) { + if (toNarrow) { + const { widthUnit, widthMagnitude } = toNarrow; + const scale = widthUnit === "*" ? unitLength : 1; + toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; + } + if (this.resizeMode === ResizeMode.Pinned && toWiden) { + const { widthUnit, widthMagnitude } = toWiden; + const scale = widthUnit === "*" ? unitLength : 1; + toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale; + } + } + } + + private get isActivated() { + const { toLeft, toRight } = this.props; + if (toLeft && toRight) { + if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { + return false; + } + return true; + } else if (toLeft) { + if (StrCast(toLeft.widthUnit) === "px") { + return false; + } + return true; + } else if (toRight) { + if (StrCast(toRight.widthUnit) === "px") { + return false; + } + return true; + } + return false; + } + + @action + private onPointerUp = () => { + this.resizeMode = ResizeMode.Undefined; + this.isResizingActive = false; + this.isHoverActive = false; + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + } + + render() { + return ( +
this.isHoverActive = true)} + onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} + > +
this.registerResizing(e, ResizeMode.Pinned)} + style={{ backgroundColor: this.resizeMode }} + /> +
this.registerResizing(e, ResizeMode.Global)} + style={{ backgroundColor: this.resizeMode }} + /> +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx new file mode 100644 index 000000000..e33d4c169 --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import { observer } from "mobx-react"; +import { computed } from "mobx"; +import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types"; + +interface WidthLabelProps { + layout: Doc; + collectionDoc: Doc; + decimals?: number; +} + +@observer +export default class WidthLabel extends React.Component { + + @computed + private get contents() { + const { layout, decimals } = this.props; + const magnitude = +NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); + const unit = StrCast(layout.widthUnit); + return {magnitude} {unit}; + } + + render() { + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + } + +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9e90f5cb1d481889def9fe22b7e5d152777ea95d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 18 Jan 2020 16:44:31 -0500 Subject: cleanup and commenting --- .../CollectionMulticolumnView.tsx | 92 +++++++++++++++------- 1 file changed, 62 insertions(+), 30 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index e57e5eb26..d2209224f 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -16,16 +16,13 @@ import ResizeBar from './MulticolumnResizer'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); -interface Unresolved { - target: Doc; +interface WidthSpecifier { magnitude: number; unit: string; } interface LayoutData { - unresolved: Unresolved[]; - numFixed: number; - numRatio: number; + widthSpecifiers: WidthSpecifier[]; starSum: number; } @@ -35,42 +32,57 @@ const resizerWidth = 4; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + /** + * @returns the list of layout documents whose width unit is + * *, denoting that it will be displayed with a ratio, not fixed pixel, value + */ @computed private get ratioDefinedDocs() { return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*"); } + /** + * This loops through all childLayoutPairs and extracts the values for widthUnit + * and widthMagnitude, ignoring any that are malformed. Additionally, it then + * normalizes the ratio values so that one * value is always 1, with the remaining + * values proportionate to that easily readable metric. + * @returns the list of the resolved width specifiers (unit and magnitude pairs) + * as well as the sum of the * coefficients, i.e. the ratio magnitudes + */ @computed private get resolvedLayoutInformation(): LayoutData { - const unresolved: Unresolved[] = []; - let starSum = 0, numFixed = 0, numRatio = 0; - - for (const { layout } of this.childLayoutPairs) { - const unit = StrCast(layout.widthUnit); - const magnitude = NumCast(layout.widthMagnitude); + let starSum = 0; + const widthSpecifiers: WidthSpecifier[] = []; + this.childLayoutPairs.map(({ layout: { widthUnit, widthMagnitude } }) => { + const unit = StrCast(widthUnit); + const magnitude = NumCast(widthMagnitude); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - if (unit === "*") { - starSum += magnitude; - numRatio++; - } else { - numFixed++; - } - unresolved.push({ target: layout, magnitude, unit }); + (unit === "*") && (starSum += magnitude); + widthSpecifiers.push({ magnitude, unit }); } - // otherwise, the particular configuration entry is ignored and the remaining - // space is allocated as if the document were absent from the configuration list - } - + /** + * Otherwise, the child document is ignored and the remaining + * space is allocated as if the document were absent from the child list + */ + }); + /** + * Here, since these values are all relative, adjustments during resizing or + * manual updating can, though their ratios remain the same, cause the values + * themselves to drift toward zero. Thus, whenever we change any of the values, + * we normalize everything (dividing by the smallest magnitude). + */ setTimeout(() => { const { ratioDefinedDocs } = this; if (ratioDefinedDocs.length > 1) { const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); - ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + if (minimum !== 0) { + ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + } } }); - return { unresolved, numRatio, numFixed, starSum }; + return { widthSpecifiers, starSum }; } /** @@ -83,12 +95,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ @computed private get totalFixedAllocation(): number | undefined { - return this.resolvedLayoutInformation?.unresolved.reduce( + return this.resolvedLayoutInformation?.widthSpecifiers.reduce( (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0); } /** - * This returns the total quantity, in pixels, that this + * @returns the total quantity, in pixels, that this * view needs to reserve for child documents that have * (with lower priority) requested a certain relative proportion of the * remaining pixel width not allocated for fixed widths. @@ -98,14 +110,14 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ @computed private get totalRatioAllocation(): number | undefined { - const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; + const layoutInfoLen = this.ratioDefinedDocs.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); } } /** - * This returns the total quantity, in pixels, that + * @returns the total quantity, in pixels, that * 1* (relative / star unit) is worth. For example, * if the configuration has three documents, with, respectively, * widths of 2*, 2* and 1*, and the panel width returns 1000px, @@ -123,8 +135,19 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } } + /** + * This wrapper function exists to prevent mobx from + * needlessly rerendering the internal ContentFittingDocumentViews + */ private getColumnUnitLength = () => this.columnUnitLength; + /** + * @param layout the document whose transform we'd like to compute + * Given a layout document, this function + * returns the resolved width it has requested, in pixels. + * @returns the stored column width if already in pixels, + * or the ratio width evaluated to a pixel value + */ private lookupPixels = (layout: Doc): number => { const columnUnitLength = this.columnUnitLength; if (columnUnitLength === undefined) { @@ -137,6 +160,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu return width; } + /** + * @returns the transform that will correctly place + * the document decorations box, shifted to the right by + * the sum of all the resolved column widths of the + * documents before the target. + */ private lookupIndividualTransform = (layout: Doc) => { const columnUnitLength = this.columnUnitLength; if (columnUnitLength === undefined) { @@ -145,14 +174,17 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - const shift = offset; - return this.props.ScreenToLocalTransform().translate(-shift, 0); + return this.props.ScreenToLocalTransform().translate(-offset, 0); } offset += this.lookupPixels(candidate) + resizerWidth; } return Transform.Identity(); // type coersion, this case should never be hit } + /** + * @returns the resolved list of rendered child documents, displayed + * at their resolved pixel widths, each separated by a resizer. + */ @computed private get contents(): JSX.Element[] | null { const { childLayoutPairs } = this; -- cgit v1.2.3-70-g09d2 From ca7faa46af2bcbc6651891c8f1430dedea55b8be Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 18 Jan 2020 17:33:24 -0500 Subject: switched mcview labels to editable views --- .../CollectionMulticolumnView.scss | 6 ++-- .../CollectionMulticolumnView.tsx | 19 +++++++----- .../collectionMulticolumn/MulticolumnResizer.tsx | 11 +++---- .../MulticolumnWidthLabel.tsx | 34 ++++++++++++++++++++-- 4 files changed, 53 insertions(+), 17 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index 062b8ac11..f57ba438a 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -8,8 +8,10 @@ display: flex; flex-direction: column; - .display { - text-align: center; + .label-wrapper { + display: flex; + flex-direction: row; + justify-content: center; height: 20px; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index d2209224f..70e56183c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -26,7 +26,12 @@ interface LayoutData { starSum: number; } -const resolvedUnits = ["*", "px"]; +export const WidthUnit = { + Pixel: "px", + Ratio: "*" +}; + +const resolvedUnits = Object.values(WidthUnit); const resizerWidth = 4; @observer @@ -38,7 +43,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ @computed private get ratioDefinedDocs() { - return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*"); + return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === WidthUnit.Ratio); } /** @@ -57,7 +62,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu const unit = StrCast(widthUnit); const magnitude = NumCast(widthMagnitude); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - (unit === "*") && (starSum += magnitude); + (unit === WidthUnit.Ratio) && (starSum += magnitude); widthSpecifiers.push({ magnitude, unit }); } /** @@ -74,7 +79,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ setTimeout(() => { const { ratioDefinedDocs } = this; - if (ratioDefinedDocs.length > 1) { + if (this.childLayoutPairs.length) { const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); if (minimum !== 0) { ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); @@ -96,7 +101,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu @computed private get totalFixedAllocation(): number | undefined { return this.resolvedLayoutInformation?.widthSpecifiers.reduce( - (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0); + (sum, { magnitude, unit }) => sum + (unit === WidthUnit.Pixel ? magnitude : 0), 0); } /** @@ -110,7 +115,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu */ @computed private get totalRatioAllocation(): number | undefined { - const layoutInfoLen = this.ratioDefinedDocs.length; + const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); } @@ -154,7 +159,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu return 0; // we're still waiting on promises to resolve } let width = NumCast(layout.widthMagnitude); - if (StrCast(layout.widthUnit) === "*") { + if (StrCast(layout.widthUnit) === WidthUnit.Ratio) { width *= columnUnitLength; } return width; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index aab98ecfd..11e210958 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -3,6 +3,7 @@ import { observer } from "mobx-react"; import { observable, action } from "mobx"; import { Doc } from "../../../../new_fields/Doc"; import { NumCast, StrCast } from "../../../../new_fields/Types"; +import { WidthUnit } from "./CollectionMulticolumnView"; interface ResizerProps { width: number; @@ -46,12 +47,12 @@ export default class ResizeBar extends React.Component { if (unitLength) { if (toNarrow) { const { widthUnit, widthMagnitude } = toNarrow; - const scale = widthUnit === "*" ? unitLength : 1; + const scale = widthUnit === WidthUnit.Ratio ? unitLength : 1; toNarrow.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; } if (this.resizeMode === ResizeMode.Pinned && toWiden) { const { widthUnit, widthMagnitude } = toWiden; - const scale = widthUnit === "*" ? unitLength : 1; + const scale = widthUnit === WidthUnit.Ratio ? unitLength : 1; toWiden.widthMagnitude = NumCast(widthMagnitude) + Math.abs(movementX) / scale; } } @@ -60,17 +61,17 @@ export default class ResizeBar extends React.Component { private get isActivated() { const { toLeft, toRight } = this.props; if (toLeft && toRight) { - if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { + if (StrCast(toLeft.widthUnit) === WidthUnit.Pixel && StrCast(toRight.widthUnit) === WidthUnit.Pixel) { return false; } return true; } else if (toLeft) { - if (StrCast(toLeft.widthUnit) === "px") { + if (StrCast(toLeft.widthUnit) === WidthUnit.Pixel) { return false; } return true; } else if (toRight) { - if (StrCast(toRight.widthUnit) === "px") { + if (StrCast(toRight.widthUnit) === WidthUnit.Pixel) { return false; } return true; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx index e33d4c169..b394fed62 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -3,6 +3,8 @@ import { observer } from "mobx-react"; import { computed } from "mobx"; import { Doc } from "../../../../new_fields/Doc"; import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types"; +import { EditableView } from "../../EditableView"; +import { WidthUnit } from "./CollectionMulticolumnView"; interface WidthLabelProps { layout: Doc; @@ -16,9 +18,35 @@ export default class WidthLabel extends React.Component { @computed private get contents() { const { layout, decimals } = this.props; - const magnitude = +NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); - const unit = StrCast(layout.widthUnit); - return {magnitude} {unit}; + const getUnit = () => StrCast(layout.widthUnit); + const getMagnitude = () => String(+NumCast(layout.widthMagnitude).toFixed(decimals ?? 3)); + return ( +
+ { + const converted = Number(value); + if (!isNaN(converted) && converted > 0) { + layout.widthMagnitude = converted; + return true; + } + return false; + }} + contents={getMagnitude()} + /> + { + if (Object.values(WidthUnit).includes(value)) { + layout.widthUnit = value; + return true; + } + return false; + }} + contents={getUnit()} + /> +
+ ); } render() { -- cgit v1.2.3-70-g09d2 From 76ca4c61c5bf68649b889ed6ac8b5f6dc5b16e0b Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 18 Jan 2020 23:25:22 -0500 Subject: added initial DocumentFromField implementation --- src/client/documents/Documents.ts | 42 ++++++++++++++++++++- .../CollectionStackingViewFieldColumn.tsx | 17 +++------ src/scraping/buxton/scraper.py | 2 +- src/scraping/buxton/source/Bill_Notes_NB75D.docx | Bin 0 -> 27696302 bytes 4 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/scraping/buxton/source/Bill_Notes_NB75D.docx (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index eacdd8214..9c064ece5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -19,7 +19,7 @@ import { AggregateFunction } from "../northstar/model/idea/idea"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { IconBox } from "../views/nodes/IconBox"; import { OmitKeys, JSONUtils } from "../../Utils"; -import { Field, Doc, Opt, DocListCastAsync } from "../../new_fields/Doc"; +import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc"; import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField"; import { HtmlField } from "../../new_fields/HtmlField"; import { List } from "../../new_fields/List"; @@ -51,6 +51,7 @@ import { DocuLinkBox } from "../views/nodes/DocuLinkBox"; import { DocumentBox } from "../views/nodes/DocumentBox"; import { InkingStroke } from "../views/InkingStroke"; import { InkField } from "../../new_fields/InkField"; +import { InkingControl } from "../views/InkingControl"; const requestImageSize = require('../util/request-image-size'); const path = require('path'); @@ -655,6 +656,45 @@ export namespace Docs { throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`); }; + export function DocumentFromField(target: Doc, fieldKey: string, proto?: Doc, options?: DocumentOptions): Doc | undefined { + let created: Doc | undefined; + let layout: ((fieldKey: string) => string) | undefined; + const field = target[fieldKey]; + const resolved = options || {}; + if (field instanceof ImageField) { + created = Docs.Create.ImageDocument((field as ImageField).url.href, resolved); + layout = ImageBox.LayoutString; + } else if (field instanceof VideoField) { + created = Docs.Create.VideoDocument((field as VideoField).url.href, resolved); + layout = VideoBox.LayoutString; + } else if (field instanceof PdfField) { + created = Docs.Create.PdfDocument((field as PdfField).url.href, resolved); + layout = PDFBox.LayoutString; + } else if (field instanceof IconField) { + created = Docs.Create.IconDocument((field as IconField).icon, resolved); + layout = IconBox.LayoutString; + } else if (field instanceof AudioField) { + created = Docs.Create.AudioDocument((field as AudioField).url.href, resolved); + layout = AudioBox.LayoutString; + } else if (field instanceof HistogramField) { + created = Docs.Create.HistogramDocument((field as HistogramField).HistoOp, resolved); + layout = HistogramBox.LayoutString; + } else if (field instanceof InkField) { + const { selectedColor, selectedWidth, selectedTool } = InkingControl.Instance; + created = Docs.Create.InkDocument(selectedColor, selectedTool, Number(selectedWidth), (field as InkField).inkData, resolved); + layout = InkingStroke.LayoutString; + } else if (field instanceof List && field[0] instanceof Doc) { + created = Docs.Create.StackingDocument(DocListCast(field), resolved); + layout = CollectionView.LayoutString; + } else { + created = Docs.Create.TextDocument({ ...{ width: 200, height: 25, autoHeight: true }, ...resolved }); + layout = FormattedTextBox.LayoutString; + } + created.layout = layout(fieldKey); + proto && (created.proto = Doc.GetProto(proto)); + return created; + } + export async function DocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 9cdb9b281..23a664359 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -138,18 +138,11 @@ export class CollectionStackingViewFieldColumn extends React.Component Date: Mon, 20 Jan 2020 00:34:45 -0500 Subject: close to buxton's initial workflow --- src/client/documents/Documents.ts | 4 ++++ src/client/util/DropConverter.ts | 3 +-- src/client/views/collections/CollectionPivotView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 17 +++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c3f03aede..4fe13fa78 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -518,6 +518,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Stacking }); } + export function MulticolumnDocument(documents: Array, options: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Multicolumn }); + } + export function MasonryDocument(documents: Array, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Masonry }); } diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index dc66bceee..3e2cc6a2e 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -7,8 +7,7 @@ import { StrCast } from "../../new_fields/Types"; import { Docs } from "../documents/Documents"; import { ScriptField } from "../../new_fields/ScriptField"; - -function makeTemplate(doc: Doc): boolean { +export function makeTemplate(doc: Doc): boolean { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0]; const fieldKey = layout.replace("fieldKey={'", "").replace(/'}$/, ""); diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 6af7cce70..02cd2e2c9 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -34,7 +34,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { facetCollection.onCheckedClick = new ScriptField(script); } - const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layoutCustom'; useRightSplit(alias); "; + const openDocText = "const alias = getAlias(this); alias.layoutKey = 'detailedDeviceView'; useRightSplit(alias); "; const openDocScript = CompileScript(openDocText, { params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name }, typecheck: false, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70860b6bd..239e6caa6 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -29,6 +29,8 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { ScriptBox } from '../ScriptBox'; +import { ImageBox } from '../nodes/ImageBox'; +import { makeTemplate } from '../../util/DropConverter'; export interface TreeViewProps { @@ -628,6 +630,21 @@ export class CollectionTreeView extends CollectionSubView(Document) { layoutItems.push({ description: (this.props.Document.hideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.hideHeaderFields = !this.props.Document.hideHeaderFields, icon: "paint-brush" }); ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" }); } + ContextMenu.Instance.addItem({ + description: "Buxton Layout", icon: "eye", event: () => { + // const [first, second, third] = new Array(3).map(() => Docs.Create.MulticolumnDocument([], {})); + const year = Docs.Create.FreeformDocument([], { title: "year" }); + const wrapper = Docs.Create.FreeformDocument([year], {}); + makeTemplate(wrapper); + const detailedLayout = Doc.MakeAlias(wrapper); + const cardLayout = ImageBox.LayoutString("hero"); + this.childLayoutPairs.forEach(({ layout }) => { + layout.layout = cardLayout; + layout.detailedDeviceView = detailedLayout; + // Doc.ApplyTemplateTo(wrapper, layout, "detailedDeviceView"); + }); + } + }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document, "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean" }) }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 60dc253f7..8c7361673 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -562,7 +562,7 @@ export class DocumentView extends DocComponent(Docu this.props.Document.viewType = CollectionViewType.Stacking; this.props.Document.layoutKey = "layout_narrative"; } else { - DocumentView.makeNativeViewClicked(this.props.Document) + DocumentView.makeNativeViewClicked(this.props.Document); } } -- cgit v1.2.3-70-g09d2 From e2d6f1d930f0f092d975bd221c45d07a8620efa7 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 20 Jan 2020 09:20:42 -0500 Subject: nothing changes. --- src/client/views/collections/CollectionPivotView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 02cd2e2c9..bada8ff28 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -34,7 +34,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { facetCollection.onCheckedClick = new ScriptField(script); } - const openDocText = "const alias = getAlias(this); alias.layoutKey = 'detailedDeviceView'; useRightSplit(alias); "; + const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layout_detailed'; useRightSplit(alias); "; const openDocScript = CompileScript(openDocText, { params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name }, typecheck: false, diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 239e6caa6..abc902491 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -633,15 +633,16 @@ export class CollectionTreeView extends CollectionSubView(Document) { ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { // const [first, second, third] = new Array(3).map(() => Docs.Create.MulticolumnDocument([], {})); - const year = Docs.Create.FreeformDocument([], { title: "year" }); + const year = Docs.Create.TextDocument({ title: "year" }); const wrapper = Docs.Create.FreeformDocument([year], {}); + wrapper.disableLOD = true; makeTemplate(wrapper); const detailedLayout = Doc.MakeAlias(wrapper); const cardLayout = ImageBox.LayoutString("hero"); this.childLayoutPairs.forEach(({ layout }) => { - layout.layout = cardLayout; - layout.detailedDeviceView = detailedLayout; - // Doc.ApplyTemplateTo(wrapper, layout, "detailedDeviceView"); + Doc.GetProto(layout).layout = cardLayout; + Doc.GetProto(layout).layout_detailed = detailedLayout; + // Doc.ApplyTemplateTo(wrapper, layout, "layout_detailed"); }); } }); -- cgit v1.2.3-70-g09d2 From 48e4149457f1075748397d4804db9e0c198b5e2e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 20 Jan 2020 09:58:02 -0500 Subject: templating fixes --- src/client/views/collections/CollectionTreeView.tsx | 7 ++++++- src/client/views/nodes/DocumentView.tsx | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index abc902491..0f61756f4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -31,6 +31,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_ import { ScriptBox } from '../ScriptBox'; import { ImageBox } from '../nodes/ImageBox'; import { makeTemplate } from '../../util/DropConverter'; +import { CollectionDockingView } from './CollectionDockingView'; export interface TreeViewProps { @@ -634,9 +635,12 @@ export class CollectionTreeView extends CollectionSubView(Document) { description: "Buxton Layout", icon: "eye", event: () => { // const [first, second, third] = new Array(3).map(() => Docs.Create.MulticolumnDocument([], {})); const year = Docs.Create.TextDocument({ title: "year" }); - const wrapper = Docs.Create.FreeformDocument([year], {}); + const wrapper = Docs.Create.StackingDocument([year], { autoHeight: true, chromeStatus: "disabled" }); wrapper.disableLOD = true; makeTemplate(wrapper); + delete Doc.GetProto(year).showTitle; + delete year.showTitle; + const detailedLayout = Doc.MakeAlias(wrapper); const cardLayout = ImageBox.LayoutString("hero"); this.childLayoutPairs.forEach(({ layout }) => { @@ -644,6 +648,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { Doc.GetProto(layout).layout_detailed = detailedLayout; // Doc.ApplyTemplateTo(wrapper, layout, "layout_detailed"); }); + CollectionDockingView.AddRightSplit(wrapper, undefined); } }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8c7361673..29f658eca 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -759,7 +759,7 @@ export class DocumentView extends DocComponent(Docu return (showTitle && !showTitleHover ? 0 : 0) + 1; } - @computed get finalLayoutKey() { return this.props.layoutKey || StrCast(this.props.Document.layoutKey, "layout"); } + @computed get finalLayoutKey() { return this.props.layoutKey || "layout"; } childScaling = () => (this.layoutDoc.fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); @computed get contents() { TraceMobx(); -- cgit v1.2.3-70-g09d2 From cdde5624bac14ba6e0520a2d30d8d3926f2cc27f Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 20 Jan 2020 12:19:40 -0500 Subject: buxton layout improvements --- src/client/util/DropConverter.ts | 4 +-- .../views/collections/CollectionTreeView.tsx | 30 +++++++++++++--------- src/scraping/buxton/scraper.py | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 3e2cc6a2e..ff0e19347 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -7,7 +7,7 @@ import { StrCast } from "../../new_fields/Types"; import { Docs } from "../documents/Documents"; import { ScriptField } from "../../new_fields/ScriptField"; -export function makeTemplate(doc: Doc): boolean { +export function makeTemplate(doc: Doc, suppressTitle = false): boolean { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0]; const fieldKey = layout.replace("fieldKey={'", "").replace(/'}$/, ""); @@ -16,7 +16,7 @@ export function makeTemplate(doc: Doc): boolean { docs.forEach(d => { if (!StrCast(d.title).startsWith("-")) { any = true; - Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)); + Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc), suppressTitle); } else if (d.type === DocumentType.COL) { any = makeTemplate(d) || any; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 0f61756f4..a48208bd9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -633,27 +633,33 @@ export class CollectionTreeView extends CollectionSubView(Document) { } ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { - // const [first, second, third] = new Array(3).map(() => Docs.Create.MulticolumnDocument([], {})); - const year = Docs.Create.TextDocument({ title: "year" }); - const wrapper = Docs.Create.StackingDocument([year], { autoHeight: true, chromeStatus: "disabled" }); + const { TextDocument, ImageDocument } = Docs.Create; + const wrapper = Docs.Create.StackingDocument([ + ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "hero" }), + TextDocument({ title: "year" }), + TextDocument({ title: "degrees_of_freedom" }), + TextDocument({ title: "company" }), + TextDocument({ title: "short_description" }), + ], { autoHeight: true, chromeStatus: "disabled" }); wrapper.disableLOD = true; - makeTemplate(wrapper); - delete Doc.GetProto(year).showTitle; - delete year.showTitle; - + makeTemplate(wrapper, true); const detailedLayout = Doc.MakeAlias(wrapper); const cardLayout = ImageBox.LayoutString("hero"); this.childLayoutPairs.forEach(({ layout }) => { - Doc.GetProto(layout).layout = cardLayout; - Doc.GetProto(layout).layout_detailed = detailedLayout; - // Doc.ApplyTemplateTo(wrapper, layout, "layout_detailed"); + const proto = Doc.GetProto(layout); + proto.layout = cardLayout; + proto.layout_detailed = detailedLayout; + layout.showTitle = "title"; + layout.showTitleHover = "titlehover"; }); - CollectionDockingView.AddRightSplit(wrapper, undefined); } }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; - onClicks.push({ description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document, "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean" }) }); + onClicks.push({ + description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document, + "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean", context: Doc.name }) + }); !existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" }); } outerXf = () => Utils.GetScreenTransform(this._mainEle!); diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index 15b5844f7..998c7617d 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -100,9 +100,9 @@ def write_collection(parse_results, display_fields, storage_key, viewType): fields[storage_key] = listify(proxify_guids(view_guids)) fields["schemaColumns"] = listify(display_fields) fields["backgroundColor"] = "white" - fields["scale"] = 0.5 fields["viewType"] = 2 fields["author"] = "Bill Buxton" + fielsd["disableLOD"] = True, fields["creationDate"] = { "date": datetime.datetime.utcnow().microsecond, "__type": "date" -- cgit v1.2.3-70-g09d2 From df61d40f92a29f948d9f513fb9f50349f16500ee Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 20 Jan 2020 12:45:47 -0500 Subject: pivot componentDidMount true hack --- src/client/views/collections/CollectionPivotView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index bada8ff28..53ad433b3 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -20,7 +20,7 @@ import { Set } from "typescript-collections"; export class CollectionPivotView extends CollectionSubView(doc => doc) { componentDidMount = () => { this.props.Document.freeformLayoutEngine = "pivot"; - if (!this.props.Document.facetCollection) { + if (true || !this.props.Document.facetCollection) { const facetCollection = Docs.Create.FreeformDocument([], { title: "facetFilters", yMargin: 0, treeViewHideTitle: true }); facetCollection.target = this.props.Document; -- cgit v1.2.3-70-g09d2