From 07e53a4a244eff804e47c6b48b8eb4f2a5096b0e Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 31 Jan 2020 15:46:42 -0500 Subject: added collectionTime view --- src/client/views/collections/CollectionViewChromes.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 073a30330..9cb668d20 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -71,6 +71,7 @@ export class CollectionViewBaseChrome extends React.ComponentMasonry - - + + +
-- cgit v1.2.3-70-g09d2 From d20a21384fc685082955cfbb9deb9c0f1176e7ad Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 31 Jan 2020 18:30:42 -0500 Subject: added multirow collection. cleaned up CollectionTimeview a bit. --- .../views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 5 + .../views/collections/CollectionViewChromes.tsx | 11 +- .../CollectionFreeFormLayoutEngines.tsx | 9 +- .../CollectionMultirowView.scss | 34 +++ .../CollectionMultirowView.tsx | 259 +++++++++++++++++++++ .../collectionMulticolumn/MultirowHeightLabel.tsx | 56 +++++ .../collectionMulticolumn/MultirowResizer.tsx | 116 +++++++++ 8 files changed, 484 insertions(+), 8 deletions(-) create mode 100644 src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss create mode 100644 src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx create mode 100644 src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx create mode 100644 src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index dfcf93ef6..19a48d6ef 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -74,7 +74,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } _canClick = false; _facetWidthOnDown = 0; - @observable _facetWidth = 200; + @observable _facetWidth = 0; onPointerDown = (e: React.PointerEvent) => { this._canClick = true; this._facetWidthOnDown = e.screenX; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 027cf2404..5a7bdef61 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -37,6 +37,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; import { CollectionTimeView } from './CollectionTimeView'; +import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); @@ -50,6 +51,7 @@ export enum CollectionViewType { Stacking, Masonry, Multicolumn, + Multirow, Pivot, Time, Carousel, @@ -68,6 +70,7 @@ export namespace CollectionViewType { ["stacking", CollectionViewType.Stacking], ["masonry", CollectionViewType.Masonry], ["multicolumn", CollectionViewType.Multicolumn], + ["multirow", CollectionViewType.Multirow], ["pivot", CollectionViewType.Pivot], ["time", CollectionViewType.Time], ["carousel", CollectionViewType.Carousel], @@ -183,6 +186,7 @@ export class CollectionView extends Touchable { case CollectionViewType.Tree: return (); case CollectionViewType.Staff: return (); case CollectionViewType.Multicolumn: return (); + case CollectionViewType.Multirow: return (); case CollectionViewType.Linear: { return (); } case CollectionViewType.Carousel: { return (); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } @@ -227,6 +231,7 @@ export class CollectionView extends Touchable { }); subItems.push({ description: "Staff", event: () => this.props.Document._viewType = CollectionViewType.Staff, icon: "music" }); subItems.push({ description: "Multicolumn", event: () => this.props.Document._viewType = CollectionViewType.Multicolumn, icon: "columns" }); + subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" }); subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" }); subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" }); subItems.push({ description: "Pivot", event: () => this.props.Document._viewType = CollectionViewType.Pivot, icon: "columns" }); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 9cb668d20..c5db6f10f 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -417,11 +417,12 @@ export class CollectionViewBaseChrome extends React.ComponentTree - - - - - + + + + + +
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 8a1147c61..6e4af3520 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -10,7 +10,6 @@ import { ObservableMap, runInAction } from "mobx"; import { Id, ToString } from "../../../../new_fields/FieldSymbols"; import { ObjectField } from "../../../../new_fields/ObjectField"; import { RefField } from "../../../../new_fields/RefField"; -import { createPromiseCapability } from "../../../../../deploy/assets/pdf.worker"; interface PivotData { type: string; @@ -142,8 +141,11 @@ export function computeTimelineLayout( poolData: ObservableMap, pivotDoc: Doc, childDocs: Doc[], - childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[] + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: (views: any) => ViewDefResult[] ) { + const fieldKey = "data"; const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200); const pivotDateGroups = new Map(); @@ -159,6 +161,9 @@ export function computeTimelineLayout( minTime = Math.min(num, minTime); maxTime = Math.max(num, maxTime); } + minTime = NumCast(pivotDoc[fieldKey + "-timelineMin"], minTime); + maxTime = NumCast(pivotDoc[fieldKey + "-timelineMax"], maxTime); + const curTime = Cast(pivotDoc[fieldKey + "-timelineCur"], "number", null); const docMap = new Map(); const groupNames: PivotData[] = []; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss new file mode 100644 index 000000000..ef4b4a19c --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss @@ -0,0 +1,34 @@ +.collectionMultirowView_contents { + display: flex; + width: 100%; + height: 100%; + overflow: hidden; + flex-direction: column; + + .document-wrapper { + display: flex; + flex-direction: row; + + .label-wrapper { + display: flex; + flex-direction: row; + justify-content: center; + height: 20px; + } + + } + + .resizer { + cursor: ew-resize; + transition: 0.5s opacity ease; + display: flex; + flex-direction: row; + + .internal { + width: 100%; + height: 100%; + transition: 0.5s background-color ease; + } + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx new file mode 100644 index 000000000..e07985bb4 --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -0,0 +1,259 @@ +import { observer } from 'mobx-react'; +import { makeInterface } from '../../../../new_fields/Schema'; +import { documentSchema } from '../../../../new_fields/documentSchemas'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import * as React from "react"; +import { Doc } from '../../../../new_fields/Doc'; +import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types'; +import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; +import { Utils } from '../../../../Utils'; +import "./collectionMultirowView.scss"; +import { computed, trace, observable, action } from 'mobx'; +import { Transform } from '../../../util/Transform'; +import HeightLabel from './MultirowHeightLabel'; +import ResizeBar from './MultirowResizer'; +import { undoBatch } from '../../../util/UndoManager'; +import { DragManager } from '../../../util/DragManager'; + +type MultirowDocument = makeInterface<[typeof documentSchema]>; +const MultirowDocument = makeInterface(documentSchema); + +interface HeightSpecifier { + magnitude: number; + unit: string; +} + +interface LayoutData { + heightSpecifiers: HeightSpecifier[]; + starSum: number; +} + +export const HeightUnit = { + Pixel: "px", + Ratio: "*" +}; + +const resolvedUnits = Object.values(HeightUnit); +const resizerHeight = 4; + +@observer +export class CollectionMultirowView extends CollectionSubView(MultirowDocument) { + + /** + * @returns the list of layout documents whose width unit is + * *, denoting that it will be displayed with a ratio, not fixed pixel, value + */ + @computed + private get ratioDefinedDocs() { + return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === HeightUnit.Ratio); + } + + /** + * This loops through all childLayoutPairs and extracts the values for widthUnit + * and widthMagnitude, ignoring any that are malformed. Additionally, it then + * normalizes the ratio values so that one * value is always 1, with the remaining + * values proportionate to that easily readable metric. + * @returns the list of the resolved width specifiers (unit and magnitude pairs) + * as well as the sum of the * coefficients, i.e. the ratio magnitudes + */ + @computed + private get resolvedLayoutInformation(): LayoutData { + let starSum = 0; + const heightSpecifiers: HeightSpecifier[] = []; + this.childLayoutPairs.map(({ layout: { heightUnit, heightMagnitude } }) => { + const unit = StrCast(heightUnit); + const magnitude = NumCast(heightMagnitude); + if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { + (unit === HeightUnit.Ratio) && (starSum += magnitude); + heightSpecifiers.push({ magnitude, unit }); + } + /** + * Otherwise, the child document is ignored and the remaining + * space is allocated as if the document were absent from the child list + */ + }); + + /** + * Here, since these values are all relative, adjustments during resizing or + * manual updating can, though their ratios remain the same, cause the values + * themselves to drift toward zero. Thus, whenever we change any of the values, + * we normalize everything (dividing by the smallest magnitude). + */ + setTimeout(() => { + const { ratioDefinedDocs } = this; + if (this.childLayoutPairs.length) { + const minimum = Math.min(...ratioDefinedDocs.map(({ heightMagnitude }) => NumCast(heightMagnitude))); + if (minimum !== 0) { + ratioDefinedDocs.forEach(layout => layout.heightMagnitude = NumCast(layout.heightMagnitude) / minimum); + } + } + }); + + return { heightSpecifiers, 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?.heightSpecifiers.reduce( + (sum, { magnitude, unit }) => sum + (unit === HeightUnit.Pixel ? magnitude : 0), 0); + } + + /** + * @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.heightSpecifiers.length; + if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { + return this.props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)); + } + } + + /** + * @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 rowUnitLength(): number | undefined { + if (this.resolvedLayoutInformation && this.totalRatioAllocation !== undefined) { + return this.totalRatioAllocation / this.resolvedLayoutInformation.starSum; + } + } + + /** + * This wrapper function exists to prevent mobx from + * needlessly rerendering the internal ContentFittingDocumentViews + */ + private getRowUnitLength = () => this.rowUnitLength; + + /** + * @param layout the document whose transform we'd like to compute + * Given a layout document, this function + * returns the resolved width it has requested, in pixels. + * @returns the stored row width if already in pixels, + * or the ratio width evaluated to a pixel value + */ + private lookupPixels = (layout: Doc): number => { + const rowUnitLength = this.rowUnitLength; + if (rowUnitLength === undefined) { + return 0; // we're still waiting on promises to resolve + } + let height = NumCast(layout.heightMagnitude); + if (StrCast(layout.heightUnit) === HeightUnit.Ratio) { + height *= rowUnitLength; + } + return height; + } + + /** + * @returns the transform that will correctly place + * the document decorations box, shifted to the right by + * the sum of all the resolved row widths of the + * documents before the target. + */ + private lookupIndividualTransform = (layout: Doc) => { + const rowUnitLength = this.rowUnitLength; + if (rowUnitLength === undefined) { + return Transform.Identity(); // we're still waiting on promises to resolve + } + let offset = 0; + for (const { layout: candidate } of this.childLayoutPairs) { + if (candidate === layout) { + return this.props.ScreenToLocalTransform().translate(0, -offset); + } + offset += this.lookupPixels(candidate) + resizerHeight; + } + return Transform.Identity(); // type coersion, this case should never be hit + } + + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + if (super.drop(e, de)) { + de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => { + d.heightUnit = "*"; + d.heightMagnitude = 1; + })); + } + return false; + } + + + @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); } + + /** + * @returns the resolved list of rendered child documents, displayed + * at their resolved pixel widths, each separated by a resizer. + */ + @computed + private get contents(): JSX.Element[] | null { + const { childLayoutPairs } = this; + const { Document, PanelWidth } = this.props; + const collector: JSX.Element[] = []; + for (let i = 0; i < childLayoutPairs.length; i++) { + const { layout } = childLayoutPairs[i]; + collector.push( +
+ this.lookupPixels(layout)} + PanelWidth={() => PanelWidth() - (BoolCast(Document.showHeightLabels) ? 20 : 0)} + getTransform={() => this.lookupIndividualTransform(layout)} + onClick={this.onChildClickHandler} + renderDepth={this.props.renderDepth + 1} + /> + +
, + + ); + } + collector.pop(); // removes the final extraneous resize bar + return collector; + } + + render(): JSX.Element { + return ( +
+ {this.contents} +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx new file mode 100644 index 000000000..56a2e868d --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx @@ -0,0 +1,56 @@ +import * as React from "react"; +import { observer } from "mobx-react"; +import { computed } from "mobx"; +import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types"; +import { EditableView } from "../../EditableView"; +import { HeightUnit } from "./CollectionMultirowView"; + +interface HeightLabelProps { + layout: Doc; + collectionDoc: Doc; + decimals?: number; +} + +@observer +export default class HeightLabel extends React.Component { + + @computed + private get contents() { + const { layout, decimals } = this.props; + const getUnit = () => StrCast(layout.heightUnit); + const getMagnitude = () => String(+NumCast(layout.heightMagnitude).toFixed(decimals ?? 3)); + return ( +
+ { + const converted = Number(value); + if (!isNaN(converted) && converted > 0) { + layout.heightMagnitude = converted; + return true; + } + return false; + }} + contents={getMagnitude()} + /> + { + if (Object.values(HeightUnit).includes(value)) { + layout.heightUnit = value; + return true; + } + return false; + }} + contents={getUnit()} + /> +
+ ); + } + + render() { + return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : (null); + } + +} \ No newline at end of file diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx new file mode 100644 index 000000000..20c6cd3df --- /dev/null +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -0,0 +1,116 @@ +import * as React from "react"; +import { observer } from "mobx-react"; +import { observable, action } from "mobx"; +import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, StrCast } from "../../../../new_fields/Types"; +import { HeightUnit } from "./CollectionMultirowView"; + +interface ResizerProps { + height: number; + columnUnitLength(): number | undefined; + toTop?: Doc; + toBottom?: Doc; +} + +enum ResizeMode { + Global = "blue", + Pinned = "red", + Undefined = "black" +} + +const resizerOpacity = 1; + +@observer +export default class ResizeBar extends React.Component { + @observable private isHoverActive = false; + @observable private isResizingActive = false; + @observable private resizeMode = ResizeMode.Undefined; + + @action + private registerResizing = (e: React.PointerEvent, mode: ResizeMode) => { + e.stopPropagation(); + e.preventDefault(); + this.resizeMode = mode; + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + window.addEventListener("pointermove", this.onPointerMove); + window.addEventListener("pointerup", this.onPointerUp); + this.isResizingActive = true; + } + + private onPointerMove = ({ movementY }: PointerEvent) => { + const { toTop: toTop, toBottom: toBottom, columnUnitLength } = this.props; + const movingDown = movementY > 0; + const toNarrow = movingDown ? toBottom : toTop; + const toWiden = movingDown ? toTop : toBottom; + const unitLength = columnUnitLength(); + if (unitLength) { + if (toNarrow) { + const { heightUnit, heightMagnitude } = toNarrow; + const scale = heightUnit === HeightUnit.Ratio ? unitLength : 1; + toNarrow.heightMagnitude = NumCast(heightMagnitude) - Math.abs(movementY) / scale; + } + if (this.resizeMode === ResizeMode.Pinned && toWiden) { + const { heightUnit, heightMagnitude } = toWiden; + const scale = heightUnit === HeightUnit.Ratio ? unitLength : 1; + toWiden.heightMagnitude = NumCast(heightMagnitude) + Math.abs(movementY) / scale; + } + } + } + + private get isActivated() { + const { toTop, toBottom } = this.props; + if (toTop && toBottom) { + if (StrCast(toTop.heightUnit) === HeightUnit.Pixel && StrCast(toBottom.heightUnit) === HeightUnit.Pixel) { + return false; + } + return true; + } else if (toTop) { + if (StrCast(toTop.heightUnit) === HeightUnit.Pixel) { + return false; + } + return true; + } else if (toBottom) { + if (StrCast(toBottom.heightUnit) === HeightUnit.Pixel) { + return false; + } + return true; + } + return false; + } + + @action + private onPointerUp = () => { + this.resizeMode = ResizeMode.Undefined; + this.isResizingActive = false; + this.isHoverActive = false; + window.removeEventListener("pointermove", this.onPointerMove); + window.removeEventListener("pointerup", this.onPointerUp); + } + + render() { + return ( +
this.isHoverActive = true)} + onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} + > +
this.registerResizing(e, ResizeMode.Pinned)} + style={{ backgroundColor: this.resizeMode }} + /> +
this.registerResizing(e, ResizeMode.Global)} + style={{ backgroundColor: this.resizeMode }} + /> +
+ ); + } + +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From feaed0e1fbfb505684c87996b020ee36b7e96224 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 1 Feb 2020 21:49:23 -0500 Subject: moved all of pivot view into TimeView. tweaked layout for pivot. better fix is straightforward. --- .../views/collections/CollectionPivotView.scss | 88 ----------- .../views/collections/CollectionPivotView.tsx | 174 --------------------- .../views/collections/CollectionTimeView.scss | 9 +- .../views/collections/CollectionTimeView.tsx | 38 ++++- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 7 +- .../views/collections/CollectionViewChromes.tsx | 34 +--- .../CollectionFreeFormLayoutEngines.tsx | 77 ++++----- .../views/presentationview/PresElementBox.scss | 2 +- 9 files changed, 80 insertions(+), 351 deletions(-) delete mode 100644 src/client/views/collections/CollectionPivotView.scss delete mode 100644 src/client/views/collections/CollectionPivotView.tsx (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/client/views/collections/CollectionPivotView.scss b/src/client/views/collections/CollectionPivotView.scss deleted file mode 100644 index 505091e98..000000000 --- a/src/client/views/collections/CollectionPivotView.scss +++ /dev/null @@ -1,88 +0,0 @@ -.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%; - } - } - - .pivotKeyEntry { - position: absolute; - top: 5px; - right: 5px; - z-index: 10; - pointer-events: all; - padding: 5px; - border: 1px solid black; - } - - .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: 100%; - height: calc(100% - 30px); - } - } - - .collectionPivotView-pivot { - display: inline-block; - width: calc(100% - 200px); - height: 100%; - } - - .collectionPivotView-dragger { - background-color: lightgray; - height: 40px; - width: 20px; - position: absolute; - border-radius: 10px; - top: 55%; - border: 1px black solid; - z-index: 2; - left: -10px; - } -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx deleted file mode 100644 index 992018a3f..000000000 --- a/src/client/views/collections/CollectionPivotView.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { faEdit } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, observable } from "mobx"; -import { observer } from "mobx-react"; -import { Set } from "typescript-collections"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { Docs } from "../../documents/Documents"; -import { EditableView } from "../EditableView"; -import { anchorPoints, Flyout } from "../TemplateMenu"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import "./CollectionPivotView.scss"; -import { CollectionSubView } from "./CollectionSubView"; -import { CollectionTreeView } from "./CollectionTreeView"; -import React = require("react"); -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { RichTextField } from "../../../new_fields/RichTextField"; - -@observer -export class CollectionPivotView extends CollectionSubView(doc => doc) { - componentDidMount() { - this.props.Document._freeformLayoutEngine = "pivot"; - const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked; - if (!this.props.Document._facetCollection) { - const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true }); - facetCollection.target = this.props.Document; - this.props.Document.excludeFields = new List(["_facetCollection", "_docFilter"]); - - const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)"; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailed'); useRightSplit(alias); "; - facetCollection.onCheckedClick = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name }); - this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name }); - this.props.Document._facetCollection = facetCollection; - this.props.Document._fitToBox = true; - } - } - bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth; - getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 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(); - } - - /** - * Responds to clicking the check box in the flyout menu - */ - facetClick = (facetHeader: string) => { - const facetCollection = this.props.Document._facetCollection; - if (facetCollection instanceof Doc) { - const found = DocListCast(facetCollection.data).findIndex(doc => doc.title === facetHeader); - if (found !== -1) { - (facetCollection.data as List).splice(found, 1); - const docFilter = Cast(this.props.Document._docFilter, listSpec("string")); - if (docFilter) { - let index: number; - while ((index = docFilter.findIndex(item => item === facetHeader)) !== -1) { - docFilter.splice(index, 3); - } - } - } else { - const newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true }); - const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc }; - const params = { layoutDoc: Doc.name, dataDoc: Doc.name, }; - newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables); - Doc.AddDocToList(facetCollection, "data", newFacet); - } - } - } - _canClick = false; - _facetWidthOnDown = 0; - @observable _facetWidth = 200; - onPointerDown = (e: React.PointerEvent) => { - this._canClick = true; - this._facetWidthOnDown = e.screenX; - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - document.addEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointerup", this.onPointerUp); - e.stopPropagation(); - e.preventDefault(); - } - - - @action - onPointerMove = (e: PointerEvent) => { - this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0); - Math.abs(e.movementX) > 6 && (this._canClick = false); - } - @action - onPointerUp = (e: PointerEvent) => { - if (Math.abs(e.screenX - this._facetWidthOnDown) < 6 && this._canClick) { - this._facetWidth = this._facetWidth < 15 ? 200 : 0; - } - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - } - - menuCallback = (x: number, y: number) => { - ContextMenu.Instance.clearItems(); - const docItems: ContextMenuProps[] = []; - const keySet: Set = new Set(); - - this.childLayoutPairs.map(pair => - Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "string").map(fieldKey => - keySet.add(fieldKey))); - keySet.toArray().map(fieldKey => - docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); - docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) - ContextMenu.Instance.addItem({ description: "Pivot Fields ...", subitems: docItems, icon: "eye" }); - const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); - ContextMenu.Instance.displayMenu(x, y, ":"); - } - - @observable private collapsed: boolean = false; - private toggleVisibility = action(() => this.collapsed = !this.collapsed); - - render() { - const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); - const flyout = ( -
- {this._allFacets.map(facet => )} -
- ); - const newEditableViewProps = { - GetValue: () => "", - SetValue: (value: any) => { - if (value?.length) { - this.props.Document.pivotField = value; - return true; - } - return false; - }, - showMenuOnLoad: true, - contents: ":" + StrCast(this.props.Document.pivotField), - toggle: this.toggleVisibility, - color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - }; - return !facetCollection ? (null) : -
-
- -
-
- -
-
-
e.stopPropagation()}> - -
- Facet Filters - -
-
-
-
- -
-
-
- -
-
; - } -} \ No newline at end of file diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index 805d06d3d..3aac2bc75 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -1,4 +1,4 @@ -.collectionTimeView { +.collectionTimeView, .collectionTimeView-pivot { display: flex; flex-direction: row; position: absolute; @@ -93,7 +93,7 @@ } } - .collectionTimeView-pivot { + .collectionTimeView-innards { display: inline-block; width: calc(100% - 200px); height: 100%; @@ -110,4 +110,9 @@ z-index: 2; left: -10px; } +} +.collectionTimeView-pivot { + .collectionFreeform-customText { + text-align: center; + } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index b4ab88f9a..253dfa890 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -107,8 +107,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { const keySet: Set = new Set(); this.childLayoutPairs.map(pair => - Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof (pair.layout[fieldKey]) === "number" || typeof (pair.layout[fieldKey]) === "string").map(fieldKey => - keySet.add(fieldKey))); + Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => + pair.layout[fieldKey] instanceof RichTextField || + typeof (pair.layout[fieldKey]) === "number" || + typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey))); keySet.toArray().map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) @@ -189,11 +191,12 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } @computed get contents() { - return
+ return
; } + _changing = false; render() { const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); const flyout = ( @@ -219,8 +222,33 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { toggle: this.toggleVisibility, color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; }; + + let nonNumbers = 0; + this.childDocs.map(doc => { + const num = NumCast(doc[StrCast(this.props.Document.pivotField)], Number(StrCast(doc[StrCast(this.props.Document.pivotField)]))); + if (Number.isNaN(num)) { + nonNumbers++; + } + }); + const doTimeline = nonNumbers / this.childDocs.length < 0.1; + if (doTimeline !== (this.props.Document._freeformLayoutEngine === "timeline")) { + if (!this._changing) { + this._changing = true; + setTimeout(() => { + if (nonNumbers / this.childDocs.length > 0.1) { + this.childDocs.map(child => child.isMinimized = false); + this.props.Document._freeformLayoutEngine = "pivot"; + } else { + this.props.Document._freeformLayoutEngine = "timeline"; + } + this._changing = false; + }, 0); + } + return (null); + } + return !facetCollection ? (null) : -
+
@@ -243,7 +271,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
{this.contents} - {!this.props.isSelected() ? (null) : <> + {!this.props.isSelected() || !doTimeline ? (null) : <>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 3cb24f079..631870866 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -659,7 +659,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { Document.childLayout = cardLayout; Document.childDetailed = detailedLayout; - Document._viewType = CollectionViewType.Pivot; + Document._viewType = CollectionViewType.Time; Document.pivotField = "company"; } }); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5a7bdef61..d5d62159b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -29,7 +29,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionLinearView } from './CollectionLinearView'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; -import { CollectionPivotView } from './CollectionPivotView'; import { CollectionSchemaView } from "./CollectionSchemaView"; import { CollectionStackingView } from './CollectionStackingView'; import { CollectionStaffView } from './CollectionStaffView'; @@ -52,7 +51,6 @@ export enum CollectionViewType { Masonry, Multicolumn, Multirow, - Pivot, Time, Carousel, Linear, @@ -71,7 +69,6 @@ export namespace CollectionViewType { ["masonry", CollectionViewType.Masonry], ["multicolumn", CollectionViewType.Multicolumn], ["multirow", CollectionViewType.Multirow], - ["pivot", CollectionViewType.Pivot], ["time", CollectionViewType.Time], ["carousel", CollectionViewType.Carousel], ["linear", CollectionViewType.Linear], @@ -191,7 +188,6 @@ export class CollectionView extends Touchable { case CollectionViewType.Carousel: { return (); } case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } - case CollectionViewType.Pivot: { return (); } case CollectionViewType.Time: { return (); } case CollectionViewType.Freeform: default: { this.props.Document._freeformLayoutEngine = undefined; return (); } @@ -234,8 +230,7 @@ export class CollectionView extends Touchable { subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" }); subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" }); subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" }); - subItems.push({ description: "Pivot", event: () => this.props.Document._viewType = CollectionViewType.Pivot, icon: "columns" }); - subItems.push({ description: "Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); + subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" }); switch (this.props.Document._viewType) { case CollectionViewType.Freeform: { subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) }); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index c5db6f10f..f00af52cf 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -70,7 +70,6 @@ export class CollectionViewBaseChrome extends React.Component { - if (StrCast(this.document._freeformLayoutEngine) !== "pivot") { - return (null); - } - return () => this.pivotKeyDisplay = e.currentTarget.value)} - onKeyPress={action((e: React.KeyboardEvent) => { - const value = e.currentTarget.value; - if (e.which === 13) { - this.pivotKey = value; - this.pivotKeyDisplay = ""; - } - })} />); - } - @action.bound clearFilter = () => { this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name }); @@ -419,10 +392,9 @@ export class CollectionViewBaseChrome extends React.ComponentMasonry - - - - + + +
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d2a2b42a0..6f84346df 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -46,10 +46,14 @@ export function computePivotLayout( poolData: ObservableMap, pivotDoc: Doc, childDocs: Doc[], - childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[] + childPairs: { layout: Doc, data?: Doc }[], + panelDim: number[], + viewDefsToJSX: (views: any) => ViewDefResult[] ) { - const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200); + const fieldKey = "data"; + const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 1000); const pivotColumnGroups = new Map, Doc[]>(); + const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3)); const pivotFieldKey = toLabel(pivotDoc.pivotField); for (const doc of childDocs) { @@ -69,16 +73,20 @@ export function computePivotLayout( const expander = 1.05; const gap = .15; let x = 0; + let max_text = 60; pivotColumnGroups.forEach((val, key) => { let y = 0; let xCount = 0; + const text = toLabel(key); + max_text = Math.max(max_text, Math.min(500, text.length)); groupNames.push({ type: "text", - text: toLabel(key), + text, x, y: pivotAxisWidth, width: pivotAxisWidth * expander * numCols, - fontSize: NumCast(pivotDoc.pivotFontSize, 20) + height: max_text, + fontSize }); for (const doc of val) { const layoutDoc = Doc.Layout(doc); @@ -103,37 +111,7 @@ export function computePivotLayout( x += pivotAxisWidth * (numCols * expander + gap); }); - const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, width: gn.width, height: undefined } as PivotData; }); - const docEles = childPairs.map(pair => - docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), width: NumCast(pair.layout._width), height: NumCast(pair.layout._height) } // new pos is computed pos, or pos written to the document's fields - ); - const minLabelHeight = 56; - const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); - const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); - const scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] - (2 * minLabelHeight) ? (panelDim[1] - (2 * minLabelHeight)) / (aggBounds.b - aggBounds.y) : wscale; - const centerY = ((panelDim[1] - 2 * minLabelHeight) - (aggBounds.b - aggBounds.y) * scale) / 2; - const centerX = (panelDim[0] - (aggBounds.r - aggBounds.x) * scale) / 2; - - childPairs.map(pair => { - const fallbackPos = { - x: NumCast(pair.layout.x), - y: NumCast(pair.layout.y), - z: NumCast(pair.layout.z), - width: NumCast(pair.layout._width), - height: NumCast(pair.layout._height) - }; - const newPosRaw = docMap.get(pair.layout) || fallbackPos; // new pos is computed pos, or pos written to the document's fields - const newPos = { x: newPosRaw.x * scale + centerX, y: (newPosRaw.y - aggBounds.y) * scale + centerY, z: newPosRaw.z, width: (newPosRaw.width || 0) * scale, height: newPosRaw.height! * scale }; - const lastPos = poolData.get(pair.layout[Id]); // last computed pos - if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.width !== lastPos.width || newPos.height !== lastPos.height) { - runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos })); - } - }); - return { - elements: viewDefsToJSX([{ type: "text", text: "", x: 0, y: -aggBounds.y * scale - minLabelHeight, width: panelDim[0], height: panelDim[1], fontSize: 1 }].concat(groupNames.map(gname => { - return { type: gname.type, text: gname.text, x: gname.x * scale + centerX, y: (gname.y - aggBounds.y) * scale + centerY, width: (gname.width || 0) * scale, height: Math.max(minLabelHeight, centerY), fontSize: gname.fontSize }; - }))) - }; + return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } @@ -186,7 +164,7 @@ export function computeTimelineLayout( groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize }); } - const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, panelDim[1] / 2.5); + const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5); let stacking: number[] = []; sortedKeys.forEach(key => { const keyDocs = pivotDateGroups.get(key)!; @@ -212,12 +190,19 @@ export function computeTimelineLayout( groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize }); } - const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, height: gn.height } as PivotData; }); + const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any; + return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]); +} + +function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: any, + poolData: any, viewDefsToJSX: any, groupNames: PivotData[], minWidth: number, extras: any[]) { + + const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, height: gn.height }) as PivotData); const docEles = childPairs.filter(d => !d.layout.isMinimized).map(pair => docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y), width: pair.layout[WidthSym](), height: pair.layout[HeightSym]() } as PivotData // new pos is computed pos, or pos written to the document's fields ); const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); - aggBounds.r = Math.max((maxTime - minTime) * scaling, aggBounds.r - aggBounds.x); + aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x); const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale; if (Number.isNaN(scale)) scale = 1; @@ -237,12 +222,18 @@ export function computeTimelineLayout( runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos })); } }); + return { - elements: viewDefsToJSX([ - { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any - ].concat(groupNames.map(gname => { - return { type: gname.type, text: gname.text, x: gname.x * scale, y: gname.y * scale, width: gname.width === undefined ? gname.width : gname.width * scale, height: Math.max(fontHeight, gname.height! * scale), fontSize: gname.fontSize }; - }))) + elements: viewDefsToJSX(extras.concat(groupNames.map(gname => ({ + type: gname.type, + text: gname.text, + x: gname.x * scale, + y: gname.y * scale, + width: gname.width === undefined ? undefined : gname.width * scale, + height: Math.max(fontHeight, gname.height! * scale), + // height: gname.height === undefined ? undefined : gname.height * scale, + fontSize: gname.fontSize + })))) }; } diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index fd9de90e0..8370af490 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -71,7 +71,7 @@ } .presElementBox-name { - font-size: 12px; + font-size: 12pxππ; position: absolute; display: inline-block; width: calc(100% - 45px); -- cgit v1.2.3-70-g09d2 From d3abbcfc975247839b587b37cabd4f07db73f28c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 8 Feb 2020 02:19:56 -0500 Subject: cleaned up links on images. fixed axis sorting on pivot views. fixed dragging link button --- src/client/views/DocumentButtonBar.tsx | 2 +- .../views/collections/CollectionSchemaView.scss | 6 +++--- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionViewChromes.tsx | 5 ++--- .../CollectionFreeFormLayoutEngines.tsx | 16 +++++++++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 23 ++-------------------- .../views/nodes/ContentFittingDocumentView.scss | 2 +- 8 files changed, 23 insertions(+), 35 deletions(-) (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 963d97d59..d6029dbe5 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -237,7 +237,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | @computed get metadataButton() { const view0 = this.view0; - return !view0 ? (null) :
+ return !view0 ? (null) :
this.props.views.filter(dv => dv).map(dv => dv!.props.Document)} suggestWithFunction /> /* tfs: @bcz This might need to be the data document? */}>
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 8b3d332af..a24140b48 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -39,9 +39,9 @@ cursor: col-resize; } - .documentView-node:first-child { - background: $light-color; - } + // .documentView-node:first-child { + // background: $light-color; + // } } .ReactTable { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 171aecc70..d772ace23 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -39,7 +39,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); } @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); } @computed get filteredChildren() { return this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); } - @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * this.gridGap); } + @computed get xMargin() { return NumCast(this.props.Document._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); } @computed get yMargin() { return Math.max(this.props.Document.showTitle && !this.props.Document.showTitleHover ? 30 : 0, NumCast(this.props.Document._yMargin, 0)); } // 2 * this.gridGap)); } @computed get gridGap() { return NumCast(this.props.Document._gridGap, 10); } @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e0e99d635..62b9e8380 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -320,7 +320,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { nativeWidth && (proto["data-nativeWidth"] = nativeWidth); nativeHeight && (proto["data-nativeHeight"] = nativeHeight); contentSize && (proto.contentSize = contentSize); - this.props.addDocument(doc); + this.props?.addDocument(doc); } }); })); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index f00af52cf..a21e78188 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -386,15 +386,14 @@ export class CollectionViewBaseChrome extends React.Component - + - + -
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 95f7794bb..baf09fe5b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -42,13 +42,13 @@ export interface ViewDefResult { ele: JSX.Element; bounds?: ViewDefBounds; } - function toLabel(target: FieldResult) { if (target instanceof ObjectField || target instanceof RefField) { return target[ToString](); } return String(target); -}/** +} +/** * Uses canvas.measureText to compute and return the width of the given text of given font in pixels. * * @param {String} text The text to be rendered. @@ -91,9 +91,17 @@ export function computePivotLayout( pivotColumnGroups.get(val)!.docs.push(doc); } } + let nonNumbers = 0; + childDocs.map(doc => { + const num = toNumber(doc[pivotFieldKey]); + if (num === undefined || Number.isNaN(num)) { + nonNumbers++; + } + }); + const pivotNumbers = nonNumbers / childDocs.length < .1; if (pivotColumnGroups.size > 10) { const arrayofKeys = Array.from(pivotColumnGroups.keys()); - const sortedKeys = arrayofKeys.sort(); + const sortedKeys = pivotNumbers ? arrayofKeys.sort((n1: FieldResult, n2: FieldResult) => toNumber(n1)! - toNumber(n2)!) : arrayofKeys.sort(); const clusterSize = Math.ceil(pivotColumnGroups.size / 10); const numClusters = Math.ceil(sortedKeys.length / clusterSize); for (let i = 0; i < numClusters; i++) { @@ -135,7 +143,7 @@ export function computePivotLayout( const expander = 1.05; const gap = .15; let x = 0; - const sortedPivotKeys = Array.from(pivotColumnGroups.keys()).sort(); + const sortedPivotKeys = pivotNumbers ? Array.from(pivotColumnGroups.keys()).sort((n1: FieldResult, n2: FieldResult) => toNumber(n1)! - toNumber(n2)!) : Array.from(pivotColumnGroups.keys()).sort(); sortedPivotKeys.forEach(key => { const val = pivotColumnGroups.get(key)!; let y = 0; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1b54a92eb..e16f4011e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -301,25 +301,6 @@ export class MarqueeView extends React.Component { const bounds = this.Bounds; - const defaultPalette = ["rgb(114,229,239)", "rgb(255,246,209)", "rgb(255,188,156)", "rgb(247,220,96)", "rgb(122,176,238)", - "rgb(209,150,226)", "rgb(127,235,144)", "rgb(252,188,189)", "rgb(247,175,81)",]; - const colorPalette = Cast(this.props.Document.colorPalette, listSpec("string")); - if (!colorPalette) this.props.Document.colorPalette = new List(defaultPalette); - const palette = Array.from(Cast(this.props.Document.colorPalette, listSpec("string")) as string[]); - const usedPaletted = new Map(); - [...this.props.activeDocuments(), this.props.Document].map(child => { - const bg = StrCast(Doc.Layout(child).backgroundColor); - if (palette.indexOf(bg) !== -1) { - palette.splice(palette.indexOf(bg), 1); - if (usedPaletted.get(bg)) usedPaletted.set(bg, usedPaletted.get(bg)! + 1); - else usedPaletted.set(bg, 1); - } - }); - usedPaletted.delete("#f1efeb"); - usedPaletted.delete("white"); - usedPaletted.delete("rgba(255,255,255,1)"); - const usedSequnce = Array.from(usedPaletted.keys()).sort((a, b) => usedPaletted.get(a)! < usedPaletted.get(b)! ? -1 : usedPaletted.get(a)! > usedPaletted.get(b)! ? 1 : 0); - const chosenColor = (usedPaletted.size === 0) ? "white" : palette.length ? palette[0] : usedSequnce[0]; // const inkData = this.ink ? this.ink.inkData : undefined; const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument; const newCollection = creator(selected, { @@ -327,8 +308,8 @@ export class MarqueeView extends React.Component Date: Sun, 16 Feb 2020 22:59:36 -0500 Subject: fixed warnings --- src/Utils.ts | 4 +- src/client/util/RichTextRules.ts | 2 +- src/client/views/DocumentButtonBar.tsx | 1 - src/client/views/DocumentDecorations.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionSchemaHeaders.tsx | 4 +- .../views/collections/CollectionViewChromes.tsx | 2 +- .../CollectionFreeFormLayoutEngines.tsx | 38 ++++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../caption_toggle/DetailedCaptionToggle.tsx | 72 ---------------------- .../document_templates/image_card/ImageCard.tsx | 15 ----- .../views/nodes/ContentFittingDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 7 +-- src/new_fields/util.ts | 2 +- 17 files changed, 38 insertions(+), 125 deletions(-) delete mode 100644 src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx delete mode 100644 src/client/views/document_templates/image_card/ImageCard.tsx (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 6a0b3fad8..9162771aa 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -495,7 +495,7 @@ export function setupMoveUpEvents( (target as any)._lastX = e.clientX; (target as any)._lastY = e.clientY; e.stopPropagation(); - } + }; const _upEvent = (e: PointerEvent): void => { upEvent(e); if (Math.abs(e.clientX - (target as any)._downX) < 4 || Math.abs(e.clientY - (target as any)._downY) < 4) { @@ -503,7 +503,7 @@ export function setupMoveUpEvents( } document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); - } + }; e.stopPropagation(); document.removeEventListener("pointermove", _moveEvent); document.removeEventListener("pointerup", _upEvent); diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index de0f46202..a4f1ff22c 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -298,5 +298,5 @@ export class RichTextRules { return null; }), ] - } + }; } diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ec1f879c2..5d289c5e5 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -318,7 +318,6 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | const isText = this.view0.props.Document.data instanceof RichTextField; // bcz: Todo - can't assume layout is using the 'data' field. need to add fieldKey to DocumentView const considerPull = isText && this.considerGoogleDocsPull; const considerPush = isText && this.considerGoogleDocsPush; - Doc.UserDoc().pr return
{this.linkButton} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cc7388a61..44e8a3a48 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -109,7 +109,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> UndoManager.RunInBatch(() => selectionTitleFieldKey && SelectionManager.SelectedDocuments().forEach(d => { const value = typeof d.props.Document[selectionTitleFieldKey] === "number" ? +this._accumulatedTitle : this._accumulatedTitle; didAnything = didAnything || d.props.Document[selectionTitleFieldKey] !== value; - Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true) + Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true); }), "title blur"); if (!didAnything) UndoManager.Undo(); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index bf0333d55..902016365 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -434,7 +434,7 @@ export class CollectionDockingView extends React.Component { tab.titleElement[0].size = e.currentTarget.value.length + 1; Doc.SetInPlace(doc, "title", e.currentTarget.value, true); - } + }; tab.titleElement[0].size = StrCast(doc.title).length + 1; tab.titleElement[0].value = doc.title; const gearSpan = document.createElement("span"); diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index 92dc8780e..c585506b3 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -5,11 +5,13 @@ import "./CollectionSchemaView.scss"; import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes } from '@fortawesome/free-solid-svg-icons'; import { library, IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Flyout, anchorPoints } from "../DocumentDecorations"; import { ColumnType } from "./CollectionSchemaView"; import { faFile } from "@fortawesome/free-regular-svg-icons"; import { SchemaHeaderField, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; +const higflyout = require("@hig/flyout"); +export const { anchorPoints } = higflyout; +export const Flyout = higflyout.default; library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index a21e78188..0378c818c 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -179,7 +179,7 @@ export class CollectionViewBaseChrome extends React.Component { this._viewSpecsOpen = false; document.removeEventListener("pointerdown", this.closeViewSpecs); - }; + } @action openDatePicker = (e: React.PointerEvent) => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 671a3e0c4..8132d2f7c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -27,15 +27,15 @@ export interface ViewDefBounds { } export interface PoolData { - x?: number, - y?: number, - z?: number, - zIndex?: number, - width?: number, - height?: number, - color?: string, - transition?: string, - highlight?: boolean, + x?: number; + y?: number; + z?: number; + zIndex?: number; + width?: number; + height?: number; + color?: string; + transition?: string; + highlight?: boolean; } export interface ViewDefResult { @@ -63,16 +63,16 @@ function toLabel(target: FieldResult) { */ function getTextWidth(text: string, font: string): number { // re-use canvas object for better performance - var canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas")); - var context = canvas.getContext("2d"); + const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas")); + const context = canvas.getContext("2d"); context.font = font; - var metrics = context.measureText(text); + const metrics = context.measureText(text); return metrics.width; } -interface pivotColumn { - docs: Doc[], - filters: string[] +interface PivotColumn { + docs: Doc[]; + filters: string[]; } @@ -86,7 +86,7 @@ export function computePivotLayout( viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; - const pivotColumnGroups = new Map, pivotColumn>(); + const pivotColumnGroups = new Map, PivotColumn>(); const pivotFieldKey = toLabel(pivotDoc._pivotField); for (const doc of filterDocs) { @@ -123,7 +123,7 @@ export function computePivotLayout( const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`; const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number); const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1] / 2); - let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1); + const maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1); const colWidth = panelDim[0] / pivotColumnGroups.size; const colHeight = panelDim[1] - max_text; @@ -223,7 +223,7 @@ export function computeTimelineLayout( const findStack = (time: number, stack: number[]) => { const index = stack.findIndex(val => val === undefined || val < x); return index === -1 ? stack.length : index; - } + }; let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq; let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq; @@ -266,7 +266,7 @@ export function computeTimelineLayout( } const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5); - let stacking: number[] = []; + const stacking: number[] = []; let zind = 0; sortedKeys.forEach(key => { if (curTime !== undefined && curTime > prevKey && curTime <= key) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 427a8d9fe..60410544b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -856,7 +856,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); return rangeFilteredDocs; } - childLayoutDocFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null) as Doc; + childLayoutDocFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null); get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; runInAction(() => diff --git a/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx b/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx deleted file mode 100644 index 3aaf4120c..000000000 --- a/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from 'react'; -import { FontStyleProperty, ColorProperty } from 'csstype'; -import { observer } from 'mobx-react'; -import { observable, action, runInAction } from 'mobx'; -import { FormattedTextBox } from '../../nodes/FormattedTextBox'; -import { FieldViewProps } from '../../nodes/FieldView'; - -interface DetailedCaptionDataProps { - captionFieldKey?: string; - detailsFieldKey?: string; -} - -interface DetailedCaptionStylingProps { - sharedFontColor?: ColorProperty; - captionFontStyle?: FontStyleProperty; - detailsFontStyle?: FontStyleProperty; - toggleSize?: number; -} - -@observer -export default class DetailedCaptionToggle extends React.Component { - @observable loaded: boolean = false; - @observable detailsExpanded: boolean = false; - - @action toggleDetails = (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - this.detailsExpanded = !this.detailsExpanded; - } - - componentDidMount() { - runInAction(() => this.loaded = true); - } - - render() { - const size = this.props.toggleSize || 20; - return ( -
- {/* caption */} -
- -
- {/* details */} -
- -
- {/* toggle */} -
- -
-
- ); - } - -} diff --git a/src/client/views/document_templates/image_card/ImageCard.tsx b/src/client/views/document_templates/image_card/ImageCard.tsx deleted file mode 100644 index 868afc423..000000000 --- a/src/client/views/document_templates/image_card/ImageCard.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import * as React from 'react'; -import { FieldViewProps } from '../../nodes/FieldView'; -import { ImageBox } from '../../nodes/ImageBox'; - -export default class ImageCard extends React.Component { - - render() { - return ( -
- -
- ); - } - -} \ No newline at end of file diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 387da88f5..73fe4fb5d 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -55,7 +55,7 @@ export class ContentFittingDocumentView extends React.Component this.scaling; private PanelWidth = () => this.panelWidth; - private PanelHeight = () => this.panelHeight;; + private PanelHeight = () => this.panelHeight; @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); } @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 330410a92..704da3c74 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -271,7 +271,7 @@ export class DocumentView extends DocComponent(Docu } preventDefault && e.preventDefault(); } - }; + } buttonClick = async (altKey: boolean, ctrlKey: boolean) => { const linkDocs = DocListCast(this.props.Document.links); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 30be64040..c2f1c9ac7 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -369,7 +369,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar }, icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar; }, icon: "expand-arrows-alt" }); funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ @@ -1067,7 +1067,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); } - sidebarWidth = () => { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); } + sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0); @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } render() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index a2aec699f..a96a26b61 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -259,7 +259,7 @@ export class PDFBox extends DocAnnotatableComponent if (!this._pdfjsRequested) { this._pdfjsRequested = true; const promise = Pdfjs.getDocument(pdfUrl.url.href).promise; - promise.then(pdf => { runInAction(() => { this._pdf = pdf; console.log("promise"); }) }); + promise.then(action(pdf => { this._pdf = pdf; console.log("promise"); })); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4f50be5b0..a9b8c6bbe 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -127,9 +127,8 @@ export class PDFViewer extends DocAnnotatableComponent this._showWaiting = this._showCover = true); this.props.startupLive && this.setupPdfJsViewer(); this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => { @@ -623,7 +622,7 @@ export class PDFViewer extends DocAnnotatableComponent {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) => - )} + )}
; } overlayTransform = () => this.scrollXf().scale(1 / this._zoomed); diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index ebc0a1272..6d7f6b56e 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -100,7 +100,7 @@ export function makeEditable() { _setter = _setterImpl; } -let layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", +const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { let prop = in_prop; -- cgit v1.2.3-70-g09d2 From e816fa75571e2149bbc946dfddb0ca78cf33ca28 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 19 Feb 2020 14:40:34 -0500 Subject: chome display set to 'none' when not 'enabled'. fixed template expansion bug. --- src/client/views/MainView.tsx | 4 ++-- src/client/views/collections/CollectionView.tsx | 9 ++++----- .../views/collections/CollectionViewChromes.scss | 3 ++- .../views/collections/CollectionViewChromes.tsx | 7 +++++-- src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 21 ++------------------- 6 files changed, 16 insertions(+), 30 deletions(-) (limited to 'src/client/views/collections/CollectionViewChromes.tsx') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1849ec250..cc75a68fe 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -454,11 +454,11 @@ export class MainView extends React.Component { {this.docButtons}
; } - //`${StrCast(sidebar.backgroundColor, this.darkScheme ? "dimGray" : "black")}` }} > + @computed get mainContent() { const sidebar = this.userDoc && this.userDoc.sidebarContainer; return !this.userDoc || !(sidebar instanceof Doc) ? (null) : ( -
+
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 95f9fa62f..157229ec8 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -109,9 +109,6 @@ export class CollectionView extends Touchable { return viewField; } - // bcz: Argh? What's the height of the collection chromes?? - chromeHeight = () => (this.props.Document._chromeStatus === "enabled" ? -60 : 0); - active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0; whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); }; @@ -128,15 +125,17 @@ export class CollectionView extends Touchable { @action.bound removeDocument(doc: Doc): boolean { + const targetDataDoc = this.props.Document[DataSym]; const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); + const value = DocListCast(targetDataDoc[this.props.fieldKey]); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); ContextMenu.Instance.clearItems(); if (index !== -1) { value.splice(index, 1); + targetDataDoc[this.props.fieldKey] = new List(value); return true; } return false; @@ -162,7 +161,7 @@ export class CollectionView extends Touchable { } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - const props: SubCollectionViewProps = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" }; + const props: SubCollectionViewProps = { ...this.props, ...renderProps, CollectionView: this, annotationsKey: "" }; switch (type) { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index 517f467b7..0c96a662c 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -2,7 +2,8 @@ @import '~js-datepicker/dist/datepicker.min.css'; .collectionViewChrome-cont { - position: relative; + position: absolute; + width:100%; opacity: 0.9; z-index: 9001; transition: top .5s; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 0378c818c..49a9e8200 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -257,6 +257,8 @@ export class CollectionViewBaseChrome extends React.Component { + const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + if (collapsed) return null; switch (this.props.type) { case CollectionViewType.Stacking: return (); case CollectionViewType.Schema: return (); @@ -368,7 +370,7 @@ export class CollectionViewBaseChrome extends React.Component -
+
-
+
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ba09a02a3..bb421d315 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -96,7 +96,7 @@ export class ImageBox extends DocAnnotatableComponent, childDoc: Doc) { const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym]; - const resolvedDataDoc = existingResolvedDataDoc || (containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); + const resolvedDataDoc = existingResolvedDataDoc || (Doc.AreProtosEqual(containerDataDoc, containerDoc) || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc); return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } - export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { - let proto: Doc | undefined = doc; - while (proto && !Doc.IsPrototype(proto) && proto.proto) { - proto = proto.proto; - } - let docExtensionForField = ((proto || doc)[fieldKey + "_ext"] as Doc); - if (!docExtensionForField) { - docExtensionForField = new Doc(doc[Id] + fieldKey, true); - docExtensionForField.title = fieldKey + ".ext"; // courtesy field--- shouldn't be needed except maybe for debugging - docExtensionForField.extendsDoc = doc; // this is used by search to map field matches on the extension doc back to the document it extends. - docExtensionForField.extendsField = fieldKey; // this can be used by search to map matches on the extension doc back to the field that was extended. - docExtensionForField.type = DocumentType.EXTENSION; - (proto || doc)[fieldKey + "_ext"] = new PrefetchProxy(docExtensionForField); - } - return docExtensionForField; - } export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { Object.keys(doc).forEach(key => { -- cgit v1.2.3-70-g09d2