From fcd9313158f8c131cf5a124880c46ca7b20a1b25 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 16 Jan 2020 11:43:38 -0500 Subject: better fix for sidebar / stacking view sizing --- src/client/views/MainView.scss | 8 -------- src/client/views/collections/CollectionStackingView.tsx | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index c7fc6096a..4c8c95529 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -5,9 +5,6 @@ .mainView-tabButtons { position: relative; width: 100%; - .documentView-node-topmost { - height: 200% !important; - } } .mainContent-div { @@ -16,11 +13,6 @@ height:100%; } -.mainView-contentArea { - .documentView-node-topmost { - height: 200% !important; - } -} // add nodes menu. Note that the + button is actually an input label, not an actual button. .mainView-docButtons { position: absolute; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 886a9c870..ca792c134 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -396,7 +396,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ref={this.createRef} style={{ transform: `scale(${Math.min(1, this.props.PanelHeight() / this.layoutDoc[HeightSym]())})`, - height: `${100 * 1 / Math.min(this.props.PanelWidth() / this.layoutDoc[WidthSym](), this.props.PanelHeight() / this.layoutDoc[HeightSym]())}%`, + height: `${Math.max(100, 100 * 1 / Math.min(this.props.PanelWidth() / this.layoutDoc[WidthSym](), this.props.PanelHeight() / this.layoutDoc[HeightSym]()))}%`, transformOrigin: "top" }} onScroll={action((e: React.UIEvent) => this._scroll = e.currentTarget.scrollTop)} -- cgit v1.2.3-70-g09d2 From 00029dc0ef5e9ee1917523dc0d5c49fa1de82562 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 16 Jan 2020 15:39:13 -0500 Subject: session key --- src/server/ApiManagers/SessionManager.ts | 7 +++---- src/server/RouteManager.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/server/ApiManagers/SessionManager.ts b/src/server/ApiManagers/SessionManager.ts index a99aa05e0..f1629b8f0 100644 --- a/src/server/ApiManagers/SessionManager.ts +++ b/src/server/ApiManagers/SessionManager.ts @@ -8,16 +8,15 @@ const permissionError = "You are not authorized!"; export default class SessionManager extends ApiManager { - private secureSubscriber = (root: string, ...params: string[]) => new RouteSubscriber(root).add("sessionKey", ...params); + private secureSubscriber = (root: string, ...params: string[]) => new RouteSubscriber(root).add("session_key", ...params); private authorizedAction = (handler: SecureHandler) => { return (core: AuthorizedCore) => { - const { req, res, isRelease } = core; - const { sessionKey } = req.params; + const { req: { params }, res, isRelease } = core; if (!isRelease) { return res.send("This can be run only on the release server."); } - if (sessionKey !== process.env.session_key) { + if (params.session_key !== process.env.session_key) { return _permission_denied(res, permissionError); } return handler(core); diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts index 5afd607fd..f9ffdaa80 100644 --- a/src/server/RouteManager.ts +++ b/src/server/RouteManager.ts @@ -197,5 +197,5 @@ export function _permission_denied(res: express.Response, message?: string) { if (message) { res.statusMessage = message; } - res.status(STATUS.BAD_REQUEST).send("Permission Denied!"); + res.status(STATUS.PERMISSION_DENIED).send("Permission Denied!"); } -- cgit v1.2.3-70-g09d2 From e183f40509edec426b6519fe77590792c1f3f346 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 16 Jan 2020 16:15:26 -0500 Subject: pivot viewer improvements. --- .../tmp/start_8210707001248201939.properties | 11 ++ src/client/documents/Documents.ts | 5 + .../views/collections/CollectionDockingView.tsx | 33 ++++++ .../views/collections/CollectionPivotView.scss | 57 ++++++++++ .../views/collections/CollectionPivotView.tsx | 119 +++++++++++++++++++++ .../views/collections/CollectionTreeView.tsx | 23 ++-- src/client/views/collections/CollectionView.tsx | 3 +- 7 files changed, 239 insertions(+), 12 deletions(-) create mode 100644 solr-8.3.1/server/tmp/start_8210707001248201939.properties create mode 100644 src/client/views/collections/CollectionPivotView.scss create mode 100644 src/client/views/collections/CollectionPivotView.tsx (limited to 'src') diff --git a/solr-8.3.1/server/tmp/start_8210707001248201939.properties b/solr-8.3.1/server/tmp/start_8210707001248201939.properties new file mode 100644 index 000000000..aebc17bdc --- /dev/null +++ b/solr-8.3.1/server/tmp/start_8210707001248201939.properties @@ -0,0 +1,11 @@ +#start.jar properties +#Thu Jan 16 20:33:22 UTC 2020 +java.version.platform=8 +java.version=1.8.0_211 +java.version.micro=0 +jetty.home=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server +java.version.minor=8 +jetty.home.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server +jetty.base=C\:\\gitstuff\\GitCode\\Dash-Web\\solr-8.3.1\\server +java.version.major=1 +jetty.base.uri=file\:///C\:/gitstuff/GitCode/Dash-Web/solr-8.3.1/server diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index be678d765..eacdd8214 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -69,6 +69,8 @@ export interface DocumentOptions { page?: number; scale?: number; fitWidth?: boolean; + fitToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents + isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents forceActive?: boolean; preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view layout?: string | Doc; @@ -114,6 +116,9 @@ export interface DocumentOptions { dropConverter?: ScriptField; // script to run when documents are dropped on this Document. strokeWidth?: number; color?: string; + treeViewHideTitle?: boolean; // whether to hide the title of a tree view + treeViewOpen?: boolean; // whether this document is expanded in a tree view + isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents // [key: string]: Opt; } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 6c50ea0f2..a7a124825 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -207,6 +207,38 @@ export class CollectionDockingView extends React.Component { + if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" && + DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.props.Document.isDisplayPanel) { + found = DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)!; + } else { + Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { + if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.props.Document.isDisplayPanel) { + found = DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!; + return true; + } + return false; + }); + } + }); + if (found) { + Doc.GetProto(found.props.Document).data = new List([document]); + } else { + const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" }) + CollectionDockingView.AddRightSplit(stackView, undefined, []); + } + } + } @undoBatch @action @@ -721,3 +753,4 @@ export class DockedFrameRenderer extends React.Component { } } Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); }); +Scripting.addGlobal(function useRightSplit(doc: any) { CollectionDockingView.UseRightSplit(doc, undefined); }); diff --git a/src/client/views/collections/CollectionPivotView.scss b/src/client/views/collections/CollectionPivotView.scss new file mode 100644 index 000000000..bd3d6c77b --- /dev/null +++ b/src/client/views/collections/CollectionPivotView.scss @@ -0,0 +1,57 @@ +.collectionPivotView { + display: flex; + flex-direction: row; + position: absolute; + height:100%; + width:100%; + .collectionPivotView-flyout { + width: 400px; + height: 300px; + display: inline-block; + .collectionPivotView-flyout-item { + background-color: lightgray; + text-align: left; + display: inline-block; + position: relative; + width: 100%; + } + } + + .collectionPivotView-treeView { + display:flex; + flex-direction: column; + width: 200px; + height: 100%; + .collectionPivotView-addfacet { + display:inline-block; + width: 200px; + height: 30px; + background: darkGray; + text-align: center; + .collectionPivotView-button { + align-items: center; + display: flex; + width: 100%; + height: 100%; + .collectionPivotView-span { + margin: auto; + } + } + > div, > div > div { + width: 100%; + height: 100%; + text-align: center; + } + } + .collectionPivotView-tree { + display:inline-block; + width: 200px; + height: calc(100% - 30px); + } + } + .collectionPivotView-pivot { + display:inline-block; + width: calc(100% - 200px); + height: 100%; + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx new file mode 100644 index 000000000..d56052ed5 --- /dev/null +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -0,0 +1,119 @@ +import { CollectionSubView } from "./CollectionSubView"; +import React = require("react"); +import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx"; +import { faEdit, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; +import "./CollectionPivotView.scss"; +import { observer } from "mobx-react"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { CollectionTreeView } from "./CollectionTreeView"; +import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; +import { Docs } from "../../documents/Documents"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { CompileScript } from "../../util/Scripting"; +import { anchorPoints, Flyout } from "../TemplateMenu"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { List } from "../../../new_fields/List"; +import { Set } from "typescript-collections"; + +@observer +export class CollectionPivotView extends CollectionSubView(doc => doc) { + componentDidMount = () => { + this.props.Document.freeformLayoutEngine = "pivot"; + if (!this.props.Document.facetCollection) { + const facetCollection = Docs.Create.FreeformDocument([], { title: "facetFilters", yMargin: 0, treeViewHideTitle: true }); + facetCollection.target = this.props.Document; + + const scriptText = "setDocFilter(context.target, heading, this.title, checked)"; + const script = CompileScript(scriptText, { + params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name }, + typecheck: false, + editable: true, + }); + if (script.compiled) { + facetCollection.onCheckedClick = new ScriptField(script); + } + + const openDocText = "const alias = getAlias(this); alias.layoutKey = 'layoutCustom'; useRightSplit(alias); "; + const openDocScript = CompileScript(openDocText, { + params: { this: Doc.name, heading: "boolean", checked: "boolean", context: Doc.name }, + typecheck: false, + editable: true, + }); + if (openDocScript.compiled) { + this.props.Document.onChildClick = new ScriptField(openDocScript); + } + + this.props.Document.facetCollection = facetCollection; + this.props.Document.fitToBox = true; + } + } + + @computed get fieldExtensionDoc() { + return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey); + } + + bodyPanelWidth = () => this.props.PanelWidth() - 200; + getTransform = () => this.props.ScreenToLocalTransform().translate(-200, 0); + + @computed get _allFacets() { + const facets = new Set(); + this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); + return facets.toArray(); + } + + facetClick = (facet: string) => { + const facetCollection = this.props.Document.facetCollection; + if (facetCollection instanceof Doc) { + let found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet); + if (found !== -1) { + //Doc.RemoveDocFromList(facetCollection, "data", DocListCast(facetCollection.data)[found]); + (facetCollection.data as List).splice(found, 1); + } else { + const facetValues = new Set(); + this.childDocs.forEach(child => { + Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facet]?.toString() || "(null)")); + facetValues.add(child[facet]?.toString() || "(null)"); + }); + this.childDocs + + const newFacetVals = facetValues.toArray().map(val => Docs.Create.TextDocument({ title: val.toString() })); + const newFacet = Docs.Create.FreeformDocument(newFacetVals, { title: facet, treeViewOpen: true, isFacetFilter: true }); + Doc.AddDocToList(facetCollection, "data", newFacet); + } + } + } + + render() { + const facetCollection = Cast(this.props.Document?.facetCollection, Doc, null); + const flyout = ( +
+ {this._allFacets.map(facet => )} +
+ ); + return !facetCollection ? (null) :
+
+
e.stopPropagation()}> + +
+ Facet Filters + +
+
+
+
+ +
+
+
+ +
+
; + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 3356aed68..70860b6bd 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -52,7 +52,7 @@ export interface TreeViewProps { outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; outerXf: () => { translateX: number, translateY: number }; - treeViewId: string; + treeViewId: Doc; parentKey: string; active: (outsideReaction?: boolean) => boolean; hideHeaderFields: () => boolean; @@ -234,8 +234,8 @@ class TreeView extends React.Component { if (inside) { addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc); } - const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments); - return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId)) || de.complete.docDragData.userDropAction) ? + const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments); + return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ? de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d) || added, false) : de.complete.docDragData.moveDocument ? movedDocs.reduce((added, d) => de.complete.docDragData?.moveDocument?.(d, undefined, addDoc) || added, false) @@ -368,12 +368,13 @@ class TreeView extends React.Component { @action bulletClick = (e: React.MouseEvent) => { - if (this.props.onCheckedClick) { + if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) { this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check"; ScriptCast(this.props.onCheckedClick).script.run({ this: this.props.document.isTemplateField && this.props.dataDoc ? this.props.dataDoc : this.props.document, heading: this.props.containingCollection.title, - checked: this.props.document.treeViewChecked === "check" ? false : this.props.document.treeViewChecked === "x" ? "x" : "none" + checked: this.props.document.treeViewChecked === "check" ? false : this.props.document.treeViewChecked === "x" ? "x" : "none", + context: this.props.treeViewId }, console.log); } else { this.treeViewOpen = !this.treeViewOpen; @@ -383,7 +384,7 @@ class TreeView extends React.Component { @computed get renderBullet() { - const checked = this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined; + const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined; return
{}
; @@ -394,7 +395,7 @@ class TreeView extends React.Component { @computed get renderTitle() { const reference = React.createRef(); - const onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); + const onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true); const headerElements = ( { } public static GetChildElements( childDocs: Doc[], - treeViewId: string, + treeViewId: Doc, containingCollection: Doc, dataDoc: Doc | undefined, key: string, @@ -655,7 +656,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()} onDrop={this.onTreeDrop} ref={this.createTreeDropTarget}> - ([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false); - })} /> + })} />)} {this.props.Document.allowClear ? this.renderClearButton : (null)}
    { - TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, + TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.hideHeaderFields), BoolCast(this.props.Document.preventTreeViewOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick)) diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 21371dd39..022fc8f48 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -36,6 +36,7 @@ import { TraceMobx } from '../../../new_fields/util'; import { Utils } from '../../../Utils'; import { ScriptBox } from '../ScriptBox'; import CollectionMulticolumnView from '../CollectionMulticolumnView'; +import { CollectionPivotView } from './CollectionPivotView'; const path = require('path'); library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); @@ -180,7 +181,7 @@ export class CollectionView extends Touchable { case CollectionViewType.Linear: { return (); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } - case CollectionViewType.Pivot: { this.props.Document.freeformLayoutEngine = "pivot"; return (); } + case CollectionViewType.Pivot: { return (); } case CollectionViewType.Freeform: default: { this.props.Document.freeformLayoutEngine = undefined; return (); } } -- cgit v1.2.3-70-g09d2 From 6caae7aa4212d84ef320fe2be412c7e603483e81 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 16 Jan 2020 19:09:13 -0500 Subject: basic multicolumn resizing implemented, still not performant at all --- src/client/views/CollectionMulticolumnView.scss | 11 +- src/client/views/CollectionMulticolumnView.tsx | 171 ++++++++++++++++++++---- src/server/RouteManager.ts | 4 +- 3 files changed, 155 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.scss b/src/client/views/CollectionMulticolumnView.scss index 84e80da4a..1c2389809 100644 --- a/src/client/views/CollectionMulticolumnView.scss +++ b/src/client/views/CollectionMulticolumnView.scss @@ -1,7 +1,14 @@ -.collectionMulticolumnView_outer, .collectionMulticolumnView_contents { + display: flex; width: 100%; height: 100%; overflow: hidden; -} + .spacer { + width: 2px; + background: black; + cursor: ew-resize; + opacity: 0.2; + } + +} \ No newline at end of file diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index 3231c0da1..ded2aa9df 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -11,10 +11,24 @@ import { ContentFittingDocumentView } from './nodes/ContentFittingDocumentView'; import { Utils } from '../../Utils'; import { Transform } from '../util/Transform'; import "./collectionMulticolumnView.scss"; +import { computed } from 'mobx'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); +interface LayoutUnit { + config: Doc; + target: Doc; +} + +interface Fixed extends LayoutUnit { + pixels: number; +} + +interface Proportional extends LayoutUnit { + ratio: number; +} + @observer export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { private _dropDisposer?: DragManager.DragDropDisposer; @@ -41,37 +55,140 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } + @computed + private get layoutInformation() { + const fixed: Fixed[] = []; + const proportional: Proportional[] = []; + let ratioSum = 0; + for (const config of this.configuration) { + const { columnWidth, target } = config; + if (!(target instanceof Doc)) { + // we're still waiting on promises, so it's not worth rendering anything yet + return (null); + } + const widthSpecifier = Cast(columnWidth, "number"); + let matches: RegExpExecArray | null; + if (widthSpecifier !== undefined) { + // we've gotten a number, referring to a pixel value + fixed.push({ config, target, pixels: widthSpecifier }); + } else if ((matches = /^(\d+(\.\d+)?)\*/.exec(StrCast(columnWidth))) !== null) { + // we've gotten a proportional measure, like 1.8* + const ratio = Number(matches[1]); + ratioSum += ratio; + proportional.push({ config, target, ratio }); + } + // otherwise, the particular configuration entry is ignored and the remaining + // space is allocated as if the document were absent from the configuration list + } + return { fixed, proportional, ratioSum }; + } + + @computed private get totalFixedPool() { + return this.layoutInformation?.fixed.reduce((sum, unit) => sum + unit.pixels, 0); + } + + @computed private get totalProportionalPool() { + const { totalFixedPool } = this; + return totalFixedPool !== undefined ? this.props.PanelWidth() - totalFixedPool : undefined; + } + + @computed private get columnUnitLength() { + const layout = this.layoutInformation; + const { totalProportionalPool } = this; + if (layout !== null && totalProportionalPool !== undefined) { + const { ratioSum, proportional } = layout; + return (totalProportionalPool - 2 * (proportional.length - 1)) / ratioSum; + } + return undefined; + } + + @computed + private get contents(): JSX.Element[] | null { + const layout = this.layoutInformation; + if (layout === null) { + return (null); + } + const { fixed, proportional } = layout; + const { columnUnitLength } = this; + if (columnUnitLength === undefined) { + return (null); + } + const { GenerateGuid } = Utils; + const toView = ({ target, pixels }: Fixed) => + pixels} + getTransform={this.props.ScreenToLocalTransform} + />; + const collector: JSX.Element[] = fixed.map(toView); + const resolvedColumns = proportional.map(({ target, ratio, config }) => ({ target, pixels: ratio * columnUnitLength, config })); + for (let i = 0; i < resolvedColumns.length; i++) { + collector.push(toView(resolvedColumns[i])); + collector.push( + + ); + } + collector.pop(); + return collector; + } + render() { - const { PanelWidth } = this.props; return ( -
    -
    - {this.configuration.map(config => { - const { target, columnWidth } = config; - if (target instanceof Doc) { - let computedWidth: number = 0; - const widthSpecifier = Cast(columnWidth, "number"); - let matches: RegExpExecArray | null; - if (widthSpecifier !== undefined) { - computedWidth = widthSpecifier; - } else if ((matches = /([\d.]+)\%/.exec(StrCast(columnWidth))) !== null) { - computedWidth = Number(matches[1]) / 100 * PanelWidth(); - } - return (!computedWidth ? (null) : - computedWidth} - getTransform={this.props.ScreenToLocalTransform} - /> - ); - } - return (null); - })} -
    +
    + {this.contents}
    ); } +} + +interface SpacerProps { + columnBaseUnit: number; + toLeft?: Doc; + toRight?: Doc; +} + +class MulticolumnSpacer extends React.Component { + + private registerResizing = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + window.addEventListener("pointermove", this.onPointerMove); + window.addEventListener("pointerup", this.onPointerUp); + } + + private onPointerMove = ({ movementX }: PointerEvent) => { + const { toLeft, toRight, columnBaseUnit } = this.props; + const target = movementX > 0 ? toRight : toLeft; + if (target) { + let widthSpecifier = Number(StrCast(target.columnWidth).replace("*", "")); + widthSpecifier -= Math.abs(movementX) / columnBaseUnit; + target.columnWidth = `${widthSpecifier}*`; + } + } + + private onPointerUp = () => { + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + } + + render() { + return ( +
    + ); + } + } \ No newline at end of file diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts index f9ffdaa80..b07aef74d 100644 --- a/src/server/RouteManager.ts +++ b/src/server/RouteManager.ts @@ -68,7 +68,7 @@ export default class RouteManager { console.log('please remove all duplicate routes before continuing'); } if (malformedCount) { - console.log(`please ensure all routes adhere to ^\/$|^\/[A-Za-z]+(\/\:[A-Za-z?]+)*$`); + console.log(`please ensure all routes adhere to ^\/$|^\/[A-Za-z]+(\/\:[A-Za-z?_]+)*$`); } process.exit(1); } else { @@ -132,7 +132,7 @@ export default class RouteManager { } else { route = subscriber.build; } - if (!/^\/$|^\/[A-Za-z]+(\/\:[A-Za-z?]+)*$/g.test(route)) { + if (!/^\/$|^\/[A-Za-z]+(\/\:[A-Za-z?_]+)*$/g.test(route)) { this.failedRegistrations.push({ reason: RegistrationError.Malformed, route -- cgit v1.2.3-70-g09d2 From 42b20c17047037ddc2c8e7f3c3625276ea8df5fa Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 16 Jan 2020 20:04:58 -0500 Subject: much more flexible approach for distributing fixed width targets --- src/client/views/CollectionMulticolumnView.tsx | 70 ++++++++++++++++++-------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index ded2aa9df..653ff5b84 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -16,17 +16,22 @@ import { computed } from 'mobx'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); -interface LayoutUnit { +interface UnitBase { config: Doc; target: Doc; } -interface Fixed extends LayoutUnit { - pixels: number; +type WidthSpecifier = { pixels: number } | { ratio: number }; +interface LayoutUnit extends UnitBase { + specifier: WidthSpecifier; } -interface Proportional extends LayoutUnit { - ratio: number; +interface Fixed extends UnitBase { + specifier: { pixels: number }; +} + +interface Ratio extends UnitBase { + specifier: { ratio: number }; } @observer @@ -57,9 +62,10 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico @computed private get layoutInformation() { - const fixed: Fixed[] = []; - const proportional: Proportional[] = []; + const values: LayoutUnit[] = []; let ratioSum = 0; + let fixedCount = 0; + let ratioCount = 0; for (const config of this.configuration) { const { columnWidth, target } = config; if (!(target instanceof Doc)) { @@ -68,23 +74,37 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico } const widthSpecifier = Cast(columnWidth, "number"); let matches: RegExpExecArray | null; + let specifier: WidthSpecifier | null = null; if (widthSpecifier !== undefined) { // we've gotten a number, referring to a pixel value - fixed.push({ config, target, pixels: widthSpecifier }); + specifier = { pixels: widthSpecifier }; + fixedCount++; } else if ((matches = /^(\d+(\.\d+)?)\*/.exec(StrCast(columnWidth))) !== null) { // we've gotten a proportional measure, like 1.8* const ratio = Number(matches[1]); ratioSum += ratio; - proportional.push({ config, target, ratio }); + specifier = { ratio }; + ratioCount++; + } + if (specifier !== null) { + values.push({ config, target, specifier }); } // otherwise, the particular configuration entry is ignored and the remaining // space is allocated as if the document were absent from the configuration list } - return { fixed, proportional, ratioSum }; + return { values, ratioCount, fixedCount, ratioSum }; } @computed private get totalFixedPool() { - return this.layoutInformation?.fixed.reduce((sum, unit) => sum + unit.pixels, 0); + const fixed: Fixed[] = []; + const layout = this.layoutInformation; + if (!layout) { + return undefined; + } + layout.values.forEach(unit => { + ("pixels" in unit.specifier) && fixed.push(unit as Fixed); + }); + return fixed.reduce((sum, unit) => sum + unit.specifier.pixels, 0); } @computed private get totalProportionalPool() { @@ -96,8 +116,8 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico const layout = this.layoutInformation; const { totalProportionalPool } = this; if (layout !== null && totalProportionalPool !== undefined) { - const { ratioSum, proportional } = layout; - return (totalProportionalPool - 2 * (proportional.length - 1)) / ratioSum; + const { ratioSum, values } = layout; + return (totalProportionalPool - 2 * (values.length - 1)) / ratioSum; } return undefined; } @@ -108,13 +128,13 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico if (layout === null) { return (null); } - const { fixed, proportional } = layout; + const { values } = layout; const { columnUnitLength } = this; if (columnUnitLength === undefined) { return (null); } const { GenerateGuid } = Utils; - const toView = ({ target, pixels }: Fixed) => + const toView = ({ target, specifier: { pixels } }: Fixed) => pixels} getTransform={this.props.ScreenToLocalTransform} />; - const collector: JSX.Element[] = fixed.map(toView); - const resolvedColumns = proportional.map(({ target, ratio, config }) => ({ target, pixels: ratio * columnUnitLength, config })); - for (let i = 0; i < resolvedColumns.length; i++) { - collector.push(toView(resolvedColumns[i])); + const resolved: Fixed[] = []; + values.forEach(value => { + const { specifier, ...remaining } = value; + if ("ratio" in specifier) { + resolved.push({ ...remaining, specifier: { pixels: specifier.ratio * columnUnitLength } }); + } else { + resolved.push(value as Fixed); + } + }); + const collector: JSX.Element[] = []; + for (let i = 0; i < resolved.length; i++) { + collector.push(toView(resolved[i])); collector.push( ); } -- cgit v1.2.3-70-g09d2 From 1055a2db6b14cbcd1eb63727995a51153ba79128 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 16 Jan 2020 22:09:55 -0500 Subject: logical differentiation between unit and magnitude for multicolumn view config width data, additional commenting and cleanup --- src/client/views/CollectionMulticolumnView.tsx | 221 +++++++++++++------------ 1 file changed, 116 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index 653ff5b84..61ce8d99c 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -16,27 +16,31 @@ import { computed } from 'mobx'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); -interface UnitBase { +interface Unresolved { config: Doc; target: Doc; + magnitude: number; + unit: string; } -type WidthSpecifier = { pixels: number } | { ratio: number }; -interface LayoutUnit extends UnitBase { - specifier: WidthSpecifier; -} - -interface Fixed extends UnitBase { - specifier: { pixels: number }; +interface Resolved { + config: Doc; + target: Doc; + pixels: number; } -interface Ratio extends UnitBase { - specifier: { ratio: number }; -} +const resolvedUnits = ["*", "px"]; @observer export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { private _dropDisposer?: DragManager.DragDropDisposer; + + /** + * Returns the list of so-called configuration documents. + * Each one is a wrapper around what we typically think of as + * the child document, just also encoding the magnitude and unit + * of the specified width. + */ private get configuration() { const { Document } = this.props; if (!Document.multicolumnData) { @@ -45,126 +49,132 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico return DocListCast(this.Document.multicolumnData); } - protected createDropTarget = (ele: HTMLDivElement) => { - this._dropDisposer && this._dropDisposer(); - if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); - } - } - - getTransform = (ele: React.RefObject) => () => { - if (!ele.current) return Transform.Identity(); - const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); - return new Transform(-translateX, -translateY, 1 / scale); - } - - public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } - @computed - private get layoutInformation() { - const values: LayoutUnit[] = []; - let ratioSum = 0; - let fixedCount = 0; - let ratioCount = 0; + private get resolvedLayoutInformation() { + const unresolved: Unresolved[] = []; + let ratioSum = 0, numFixed = 0, numRatio = 0; for (const config of this.configuration) { - const { columnWidth, target } = config; - if (!(target instanceof Doc)) { - // we're still waiting on promises, so it's not worth rendering anything yet - return (null); + const { target, widthMagnitude, widthUnit } = config; + if (target instanceof Doc) { + const unit = StrCast(widthUnit); + const magnitude = NumCast(widthMagnitude); + if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { + switch (unit) { + case "*": + ratioSum += magnitude; + numRatio++; + break; + case "px": + numFixed++; + break; + } + unresolved.push({ config, target, 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 } - const widthSpecifier = Cast(columnWidth, "number"); - let matches: RegExpExecArray | null; - let specifier: WidthSpecifier | null = null; - if (widthSpecifier !== undefined) { - // we've gotten a number, referring to a pixel value - specifier = { pixels: widthSpecifier }; - fixedCount++; - } else if ((matches = /^(\d+(\.\d+)?)\*/.exec(StrCast(columnWidth))) !== null) { - // we've gotten a proportional measure, like 1.8* - const ratio = Number(matches[1]); - ratioSum += ratio; - specifier = { ratio }; - ratioCount++; - } - if (specifier !== null) { - values.push({ config, target, specifier }); - } - // otherwise, the particular configuration entry is ignored and the remaining - // space is allocated as if the document were absent from the configuration list } - return { values, ratioCount, fixedCount, ratioSum }; + return { unresolved, numRatio, numFixed, ratioSum }; } - @computed private get totalFixedPool() { - const fixed: Fixed[] = []; - const layout = this.layoutInformation; + /** + * 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 { + const layout = this.resolvedLayoutInformation; if (!layout) { return undefined; } - layout.values.forEach(unit => { - ("pixels" in unit.specifier) && fixed.push(unit as Fixed); - }); - return fixed.reduce((sum, unit) => sum + unit.specifier.pixels, 0); + let sum = 0; + for (const { magnitude, unit } of layout.unresolved) { + if (unit === "px") { + sum += magnitude; + } + } + return sum; } - @computed private get totalProportionalPool() { - const { totalFixedPool } = this; - return totalFixedPool !== undefined ? this.props.PanelWidth() - totalFixedPool : undefined; + /** + * 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 { totalFixedAllocation } = this; + return totalFixedAllocation !== undefined ? this.props.PanelWidth() - totalFixedAllocation : undefined; } - @computed private get columnUnitLength() { - const layout = this.layoutInformation; - const { totalProportionalPool } = this; - if (layout !== null && totalProportionalPool !== undefined) { - const { ratioSum, values } = layout; - return (totalProportionalPool - 2 * (values.length - 1)) / ratioSum; + /** + * This returns the total quantity, in pixels, that + * 1* (relative / star unit) is worth. For example, + * if the configuration had three documents, with, respectively, + * widths of 2*, 2* and 1*, and the panel width was 1000px, + * this value would return 1000 / (2 + 2 + 1), or 200px. + * This is then multiplied by each relative-width + * document's * factor 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 { + const layout = this.resolvedLayoutInformation; + const { totalRatioAllocation } = this; + if (layout !== null && totalRatioAllocation !== undefined) { + const { ratioSum, unresolved } = layout; + return (totalRatioAllocation - 2 * (unresolved.length - 1)) / ratioSum; } return undefined; } @computed private get contents(): JSX.Element[] | null { - const layout = this.layoutInformation; - if (layout === null) { - return (null); - } - const { values } = layout; - const { columnUnitLength } = this; - if (columnUnitLength === undefined) { - return (null); + const layout = this.resolvedLayoutInformation; + const columnUnitLength = this.columnUnitLength; + if (layout === null || columnUnitLength === undefined) { + return (null); // we're still waiting on promises to resolve } - const { GenerateGuid } = Utils; - const toView = ({ target, specifier: { pixels } }: Fixed) => - { + const { unit, magnitude, ...remaining } = value; + let width = magnitude; + if (unit === "*") { + width = magnitude * columnUnitLength; + } + resolved.push({ pixels: width, ...remaining, }); + }); + const collector: JSX.Element[] = []; + for (let i = 0; i < resolved.length; i++) { + const { target, pixels, config } = resolved[i]; + collector.push( pixels} getTransform={this.props.ScreenToLocalTransform} - />; - const resolved: Fixed[] = []; - values.forEach(value => { - const { specifier, ...remaining } = value; - if ("ratio" in specifier) { - resolved.push({ ...remaining, specifier: { pixels: specifier.ratio * columnUnitLength } }); - } else { - resolved.push(value as Fixed); - } - }); - const collector: JSX.Element[] = []; - for (let i = 0; i < resolved.length; i++) { - collector.push(toView(resolved[i])); + />); collector.push( ); } - collector.pop(); + collector.pop(); // not the cleanest, but simply removes the final extraneous spacer return collector; } @@ -179,7 +189,7 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico } interface SpacerProps { - columnBaseUnit: number; + columnUnitLength: number; toLeft?: Doc; toRight?: Doc; } @@ -196,12 +206,13 @@ class MulticolumnSpacer extends React.Component { } private onPointerMove = ({ movementX }: PointerEvent) => { - const { toLeft, toRight, columnBaseUnit } = this.props; + const { toLeft, toRight, columnUnitLength } = this.props; const target = movementX > 0 ? toRight : toLeft; if (target) { - let widthSpecifier = Number(StrCast(target.columnWidth).replace("*", "")); - widthSpecifier -= Math.abs(movementX) / columnBaseUnit; - target.columnWidth = `${widthSpecifier}*`; + const { widthUnit, widthMagnitude } = target; + if (widthUnit === "*") { + target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / columnUnitLength; + } } } -- cgit v1.2.3-70-g09d2 From 05eb320bef0395fef704f583d69673bfa5abaa77 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 00:39:03 -0500 Subject: visual displays for widths --- src/client/views/CollectionMulticolumnView.scss | 12 ++- src/client/views/CollectionMulticolumnView.tsx | 91 ++++++++++++---------- .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionPivotView.tsx | 2 +- 4 files changed, 65 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.scss b/src/client/views/CollectionMulticolumnView.scss index 1c2389809..8c4410f01 100644 --- a/src/client/views/CollectionMulticolumnView.scss +++ b/src/client/views/CollectionMulticolumnView.scss @@ -4,8 +4,18 @@ height: 100%; overflow: hidden; + .fish { + display: flex; + flex-direction: column; + + .display { + text-align: center; + height: 20px; + } + + } + .spacer { - width: 2px; background: black; cursor: ew-resize; opacity: 0.2; diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index 61ce8d99c..20923d8e6 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -1,15 +1,14 @@ import { observer } from 'mobx-react'; -import { makeInterface, listSpec } from '../../new_fields/Schema'; +import { makeInterface } from '../../new_fields/Schema'; import { documentSchema } from '../../new_fields/documentSchemas'; import { CollectionSubView } from './collections/CollectionSubView'; import { DragManager } from '../util/DragManager'; import * as React from "react"; import { Doc, DocListCast } from '../../new_fields/Doc'; -import { NumCast, Cast, StrCast } from '../../new_fields/Types'; +import { NumCast, StrCast } from '../../new_fields/Types'; import { List } from '../../new_fields/List'; import { ContentFittingDocumentView } from './nodes/ContentFittingDocumentView'; import { Utils } from '../../Utils'; -import { Transform } from '../util/Transform'; import "./collectionMulticolumnView.scss"; import { computed } from 'mobx'; @@ -29,7 +28,15 @@ interface Resolved { pixels: number; } +interface LayoutData { + unresolved: Unresolved[]; + numFixed: number; + numRatio: number; + starSum: number; +} + const resolvedUnits = ["*", "px"]; +const resizerWidth = 2; @observer export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { @@ -50,23 +57,20 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico } @computed - private get resolvedLayoutInformation() { + private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; - let ratioSum = 0, numFixed = 0, numRatio = 0; + let starSum = 0, numFixed = 0, numRatio = 0; for (const config of this.configuration) { const { target, widthMagnitude, widthUnit } = config; if (target instanceof Doc) { const unit = StrCast(widthUnit); const magnitude = NumCast(widthMagnitude); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - switch (unit) { - case "*": - ratioSum += magnitude; - numRatio++; - break; - case "px": - numFixed++; - break; + if (unit === "*") { + starSum += magnitude; + numRatio++; + } else { + numFixed++; } unresolved.push({ config, target, magnitude, unit }); } @@ -74,7 +78,7 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico // space is allocated as if the document were absent from the configuration list } } - return { unresolved, numRatio, numFixed, ratioSum }; + return { unresolved, numRatio, numFixed, starSum }; } /** @@ -112,17 +116,21 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico @computed private get totalRatioAllocation(): number | undefined { const { totalFixedAllocation } = this; - return totalFixedAllocation !== undefined ? this.props.PanelWidth() - totalFixedAllocation : undefined; + const layout = this.resolvedLayoutInformation; + if (!layout) { + return undefined; + } + return totalFixedAllocation !== undefined ? this.props.PanelWidth() - (totalFixedAllocation + resizerWidth * (layout.unresolved.length - 1)) : undefined; } /** * This returns the total quantity, in pixels, that * 1* (relative / star unit) is worth. For example, - * if the configuration had three documents, with, respectively, - * widths of 2*, 2* and 1*, and the panel width was 1000px, - * this value would return 1000 / (2 + 2 + 1), or 200px. - * This is then multiplied by each relative-width - * document's * factor to compute its actual width (400px, 400px and 200px). + * 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. @@ -131,11 +139,10 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico private get columnUnitLength(): number | undefined { const layout = this.resolvedLayoutInformation; const { totalRatioAllocation } = this; - if (layout !== null && totalRatioAllocation !== undefined) { - const { ratioSum, unresolved } = layout; - return (totalRatioAllocation - 2 * (unresolved.length - 1)) / ratioSum; + if (layout === null || totalRatioAllocation === undefined) { + return undefined; } - return undefined; + return totalRatioAllocation / layout.starSum; } @computed @@ -146,27 +153,31 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico return (null); // we're still waiting on promises to resolve } const resolved: Resolved[] = []; - layout.unresolved.forEach(value => { - const { unit, magnitude, ...remaining } = value; + layout.unresolved.forEach(item => { + const { unit, magnitude, ...remaining } = item; let width = magnitude; if (unit === "*") { width = magnitude * columnUnitLength; } - resolved.push({ pixels: width, ...remaining, }); + resolved.push({ pixels: width, ...remaining }); }); const collector: JSX.Element[] = []; for (let i = 0; i < resolved.length; i++) { const { target, pixels, config } = resolved[i]; - collector.push( pixels} - getTransform={this.props.ScreenToLocalTransform} - />); collector.push( - + pixels} + getTransform={this.props.ScreenToLocalTransform} + /> + {NumCast(config.widthMagnitude).toFixed(3)} {StrCast(config.widthUnit)} +
    , + ); } - collector.pop(); // not the cleanest, but simply removes the final extraneous spacer + collector.pop(); // removes the final extraneous resize bar return collector; } - render() { + render(): JSX.Element { return (
    {this.contents} @@ -189,12 +200,13 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico } interface SpacerProps { + width: number; columnUnitLength: number; toLeft?: Doc; toRight?: Doc; } -class MulticolumnSpacer extends React.Component { +class ResizeBar extends React.Component { private registerResizing = (e: React.PointerEvent) => { e.stopPropagation(); @@ -225,6 +237,7 @@ class MulticolumnSpacer extends React.Component { return (
    ); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index a7a124825..022eccc13 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -234,7 +234,7 @@ export class CollectionDockingView extends React.Component([document]); } else { - const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" }) + const stackView = Docs.Create.FreeformDocument([document], { fitToBox: true, isDisplayPanel: true, title: "document viewer" }); CollectionDockingView.AddRightSplit(stackView, undefined, []); } } diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index d56052ed5..d6261c7ee 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -65,7 +65,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { facetClick = (facet: string) => { const facetCollection = this.props.Document.facetCollection; if (facetCollection instanceof Doc) { - let found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet); + const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facet); if (found !== -1) { //Doc.RemoveDocFromList(facetCollection, "data", DocListCast(facetCollection.data)[found]); (facetCollection.data as List).splice(found, 1); -- cgit v1.2.3-70-g09d2 From 2706f80b352e8a4fba692a9ad0b69ea2a7e25c2d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 01:25:02 -0500 Subject: opacity --- src/client/views/CollectionMulticolumnView.scss | 3 +-- src/client/views/CollectionMulticolumnView.tsx | 28 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.scss b/src/client/views/CollectionMulticolumnView.scss index 8c4410f01..120603a0b 100644 --- a/src/client/views/CollectionMulticolumnView.scss +++ b/src/client/views/CollectionMulticolumnView.scss @@ -15,10 +15,9 @@ } - .spacer { + .resizer { background: black; cursor: ew-resize; - opacity: 0.2; } } \ No newline at end of file diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index 20923d8e6..0b2ca82f1 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -228,6 +228,27 @@ class ResizeBar extends React.Component { } } + private get opacity() { + const { toLeft, toRight } = this.props; + if (toLeft && toRight) { + if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { + return 0; + } + return 0.4; + } else if (toLeft) { + if (StrCast(toLeft.widthUnit) === "px") { + return 0; + } + return 0.4; + } else if (toRight) { + if (StrCast(toRight.widthUnit) === "px") { + return 0; + } + return 0.4; + } + return 0; + } + private onPointerUp = () => { window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); @@ -236,8 +257,11 @@ class ResizeBar extends React.Component { render() { return (
    ); -- cgit v1.2.3-70-g09d2 From 12f3a4a1bfce522c7e647317035ec0deda5c73d5 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 Jan 2020 10:28:52 -0500 Subject: moving things around. changed multiColumnView to not use intermediate config docs. --- src/client/views/CollectionLinearView.scss | 75 --------------- src/client/views/CollectionLinearView.tsx | 106 --------------------- src/client/views/CollectionMulticolumnView.tsx | 85 +++++------------ src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionLinearView.scss | 75 +++++++++++++++ .../views/collections/CollectionLinearView.tsx | 106 +++++++++++++++++++++ .../views/collections/CollectionPivotView.tsx | 1 - src/client/views/collections/CollectionView.tsx | 43 ++++----- 8 files changed, 227 insertions(+), 266 deletions(-) delete mode 100644 src/client/views/CollectionLinearView.scss delete mode 100644 src/client/views/CollectionLinearView.tsx create mode 100644 src/client/views/collections/CollectionLinearView.scss create mode 100644 src/client/views/collections/CollectionLinearView.tsx (limited to 'src') diff --git a/src/client/views/CollectionLinearView.scss b/src/client/views/CollectionLinearView.scss deleted file mode 100644 index 81210d7ae..000000000 --- a/src/client/views/CollectionLinearView.scss +++ /dev/null @@ -1,75 +0,0 @@ -@import "globalCssVariables"; -@import "nodeModuleOverrides"; - -.collectionLinearView-outer{ - overflow: hidden; - height:100%; - .collectionLinearView { - display:flex; - height: 100%; - >label { - background: $dark-color; - color: $light-color; - display: inline-block; - border-radius: 18px; - font-size: 12.5px; - width: 18px; - height: 18px; - margin-top:auto; - margin-bottom:auto; - margin-right: 3px; - cursor: pointer; - transition: transform 0.2s; - } - - label p { - padding-left:5px; - } - - label:hover { - background: $main-accent; - transform: scale(1.15); - } - - >input { - display: none; - } - >input:not(:checked)~.collectionLinearView-content { - display: none; - } - - >input:checked~label { - transform: rotate(45deg); - transition: transform 0.5s; - cursor: pointer; - } - - .collectionLinearView-content { - display: flex; - opacity: 1; - position: relative; - margin-top: auto; - - .collectionLinearView-docBtn, .collectionLinearView-docBtn-scalable { - position:relative; - margin:auto; - margin-left: 3px; - transform-origin: center 80%; - } - .collectionLinearView-docBtn-scalable:hover { - transform: scale(1.15); - } - - .collectionLinearView-round-button { - width: 18px; - height: 18px; - border-radius: 18px; - font-size: 15px; - } - - .collectionLinearView-round-button:hover { - transform: scale(1.15); - } - } - } -} diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx deleted file mode 100644 index 5ca861f71..000000000 --- a/src/client/views/CollectionLinearView.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { action, IReactionDisposer, observable, reaction } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { Doc, HeightSym, WidthSym } from '../../new_fields/Doc'; -import { makeInterface } from '../../new_fields/Schema'; -import { BoolCast, NumCast, StrCast } from '../../new_fields/Types'; -import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; -import { DragManager } from '../util/DragManager'; -import { Transform } from '../util/Transform'; -import "./CollectionLinearView.scss"; -import { CollectionViewType } from './collections/CollectionView'; -import { CollectionSubView } from './collections/CollectionSubView'; -import { DocumentView } from './nodes/DocumentView'; -import { documentSchema } from '../../new_fields/documentSchemas'; -import { Id } from '../../new_fields/FieldSymbols'; - - -type LinearDocument = makeInterface<[typeof documentSchema,]>; -const LinearDocument = makeInterface(documentSchema); - -@observer -export class CollectionLinearView extends CollectionSubView(LinearDocument) { - @observable public addMenuToggle = React.createRef(); - private _dropDisposer?: DragManager.DragDropDisposer; - private _widthDisposer?: IReactionDisposer; - - componentWillUnmount() { - this._dropDisposer && this._dropDisposer(); - this._widthDisposer && this._widthDisposer(); - } - - componentDidMount() { - // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). - this._widthDisposer = reaction(() => NumCast(this.props.Document.height, 0) + this.childDocs.length + (this.props.Document.isExpanded ? 1 : 0), - () => this.props.Document.width = 5 + (this.props.Document.isExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), - { fireImmediately: true } - ); - } - protected createDropTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view - this._dropDisposer && this._dropDisposer(); - if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); - } - } - - public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } - - dimension = () => NumCast(this.props.Document.height); // 2 * the padding - getTransform = (ele: React.RefObject) => () => { - if (!ele.current) return Transform.Identity(); - const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); - return new Transform(-translateX, -translateY, 1 / scale); - } - - render() { - const guid = Utils.GenerateGuid(); - return
    -
    - this.props.Document.isExpanded = this.addMenuToggle.current!.checked)} /> - - -
    - {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => { - const nested = pair.layout.viewType === CollectionViewType.Linear; - const dref = React.createRef(); - const nativeWidth = NumCast(pair.layout.nativeWidth, this.dimension()); - const deltaSize = nativeWidth * .15 / 2; - return
    - this.dimension()}// ugh - need to get rid of this inline function to avoid recomputing - PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()} - renderDepth={this.props.renderDepth + 1} - focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - bringToFront={emptyFunction} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - zoomToScale={emptyFunction} - getScale={returnOne}> - -
    ; - })} -
    -
    -
    ; - } -} \ No newline at end of file diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx index 0b2ca82f1..99242e8be 100644 --- a/src/client/views/CollectionMulticolumnView.tsx +++ b/src/client/views/CollectionMulticolumnView.tsx @@ -4,9 +4,8 @@ import { documentSchema } from '../../new_fields/documentSchemas'; import { CollectionSubView } from './collections/CollectionSubView'; import { DragManager } from '../util/DragManager'; import * as React from "react"; -import { Doc, DocListCast } from '../../new_fields/Doc'; +import { Doc } from '../../new_fields/Doc'; import { NumCast, StrCast } from '../../new_fields/Types'; -import { List } from '../../new_fields/List'; import { ContentFittingDocumentView } from './nodes/ContentFittingDocumentView'; import { Utils } from '../../Utils'; import "./collectionMulticolumnView.scss"; @@ -16,14 +15,12 @@ type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); interface Unresolved { - config: Doc; target: Doc; magnitude: number; unit: string; } interface Resolved { - config: Doc; target: Doc; pixels: number; } @@ -40,43 +37,24 @@ const resizerWidth = 2; @observer export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { - private _dropDisposer?: DragManager.DragDropDisposer; - - /** - * Returns the list of so-called configuration documents. - * Each one is a wrapper around what we typically think of as - * the child document, just also encoding the magnitude and unit - * of the specified width. - */ - private get configuration() { - const { Document } = this.props; - if (!Document.multicolumnData) { - Document.multicolumnData = new List(); - } - return DocListCast(this.Document.multicolumnData); - } - @computed private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; let starSum = 0, numFixed = 0, numRatio = 0; - for (const config of this.configuration) { - const { target, widthMagnitude, widthUnit } = config; - if (target instanceof Doc) { - 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({ config, target, magnitude, unit }); + for (const target of this.childDocs) { + const unit = StrCast(target.widthUnit); + const magnitude = NumCast(target.widthMagnitude); + if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { + if (unit === "*") { + starSum += magnitude; + numRatio++; + } else { + numFixed++; } - // otherwise, the particular configuration entry is ignored and the remaining - // space is allocated as if the document were absent from the configuration list + unresolved.push({ target, 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 } return { unresolved, numRatio, numFixed, starSum }; } @@ -91,17 +69,8 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico */ @computed private get totalFixedAllocation(): number | undefined { - const layout = this.resolvedLayoutInformation; - if (!layout) { - return undefined; - } - let sum = 0; - for (const { magnitude, unit } of layout.unresolved) { - if (unit === "px") { - sum += magnitude; - } - } - return sum; + return this.resolvedLayoutInformation?.unresolved.reduce( + (sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0); } /** @@ -115,12 +84,9 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico */ @computed private get totalRatioAllocation(): number | undefined { - const { totalFixedAllocation } = this; - const layout = this.resolvedLayoutInformation; - if (!layout) { - return undefined; - } - return totalFixedAllocation !== undefined ? this.props.PanelWidth() - (totalFixedAllocation + resizerWidth * (layout.unresolved.length - 1)) : undefined; + const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; + if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) + return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); } /** @@ -137,12 +103,9 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico */ @computed private get columnUnitLength(): number | undefined { - const layout = this.resolvedLayoutInformation; - const { totalRatioAllocation } = this; - if (layout === null || totalRatioAllocation === undefined) { - return undefined; + if (this.resolvedLayoutInformation && this.totalRatioAllocation !== undefined) { + return this.totalRatioAllocation / this.resolvedLayoutInformation.starSum; } - return totalRatioAllocation / layout.starSum; } @computed @@ -163,7 +126,7 @@ export default class CollectionMulticolumnView extends CollectionSubView(Multico }); const collector: JSX.Element[] = []; for (let i = 0; i < resolved.length; i++) { - const { target, pixels, config } = resolved[i]; + const { target, pixels } = resolved[i]; collector.push(
    pixels} getTransform={this.props.ScreenToLocalTransform} /> - {NumCast(config.widthMagnitude).toFixed(3)} {StrCast(config.widthUnit)} + {NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)}
    , ); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 91c7f909b..3648ddccf 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -22,7 +22,7 @@ import { Docs, DocumentOptions } from '../documents/Documents'; import { HistoryUtil } from '../util/History'; import SharingManager from '../util/SharingManager'; import { Transform } from '../util/Transform'; -import { CollectionLinearView } from './CollectionLinearView'; +import { CollectionLinearView } from './collections/CollectionLinearView'; import { CollectionViewType, CollectionView } from './collections/CollectionView'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { ContextMenu } from './ContextMenu'; diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss new file mode 100644 index 000000000..eae9e0220 --- /dev/null +++ b/src/client/views/collections/CollectionLinearView.scss @@ -0,0 +1,75 @@ +@import "../globalCssVariables"; +@import "../_nodeModuleOverrides"; + +.collectionLinearView-outer{ + overflow: hidden; + height:100%; + .collectionLinearView { + display:flex; + height: 100%; + >label { + background: $dark-color; + color: $light-color; + display: inline-block; + border-radius: 18px; + font-size: 12.5px; + width: 18px; + height: 18px; + margin-top:auto; + margin-bottom:auto; + margin-right: 3px; + cursor: pointer; + transition: transform 0.2s; + } + + label p { + padding-left:5px; + } + + label:hover { + background: $main-accent; + transform: scale(1.15); + } + + >input { + display: none; + } + >input:not(:checked)~.collectionLinearView-content { + display: none; + } + + >input:checked~label { + transform: rotate(45deg); + transition: transform 0.5s; + cursor: pointer; + } + + .collectionLinearView-content { + display: flex; + opacity: 1; + position: relative; + margin-top: auto; + + .collectionLinearView-docBtn, .collectionLinearView-docBtn-scalable { + position:relative; + margin:auto; + margin-left: 3px; + transform-origin: center 80%; + } + .collectionLinearView-docBtn-scalable:hover { + transform: scale(1.15); + } + + .collectionLinearView-round-button { + width: 18px; + height: 18px; + border-radius: 18px; + font-size: 15px; + } + + .collectionLinearView-round-button:hover { + transform: scale(1.15); + } + } + } +} diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx new file mode 100644 index 000000000..9191bf822 --- /dev/null +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -0,0 +1,106 @@ +import { action, IReactionDisposer, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { makeInterface } from '../../../new_fields/Schema'; +import { BoolCast, NumCast, StrCast } from '../../../new_fields/Types'; +import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../../Utils'; +import { DragManager } from '../../util/DragManager'; +import { Transform } from '../../util/Transform'; +import "./CollectionLinearView.scss"; +import { CollectionViewType } from './CollectionView'; +import { CollectionSubView } from './CollectionSubView'; +import { DocumentView } from '../nodes/DocumentView'; +import { documentSchema } from '../../../new_fields/documentSchemas'; +import { Id } from '../../../new_fields/FieldSymbols'; + + +type LinearDocument = makeInterface<[typeof documentSchema,]>; +const LinearDocument = makeInterface(documentSchema); + +@observer +export class CollectionLinearView extends CollectionSubView(LinearDocument) { + @observable public addMenuToggle = React.createRef(); + private _dropDisposer?: DragManager.DragDropDisposer; + private _widthDisposer?: IReactionDisposer; + + componentWillUnmount() { + this._dropDisposer && this._dropDisposer(); + this._widthDisposer && this._widthDisposer(); + } + + componentDidMount() { + // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). + this._widthDisposer = reaction(() => NumCast(this.props.Document.height, 0) + this.childDocs.length + (this.props.Document.isExpanded ? 1 : 0), + () => this.props.Document.width = 5 + (this.props.Document.isExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), + { fireImmediately: true } + ); + } + protected createDropTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + this._dropDisposer && this._dropDisposer(); + if (ele) { + this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); + } + } + + public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } + + dimension = () => NumCast(this.props.Document.height); // 2 * the padding + getTransform = (ele: React.RefObject) => () => { + if (!ele.current) return Transform.Identity(); + const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); + return new Transform(-translateX, -translateY, 1 / scale); + } + + render() { + const guid = Utils.GenerateGuid(); + return
    +
    + this.props.Document.isExpanded = this.addMenuToggle.current!.checked)} /> + + +
    + {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => { + const nested = pair.layout.viewType === CollectionViewType.Linear; + const dref = React.createRef(); + const nativeWidth = NumCast(pair.layout.nativeWidth, this.dimension()); + const deltaSize = nativeWidth * .15 / 2; + return
    + this.dimension()}// ugh - need to get rid of this inline function to avoid recomputing + PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()} + renderDepth={this.props.renderDepth + 1} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + zoomToScale={emptyFunction} + getScale={returnOne}> + +
    ; + })} +
    +
    +
    ; + } +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index d6261c7ee..6af7cce70 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -75,7 +75,6 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facet]?.toString() || "(null)")); facetValues.add(child[facet]?.toString() || "(null)"); }); - this.childDocs const newFacetVals = facetValues.toArray().map(val => Docs.Create.TextDocument({ title: val.toString() })); const newFacet = Docs.Create.FreeformDocument(newFacetVals, { title: facet, treeViewOpen: true, isFacetFilter: true }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 022fc8f48..ce3aab579 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -4,39 +4,38 @@ import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagra import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from "mobx-react"; import * as React from 'react'; +import Lightbox from 'react-image-lightbox-with-rotate'; +import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app +import { DateField } from '../../../new_fields/DateField'; +import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; -import { StrCast, BoolCast, Cast } from '../../../new_fields/Types'; +import { listSpec } from '../../../new_fields/Schema'; +import { BoolCast, Cast, StrCast } 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'; +import { Utils } from '../../../Utils'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { DocumentManager } from '../../util/DocumentManager'; +import { ImageUtils } from '../../util/Import & Export/ImageUtils'; +import { SelectionManager } from '../../util/SelectionManager'; +import CollectionMulticolumnView from '../CollectionMulticolumnView'; import { ContextMenu } from "../ContextMenu"; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; +import { ScriptBox } from '../ScriptBox'; +import { Touchable } from '../Touchable'; import { CollectionDockingView } from "./CollectionDockingView"; import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionLinearView } from './CollectionLinearView'; +import { CollectionPivotView } from './CollectionPivotView'; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; +import { CollectionStaffView } from './CollectionStaffView'; import { CollectionTreeView } from "./CollectionTreeView"; +import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; -import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { CollectionLinearView } from '../CollectionLinearView'; -import { CollectionStaffView } from './CollectionStaffView'; -import { DocumentType } from '../../documents/DocumentTypes'; -import { ImageField } from '../../../new_fields/URLField'; -import { DocListCast } from '../../../new_fields/Doc'; -import Lightbox from 'react-image-lightbox-with-rotate'; -import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app export const COLLECTION_BORDER_WIDTH = 2; -import { DateField } from '../../../new_fields/DateField'; -import { Doc, } from '../../../new_fields/Doc'; -import { listSpec } from '../../../new_fields/Schema'; -import { DocumentManager } from '../../util/DocumentManager'; -import { SelectionManager } from '../../util/SelectionManager'; -import './CollectionView.scss'; -import { FieldViewProps, FieldView } from '../nodes/FieldView'; -import { Touchable } from '../Touchable'; -import { TraceMobx } from '../../../new_fields/util'; -import { Utils } from '../../../Utils'; -import { ScriptBox } from '../ScriptBox'; -import CollectionMulticolumnView from '../CollectionMulticolumnView'; -import { CollectionPivotView } from './CollectionPivotView'; const path = require('path'); library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); -- cgit v1.2.3-70-g09d2 From 810f6b9b2737f3617910e498f577499fcbf3ffab Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 Jan 2020 10:33:05 -0500 Subject: moved multilcolumnview into collections directory --- src/client/views/CollectionMulticolumnView.scss | 23 -- src/client/views/CollectionMulticolumnView.tsx | 233 --------------------- .../collections/CollectionMulticolumnView.scss | 23 ++ .../collections/CollectionMulticolumnView.tsx | 232 ++++++++++++++++++++ src/client/views/collections/CollectionView.tsx | 2 +- 5 files changed, 256 insertions(+), 257 deletions(-) delete mode 100644 src/client/views/CollectionMulticolumnView.scss delete mode 100644 src/client/views/CollectionMulticolumnView.tsx create mode 100644 src/client/views/collections/CollectionMulticolumnView.scss create mode 100644 src/client/views/collections/CollectionMulticolumnView.tsx (limited to 'src') diff --git a/src/client/views/CollectionMulticolumnView.scss b/src/client/views/CollectionMulticolumnView.scss deleted file mode 100644 index 120603a0b..000000000 --- a/src/client/views/CollectionMulticolumnView.scss +++ /dev/null @@ -1,23 +0,0 @@ -.collectionMulticolumnView_contents { - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - - .fish { - display: flex; - flex-direction: column; - - .display { - text-align: center; - height: 20px; - } - - } - - .resizer { - background: black; - cursor: ew-resize; - } - -} \ No newline at end of file diff --git a/src/client/views/CollectionMulticolumnView.tsx b/src/client/views/CollectionMulticolumnView.tsx deleted file mode 100644 index 99242e8be..000000000 --- a/src/client/views/CollectionMulticolumnView.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import { observer } from 'mobx-react'; -import { makeInterface } from '../../new_fields/Schema'; -import { documentSchema } from '../../new_fields/documentSchemas'; -import { CollectionSubView } from './collections/CollectionSubView'; -import { DragManager } from '../util/DragManager'; -import * as React from "react"; -import { Doc } from '../../new_fields/Doc'; -import { NumCast, StrCast } from '../../new_fields/Types'; -import { ContentFittingDocumentView } from './nodes/ContentFittingDocumentView'; -import { Utils } from '../../Utils'; -import "./collectionMulticolumnView.scss"; -import { computed } from 'mobx'; - -type MulticolumnDocument = makeInterface<[typeof documentSchema]>; -const MulticolumnDocument = makeInterface(documentSchema); - -interface Unresolved { - target: Doc; - magnitude: number; - unit: string; -} - -interface Resolved { - target: Doc; - pixels: number; -} - -interface LayoutData { - unresolved: Unresolved[]; - numFixed: number; - numRatio: number; - starSum: number; -} - -const resolvedUnits = ["*", "px"]; -const resizerWidth = 2; - -@observer -export default class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { - @computed - private get resolvedLayoutInformation(): LayoutData { - const unresolved: Unresolved[] = []; - let starSum = 0, numFixed = 0, numRatio = 0; - for (const target of this.childDocs) { - const unit = StrCast(target.widthUnit); - const magnitude = NumCast(target.widthMagnitude); - if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { - if (unit === "*") { - starSum += magnitude; - numRatio++; - } else { - numFixed++; - } - unresolved.push({ target, 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 - } - 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; - } - } - - @computed - private get contents(): JSX.Element[] | null { - const layout = this.resolvedLayoutInformation; - const columnUnitLength = this.columnUnitLength; - if (layout === null || columnUnitLength === undefined) { - return (null); // we're still waiting on promises to resolve - } - const resolved: Resolved[] = []; - layout.unresolved.forEach(item => { - const { unit, magnitude, ...remaining } = item; - let width = magnitude; - if (unit === "*") { - width = magnitude * columnUnitLength; - } - resolved.push({ pixels: width, ...remaining }); - }); - const collector: JSX.Element[] = []; - for (let i = 0; i < resolved.length; i++) { - const { target, pixels } = resolved[i]; - collector.push( -
    - pixels} - getTransform={this.props.ScreenToLocalTransform} - /> - {NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)} -
    , - - ); - } - collector.pop(); // removes the final extraneous resize bar - return collector; - } - - render(): JSX.Element { - return ( -
    - {this.contents} -
    - ); - } - -} - -interface SpacerProps { - width: number; - columnUnitLength: number; - toLeft?: Doc; - toRight?: Doc; -} - -class ResizeBar extends React.Component { - - private registerResizing = (e: React.PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - window.addEventListener("pointermove", this.onPointerMove); - window.addEventListener("pointerup", this.onPointerUp); - } - - private onPointerMove = ({ movementX }: PointerEvent) => { - const { toLeft, toRight, columnUnitLength } = this.props; - const target = movementX > 0 ? toRight : toLeft; - if (target) { - const { widthUnit, widthMagnitude } = target; - if (widthUnit === "*") { - target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / columnUnitLength; - } - } - } - - private get opacity() { - const { toLeft, toRight } = this.props; - if (toLeft && toRight) { - if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { - return 0; - } - return 0.4; - } else if (toLeft) { - if (StrCast(toLeft.widthUnit) === "px") { - return 0; - } - return 0.4; - } else if (toRight) { - if (StrCast(toRight.widthUnit) === "px") { - return 0; - } - return 0.4; - } - return 0; - } - - private onPointerUp = () => { - window.removeEventListener("pointermove", this.onPointerMove); - window.removeEventListener("pointerup", this.onPointerUp); - } - - render() { - return ( -
    - ); - } - -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss new file mode 100644 index 000000000..120603a0b --- /dev/null +++ b/src/client/views/collections/CollectionMulticolumnView.scss @@ -0,0 +1,23 @@ +.collectionMulticolumnView_contents { + display: flex; + width: 100%; + height: 100%; + overflow: hidden; + + .fish { + display: flex; + flex-direction: column; + + .display { + text-align: center; + height: 20px; + } + + } + + .resizer { + background: black; + cursor: ew-resize; + } + +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx new file mode 100644 index 000000000..19a7b1123 --- /dev/null +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -0,0 +1,232 @@ +import { observer } from 'mobx-react'; +import { makeInterface } from '../../../new_fields/Schema'; +import { documentSchema } from '../../../new_fields/documentSchemas'; +import { CollectionSubView } from './CollectionSubView'; +import * as React from "react"; +import { Doc } from '../../../new_fields/Doc'; +import { NumCast, StrCast } from '../../../new_fields/Types'; +import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView'; +import { Utils } from '../../../Utils'; +import "./collectionMulticolumnView.scss"; +import { computed } from 'mobx'; + +type MulticolumnDocument = makeInterface<[typeof documentSchema]>; +const MulticolumnDocument = makeInterface(documentSchema); + +interface Unresolved { + target: Doc; + magnitude: number; + unit: string; +} + +interface Resolved { + target: Doc; + pixels: number; +} + +interface LayoutData { + unresolved: Unresolved[]; + numFixed: number; + numRatio: number; + starSum: number; +} + +const resolvedUnits = ["*", "px"]; +const resizerWidth = 2; + +@observer +export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + @computed + private get resolvedLayoutInformation(): LayoutData { + const unresolved: Unresolved[] = []; + let starSum = 0, numFixed = 0, numRatio = 0; + for (const target of this.childDocs) { + const unit = StrCast(target.widthUnit); + const magnitude = NumCast(target.widthMagnitude); + if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { + if (unit === "*") { + starSum += magnitude; + numRatio++; + } else { + numFixed++; + } + unresolved.push({ target, 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 + } + 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; + } + } + + @computed + private get contents(): JSX.Element[] | null { + const layout = this.resolvedLayoutInformation; + const columnUnitLength = this.columnUnitLength; + if (layout === null || columnUnitLength === undefined) { + return (null); // we're still waiting on promises to resolve + } + const resolved: Resolved[] = []; + layout.unresolved.forEach(item => { + const { unit, magnitude, ...remaining } = item; + let width = magnitude; + if (unit === "*") { + width = magnitude * columnUnitLength; + } + resolved.push({ pixels: width, ...remaining }); + }); + const collector: JSX.Element[] = []; + for (let i = 0; i < resolved.length; i++) { + const { target, pixels } = resolved[i]; + collector.push( +
    + pixels} + getTransform={this.props.ScreenToLocalTransform} + /> + {NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)} +
    , + + ); + } + collector.pop(); // removes the final extraneous resize bar + return collector; + } + + render(): JSX.Element { + return ( +
    + {this.contents} +
    + ); + } + +} + +interface SpacerProps { + width: number; + columnUnitLength: number; + toLeft?: Doc; + toRight?: Doc; +} + +class ResizeBar extends React.Component { + + private registerResizing = (e: React.PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + window.addEventListener("pointermove", this.onPointerMove); + window.addEventListener("pointerup", this.onPointerUp); + } + + private onPointerMove = ({ movementX }: PointerEvent) => { + const { toLeft, toRight, columnUnitLength } = this.props; + const target = movementX > 0 ? toRight : toLeft; + if (target) { + const { widthUnit, widthMagnitude } = target; + if (widthUnit === "*") { + target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / columnUnitLength; + } + } + } + + private get opacity() { + const { toLeft, toRight } = this.props; + if (toLeft && toRight) { + if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { + return 0; + } + return 0.4; + } else if (toLeft) { + if (StrCast(toLeft.widthUnit) === "px") { + return 0; + } + return 0.4; + } else if (toRight) { + if (StrCast(toRight.widthUnit) === "px") { + return 0; + } + return 0.4; + } + return 0; + } + + private onPointerUp = () => { + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + } + + render() { + return ( +
    + ); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ce3aab579..4bd456233 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -19,7 +19,6 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { SelectionManager } from '../../util/SelectionManager'; -import CollectionMulticolumnView from '../CollectionMulticolumnView'; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { ScriptBox } from '../ScriptBox'; @@ -28,6 +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 { CollectionPivotView } from './CollectionPivotView'; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; -- cgit v1.2.3-70-g09d2 From fc4dd8c7d361bc848b6b27c67d5da26b8aab408e Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 Jan 2020 10:58:19 -0500 Subject: adjustments to multiColumnView to support templates --- src/client/views/collections/CollectionMulticolumnView.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 19a7b1123..157c5e367 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -40,9 +40,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; let starSum = 0, numFixed = 0, numRatio = 0; - for (const target of this.childDocs) { - const unit = StrCast(target.widthUnit); - const magnitude = NumCast(target.widthMagnitude); + for (const pair of this.childLayoutPairs) { + const unit = StrCast(pair.layout.widthUnit); + const magnitude = NumCast(pair.layout.widthMagnitude); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { if (unit === "*") { starSum += magnitude; @@ -50,7 +50,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } else { numFixed++; } - unresolved.push({ target, magnitude, unit }); + unresolved.push({ target: pair.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 @@ -132,7 +132,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu {...this.props} key={Utils.GenerateGuid()} Document={target} - DataDocument={undefined} + DataDocument={target.resolvedDataDoc as Doc} PanelWidth={() => pixels} getTransform={this.props.ScreenToLocalTransform} /> -- cgit v1.2.3-70-g09d2 From 9af3c5967e45b98186a2862a1f23e2494630ddb3 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 17 Jan 2020 11:32:56 -0500 Subject: fixed placement of documentdecorations for multicolumnview --- src/client/views/collections/CollectionMulticolumnView.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 157c5e367..a04df171a 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -124,8 +124,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu resolved.push({ pixels: width, ...remaining }); }); const collector: JSX.Element[] = []; + let offset = 0; for (let i = 0; i < resolved.length; i++) { const { target, pixels } = resolved[i]; + const shiftX = offset; collector.push(
    pixels} - getTransform={this.props.ScreenToLocalTransform} + getTransform={() => this.props.ScreenToLocalTransform().translate(-shiftX, 0)} /> {NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)}
    , @@ -146,6 +148,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu toRight={resolved[i + 1]?.target} /> ); + offset += pixels + resizerWidth; } collector.pop(); // removes the final extraneous resize bar return collector; -- cgit v1.2.3-70-g09d2 From f783e6cd66d4a7e303bd327d028076e3d76815bc Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 11:45:49 -0500 Subject: drop target added to mc view --- src/client/views/collections/CollectionMulticolumnView.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 157c5e367..4744de34c 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -36,6 +36,7 @@ const resizerWidth = 2; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + @computed private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; @@ -84,8 +85,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu @computed private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; - if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) + if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); + } } /** @@ -153,7 +155,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu render(): JSX.Element { return ( -
    +
    {this.contents}
    ); -- cgit v1.2.3-70-g09d2